debug

site変数

site = 
{
  "categories": {
  },
  "collections": [
    {
      "directory": "/github/workspace/_posts",
      "files": [

      ],
      "relative_directory": "_posts",
      "output": true,
      "docs": [
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>python の async/await</title>\n  </head>\n  <body>\n    <header>\n      <h1>python の async/await</h1>\n      <p>python の async/awaitってどう動くんだっけ?</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h2 id=\"python-の-asyncawaitってどう動くんだっけ\">python の async/awaitってどう動くんだっけ?</h2>\n\n<p>と思ったので、ちょっとテストプログラムを書いて試してみた。</p>\n\n<p>asyncioはnon-preemptiveなので、最近のpreemptiveに慣れ切った脳ミソにはややこしい。</p>\n\n<p>preemptiveなプログラムを書きたければ、threadingを使えば良い。適材適所というやつだ。</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">asyncio</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n\n<span class=\"n\">argvs</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span>  <span class=\"c1\"># コマンドライン引数を格納したリストの取得\n</span><span class=\"n\">argc</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">)</span> <span class=\"c1\"># 引数の個数\n</span>\n<span class=\"k\">if</span> <span class=\"n\">argc</span> <span class=\"o\">></span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"mi\">5</span>        <span class=\"c1\"># テストケース\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"testCase = \"</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">testCase</span><span class=\"p\">))</span>\n\n<span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>           <span class=\"c1\"># 念のため宣言だけしておく\n</span>\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">sub</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub start        \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub wakeup       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"mi\">42</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"n\">task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">sub</span><span class=\"p\">())</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"k\">await</span> <span class=\"n\">task</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">task</span>\n    \n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main wakeup      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main2</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 start      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 wakeup     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n\n<span class=\"c1\"># =============================================================================\n</span><span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>     <span class=\"c1\"># 開始時刻を記憶\n</span><span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">or</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">4</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">wait</span><span class=\"p\">([</span><span class=\"n\">main</span><span class=\"p\">(),</span> <span class=\"n\">main2</span><span class=\"p\">()]))</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">5</span> <span class=\"p\">:</span>\n    <span class=\"n\">loop</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">get_event_loop</span><span class=\"p\">()</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"unknown test case!!\"</span><span class=\"p\">)</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n\n<p>以下のようにコマンドラインからテストケース番号を指定して実行する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python test.py <testCase>\n</code></pre></div></div>\n\n<h2 id=\"実行結果\">実行結果</h2>\n<h3 id=\"testcase1\">testCase=1</h3>\n\n<p>基本的なパターン、というか、全然非同期実行になってないけど。。。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code>→ <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p>awaitが付いていると、その場でタスクに実行権を渡し、そのタスクが終了するまで待つ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 1\ntestCase <span class=\"o\">=</span>  1\nbefor create     0.00026416778564453125\nafter create     0.00034689903259277344\nbefor call       0.00040340423583984375\nsub start        0.00047469139099121094\nsub wakeup       2.0033931732177734\nafter call       2.0035252571105957\nmain wakeup      3.004753351211548\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase2\">testCase=2</h3>\n\n<p>基本的なパターン、こっちが非同期実行として本命。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code>を実行するときに<code class=\"language-plaintext highlighter-rouge\">await</code>を付けない。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">await</code>が付いていないと、その場でタスクに実行権を渡さず、自分の実行を中断する部分か終了するまでそのまま実行する。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> 呼び出し箇所では即時実行されず、sleep(2)で <code class=\"language-plaintext highlighter-rouge\">main</code> の実行が中断されたところで <code class=\"language-plaintext highlighter-rouge\">sub</code> へ切り替わる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> で <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> が実行されると実行されるタスクがなくなるので、イベントループは実行可能タスク待ちになる。</p>\n\n<p>1秒後、<code class=\"language-plaintext highlighter-rouge\">main</code> が起床するので、そのままmainが終了される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> で イベントループは <code class=\"language-plaintext highlighter-rouge\">main</code> の終了を待っているので、<code class=\"language-plaintext highlighter-rouge\">sub</code> が実行中でも無関係にイベントループを終了してしまい、\n <code class=\"language-plaintext highlighter-rouge\">sub</code> の残りは実行されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 2\ntestCase <span class=\"o\">=</span>  2\nbefor create     0.0002646446228027344\nafter create     0.00034308433532714844\nbefor call       0.00039768218994140625\nafter call       0.0004489421844482422\nsub start        0.0005385875701904297\nmain wakeup      1.0014407634735107\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase3\">testCase=3</h3>\n\n<p>testCase=2 でsubの残りも実行するには?と思って試したパターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で、即座に <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main2())</code> を実行してみた。</p>\n\n<p>見事失敗。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→ <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p>どうやら、 <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で イベントループは一旦 <code class=\"language-plaintext highlighter-rouge\">close</code> されてしまうらしい。</p>\n\n<p>単にtestCase=2の後ろにmain2の実行を付け加えただけになってしまった。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 3\ntestCase <span class=\"o\">=</span>  3\nbefor create     0.00029540061950683594\nafter create     0.0003790855407714844\nbefor call       0.0004353523254394531\nafter call       0.00048828125\nsub start        0.0005817413330078125\nmain wakeup      1.0015552043914795\nmain2 start      1.0021519660949707\nmain2 wakeup     4.0038042068481445\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase4\">testCase=4</h3>\n\n<p>testCase=3 の失敗挽回パターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でmainとmain2をまとめてみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でまとめたタスクがすべて終了するまでイベントループは<code class=\"language-plaintext highlighter-rouge\">close</code> されないので、<code class=\"language-plaintext highlighter-rouge\">sub</code>は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> と <code class=\"language-plaintext highlighter-rouge\">main2</code> のどちらが先に実行されるかは規定されていない様子。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 4\ntestCase <span class=\"o\">=</span>  4\nmain2 start      0.0003325939178466797\nbefor create     0.0004305839538574219\nafter create     0.0005018711090087891\nbefor call       0.0005679130554199219\nafter call       0.0006389617919921875\nsub start        0.0007307529449462891\nmain wakeup      1.002068042755127\nsub wakeup       2.002253293991089\nmain2 wakeup     3.003903388977051\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase5\">testCase=5</h3>\n\n<p>testCase=3 の失敗挽回パターン その2。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.get_event_loop()</code> でイベントループを取得し、<code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> でそれぞれのタスクを実行してみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> → イベントループ終了\nとなっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> ではタスクが終了してもイベントループはcloseされないので、同じイベントループで<code class=\"language-plaintext highlighter-rouge\">main2</code>が実行される。\n結果、<code class=\"language-plaintext highlighter-rouge\">sub</code> は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> が終了するまで <code class=\"language-plaintext highlighter-rouge\">main2</code> は実行(起動)されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 5\ntestCase <span class=\"o\">=</span>  5\nbefor create     0.0002574920654296875\nafter create     0.0003345012664794922\nbefor call       0.00038933753967285156\nafter call       0.0004410743713378906\nsub start        0.0005307197570800781\nmain wakeup      1.0010528564453125\nmain2 start      1.0011804103851318\nsub wakeup       2.002350330352783\nmain2 wakeup     4.002865314483643\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 18.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 18.04のインストール</h1>\n      <p>Ubuntu 18.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Facebook noteに書いておいたら、消されちゃったみたいなので、メモから再度作成<br />\nメモから書き起こしているので、細かいところが違うかも。<br />\n最新版では変更されている箇所があるかも。</p>\n\n<p>VirtualBox へのインストール前提で書いてます。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-1804-インストール媒体の入手\">Ubuntu 18.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら</p>\n\n<p><a href=\"https://www.ubuntulinux.jp/download)\">https://www.ubuntulinux.jp/download)</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを2048MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシーを選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"nb\">sudo </span>apt dist-upgrade <span class=\"o\">(</span>必要なら<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが</p>\n\n<h4 id=\"amazonなんちゃらのやつ\">amazonなんちゃらのやつ</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove ubuntu-web-launchers\n</code></pre></div></div>\n\n<h4 id=\"ツール類\">ツール類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n</code></pre></div></div>\n\n<h4 id=\"ゲーム類\">ゲーム類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h4 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-panel\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n一旦再起動して<br />\nサインインボタン横の歯車ボタンで「GNOME Flashback (Metacity)」を選択してログインする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!IMPORTANT]\n「GNOME Flashback(Compiz)」だとうまく動かない。<br />\n以前はログアウトだけで良かったはずなんだけど、<br />\n再起動しないとダメみたい</p>\n</blockquote>\n\n<h4 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h4>\n<blockquote>\n  <p>[!TIP]\n端末を起動し、メニューの「編集」→「Preferences」を選択<br />\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\nCustom font にチェックを入れ、その右側でフォントを選ぶ<br />\n    Ubuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n</blockquote>\n\n<h4 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj\n<span class=\"nb\">sudo mkdir</span> /work1\n<span class=\"nb\">sudo mkdir</span> /work2\n<span class=\"nb\">sudo mkdir</span> /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h4 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h4>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h4 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h4 id=\"bashの設定変更\">bashの設定変更</h4>\n<p>~/.bashrcに以下を追記</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n</code></pre></div></div>\n\n<h4 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/metacity/edge-tiling                false<br />\n       /org/gnome/mutter/edge-tiling                  false<br />\n       /org/gnome/shell/overrides/edge-tiling         false</p>\n</blockquote>\n\n<h4 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferences/auto-rise             false<br />\n       /org/gnome/descktop/wm/preferences/focus-mode            sloppy or mouse<br />\n       /org/gnome/descktop/wm/preferences/rise-on-click         true</p>\n</blockquote>\n\n<h4 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/nautilus/desktop/trash-icon-visible         false<br />\n       /org/gnome/nautilus/desktop/home-icon-visible          false</p>\n</blockquote>\n\n<h4 id=\"日本語入力\">日本語入力</h4>\n<ul>\n  <li>右上のJaまたはMoと書かれたアイコンをクリック→テキスト入力設定を選択</li>\n  <li>インストールされている言語の管理をクリック</li>\n  <li>「言語サポートが完全にはインストールされていません」と出るので<br />\n「インストール」をクリック</li>\n  <li>一旦log offして再log in</li>\n  <li>右上のJaまたはMoと書かれたアイコンをクリック\n    <ul>\n      <li>Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)</li>\n    </ul>\n  </li>\n  <li>キーボードの全角/半角キーで切り替えられるようになる</li>\n</ul>\n\n<h4 id=\"sambaのインストール\">sambaのインストール</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h4 id=\"nfsのインストール\">NFSのインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h4 id=\"apache-のインストール\">apache のインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>apache2\n<span class=\"nb\">mkdir</span> /proj/wwwroot\n</code></pre></div></div>\n\n<p>/etc/apache2/apache2.conf に以下を追加<br />\n<Directory ~と書いてあるところがあるので、その並びに追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><Directory /proj/wwwroot/>\n    Options Indexes FollowSymLinks\n    AllowOverride None\n    Require all granted\n</Directory>\n</code></pre></div></div>\n\n<p>/etc/apache2/sites-available/000-default.conf の以下を修正</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>DocumentRoot /proj/wwwroot\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/apache2 restart\n</code></pre></div></div>\n\n<h3 id=\"以上でインストールは終了\">以上でインストールは終了</h3>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hosts は書き換えられないので、手動で書き換える</p>\n</blockquote>\n\n<p>IPアドレスの変更(固定アドレスにしたい場合)</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのインストール</h1>\n      <p>pyenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>システムのpythonのバージョンを変更したり、モジュールの変更をしたりするとシステム上のスクリプトの動作に影響が出る場合があるので、pyenvで個別のpython環境を構築するのがベター。<br />\nさらに、virtualenvプラグインを使うと、同じpythonのバージョンでもそれぞれに別のモジュールをインストールできる、仮想環境を構築できる。</p>\n\n<p>なお、pyenvはpythonをバイナリインストールできなくて、ソースからコンパイルするので、インストールにはそれなりに時間がかかる(RasPi2で1~2時間くらい?)。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<h3 id=\"必要なモジュールをインストール\">必要なモジュールをインストール</h3>\n<p>インストールに必要なモジュールをインストールする。</p>\n<ul>\n  <li>Bullseye以降ではこちら<br />\n(<code class=\"language-plaintext highlighter-rouge\">python-openssl</code> →  <code class=\"language-plaintext highlighter-rouge\">python3-openssl</code>)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>Buster以前ではこちら\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"bluetoothを使用する場合\">bluetoothを使用する場合</h3>\n<p>bluetoothを使用する場合は以下も必要</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以前、 ubuntuの場合は以下と書いていたが、<code class=\"language-plaintext highlighter-rouge\">libbluetooth3-dev</code>は<code class=\"language-plaintext highlighter-rouge\">libbluetooth-dev</code>の別名定義だったので上のコマンドでOKのはず。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth3-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"pyenv本体とvirtualenvプラグインのインストール\">pyenv本体とvirtualenvプラグインのインストール</h2>\n\n<p>pyenv本体とvirtualenvプラグインをインストール。<br />\nついでにupdateプラグインも入れとく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>pyenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n<span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>Raspbianでは以下も追加<br />\nnumpyをimportしたとき、undefined symbol: PyFPE_jbuf でエラーになる対策。<br />\n参考: <a href=\"https://research.itplants.com/?p=2437\">https://research.itplants.com/?p=2437</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"--enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-fpectl\"</span>\n</code></pre></div></div>\n\n<p>Ubuntuでは以下を追加しておく(デフォルトだとShared Library のimportでエラーになる)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h2 id=\"sudoでpyenv環境を実行するように設定する\">sudoでpyenv環境を実行するように設定する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo</code>でpythonを実行すると、pyenvの設定に関係なくsystemのpythonが実行されてしまいます。<br />\nこれを防ぐためには、<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers</code>の<code class=\"language-plaintext highlighter-rouge\">Defaults secure_path</code>に以下のpathを追加します。</p>\n\n<ul>\n  <li>«pyenvインストール先»/plugins/pyenv-virtualenv/shims:</li>\n  <li>«pyenvインストール先»shims:</li>\n  <li>«pyenvインストール先»/bin:</li>\n</ul>\n\n<p>具体的には以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 変更前\nDefaults  secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n    ↓\n# 変更後\nDefaults  secure_path=\"/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n</code></pre></div></div>\n<ul>\n  <li></li>\n</ul>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"pyenvでインストールできるバージョンの一覧を表示\">pyenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span> \n</code></pre></div></div>\n\n<h3 id=\"pythonのインストール\">pythonのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.4\n</code></pre></div></div>\n\n<p>・・・ 気長に待つ。 ・・・</p>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global 3.6.4\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-V</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境の構築\">仮想環境の構築</h3>\n\n<p>色々試したあとに、インストールしたモジュールをチャラにしたいときを考えて、仮想環境を構築しておく。<br />\nここでは、python 3.6.4を使用して 仮想環境名 mypython を作成。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.6.4 mypython\n</code></pre></div></div>\n\n<p>デフォルトをmypythonに変更する場合は以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global mypython\n</code></pre></div></div>\n\n<h3 id=\"pipのバージョンアップ\">pipのバージョンアップ</h3>\n\n<p>「pipが古い~」と言われる前にバージョンアップ。ついでにsetuptoolsとwheelも。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n<blockquote>\n  <p>[!IMPORTANT]\nベース環境をバージョンアップしても、仮想環境に引き継がれないので、仮想環境毎に実行が必要。</p>\n</blockquote>\n\n<h3 id=\"ローカルバージョンの設定\">ローカルバージョンの設定</h3>\n\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは3.4.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">local</span> <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"i2cを使用する場合raspi\">I2Cを使用する場合(RasPi)</h1>\n\n<p>RaspberryPi環境で、I2Cを使うためのsmbusモジュールは、通常 <code class=\"language-plaintext highlighter-rouge\">sudo apt install python3-smbus</code> でインストールするが、これだとpyenv環境にインストールできない。<br />\nこれはsmbus2をインストールして使用することで回避できる。\nインストールは以下のように実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>smbus2\n</code></pre></div></div>\n<p>ちなみに、pyenv 環境へのモジュールのインストールには <code class=\"language-plaintext highlighter-rouge\">sudo</code> は不要。/usr 下へのインストールではないので。</p>\n\n<p>で、プログラムソース側はsmbusのインストール部分を以下のように修正。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus</span>\n<span class=\"k\">except</span> <span class=\"nb\">ImportError</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus2</span> <span class=\"k\">as</span> <span class=\"n\">smbus</span>\n</code></pre></div></div>\n\n<p>smbus2 だけにしても良いけど、smbus でも動作できるようにしておくのがベターかな。</p>\n\n<h1 id=\"pyenvのバージョンアップ\">pyenvのバージョンアップ</h1>\n<p>pythonの新しいバージョンがリリースされ、それをインストールしたい場合など、pyenvのバージョンアップが必要。<br />\npyenv-updateをインストールしておけば(上記手順でインストール済み)、以下のコマンドですべてのプラグインを含めてバージョンアップしてくれる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv update\n</code></pre></div></div>\n\n<h2 id=\"古い方法\">古い方法</h2>\n<p>pyenv-updateをインストールしていない場合は以下の手順でそれぞれのリポジトリをpullする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit pull\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのpythonを使いたい場合は以下のように実行\">システムのpythonを使いたい場合は以下のように実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv version\n</code></pre></div></div>\n\n<h3 id=\"pyenvでインストールされているpythonのバージョン仮想環境を確認\">pyenvでインストールされているpythonのバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"pyenv自体のバージョン確認\">pyenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"pyenvで使用できるコマンドの確認\">pyenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv commands\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>nodenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>nodenvのインストール</h1>\n      <p>nodenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonのpyenvと同様にNode.jsのバージョン管理システムのnodenvを使用する。<br />\n(両方インストールするくらいならanyenvを使えという説もあるが…)</p>\n\n<p>他にもnvmやnodebrewなんてのもあるらしい。nodenvはディレクトリごとにローカルバージョンを設定できてとても便利なのでおススメ。<br />\nnodeenv(eが2つ)という超マイナーなのもあるけど、間違わないように。</p>\n\n<p>Node.jsはリポジトリにバイナリパッケージが用意されているバージョンはバイナリインストールできる。用意されていないバージョンはソースからコンパイルされるが、必要なライブラリ類のインストールなど必要。ここでは手順は割愛。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>インストールに必要なモジュールをインストールする。インストール済みならスキップして可。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>git\n</code></pre></div></div>\n\n<h2 id=\"nodenv本体のインストール\">nodenv本体のインストール</h2>\n\n<p>nodenv本体をインストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\ngit clone git://github.com/nodenv/nodenv.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/nodenv/node-build.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>nodenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"nodenvでインストールできるバージョンの一覧を表示\">nodenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install</span> <span class=\"nt\">-l</span>\n</code></pre></div></div>\n<p>バイナリインストールできるか確認したい場合は以下。<br />\nバイナリがなければソースからコンパイルされるが、時間がかかるのが嫌な場合に(大抵のバージョンはバイナリが用意されているようだ)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"nt\">-r</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/share/\n<span class=\"c\"># ただし、uname -m が x86_64 | amd64 | i686-64 のときはx64に置き換える</span>\n</code></pre></div></div>\n\n<h3 id=\"nodejsのインストール\">Node.jsのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install </span>10.15.3 \n</code></pre></div></div>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv global 10.15.3\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境について\">仮想環境について</h3>\n\n<p>pyenvと異なり、nodenvは仮想環境をサポートしていない。<br />\nNode.jsはローカルモジュールのインストールが簡単なので、仮想環境を構築しなくても個々のディレクトリでローカルモジュールをインストールすることで仮想環境相当のことが実現できる。</p>\n\n<h3 id=\"npmのバージョンアップ\">npmのバージョンアップ</h3>\n\n<p>「npmが古い~」と言われる前にバージョンアップ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> npm\n</code></pre></div></div>\n\n<h3 id=\"ローカルで使用するバージョンの設定\">ローカルで使用するバージョンの設定</h3>\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは9.11.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">local</span> <バージョン名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv shell <バージョン名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"nodenvのバージョンアップ\">nodenvのバージョンアップ</h1>\n\n<p>Node.jsの新しいバージョンがリリースされ、それをインストールしたい場合など、nodenvのバージョンアップが必要。<br />\n<strong>下記その2の方がおススメ。こっちの手順は参考までに。</strong></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/\ngit pull\n</code></pre></div></div>\n<p>実行後、ターミナルを開きなおす</p>\n\n<h1 id=\"nodenvのバージョンアップ-その2\">nodenvのバージョンアップ その2</h1>\n<p>nodenv-updateをインストールしておけば、<code class=\"language-plaintext highlighter-rouge\">nodenv update</code>を実行するだけですべてのプラグインを含めてバージョンアップしてくれるので、おススメ。インストール方法は下記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/nodenv/nodenv-update.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/nodenv-update\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのnodejsを使いたい場合\">システムのNode.jsを使いたい場合</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv version\n</code></pre></div></div>\n\n<h3 id=\"nodenvでインストールされているnodejsのバージョンを確認\">nodenvでインストールされているNode.jsのバージョンを確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"nodenv自体のバージョン確認\">nodenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"nodenvで使用できるコマンドの確認\">nodenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv commands\n</code></pre></div></div>\n\n<h3 id=\"nodenvのヘルプの表示\">nodenvのヘルプの表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">help</span>\n\n<span class=\"c\"># 各コマンドのヘルプを表示するには以下</span>\nnodenv <span class=\"nb\">help</span> <<span class=\"nb\">command</span><span class=\"o\">></span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 16.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 16.04のインストール</h1>\n      <p>Ubuntu 16.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 16.04 のインストール手順のメモです。<br />\nVirtualBox へのインストール前提で書いてます。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-1604-インストール媒体の入手\">Ubuntu 16.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら</p>\n\n<p><a href=\"http://old-releases.ubuntu.com/releases/16.04.5/\">http://old-releases.ubuntu.com/releases/16.04.5/</a></p>\n\n<p>ファイル一覧の下の方の<br />\n<a href=\"http://old-releases.ubuntu.com/releases/16.04.5/ubuntu-16.04.5-desktop-amd64.iso\">「ubuntu-16.04.5-desktop-amd64.iso」</a><br />\nを選択する</p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを1024MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動し、画面の明るさとロックを選択<br />\n「次の時間アイドル状態が続けば画面をオフにする」を「しない」に設定。<br />\n「ロックする」を「オフ」に設定。</p>\n</blockquote>\n\n<h3 id=\"ap-getよりaptが使いやすい\">ap-getよりaptが使いやすい</h3>\n\n<p>最初から入ってたっけ??<br />\n入ってなかったら以下で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>apt\n</code></pre></div></div>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"nb\">sudo </span>apt dist-upgrade <span class=\"o\">(</span>必要なら<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p>終わったらリブート</p>\n\n<h3 id=\"gccとかmakeとかは最初からインストールされているはず\">gccとかmakeとかは最初からインストールされているはず</h3>\n\n<p>入っていない場合は以下でインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<h4 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h2 id=\"使わないパッケージをアンインストール\">使わないパッケージをアンインストール</h2>\n\n<p>使わないパッケージはディスクの肥やしになるだけでなく、余計なアップデートで時間を食うので、以下の感じでアンインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove <package name>\n</code></pre></div></div>\n<p>インストール済みのパッケージは以下で確認できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--manual-installed</span>\n</code></pre></div></div>\n\n<p>依存関係によってインストールされたパッケージも含めて確認するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span>\n</code></pre></div></div>\n\n<h4 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-panel\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n一旦ログアウトして<br />\nサインインボタン横のUbuntuアイコンで「GNOME Flashback (Compiz)」を選択してログインする<br />\n選択した内容は次回起動時も覚えている。</p>\n</blockquote>\n\n<h4 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h4>\n<blockquote>\n  <p>[!TIP]\n端末を起動し、メニューの「編集」→「設定」を選択<br />\n「プロファイル」タブを選択<br />\n使用中のプロファイル(最初のは「default」)を選択し、「編集」をクリック<br />\n「全般」タブの「フォントを指定する」 にチェックを入れ、その右側でフォントを選ぶ<br />\n        Takao ゴシック Regular あたりがおススメ<br />\nついでに「起動時の端末サイズ」も修正しておくとよい</p>\n</blockquote>\n\n<h4 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj\n<span class=\"nb\">sudo mkdir</span> /work1\n<span class=\"nb\">sudo mkdir</span> /work2\n<span class=\"nb\">sudo mkdir</span> /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h4 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h4>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h4 id=\"bashの設定変更\">bashの設定変更</h4>\n<p>~/.bashrcに以下を追記</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n</code></pre></div></div>\n\n<h4 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>compizconfig-settings-manager \n</code></pre></div></div>\n<p>アプリケーション→システムツール→Preference→CompizeConfigSettingsManager でプログラム起動<br />\nウィンドウ・マネジメントのGridのチェックをはずす</p>\n\n<h4 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferenceを選択<br />\n    auto-rise             false<br />\n    focus-mode            sloppy or mouse<br />\n    rise-on-click         true</p>\n</blockquote>\n\n<h4 id=\"ウィンドウのボタンの位置を右側にする\">ウィンドウのボタンの位置を右側にする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferenceを選択<br />\n    「button-layout」に 「menu:minimize,maximize,close」を設定</p>\n</blockquote>\n\n<h4 id=\"日本語入力\">日本語入力</h4>\n<ul>\n  <li>アプリケーション→システムツール→システム設定→言語サポートを選択</li>\n  <li>「言語サポートが完全にはインストールされていません」と出るので<br />\n「インストール」をクリック</li>\n  <li>一旦ログアウトして再ログイン</li>\n  <li>アプリケーション→システムツール→システム設定→テキスト入力設定を選択</li>\n  <li>入力ソースタブを選択</li>\n  <li>左下の+ボタンを押してMozc(Fcitx)を選択して追加ボタンを押す</li>\n</ul>\n\n<h4 id=\"sambaのインストール\">sambaのインストール</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h4 id=\"nfsのインストール\">NFSのインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認(IPアドレスは環境に合わせて変更してね)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h4 id=\"apache-のインストール\">apache のインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>apache2\n<span class=\"nb\">mkdir</span> /proj/wwwroot\n</code></pre></div></div>\n\n<p>/etc/apache2/apache2.conf に以下を追加<br />\n<Directory ~と書いてあるところがあるので、その並びに追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><Directory /proj/wwwroot/>\n    Options Indexes FollowSymLinks\n    AllowOverride None\n    Require all granted\n</Directory>\n</code></pre></div></div>\n\n<p>/etc/apache2/sites-available/000-default.conf の以下を修正</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>DocumentRoot /proj/wwwroot\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/apache2 restart\n</code></pre></div></div>\n\n<h3 id=\"以上でインストールは終了\">以上でインストールは終了</h3>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"nmcliが入ってなかったら以下でインストール\">nmcliが入ってなかったら以下でインストール</h3>\n\n<p>入ってたか、入れたか、何かの依存関係で入ったか覚えてない…</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>network-manager\n</code></pre></div></div>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hostnameを直接エディタで書き換えても可。</p>\n</blockquote>\n\n<h3 id=\"etchosts-の変更\">/etc/hosts の変更</h3>\n<p>旧ホスト名を「old_hostname」、新しいホスト名を「new_hostname」とした場合、以下のコマンドで書き換えられる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/old_hostname/new_hostname/'</span> /etc/hosts\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nエディタで書き換えても可。/etc/hostsを開いて旧ホスト名を新しいものに書き換える。</p>\n</blockquote>\n\n<h3 id=\"ipアドレスの変更固定アドレスにしたい場合\">IPアドレスの変更(固定アドレスにしたい場合)</h3>\n<blockquote>\n  <p>[!TIP]\nシステム設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん。<br />\nなんかこんな感じ。</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"各接続の設定値の表示\">各接続の設定値の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show  <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n<p>「”有線接続 2”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n<p>「”有線接続 2”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n<p>「”有線接続 3”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h1 id=\"共有フォルダの設定とマウント\">共有フォルダの設定とマウント</h1>\n\n<h2 id=\"virtualboxでの共有フォルダの設定\">VirtualBoxでの共有フォルダの設定</h2>\n\n<ul>\n  <li>仮想マシン→設定で設定ダイアログを表示\n    <ul>\n      <li>「共有フォルダ」で「共有フォルダの追加」ボタンをクリック\n        <ul>\n          <li>「フォルダーのパス」に共有するフォルダを指定</li>\n          <li>「フォルダ名」に名前を付ける(例:Share))</li>\n          <li>その他は空欄のまま</li>\n          <li>「OK」をクリック</li>\n        </ul>\n      </li>\n      <li>「OK」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"マウントポイントの作成\">マウントポイントの作成</h2>\n\n<p>マウントポイントを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /Share\n</code></pre></div></div>\n\n<h2 id=\"手動でマウント\">手動でマウント</h2>\n\n<p>以下のコマンドでマウントできる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> vboxsf Share /Share/\n</code></pre></div></div>\n\n<p>アンマウントするときはこちら。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount /Share/\n</code></pre></div></div>\n\n<h2 id=\"自動でマウント\">自動でマウント</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/fstab</code> に以下の内容を追加。\nこれで、起動時に自動でマウントされる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Share /Share vboxsf defaults 0 0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>rbenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>rbenvのインストール</h1>\n      <p>rbenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonに対するpyenvのようにrubyのバージョンを変更したり、個別にモジュールを管理したりできるrbenvを導入する。<br />\nあと、モジュールをインストールする <code class=\"language-plaintext highlighter-rouge\">gem install</code> に <code class=\"language-plaintext highlighter-rouge\">sudo</code> を付けなくても良いのも地味に便利。<br />\ngemset(pyenvの仮想環境のようなもの)を作って個別にモジュール管理すれば、色々インストールして訳わからん状態になったときでも、一旦チャラにして観光構築をやりなおせる。</p>\n\n<p>なお、rbenvはrubyをバイナリインストールできなくて、ソースからコンパイルするので、インストールにはそれなりに時間がかかる。</p>\n\n<p>以下の手順はUbuntu 16.04で動作確認した。他のバージョンでは、特にインストールの準備に微妙な違いがあるかもしれない。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>インストールに必要なモジュールをインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>git autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev\n</code></pre></div></div>\n\n<h2 id=\"rbenv本体とプラグインのインストール\">rbenv本体とプラグインのインストール</h2>\n\n<p>rbenv本体とプラグインをインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">RBENV_ROOT</span><span class=\"o\">=</span>/proj/.rbenv    <span class=\"c\"># 環境に合わせて修正してね</span>\ngit clone https://github.com/sstephenson/rbenv.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/sstephenson/ruby-build.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/ruby-build\ngit clone git://github.com/jf/rbenv-gemset.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-gemset\ngit clone https://github.com/sstephenson/rbenv-gem-rehash.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-gem-rehash\ngit clone https://github.com/rkh/rbenv-update.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-update\n</code></pre></div></div>\n<p>rbenv-gemset をインストールすることで、個別のモジュール環境を構築できる。pyenvのvirtualenvみたいな感じ。<br />\nrbenv-gem-rehashをインストールすることで、バージョン切り替えやgemのインストールの度にrbenv rehash を実行しなくてもよくなる。<br />\nrbenv-updateをインストールすることで、<code class=\"language-plaintext highlighter-rouge\">rbenv uppppdate</code> でrbenvと各プラグインのアップデートができる。</p>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>rbenvの設定のため、~/.bashrc に以下を追加。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">RBENV_ROOT</span><span class=\"o\">=</span>/proj/.rbenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$RBENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>rbenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h1 id=\"設定と使い方\">設定と使い方</h1>\n\n<h3 id=\"rbenvでインストールできるバージョンの一覧を表示\">rbenvでインストールできるバージョンの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span>\n</code></pre></div></div>\n\n<h3 id=\"rubyのインストール\">rubyのインストール</h3>\n\n<p>インストールしたいバージョンを指定して実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">install </span>2.6.3\n</code></pre></div></div>\n\n<p>・・・ 気長に待つ。 ・・・</p>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<p>デフォルトで使用したいバージョンを指定して実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv global 2.6.3\n</code></pre></div></div>\n\n<p>念のため指定したバージョンが実行されることを確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ruby <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h3 id=\"gemsetの作成\">gemsetの作成</h3>\n\n<p>色々試したあとに、インストールしたモジュールをチャラにしたいときを考えて、gemset(仮想環境みたいなもん)を構築しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset create 《ベースバージョン》 《gemset名》\n</code></pre></div></div>\n\n<p>例えば、ruby 2.6.3 に test1 という名前のgemsetを作成する場合。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset create 2.6.3 test1\n</code></pre></div></div>\n\n<p>gemsetはインストールされた各バージョンに紐づいて作成される。</p>\n\n<h3 id=\"gemsetの設定\">gemsetの設定</h3>\n\n<p>gemsetはディレクトリ毎に指定する。<br />\nカレントディレクトリに設定されたgemset(なければその親、さらに親と探す)と\nカレントのRubyバージョンが使用される。<br />\nカレントのRubyのバージョンに指定されたgemsetが存在しなければ新しくgemsetを作成するが、中身は空。<br />\nなので、gemsetを指定したときは、同時に <code class=\"language-plaintext highlighter-rouge\">rbenv local</code> でローカルバージョンも指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> 《設定したいディレクトリ》\nrbenv <span class=\"nb\">local</span> 《バージョン》\nrbenv gemset init 《gemset名》\n</code></pre></div></div>\n<p>gemset名を省略するとカレントディレクトリ名と同じ名前でgemsetが作成され、そのgemsetに設定される</p>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\nrbenv gemset init test1\n</code></pre></div></div>\n\n<h3 id=\"作成されたgemsetの一覧表示\">作成されたgemsetの一覧表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset list\n</code></pre></div></div>\n<p>こんな感じで表示される。Rubyのバージョンが異なれば同名のgemsetも作成できる。<br />\nただし、中身は別物。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>rbenv gemset list\n2.3.8:\n  test1\n2.6.3:\n  test1\n</code></pre></div></div>\n\n<h3 id=\"カレントディレクトリで有効なgemsetの確認\">カレントディレクトリで有効なgemsetの確認</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset active\n</code></pre></div></div>\n\n<p>ついでにRubyのバージョンも確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv version\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>rbenv gemset active\nenv1 global\n<span class=\"nv\">$ </span>rbenv version\n2.6.3 <span class=\"o\">(</span><span class=\"nb\">set </span>by /*******/.ruby-version<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"gemsetの指定を無効にするにはrbenv-gemsets-ファイルを削除する\">gemsetの指定を無効にするには.rbenv-gemsets ファイルを削除する</h3>\n\n<p>コマンドで指定を無効にできないので、指定ファイルを手動で削除する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> .rbenv-gemsets\n</code></pre></div></div>\n<p>使用するgemsetを変更したい場合、すでにgemset設定済みのディレクトリでは再設定できない。<br />\n一旦gemsetの指定を無効にしてから、再度 <code class=\"language-plaintext highlighter-rouge\">rbenv gemset init ~</code> する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n\n<h3 id=\"gem関連の設定を確認\">gem関連の設定を確認</h3>\n\n<p>gem関連の設定(GEM_PATHSなど)を確認したいときは以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem <span class=\"nb\">env</span>\n</code></pre></div></div>\n<h3 id=\"helpの表示\">helpの表示</h3>\n\n<p>rbenv 全体のヘルプ(コマンドの確認など)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">help</span>\n</code></pre></div></div>\n\n<p>各コマンドのヘルプ(パラメータやオプションの確認など)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">help</span> 《コマンド》\n</code></pre></div></div>\n\n<h1 id=\"メモ\">メモ</h1>\n\n<h3 id=\"rehashについて\">rehashについて</h3>\n\n<p>設定を変えたりした場合は以下を実行する必要があるが、rbenv-gem-rehashをインストールしてあれば必要なタイミングで自動で行われるので不要。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv rehash \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのローカル環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのローカル環境での実行</h1>\n      <p>github pagesをローカル環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行することができる。</p>\n\n<p>以下の手順はUbuntu 16.04で動作確認した。他のバージョンでは、特にインストールの準備に微妙な違いがあるかもしれない。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<p>apt または rbenvでrubyをインストールしておく。</p>\n\n<p>aptの場合は以下(nativeなライブラリを使うので-devパッケージをインストール) 。<br />\nrbenvの場合は<a href=\"/memoBlog/2019/07/07/rbenv.html\">rbenvのインストール</a>参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ruby-dev\n</code></pre></div></div>\n\n<p>bundlerをインストールする。bundlerはNode.jsでいうところのnpmのうち、package.jsonでローカルインストールしたモジュールを管理する部分に相当するもの(かな?)。<br />\naptでrubyをインストールした場合はrootでインストール必要があるので、<code class=\"language-plaintext highlighter-rouge\">sudo</code>を付けて実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem <span class=\"nb\">install </span>bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span>\n</code></pre></div></div>\n\n<p>モジュールをローカルにインストールすることもできる。<br />\nその場合は以下で。<br />\n–pathオプションのパラメータはお好みで変更してちょ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span> <span class=\"nt\">--path</span> gems\n</code></pre></div></div>\n\n<p>このとき、<code class=\"language-plaintext highlighter-rouge\">_config.yml</code>の以下の部分にモジュールのインストール先(上の例では<code class=\"language-plaintext highlighter-rouge\">gems</code>)を追加しておく(追加しないとjekyll実行時にエラーになる)。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<div style=\"text-align: center;\">↓</div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [gems, server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n\n<h2 id=\"サーバ起動\">サーバ起動</h2>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./server.sh\n</code></pre></div></div>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>ブラウザ(firefoxとchromeで動作確認した。IEでは動かない。Edgeはよーわからん)を起動し、サーバを起動しているマシンのport 4000に接続。このとき、ブラウザはサーバと同じマシンである必要はない。</p>\n\n<h2 id=\"サーバの停止\">サーバの停止</h2>\n\n<p>CTRL+cで停止。</p>\n\n<h2 id=\"サーバの-listen-port-の変更\">サーバの listen port の変更</h2>\n\n<p>必要ならサーバの listen port を変更できる。<br />\nserver.sh 内のコマンドの <code class=\"language-plaintext highlighter-rouge\">--port</code> オプションを変更すればOK.</p>\n\n<h1 id=\"ディレクトリ構成\">ディレクトリ構成</h1>\n\n<p>ディレクトリ構成は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── _config.yml                             jekyllの設定ファイル\n├── Gemfile                                 bundlerの管理ファイル\n├── _layouts                                ページレイアウト用HTMLファイル置き場\n│   ├── default.html                           デフォルト使用\n│   ├── toppage.html                           トップページ用\n│   └── debug.html                             デバッグページ用\n│                                                 どのレイアウトを使うかは各MarkdownファイルのFront-matterで指定する\n├── _includes                               共通で使用するレイアウトはここに置いておく\n│   └── footer.html\n├── _posts                                   投稿記事置き場\n│   ├── 2019-06-22-asyncawait.md\n│   ├── ・・・・\n│   └── YYYY-MM-DD-title.md                     ブログの投稿記事  ファイル名は年-月-日-タイトル とする。\n├── _sass                                    sassのインクルードファイルを置いておく\n│   └── _my_theme.scss                          大本のテーマ設定用sassファイル\n├── assets\n│   ├── css\n│   │   ├── jquery.floatingscroll.css      jQuery の floatingscroll プラグインのCSSファイル\n│   │   └── style.scss                     このページのメインのcssになるsassファイル\n│   └── js\n│       ├── jquery.floatingscroll.min.js    jQuery の floatingscroll プラグインのスクリプトファイル\n│       └── main.js                         各ページで実行するjavascriptファイル\n├── index.md                                 トップページ\n├── misc                                     以下にその他のページデータを置く\n│   ├── debug.md\n│   └── sample.md\n├── favicon.ico                              favicon画像\n├── compile.sh                               サイト構築のみ行うスクリプト\n├── server.sh                                サーバ起動用スクリプト(サイト構築も同時に行う)\n└── _site                                    以下にサイト構築データが生成される\n</code></pre></div></div>\n\n<h1 id=\"投稿記事のファイル名\">投稿記事のファイル名</h1>\n\n<p>投稿記事のファイル名は<code class=\"language-plaintext highlighter-rouge\">YYYY-MM-DD-title.拡張子</code>とする。<br />\nそれ以外のファイル名を付けると無視される。</p>\n\n<p>日付、タイトルは後述のFrontMatterに設定があればそちらが優先される。</p>\n\n<h1 id=\"front-matterの構成\">Front Matterの構成</h1>\n\n<p>Front Matterの主な項目は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>---\ntitle: XXXX                タイトル  指定無ければファイル名のタイトル部分が使用される\ndate: 2019-07-07           日付 指定無ければファイル名の日付部分が使用される\ntags: [\"YYY\",\"ZZZ\"]        タグを指定  このタグでトップページでカテゴリを選択できる 大文字/小文字は区別される\nlayout: toppage            使用するレイアウト 指定無ければdefaultが使用される\nexcerpt: xxxxxx            抜粋  トップページのタイトルの下に表示される\n---\n</code></pre></div></div>\n\n<h1 id=\"あとはお好きに変更してちょ\">あとはお好きに変更してちょ</h1>\n\n<p>自分のリポジトリにpushして、そのリポジトリの設定でgithub pagesを有効にすればいっちょ上がり。</p>\n\n<p>ちなみに、ファイルが一つもないリポジトリではgithub pagesを有効にできないので、ダミーでもいいからファイルをpushしてから設定すること。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git + samba環境</title>\n  </head>\n  <body>\n    <header>\n      <h1>git + samba環境</h1>\n      <p>gitのローカルリポジトリをsamba環境で使用する際の注意事項</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>gitのローカルリポジトリをsamba経由で見ると、ファイルのAttributeの実行属性が変更されたと誤検出してしまうことがある。\nそんなときは、以下のコマンドでファイルのAttributeを無視するように設定すれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--unset</span> core.filemode\ngit config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>サーバ側は以下を一回だけ実行しておけばサーバ側でのAttributeの管理は有効になる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<p>意図的に実行属性を設定したい場合などは、サーバ側で<code class=\"language-plaintext highlighter-rouge\">git add</code>する。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのWindows環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのWindows環境での実行</h1>\n      <p>github pagesをWindows環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行できるようにした(<a href=\"/memoBlog/2019/07/17/githubpages.html\">参照</a>)が、\nわざわざUbuntu立ち上げるのが面倒になってきたので、Windows上で実行できるようにしてみた。</p>\n\n<h1 id=\"何はともあれrubyのインストール\">何はともあれRubyのインストール</h1>\n<p>Windows版Rubyをインストールしないとはじまらないので、\n<a href=\"https://www.ruby-lang.org/ja/\">Rubyの総本山</a> から(RubyInstaller のダウンロード](https://rubyinstaller.org/downloads/)\nへ行ってダウンロード。<br />\nWITH DEVKIT を選んでおく方が良いらしい。<br />\nバージョンは最新で良いでしょう(私は Ruby+Devkit 2.6.3-1 (x64) を選びました)。</p>\n\n<p>ダウンロードしたらなんとなーくインストーラ実行して案内にしたがってなんとな~く進んでちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\ngccも要るのかな?Rubyインストール時にMSYS64環境がインストールされるみたいなので、大丈夫かな?<br />\nちなみに、うちの環境はmingw-w64が入ってる。</p>\n</blockquote>\n\n<p>とりあえずbundlerはグローバルに入れとく。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem install bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。<br />\n一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをローカルにインストールする。<br />\nUbuntuみたいにrdenv環境じゃないので、グローバル環境はなるべく汚染したくないので、<code class=\"language-plaintext highlighter-rouge\">--path</code>指定してローカルにインストールする。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div></div>\n\n<p>あるいは、<code class=\"language-plaintext highlighter-rouge\">install.cmd</code>に登録してあるので、そっちを実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRubyのバージョンを変更したり、ディレクトリを移動した場合はgemsディレクトリを削除してから</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div>  </div>\n  <p>を実行する</p>\n</blockquote>\n\n<p>windows対応にあたって、リポジトリの _config.yml と .gitignore は対処済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>サーバ起動</p>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\\server.cmd\n</code></pre></div></div>\n\n<p>もちろん、エクスプローラなどから <code class=\"language-plaintext highlighter-rouge\">server.cmd</code> をダブルクリックして実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこのときのキモ、jekyll実行前に以下を実行してRubyのエンコードをUTF-8に設定している。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>set RUBYOPT=--encoding=UTF-8`  \n</code></pre></div>  </div>\n  <p>これがないとエンコードエラーが発生する。<br />\n環境変数で設定しておけば逐一設定しなくても良いが、どうせcmdファイル書いてあるので、ついでに設定している。</p>\n</blockquote>\n\n<p>firewallが警告を表示するので、許可してちょ。<br />\nまごまごしてるとjekyllがエラー終了しちゃうけど、その後でも許可してしまえば次回からは大丈夫。</p>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>以降は<a href=\"/memoBlog/2019/07/17/githubpages.html\">こっち</a>を見てちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(RaspberryPi編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(RaspberryPi編)</h1>\n      <p>過去のブログ(RaspberryPi編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"センサ接続gpio\">センサ接続/GPIO</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4f2290b79f3005f839afe798c424fadd\">BOSCH 9軸センサ bmx055 ドライバ(Node.js用) </a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/310580fc726f8b2315d2a81486cbe551\">RaspberryPi向けBOSCH 温度/湿度/気圧センサ(BME280)、9軸センサ(加速度/ジャイロ/地磁気)(BMX055)動作確認プログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/dc6f4c0987e462ca94f003b8d20ea456\">RaspberryPi向けGPIO操作テストプログラム</a></li>\n</ol>\n\n<h1 id=\"webサーバ\">WEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/e37a1d11ac25cf7e421f4d6c32d9a03c\">RaspberryPi向けWEBサーバ&センサテストプログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/18ee6da1c77671949e881eb45dda6edf\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/b23849cf9b82b83fe0c2df22836b6c27\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ/ついでに3D姿勢計算もブラウザでやるっちゃ</a></li>\n</ol>\n\n<h1 id=\"もう一つのwebサーバ\">もう一つのWEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/bcaa47ce1b04bd6b8285e553d6fb9f4f\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/11cc216ffde610e26a5b8cd4ee5b599b\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js/webサーバにExpressを使ってサッパリと</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/8179edb10867faf98e233a52965a9e53\">Raspbianのシリアルコンソールでloginするとイケてないのを改善する</a></li>\n</ol>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(Windows編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(Windows編)</h1>\n      <p>過去のブログ(Windows編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"リモートデバッグ\">リモートデバッグ</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4784a559cb0e78d060fe01d69a3c829d\">windowsのVisualStudioCodeでRasPiのNode.jsをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/aed3ddde84d76cca5c5be62df1120f81\">windowsのVisualStudioCodeでRasPiのPythonをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/46e92ee968b99174c1e1fa3199465877\">VisualStudioCodeのリモート開発が使えるようになったらしいので試してみる</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/c9bf43575d8fce47233bf191b21fbaad\">NW.jsによるWebアプリのデスクトップアプリ化</a></li>\n</ol>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その1)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その1)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Intel NCStick用TinyYOLOの<a href=\"http://jellyware.jp/kurage/movidius/c13_tinyyolo_run.html\">解説記事</a>を見かけた。<br />\n<a href=\"https://github.com/movidius/ncappzoo/blob/ncsdk2/caffe/TinyYolo/run.py\">ソース</a>を読んでみたが、\n結構難解で(特にnumpy回り)、自分の鶏頭でも思い出せるように調べた結果をメモしてみた。<br />\nNCStick持ってないから実際に動かしてないけど。。。</p>\n\n<p>リポジトリは <a href=\"https://github.com/movidius/ncappzoo\">https://github.com/movidius/ncappzoo</a> だが、このソースはmasterブランチには存在しない。必ずncsdk2ブランチを選択すること。<br />\n<code class=\"language-plaintext highlighter-rouge\">git clone</code> する場合は要注意。</p>\n\n<p>どっか行っちゃうといけないので、ソースのコピーを<a href=\"TinyYOLO_src\">ここ</a>にも置いておく。</p>\n\n<h1 id=\"モジュールのインポート\">モジュールのインポート</h1>\n\n<p>特に難しいことはしてない。mvncがNCStickのドライバ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">mvnc</span> <span class=\"kn\">import</span> <span class=\"n\">mvncapi</span> <span class=\"k\">as</span> <span class=\"n\">mvnc</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n</code></pre></div></div>\n\n<h1 id=\"ファイル名定義\">ファイル名定義</h1>\n\n<p>13行目<br />\n<code class=\"language-plaintext highlighter-rouge\">input_image_file</code> : ここに書かれたファイルを読み込んで認識する。<br />\n<code class=\"language-plaintext highlighter-rouge\">tiny_yolo_graph_file</code> : ニューラルネットのネットリスト(?)  ニューロンの接続情報と重みが入っていると思われる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">input_image_file</span><span class=\"o\">=</span> <span class=\"s\">'../../data/images/nps_chair.png'</span>\n<span class=\"n\">tiny_yolo_graph_file</span><span class=\"o\">=</span> <span class=\"s\">'./graph'</span>\n</code></pre></div></div>\n\n<h1 id=\"認識用の画像サイズ定義\">認識用の画像サイズ定義</h1>\n\n<p>17行目<br />\nニューラルネットに入力する画像サイズ。任意のサイズの画像をこのサイズにリサイズしてから入力する。<br />\nこのサイズはニューラルネット構築の際に決定された値。Graphファイルに紐づいた値と考えられる。</p>\n\n<p>Grid分割数が7×7で、1Grid当たりの画像サイズが64pixelなので、7×64 = 448 でおのずと決まる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">NETWORK_IMAGE_WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n<span class=\"n\">NETWORK_IMAGE_HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n</code></pre></div></div>\n\n<h1 id=\"ncstickの出力を整理する処理ルーチンfilter_objects\">NCStickの出力を整理する処理ルーチン(filter_objects)</h1>\n\n<p>35行目<br />\n<a href=\"TinyYOLO_2\">別ページ</a></p>\n\n<h1 id=\"重なったボックス情報を削除するためのマスク情報配列を取得get_duplicate_box_mask\">重なったボックス情報を削除するためのマスク情報配列を取得(get_duplicate_box_mask)</h1>\n\n<p>109行目<br />\n<a href=\"TinyYOLO_3\">別ページ</a></p>\n\n<h1 id=\"バウンティングボックス情報の単位変換boxes_to_pixel_units\">バウンティングボックス情報の単位変換(boxes_to_pixel_units)</h1>\n\n<p>129行目<br />\n<a href=\"TinyYOLO_4\">別ページ</a></p>\n\n<h1 id=\"2つのboxの重なり比率を計算get_intersection_over_union\">2つのBOXの重なり比率を計算(get_intersection_over_union)</h1>\n\n<p>163行目<br />\n<a href=\"TinyYOLO_3\">別ページ</a></p>\n\n<h1 id=\"認識結果の表示ルーチンdisplay_objects_in_gui\">認識結果の表示ルーチン(display_objects_in_gui)</h1>\n\n<p>203行目<br />\n<a href=\"TinyYOLO_5\">別ページ</a></p>\n\n<h1 id=\"mainルーチン\">mainルーチン</h1>\n\n<h3 id=\"関数の先頭とオープニングメッセージ\">関数の先頭とオープニングメッセージ</h3>\n\n<p>255行目</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Running NCS Caffe TinyYolo example'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickドライバのオプション設定\">NCStickドライバのオプション設定</h3>\n<p>258行目</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Set logging level to only log errors\n</span>    <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">global_set_option</span><span class=\"p\">(</span><span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">GlobalOption</span><span class=\"p\">.</span><span class=\"n\">RW_LOG_LEVEL</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickの検出とオープン\">NCStickの検出とオープン</h3>\n\n<p>260行目<br />\nなかったらエラー終了。<br />\n複数見つかった場合は最初のものをオープンする。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">devices</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">enumerate_devices</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'No devices found'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"mi\">1</span>\n    <span class=\"n\">device</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Device</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"nb\">open</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h3 id=\"graphファイルの読み込み\">Graphファイルの読み込み</h3>\n\n<p>267行目<br />\n14行目で設定したGraphファイルを読み込んで、NCStickドライバに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\">#Load graph from disk and allocate graph via API\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tiny_yolo_graph_file</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'rb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">graph_from_disk</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Graph</span><span class=\"p\">(</span><span class=\"s\">\"Tiny Yolo Graph\"</span><span class=\"p\">)</span>\n    <span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span> <span class=\"o\">=</span> <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">allocate_with_fifos</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"n\">graph_from_disk</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"入力画像の読み込みと前処理\">入力画像の読み込みと前処理</h3>\n\n<p>276行目</p>\n<ul>\n  <li>13行目で設定した画像ファイルを読み込んむ(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>結果表示用にオリジナルサイズのままコピーを取っておく(<code class=\"language-plaintext highlighter-rouge\">display_image</code>)</li>\n  <li>NCStickに入力する画像サイズにリサイズ(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>各画素の値をfloat32型に変換(<code class=\"language-plaintext highlighter-rouge\">input_image</code>  元データは<code class=\"language-plaintext highlighter-rouge\">int</code>)</li>\n  <li>さらに各画素の値を0.0~1.0に正規化(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>色並びをBGRからRGBに再配列(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">input_image_file</span><span class=\"p\">)</span>\n    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span><span class=\"p\">,</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">INTER_LINEAR</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">divide</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"mf\">255.0</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>  <span class=\"c1\"># convert to RGB\n</span></code></pre></div></div>\n\n<h3 id=\"ncstick-による処理\">NCStick による処理</h3>\n\n<p>284行目<br />\nNCStickに前処理した画像を入力し、計算結果を得る。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">input_image</code>の各要素はfloat32型に変換して入力する。(既に変換済みな気もするが…)<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">input_image</code>そのものの型は <code class=\"language-plaintext highlighter-rouge\">numpy.ndarray</code>。<br />\nニューラルネットの処理本体の処理は実質この2行だけ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Load tensor and get result.  This executes the inference on the NCS\n</span>    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">queue_inference_with_fifo_elem</span><span class=\"p\">(</span><span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span><span class=\"p\">,</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">output</span><span class=\"p\">,</span> <span class=\"n\">userobj</span> <span class=\"o\">=</span> <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">read_elem</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickの出力を整理する\">NCStickの出力を整理する</h3>\n\n<p>288行目<br />\n<code class=\"language-plaintext highlighter-rouge\">filter_objects</code>(35行目)で  NCStickの出力を整理する。<br />\n<a href=\"TinyYOLO_2\">別ページ</a>を参照。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">output.astype(np.float32)</code> : NCStickの出力をfloat32にキャストした配列(1次元)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image.shape[1]     </code> : 画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image.shape[0]     </code> : 画像高(448)</li>\n</ul>\n\n<p>得られるデータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> : 整理された認識結果</li>\n</ul>\n\n<p><code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">filtered_objs</span> <span class=\"o\">=</span> <span class=\"n\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">output</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<h3 id=\"認識結果の表示\">認識結果の表示</h3>\n\n<p>290行目<br />\n<code class=\"language-plaintext highlighter-rouge\">display_objects_in_gui</code> (203行目)で 表示用イメージと整理された認識結果を表示。<br />\n<a href=\"TinyYOLO_5\">別ページ</a>を参照。<br />\nパラメータは<br />\n<code class=\"language-plaintext highlighter-rouge\">display_image</code> : 表示用画像\n<code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> : 整理された認識結果</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Displaying image with objects detected in GUI'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Click in the GUI window and hit any key to exit'</span><span class=\"p\">)</span>\n    <span class=\"c1\">#display the filtered objects/boxes in a GUI window\n</span>    <span class=\"n\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"後片付け\">後片付け</h3>\n\n<p>295行目<br />\n各クローズ処理。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">fifo_in</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Finished'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"mainルーチン呼び出し\">mainルーチン呼び出し</h1>\n\n<p>お約束の処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その2)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ncstickの出力を整理する処理ルーチンfilter_objects\">NCStickの出力を整理する処理ルーチン(filter_objects)</h1>\n\n<p>35行目<br />\nNCStickの生の出力を整理して、各Gridが何と認識したのか整理して出力する。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">inference_result  </code> : NCStickの出力をfloat32にキャストした配列(1次元×要素数1470)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image_width </code> : 画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image_height</code> : 画像高(448)</li>\n</ul>\n\n<p>出力は</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs</code> : 整理された認識結果</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<h2 id=\"各パラメータのサイズ\">各パラメータのサイズ</h2>\n\n<p>37行目<br />\nこのサイズはニューラルネット構築の際に決定された値。<br />\nGraphファイルに紐づいた値と考えられる。<br />\nなので、グローバル変数で定義しておいてパラメータで渡す方が良さそうだが。。。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">num_inference_results </code> :  NCStickの出力のサイズ(1470 : 未使用)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">network_classifications</code> : 各クラスのラベル(認識結果の名称)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">num_classifications  </code> :  その個数(20)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">grid_size             </code> :  画像のGrid分割数(7)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_per_grid_cell   </code> :  各グリッドに割り当てられたバウンティングボックス数(2)</li>\n</ul>\n\n<p>以下は認識結果を整理するためのパラメータ。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">probability_threshold </code> :  認識結果の確率の閾値。これ以下の確率は無視する。</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># the raw number of floats returned from the inference (GetResult())\n</span>    <span class=\"n\">num_inference_results</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># the 20 classes this network was trained on\n</span>    <span class=\"n\">network_classifications</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">\"aeroplane\"</span><span class=\"p\">,</span> <span class=\"s\">\"bicycle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bird\"</span><span class=\"p\">,</span> <span class=\"s\">\"boat\"</span><span class=\"p\">,</span> <span class=\"s\">\"bottle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bus\"</span><span class=\"p\">,</span> <span class=\"s\">\"car\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"cat\"</span><span class=\"p\">,</span> <span class=\"s\">\"chair\"</span><span class=\"p\">,</span> <span class=\"s\">\"cow\"</span><span class=\"p\">,</span> <span class=\"s\">\"diningtable\"</span><span class=\"p\">,</span> <span class=\"s\">\"dog\"</span><span class=\"p\">,</span> <span class=\"s\">\"horse\"</span><span class=\"p\">,</span> <span class=\"s\">\"motorbike\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"person\"</span><span class=\"p\">,</span> <span class=\"s\">\"pottedplant\"</span><span class=\"p\">,</span> <span class=\"s\">\"sheep\"</span><span class=\"p\">,</span> <span class=\"s\">\"sofa\"</span><span class=\"p\">,</span> <span class=\"s\">\"train\"</span><span class=\"p\">,</span><span class=\"s\">\"tvmonitor\"</span><span class=\"p\">]</span>\n\n    <span class=\"n\">probability_threshold</span> <span class=\"o\">=</span> <span class=\"mf\">0.07</span>\n\n    <span class=\"n\">num_classifications</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">network_classifications</span><span class=\"p\">)</span> <span class=\"c1\"># should be 20\n</span>\n    <span class=\"n\">grid_size</span> <span class=\"o\">=</span> <span class=\"mi\">7</span> <span class=\"c1\"># the image is a 7x7 grid.  Each box in the grid is 64x64 pixels\n</span>    <span class=\"n\">boxes_per_grid_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span> <span class=\"c1\"># the number of boxes returned for each grid cell\n</span></code></pre></div></div>\n\n<h2 id=\"すべての確率配列\">すべての確率配列</h2>\n\n<p>55行目<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)×クラス数(20) で、一旦0クリアしておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">all_probabilities</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<h2 id=\"各クラスの確率配列\">各クラスの確率配列</h2>\n\n<p>60行目<br />\n<code class=\"language-plaintext highlighter-rouge\">classification_probabilities</code> : NCStickの出力から各クラスの確率配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×クラス数(20)<br />\n入力側は1次元配列なので、要素 0 ~ 979 (980個 = 7×7×20)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classification_probabilities</span> <span class=\"o\">=</span> \\\n        <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">980</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n    <span class=\"n\">num_of_class_probs</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"各バウンティングボックスの確率配列\">各バウンティングボックスの確率配列</h2>\n\n<p>65行目<br />\n<code class=\"language-plaintext highlighter-rouge\">box_prob_scale_factor</code> : NCStickの出力から各バウンティングボックスの確率配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)<br />\n入力側は1次元配列なので、要素 980 ~ 1077 (98個 = 7×7×2)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_prob_scale_factor</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">980</span><span class=\"p\">:</span><span class=\"mi\">1078</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<h2 id=\"各バウンティングボックスの座標サイズ情報配列\">各バウンティングボックスの座標/サイズ情報配列</h2>\n\n<p>68行目<br />\nNCStickの出力から各バウンティングボックスの座標/サイズ情報配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)×XY幅高さ(4)<br />\n入力側は1次元配列なので、要素 1078 ~ 1469 (392個 = 7×7×2×4)<br />\n<code class=\"language-plaintext highlighter-rouge\">all_boxes</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n      [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n<p>幅と高さがイメージサイズに対する比率の平方根な理由は謎。。。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># get the boxes from the results and adjust to be pixel units\n</span>    <span class=\"n\">all_boxes</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">1078</span><span class=\"p\">:],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>69行目<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_to_pixel_units</code>(129行目)で<br />\n各バウンティングボックスの座標/サイズ情報配列を、入力画像幅(448)、入力画像高(448)、グリッドサイズ(7)からピクセル単位に変換</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">all_boxes</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">boxes_to_pixel_units</code> 実行後の <code class=\"language-plaintext highlighter-rouge\">all_boxes</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n\n<p>これらの配列の再配列のイメージはこんな感じ。<br />\n<img src=\"/memoBlog/misc/TinyYOLO_2_1.png\" alt=\"結果の再配列のイメージ\" /></p>\n\n<p>72行目<br />\n各グリッドに対する各クラスの確率と各バウンティングボックスの確率を乗じてすべての確率配列を生成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities</code> は Grid_Y × Grid_X × BBox × NumClass の4次元配列。<br />\nデータはバウンティングボックスごとの各クラスのスコアを示している。<br />\n(バウンティングボックスの確率 × クラスの確率)<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [     0.5488,     0.7152,     0.6028,     0.5449,     0.4237,     0.6459, ]\n      [     0.4376,     0.8918,     0.9637,     0.3834,     0.7917,     0.5289, ]\n    ]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">for</span> <span class=\"n\">box_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">):</span> <span class=\"c1\"># loop over boxes\n</span>        <span class=\"k\">for</span> <span class=\"n\">class_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">):</span> <span class=\"c1\"># loop over classifications\n</span>            <span class=\"n\">all_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">,</span><span class=\"n\">class_index</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">class_index</span><span class=\"p\">],</span><span class=\"n\">box_prob_scale_factor</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>77行目<br />\nすべての確率のマスク配列<code class=\"language-plaintext highlighter-rouge\">probability_threshold_mask</code>を生成する。<br />\nデータはall_probabilitiesの要素の値がprobability_threshold以上であればTrue、未満ならFalseが入っている。<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [ True, True, True, True, False, True, ]\n      [ False, True, True, False, True, True, ]\n    ]\n    ・・・・\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"o\">>=</span><span class=\"n\">probability_threshold</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">),</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">probability_threshold</span>\n</code></pre></div></div>\n\n<p>78行目<br />\n<code class=\"language-plaintext highlighter-rouge\">box_threshold_mask</code> は 4 × 閾値を超えたスコアの数 の 2次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_boxes</code>、<code class=\"language-plaintext highlighter-rouge\">all_probabilities</code>から有効なデータを取り出すためのマスクデータ。<br />\n<code class=\"language-plaintext highlighter-rouge\">probability_threshold_mask</code>で要素が<code class=\"language-plaintext highlighter-rouge\">true</code>のもの(=ゼロでないもの)のインデックス一覧をに格納する。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[0][n]</code> : n番目の閾値を超えたスコアを持つY方向のグリッド番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[1][n]</code> : n番目の閾値を超えたスコアを持つX方向のグリッド番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[2][n]</code> : n番目の閾値を超えたスコアを持つバウンティングボックス番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[3][n]</code> : n番目の閾値を超えたスコアを持つクラス番号</li>\n</ul>\n\n<p>つまり、<br />\n    <code class=\"language-plaintext highlighter-rouge\">all_boxes[box_threshold_mask[0][n]][box_threshold_mask[1][n]][box_threshold_mask[2][n]]</code><br />\n    <code class=\"language-plaintext highlighter-rouge\">all_probabilities[box_threshold_mask[0][n]][box_threshold_mask[1][n]][box_threshold_mask[2][n]][0または1]</code><br />\nがそれぞれn番目の閾値を超えたスコアを持つバウンティングボックスの座標/大きさ情報とスコア(バウンティングボックスごとのペア)を持つ</p>\n\n<p>データ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [ 0, 0, 0, 0, 0, 0, ・・・・\n  [ 0, 0, 0, 0, 0, 0, ・・・・]\n  [ 0, 0, 0, 0, 0, 1, ・・・・]\n  [ 0, 1, 2, 3, 5, 1, ・・・・]\n]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">nonzero</span><span class=\"p\">(</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">gx_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">gy_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">bb_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">cls_list</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n                        <span class=\"n\">gy_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">gy_list</span><span class=\"p\">,</span>  <span class=\"n\">gy</span><span class=\"p\">)</span>\n                        <span class=\"n\">gx_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">gx_list</span><span class=\"p\">,</span>  <span class=\"n\">gx</span><span class=\"p\">)</span>\n                        <span class=\"n\">bb_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">bb_list</span><span class=\"p\">,</span>  <span class=\"n\">bb</span><span class=\"p\">)</span>\n                        <span class=\"n\">cls_list</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">cls_list</span><span class=\"p\">,</span> <span class=\"n\">cls</span><span class=\"p\">)</span>\n    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">gy_list</span><span class=\"p\">,</span> <span class=\"n\">gx_list</span><span class=\"p\">,</span> <span class=\"n\">bb_list</span><span class=\"p\">,</span> <span class=\"n\">cls_list</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>79行目<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 閾値を超えたスコアの数 × 4 の 2次元配列</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n]</code>    : n番目の閾値を超えたスコアを持つバウンティングボックスの座標/サイズ情報のセット\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][0]</code> : X座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][1]</code> : Y座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][2]</code> : 幅(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][3]</code> : 高さ(pixel単位)</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">((</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">),</span> <span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i0</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span> <span class=\"p\">:</span>\n        <span class=\"n\">box_info</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]]</span>\n        <span class=\"n\">box_info</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">box_info</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n        <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">,</span> <span class=\"n\">box_info</span><span class=\"p\">,</span> <span class=\"n\">axis</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>80行目<br />\n・・・  う~ん ・・・</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p>なんか複雑な式なのでちょっと分割してみる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tmp_data</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">tmp_data</code> は Grid_Y × Grid_X × BBox の3次元配列<br />\nデータは各グリッドにBBoxずつ定義されたバウンティングボックスの各クラスに対するスコアの中から最大値を持つ要素のインデックス(=クラス番号)</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">np.argmax()</code>は配列要素の最大値を取るメソッド。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities[GY][GX][BB][CLS]</code>の4次元配列に対してaxis=3を指定して実行していて、<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities[gy][gx][bb][0~NumCls]</code>の最大値を持つ要素のインデックスを <code class=\"language-plaintext highlighter-rouge\">tmp_data[gy][gx][bb]</code>に格納する</p>\n\n<p>データ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [ 1, 2, ]\n    [ 1, 2, ]\n    [ 3, 1, ]\n    [ 2, 0, ]\n    [ 4, 2, ]\n    [ 2, 4, ]\n    [ 0, 5, ]\n  ]\n  ・・・\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code> は 閾値を超えたスコアの数 の 1次元配列<br />\nデータは各グリッドのスコアが最大のクラス番号を格納した1次元配列\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ 1, 1, 1, 1, ・・・\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tmp_data</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_cell</span><span class=\"p\">),</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">].</span><span class=\"n\">tolist</span><span class=\"p\">()</span>\n                <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">a</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">))</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span>  <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i0</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span> <span class=\"p\">:</span>\n        <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">,</span> <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]])</span>\n</code></pre></div></div>\n\n<p>81行目<br />\n<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code> は 閾値を超えたスコアの数 の 1次元配列。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold[n]</code>    : n番目の閾値を超えたスコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probabilities_above_threshold</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'float'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n                        <span class=\"n\">probabilities_above_threshold</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">,</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>この時点でスコアが閾値を超えたグリッドの情報が</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code></li>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code></li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code></li>\n</ul>\n\n<p>に格納される。これらは 一対一対一 の関係になっている。<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 2次元配列だが、X, Y, WIDTH, HEIGHT のペアの配列と考えればわかりやすい。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above[n]</code>  : n番目の閾値を超えたスコアを持つクラス番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold[n]</code>    : n番目の閾値を超えたスコア</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n]</code>            : n番目の閾値を超えたスコアを持つバウンティングボックスの座標/サイズ情報のセット\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][0]</code>       : X座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][1]</code>       : Y座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][2]</code>       : 幅(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][3]</code>       : 高さ(pixel単位)</li>\n    </ul>\n  </li>\n</ul>\n\n<p>85行目<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort</code> は <code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code> の各要素を降順に並べた際のインデックス番号を取り出した1次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort(~)</code> は 指定された配列 の各要素を昇順に並べた際のインデックス番号を取り出した配列を得るメソッド。<br />\n<code class=\"language-plaintext highlighter-rouge\">[::-1]</code>を付けてあるので降順になる。<br />\nそのままだと<code class=\"language-plaintext highlighter-rouge\">list</code>型になってしまうので、<code class=\"language-plaintext highlighter-rouge\">np.array()</code>で<code class=\"language-plaintext highlighter-rouge\">np.ndarray</code>型に変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">argsort</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argsort</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">))[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>86行目<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort</code>  を使って\n<code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code>、<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code>、<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> から <code class=\"language-plaintext highlighter-rouge\">argsort</code>で示されたインデックスで示された順に取り出す。<br />\n⇒ スコアの降順にそれぞれを並べ変える。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>書き換えるほどでもないので、ま、いっか。</p>\n\n<p>92行目<br />\n<code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code> は <code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> を検索して重なったボックス情報を削除するためのマスク情報配列。<br />\n閾値を超えたスコアの数 の dtype.bool型の1次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">get_duplicate_box_mask()</code> は <a href=\"TinyYOLO_3\">別ページ</a>参照。<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ True, True, False, False, True, ・・・]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 既にスコアの高い順に並べ替えられているので、先頭から検索していって最初の出てきたボックスを優先すれば良い。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">duplicate_box_mask</span> <span class=\"o\">=</span> <span class=\"n\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>95行目<br />\n<code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code>  を使ってそれぞれの配列からダブったデータを削除する。<br />\n<code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code>、<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code>、<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> から <code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code>でTrueの要素だけ取り出す。<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code>は ダブっていない結果の数(最終認識結果の数) × 4 の 2次元配列<br />\nそれ以外は ダブっていない結果の数(最終認識結果の数)の 1次元配列</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>99行目<br />\n最終認識結果をlistにまとめなおしてリターンする。<br />\n<code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classes_boxes_and_probs</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)):</span>\n        <span class=\"n\">classes_boxes_and_probs</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">([</span><span class=\"n\">network_classifications</span><span class=\"p\">[</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]])</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">classes_boxes_and_probs</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その3)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その3)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"重なったボックス情報を削除するためのマスク情報配列を取得get_duplicate_box_mask\">重なったボックス情報を削除するためのマスク情報配列を取得(get_duplicate_box_mask)</h1>\n\n<p>109行目<br />\n重なったボックス情報を削除するためのマスク情報配列を取得する。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_list</code> : バウンティングボックスの座標/サイズ情報のセットの配列<br />\n<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [X座標, Y座標, 幅, 高さ],\n  [X座標, Y座標, 幅, 高さ],\n  ・・・\n]\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>出力は<br />\n重なったボックス情報を削除するためのマスク情報配列。<br />\n閾値を超えたスコアの数 の dtype.bool型の1次元配列。<br />\n出力の配列の構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ True, True, False, False, True, ・・・]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>113行目<br />\n重なっていると判断する重なり比率の閾値</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">max_iou</span> <span class=\"o\">=</span> <span class=\"mf\">0.35</span>\n</code></pre></div></div>\n\n<p>115行目<br />\n重なり判断済みフラグを1で初期化<br />\ndtype=’bool’ で良い気がするが…そうすれば最後のboolへの変換処理が不要になるのに…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">ones</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>117行目<br />\n総当たりチェックを行うためのループ処理<br />\n重なり判断済みフラグが0なら既に重なりBOXとして削除済みなのでスキップ</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n</code></pre></div></div>\n\n<p>120行目<br />\n2つのBOXの重なり比率を計算し、<code class=\"language-plaintext highlighter-rouge\">max_iou</code>より大きければ重なっていると判断する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"k\">if</span> <span class=\"n\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">max_iou</span><span class=\"p\">:</span>\n                <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span>\n</code></pre></div></div>\n<p>123行目<br />\n重なり判断済みフラグをbool型に変換したものを返す</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">filter_iou_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">box_mask</span> <span class=\"o\">></span> <span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">filter_iou_mask</span>\n</code></pre></div></div>\n\n<h1 id=\"2つのboxの重なり比率を計算get_intersection_over_union\">2つのBOXの重なり比率を計算(get_intersection_over_union)</h1>\n\n<p>163行目<br />\nパラメータで与えられる2つのBOXの重なり比率を計算する</p>\n\n<p>パラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_1</code> : ボックス1の座標/サイズ情報</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_2</code> : ボックス2の座標/サイズ情報</li>\n</ul>\n\n<p>各パラメータの配列構成は</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[0]</code> : ボックスのX座標(中心, pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[1]</code> : ボックスのY座標(中心, pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[2]</code> : ボックスの幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[3]</code> : ボックスの高さ(pixel単位)</li>\n</ul>\n\n<p>なお、座標系は  X座標は左端が原点、Y座標は上端が原点</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>166行目<br />\nbox_1 の右端座標 と box_2 の 右端座標 の小さい方 の座標 から<br />\nbox_1 の左端座標 と box_2 の 左端座標 の大きい方 の座標を引く<br />\n    ⇒ 重なっている部分の幅</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">intersection_dim_1</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n</code></pre></div></div>\n\n<p>170行目<br />\nbox_1 の下端座標 と box_2 の下端座標 の小さい方 の座標 から<br />\nbox_1 の上端座標 と box_2 の上端座標 の大きい方 の座標を引く<br />\n    ⇒ 重なっている部分の高さ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">intersection_dim_2</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>173行目<br />\n重なっている部分の幅と高さのどちらかが負数<br />\n    ⇒ 重なっている部分はないので、その面積は0</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">if</span> <span class=\"n\">intersection_dim_1</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">intersection_dim_2</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># no intersection area\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n</code></pre></div></div>\n\n<p>176行目<br />\n重なっている部分の幅と高さのどちらかが正数<br />\n    ⇒ 重なっている部分の面積を計算</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># intersection area is product of intersection dimensions\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span>  <span class=\"n\">intersection_dim_1</span><span class=\"o\">*</span><span class=\"n\">intersection_dim_2</span>\n</code></pre></div></div>\n\n<p>183行目<br />\nbox_1とbox_2の合計面積を計算(box_1の面積 + box_2の面積 - 重なっている部分の面積)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">union_area</span> <span class=\"o\">=</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">intersection_area</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<p>186行目<br />\nbox_1とbox_2の合計面積のうち、重なっている部分の比率を返す。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">iou</span> <span class=\"o\">=</span> <span class=\"n\">intersection_area</span> <span class=\"o\">/</span> <span class=\"n\">union_area</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">iou</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その4)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その4)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"バウンティングボックス情報の単位変換boxes_to_pixel_units\">バウンティングボックス情報の単位変換(boxes_to_pixel_units)</h1>\n\n<p>129行目<br />\n各バウンティングボックスの座標/サイズ情報配列内のデータは各グリッド内の相対位置/相対サイズなので、画像内の座標に変換する。</p>\n\n<p>パラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_list   </code> : 各バウンティングボックスの座標/サイズ情報配列、</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">image_width</code> : 入力画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">image_height</code> : 入力画像高(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">grid_size  </code> : グリッドサイズ(7)<br />\n<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n [\n   [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n   [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n ]\n ・・・\n 同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>変換後の<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>132行目<br />\n定義されたバウンティングボックスの数。<br />\nGraphファイルに紐づいた値と考えられるので、トップレベルで定義しておいた方が分かりやすいと思うのだが。。。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n</code></pre></div></div>\n\n<p>136行目<br />\nグリッド内オフセットから画像内オフセットに変換するための作業用配列を作成。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">)),(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)),(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>う~ん、まとめて書いてあって分かり難いので、分解してみる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">aa</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span>\n    <span class=\"n\">bb</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">aa</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n    <span class=\"n\">cc</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">bb</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">))</span>\n    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">cc</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>としたとき、</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>aa = [\n       [0, 1, 2, 3, 4, 5, 6]\n     ]\nbb = [\n       [0, 1, 2, 3, 4, 5, 6],\n       ・・・\n       同じものがあと13組(合計14組)\n     ]\ncc = [\n       [\n         [0, 1, 2, 3, 4, 5, 6],\n         ・・・\n         同じものがあと6組(合計7組)\n       ],\n       ・・・\n       同じものがあと1組(合計2組)\n     ]\nbox_offset = [\n               [\n                 [0, 0],\n                 [1, 1],\n                 [2, 2],\n                 [3, 3],\n                 [4, 4],\n                 [5, 5],\n                 [6, 6]\n               ],\n               ・・・\n               同じものがあと6組(合計7組)\n             ]\n</code></pre></div></div>\n<p>となる。</p>\n\n<p>139行目<br />\n各グリッドのX座標データにグリッド番号を加算する(画像内絶対位置になる。単位:グリッド)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">box_offset</span>\n</code></pre></div></div>\n\n<p>140行目<br />\n各グリッドのY座標データにグリッド番号を加算する(画像内絶対位置になる。単位:グリッド)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">box_offset</span><span class=\"p\">,(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>141行目<br />\n各グリッドのX座標とY座標データをグリッド数で割る(画像内相対位置になる)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># adjust the lengths and widths\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n</code></pre></div></div>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\">#scale the boxes to the image size in pixels\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n</code></pre></div></div>\n\n<h2 id=\"処理を書き換えてみる\">処理を書き換えてみる</h2>\n<p>なにやら小難しいことをやっているので、実行速度を考えずに分かりやすく書き換えると以下のようになる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units_alt</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>                               <span class=\"c1\"># 定義されたバウンティングボックス数  \n</span>    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>                     <span class=\"c1\"># グリッド縦方向ループ\n</span>        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>                 <span class=\"c1\"># グリッド横方向ループ\n</span>            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>        <span class=\"c1\"># バウンティングボックスループ\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">gx</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span>        <span class=\"c1\"># box_x\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">gy</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span>       <span class=\"c1\"># box_y\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">**</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span>                             <span class=\"c1\"># box_widtn\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">**</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span>                            <span class=\"c1\"># box_height\n</span></code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その5)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その5)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"認識結果の表示ルーチンdisplay_objects_in_gui\">認識結果の表示ルーチン(display_objects_in_gui)</h1>\n\n<p>203行目<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">source_image</code>:入力画像(表示画像)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects</code>:整理された認識結果</li>\n</ul>\n\n<p><code class=\"language-plaintext highlighter-rouge\">filtered_objects</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">source_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objects</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>205行目<br />\n入力画像を表示用に<code class=\"language-plaintext highlighter-rouge\">display_image</code>にコピーする。(もともと入力された<code class=\"language-plaintext highlighter-rouge\">source_image</code>は汚さない。)<br />\n<code class=\"language-plaintext highlighter-rouge\">source_image_width</code>、<code class=\"language-plaintext highlighter-rouge\">source_image_height</code>は入力画像の幅と高さ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n    <span class=\"n\">source_image_width</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">source_image_height</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>209行目<br />\n<code class=\"language-plaintext highlighter-rouge\">NETWORK_IMAGE_WIDTH</code>と<code class=\"language-plaintext highlighter-rouge\">NETWORK_IMAGE_HEIGHT</code> は ニューラルネットに入力した画像サイズ(グローバル変数)。<br />\nどうせなら関数パラメータで渡した方がスマートだと思うが…<br />\n<code class=\"language-plaintext highlighter-rouge\">filtered_objects</code>の各データはこのサイズで定義されているので、表示用に変換するための比率を<code class=\"language-plaintext highlighter-rouge\">x_ratio</code>、<code class=\"language-plaintext highlighter-rouge\">y_ratio</code>として得る。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">x_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_width</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_WIDTH</span>\n    <span class=\"n\">y_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_height</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span>\n</code></pre></div></div>\n\n<p>213行目<br />\nそれぞれのバウンティングボックスに対してのループ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Found this many objects in the image: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)))</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)):</span>\n</code></pre></div></div>\n\n<p>215行目<br />\n認識結果のX座標(中心)、Y座標(中心)、幅、高さを表示用画像のサイズに変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">center_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span> \n        <span class=\"n\">center_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span>\n        <span class=\"n\">half_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n        <span class=\"n\">half_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n</code></pre></div></div>\n\n<p>221行目<br />\nX座標(中心)、Y座標(中心)、幅、高さからX座標(左端)、Y座標(上端)、X座標(右端)、Y座標(右端)に変換。<br />\n表示画像の範囲からはみ出ないように制限処理を付けてある。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">box_left</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">-</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_top</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">-</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_right</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">+</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"n\">source_image_width</span><span class=\"p\">)</span>\n        <span class=\"n\">box_bottom</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">+</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"n\">source_image_height</span><span class=\"p\">)</span>\n\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'box at index '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj_index</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">' is... left: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', top: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_top</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', right: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_right</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', bottom: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_bottom</span><span class=\"p\">))</span>  \n</code></pre></div></div>\n\n<p>229行目<br />\n表示画像にバウンティングボックスの四角を描く。<br />\n色は緑、線幅は2。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">box_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>  <span class=\"c1\"># green box\n</span>        <span class=\"n\">box_thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span> <span class=\"n\">box_bottom</span><span class=\"p\">),</span> <span class=\"n\">box_color</span><span class=\"p\">,</span> <span class=\"n\">box_thickness</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>234行目<br />\n表示画像に認識結果の名称とスコアを書く。<br />\n背景は暗い緑。文字色は白。<br />\n表示位置はバウンティングボックスの上20ピクセルの場所。<br />\nサイズは縦20ピクセル、横バウンティングボックスと同サイズ。<br />\n(バウンティングボックスの上端が20未満の時大丈夫なんだろか?表示が切れるだけ?)<br />\n(バウンティングボックスの右端より認識結果文字列が長いときも?)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">label_background_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">70</span><span class=\"p\">,</span> <span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">70</span><span class=\"p\">)</span> <span class=\"c1\"># greyish green background for text\n</span>        <span class=\"n\">label_text_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>   <span class=\"c1\"># white text\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">20</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"p\">),</span> <span class=\"n\">label_background_color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">' : %.2f'</span> <span class=\"o\">%</span> <span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">5</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"o\">+</span><span class=\"mi\">5</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"n\">label_text_color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>ループはここまで。</p>\n\n<p>239行目<br />\n画像の表示</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">window_name</span> <span class=\"o\">=</span> <span class=\"s\">'TinyYolo (hit key to exit)'</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">display_image</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>242行目<br />\nキー入力待ち。待ち時間は1msec。<br />\n待ち時間内にキーが押されなければ-1が返ってくる。<br />\nキー入力はGUIで表示されたウィンドウにフォーカスが当たっているときのみ有効で、コンソール(ターミナルなど)で入力してもダメ。<br />\n64bitマシンでは、キーコードを使用する場合は値を<code class=\"language-plaintext highlighter-rouge\">& 0xff</code>する必要があるが、入力なしを検出するだけなのでそのままでOK。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"n\">raw_key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>247行目<br />\nウィンドウパラメータの取得。<br />\nウィンドウが閉じられていれば-1.0が返る。表示状態ならウィンドウのアクセプト比が返る。<br />\n×ボタンでウィンドウを閉じたときの対策。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">prop_val</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">getWindowProperty</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">WND_PROP_ASPECT_RATIO</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>247行目<br />\nキー入力があった、または、×ボタンでウィンドウが閉じられたら終了。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">raw_key</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"n\">prop_val</span> <span class=\"o\"><</span> <span class=\"mf\">0.0</span><span class=\"p\">)):</span>\n            <span class=\"c1\"># the user hit a key or closed the window (in that order)\n</span>            <span class=\"k\">break</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Intel NCStick用TinyYOLOの<a href=\"https://github.com/movidius/ncappzoo/blob/ncsdk2/caffe/TinyYolo/run.py\">ソース</a>のコピー</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#! /usr/bin/env python3\n</span>\n<span class=\"c1\"># Copyright(c) 2017 Intel Corporation. \n# License: MIT See LICENSE file in root directory.\n</span>\n<span class=\"kn\">from</span> <span class=\"nn\">mvnc</span> <span class=\"kn\">import</span> <span class=\"n\">mvncapi</span> <span class=\"k\">as</span> <span class=\"n\">mvnc</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n\n\n<span class=\"c1\"># Assume running in examples/caffe/TinyYolo and graph file is in current directory.\n</span><span class=\"n\">input_image_file</span><span class=\"o\">=</span> <span class=\"s\">'../../data/images/nps_chair.png'</span>\n<span class=\"n\">tiny_yolo_graph_file</span><span class=\"o\">=</span> <span class=\"s\">'./graph'</span>\n\n<span class=\"c1\"># Tiny Yolo assumes input images are these dimensions.\n</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n<span class=\"n\">NETWORK_IMAGE_HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n\n\n<span class=\"c1\"># Interpret the output from a single inference of TinyYolo (GetResult)\n# and filter out objects/boxes with low probabilities.\n# output is the array of floats returned from the API GetResult but converted\n# to float32 format.\n# input_image_width is the width of the input image\n# input_image_height is the height of the input image\n# Returns a list of lists. each of the inner lists represent one found object and contain\n# the following 6 values:\n#    string that is network classification ie 'cat', or 'chair' etc\n#    float value for box center X pixel location within source image\n#    float value for box center Y pixel location within source image\n#    float value for box width in pixels within source image\n#    float value for box height in pixels within source image\n#    float value that is the probability for the network classification.\n</span><span class=\"k\">def</span> <span class=\"nf\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># the raw number of floats returned from the inference (GetResult())\n</span>    <span class=\"n\">num_inference_results</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># the 20 classes this network was trained on\n</span>    <span class=\"n\">network_classifications</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">\"aeroplane\"</span><span class=\"p\">,</span> <span class=\"s\">\"bicycle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bird\"</span><span class=\"p\">,</span> <span class=\"s\">\"boat\"</span><span class=\"p\">,</span> <span class=\"s\">\"bottle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bus\"</span><span class=\"p\">,</span> <span class=\"s\">\"car\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"cat\"</span><span class=\"p\">,</span> <span class=\"s\">\"chair\"</span><span class=\"p\">,</span> <span class=\"s\">\"cow\"</span><span class=\"p\">,</span> <span class=\"s\">\"diningtable\"</span><span class=\"p\">,</span> <span class=\"s\">\"dog\"</span><span class=\"p\">,</span> <span class=\"s\">\"horse\"</span><span class=\"p\">,</span> <span class=\"s\">\"motorbike\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"person\"</span><span class=\"p\">,</span> <span class=\"s\">\"pottedplant\"</span><span class=\"p\">,</span> <span class=\"s\">\"sheep\"</span><span class=\"p\">,</span> <span class=\"s\">\"sofa\"</span><span class=\"p\">,</span> <span class=\"s\">\"train\"</span><span class=\"p\">,</span><span class=\"s\">\"tvmonitor\"</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># only keep boxes with probabilities greater than this\n</span>    <span class=\"n\">probability_threshold</span> <span class=\"o\">=</span> <span class=\"mf\">0.07</span>\n\n    <span class=\"n\">num_classifications</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">network_classifications</span><span class=\"p\">)</span> <span class=\"c1\"># should be 20\n</span>    <span class=\"n\">grid_size</span> <span class=\"o\">=</span> <span class=\"mi\">7</span> <span class=\"c1\"># the image is a 7x7 grid.  Each box in the grid is 64x64 pixels\n</span>    <span class=\"n\">boxes_per_grid_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span> <span class=\"c1\"># the number of boxes returned for each grid cell\n</span>\n    <span class=\"c1\"># grid_size is 7 (grid is 7x7)\n</span>    <span class=\"c1\"># num classifications is 20\n</span>    <span class=\"c1\"># boxes per grid cell is 2\n</span>    <span class=\"n\">all_probabilities</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># classification_probabilities  contains a probability for each classification for\n</span>    <span class=\"c1\"># each 64x64 pixel square of the grid.  The source image contains\n</span>    <span class=\"c1\"># 7x7 of these 64x64 pixel squares and there are 20 possible classifications\n</span>    <span class=\"n\">classification_probabilities</span> <span class=\"o\">=</span> \\\n        <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">980</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n    <span class=\"n\">num_of_class_probs</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># The probability scale factor for each box\n</span>    <span class=\"n\">box_prob_scale_factor</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">980</span><span class=\"p\">:</span><span class=\"mi\">1078</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># get the boxes from the results and adjust to be pixel units\n</span>    <span class=\"n\">all_boxes</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">1078</span><span class=\"p\">:],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n    <span class=\"n\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">all_boxes</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># adjust the probabilities with the scaling factor\n</span>    <span class=\"k\">for</span> <span class=\"n\">box_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">):</span> <span class=\"c1\"># loop over boxes\n</span>        <span class=\"k\">for</span> <span class=\"n\">class_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">):</span> <span class=\"c1\"># loop over classifications\n</span>            <span class=\"n\">all_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">,</span><span class=\"n\">class_index</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">class_index</span><span class=\"p\">],</span><span class=\"n\">box_prob_scale_factor</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">])</span>\n\n\n    <span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"o\">>=</span><span class=\"n\">probability_threshold</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">nonzero</span><span class=\"p\">(</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">)</span>\n    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># sort the boxes from highest probability to lowest and then\n</span>    <span class=\"c1\"># sort the probabilities and classifications to match\n</span>    <span class=\"n\">argsort</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argsort</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">))[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n\n\n    <span class=\"c1\"># get mask for boxes that seem to be the same object\n</span>    <span class=\"n\">duplicate_box_mask</span> <span class=\"o\">=</span> <span class=\"n\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># update the boxes, probabilities and classifications removing duplicates.\n</span>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n\n    <span class=\"n\">classes_boxes_and_probs</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)):</span>\n        <span class=\"n\">classes_boxes_and_probs</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">([</span><span class=\"n\">network_classifications</span><span class=\"p\">[</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]])</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">classes_boxes_and_probs</span>\n\n<span class=\"c1\"># creates a mask to remove duplicate objects (boxes) and their related probabilities and classifications\n# that should be considered the same object.  This is determined by how similar the boxes are\n# based on the intersection-over-union metric.\n# box_list is as list of boxes (4 floats for centerX, centerY and Length and Width)\n</span><span class=\"k\">def</span> <span class=\"nf\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">):</span>\n    <span class=\"c1\"># The intersection-over-union threshold to use when determining duplicates.\n</span>    <span class=\"c1\"># objects/boxes found that are over this threshold will be\n</span>    <span class=\"c1\"># considered the same object\n</span>    <span class=\"n\">max_iou</span> <span class=\"o\">=</span> <span class=\"mf\">0.35</span>\n\n    <span class=\"n\">box_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">ones</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">))</span>\n\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">max_iou</span><span class=\"p\">:</span>\n                <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span>\n\n    <span class=\"n\">filter_iou_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">box_mask</span> <span class=\"o\">></span> <span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">filter_iou_mask</span>\n\n<span class=\"c1\"># Converts the boxes in box list to pixel units\n# assumes box_list is the output from the box output from\n# the tiny yolo network and is [grid_size x grid_size x 2 x 4].\n</span><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># number of boxes per grid cell\n</span>    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n\n    <span class=\"c1\"># setup some offset values to map boxes to pixels\n</span>    <span class=\"c1\"># box_offset will be [[ [0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6]] ...repeated for 7 ]\n</span>    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">)),(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)),(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># adjust the box center\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">box_offset</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">box_offset</span><span class=\"p\">,(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># adjust the lengths and widths\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n\n    <span class=\"c1\">#scale the boxes to the image size in pixels\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n\n\n<span class=\"c1\"># Evaluate the intersection-over-union for two boxes\n# The intersection-over-union metric determines how close\n# two boxes are to being the same box.  The closer the boxes\n# are to being the same, the closer the metric will be to 1.0\n# box_1 and box_2 are arrays of 4 numbers which are the (x, y)\n# points that define the center of the box and the length and width of\n# the box.\n# Returns the intersection-over-union (between 0.0 and 1.0)\n# for the two boxes specified.\n</span><span class=\"k\">def</span> <span class=\"nf\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># one diminsion of the intersecting box\n</span>    <span class=\"n\">intersection_dim_1</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># the other dimension of the intersecting box\n</span>    <span class=\"n\">intersection_dim_2</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">intersection_dim_1</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">intersection_dim_2</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># no intersection area\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># intersection area is product of intersection dimensions\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span>  <span class=\"n\">intersection_dim_1</span><span class=\"o\">*</span><span class=\"n\">intersection_dim_2</span>\n\n    <span class=\"c1\"># calculate the union area which is the area of each box added\n</span>    <span class=\"c1\"># and then we need to subtract out the intersection area since\n</span>    <span class=\"c1\"># it is counted twice (by definition it is in each box)\n</span>    <span class=\"n\">union_area</span> <span class=\"o\">=</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">intersection_area</span><span class=\"p\">;</span>\n\n    <span class=\"c1\"># now we can return the intersection over union\n</span>    <span class=\"n\">iou</span> <span class=\"o\">=</span> <span class=\"n\">intersection_area</span> <span class=\"o\">/</span> <span class=\"n\">union_area</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">iou</span>\n\n<span class=\"c1\"># Displays a gui window with an image that contains\n# boxes and lables for found objects.  will not return until\n# user presses a key.\n# source_image is the original image for the inference before it was resized or otherwise changed.\n# filtered_objects is a list of lists (as returned from filter_objects()\n# each of the inner lists represent one found object and contain\n# the following 6 values:\n#    string that is network classification ie 'cat', or 'chair' etc\n#    float value for box center X pixel location within source image\n#    float value for box center Y pixel location within source image\n#    float value for box width in pixels within source image\n#    float value for box height in pixels within source image\n#    float value that is the probability for the network classification.\n</span><span class=\"k\">def</span> <span class=\"nf\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">source_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objects</span><span class=\"p\">):</span>\n    <span class=\"c1\"># copy image so we can draw on it. Could just draw directly on source image if not concerned about that.\n</span>    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n    <span class=\"n\">source_image_width</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">source_image_height</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"n\">x_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_width</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_WIDTH</span>\n    <span class=\"n\">y_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_height</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span>\n\n    <span class=\"c1\"># loop through each box and draw it on the image along with a classification label\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Found this many objects in the image: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)))</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)):</span>\n        <span class=\"n\">center_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span> \n        <span class=\"n\">center_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span>\n        <span class=\"n\">half_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n        <span class=\"n\">half_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n\n        <span class=\"c1\"># calculate box (left, top) and (right, bottom) coordinates\n</span>        <span class=\"n\">box_left</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">-</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_top</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">-</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_right</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">+</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"n\">source_image_width</span><span class=\"p\">)</span>\n        <span class=\"n\">box_bottom</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">+</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"n\">source_image_height</span><span class=\"p\">)</span>\n\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'box at index '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj_index</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">' is... left: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', top: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_top</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', right: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_right</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', bottom: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_bottom</span><span class=\"p\">))</span>  \n\n        <span class=\"c1\">#draw the rectangle on the image.  This is hopefully around the object\n</span>        <span class=\"n\">box_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>  <span class=\"c1\"># green box\n</span>        <span class=\"n\">box_thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span> <span class=\"n\">box_bottom</span><span class=\"p\">),</span> <span class=\"n\">box_color</span><span class=\"p\">,</span> <span class=\"n\">box_thickness</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># draw the classification label string just above and to the left of the rectangle\n</span>        <span class=\"n\">label_background_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">70</span><span class=\"p\">,</span> <span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">70</span><span class=\"p\">)</span> <span class=\"c1\"># greyish green background for text\n</span>        <span class=\"n\">label_text_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>   <span class=\"c1\"># white text\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">20</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"p\">),</span> <span class=\"n\">label_background_color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">' : %.2f'</span> <span class=\"o\">%</span> <span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">5</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"o\">+</span><span class=\"mi\">5</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"n\">label_text_color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n    <span class=\"n\">window_name</span> <span class=\"o\">=</span> <span class=\"s\">'TinyYolo (hit key to exit)'</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">display_image</span><span class=\"p\">)</span>\n\n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"n\">raw_key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># check if the window is visible, this means the user hasn't closed\n</span>        <span class=\"c1\"># the window via the X button (may only work with opencv 3.x\n</span>        <span class=\"n\">prop_val</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">getWindowProperty</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">WND_PROP_ASPECT_RATIO</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">raw_key</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"n\">prop_val</span> <span class=\"o\"><</span> <span class=\"mf\">0.0</span><span class=\"p\">)):</span>\n            <span class=\"c1\"># the user hit a key or closed the window (in that order)\n</span>            <span class=\"k\">break</span>\n\n\n<span class=\"c1\"># This function is called from the entry point to do\n# all the work.\n</span><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Running NCS Caffe TinyYolo example'</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Set logging level to only log errors\n</span>    <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">global_set_option</span><span class=\"p\">(</span><span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">GlobalOption</span><span class=\"p\">.</span><span class=\"n\">RW_LOG_LEVEL</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"n\">devices</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">enumerate_devices</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'No devices found'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"mi\">1</span>\n    <span class=\"n\">device</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Device</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"nb\">open</span><span class=\"p\">()</span>\n\n    <span class=\"c1\">#Load graph from disk and allocate graph via API\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tiny_yolo_graph_file</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'rb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">graph_from_disk</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Graph</span><span class=\"p\">(</span><span class=\"s\">\"Tiny Yolo Graph\"</span><span class=\"p\">)</span>\n    <span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span> <span class=\"o\">=</span> <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">allocate_with_fifos</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"n\">graph_from_disk</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Read image from file, resize it to network width and height\n</span>    <span class=\"c1\"># save a copy in display_image for display, then convert to float32, normalize (divide by 255),\n</span>    <span class=\"c1\"># and finally convert to convert to float16 to pass to LoadTensor as input for an inference\n</span>    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">input_image_file</span><span class=\"p\">)</span>\n    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span><span class=\"p\">,</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">INTER_LINEAR</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">divide</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"mf\">255.0</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>  <span class=\"c1\"># convert to RGB\n</span>\n    <span class=\"c1\"># Load tensor and get result.  This executes the inference on the NCS\n</span>    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">queue_inference_with_fifo_elem</span><span class=\"p\">(</span><span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span><span class=\"p\">,</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">output</span><span class=\"p\">,</span> <span class=\"n\">userobj</span> <span class=\"o\">=</span> <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">read_elem</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># filter out all the objects/boxes that don't meet thresholds\n</span>    <span class=\"n\">filtered_objs</span> <span class=\"o\">=</span> <span class=\"n\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">output</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Displaying image with objects detected in GUI'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Click in the GUI window and hit any key to exit'</span><span class=\"p\">)</span>\n    <span class=\"c1\">#display the filtered objects/boxes in a GUI window\n</span>    <span class=\"n\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objs</span><span class=\"p\">)</span>\n\n    <span class=\"n\">fifo_in</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Finished'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># main entry point for program. we'll call main() to do what needs to be done.\n</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian Busterのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian Busterのインストール</h1>\n      <p>Raspbian Buster with desktopのインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspbian Buster with desktop」 の 「DownloadZIP」でダウンロードしてSDカードに書き込んでブート。<br />\n(「・・・ and recommended software」 の方ではない)<br />\n以下の手順は、RaspberryPi3 model B+、「Version: July 2019」 で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>は表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nframebuffer_width=1920\nframebuffer_height=1080\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B1 Desktop / CLI\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B3 Splash Screen\n            Would you like to show the splash screen at boot? \n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    5 Interfacing Options        \n        P3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>    \n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n<p>Windows側のクライアントは、<br />\n<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a> \nから VNC Viewerをダウンロード。<br />\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。<br />\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。<br />\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。<br />\n日本語化の手順はこちらを参考に。 <a href=\"http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"c\"># export PYENV_ROOT=/proj/.pyenv</span>\n<span class=\"c\"># export PATH=$PYENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(pyenv init -)\"</span>\n<span class=\"c\"># eval \"$(pyenv virtualenv-init -)\"</span>\n\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"c\"># export NODENV_ROOT=/proj/.nodenv</span>\n<span class=\"c\"># export PATH=$NODENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(nodenv init -)\"</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マウスフォーカスの変更\">マウスフォーカスの変更</h1>\n\n<p>ウィンドウをクリックしないとフォーカスが移動しないのはイライラするので x-mouse相当の設定をする。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/xdg/openbox/lxde-pi-rc.xml</code>の以下の部分をnoからyesに変更。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><followMouse>yes</followMouse>\n</code></pre></div></div>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick2用動作環境の構築</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick2用動作環境の構築</h1>\n      <p>Intel NCStick2用動作環境の構築</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Dセンセの悪魔の囁きに踊らされ、Intel NCStick2をポチってしまった。<br />\nで、動作環境を構築したときのメモを残しておく。</p>\n\n<p>ホストマシンは、RaspberryPi3 model B+ で Raspbian Buster を使用。</p>\n\n<p>Raspbian Busterのインストールは、\n<a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\">Raspbian Busterのインストール</a>\nの手順で行った。</p>\n\n<p><a href=\"http://jellyware.jp/openvino/\">JellyWare:ゼロから学ぶディープラーニング推論</a> \n → <a href=\"http://jellyware.jp/kurage/openvino/c03_setting.html\">ゼロから始めるインストール</a> をマネしただけだが、\nダウンロード先の<strong>URLが微妙に変更</strong>されてたり、\nこのページの説明が<strong>細かすぎてちょっとイラっとした</strong>ので、\n以下に手順の要約を書いておく。</p>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2\n<span class=\"nb\">cd</span> /work/NCS2/\n</code></pre></div></div>\n\n<h2 id=\"openvino-の取得とインストール\">openVINO の取得とインストール</h2>\n\n<p>アーカイブファイル落としてきて、展開するだけ。<br />\nR3がリリースされているようなので、これを使う。(2019/10/01現在)\nちょくちょくリリースされるみたいなので、<a href=\"https://download.01.org/opencv/2019/openvinotoolkit/\">https://download.01.org/opencv/2019/openvinotoolkit/</a>をチェックしてね。<br />\n2020年になったら、~download.01.org/opencv/2020/~ なのかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R3/l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz\n\n<span class=\"c\"># インストール先ディレクトリの作成 & オーナー変更(あとあとめんどくさいので)</span>\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span>  <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n\n<span class=\"c\"># 展開</span>\n<span class=\"nb\">tar </span>xzvf l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span> <span class=\"nt\">--strip-components</span><span class=\"o\">=</span>1\n<span class=\"nb\">sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以下以前の情報</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R2/l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz\n\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo tar</span> <span class=\"nt\">-xf</span> l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz <span class=\"nt\">--strip</span> 1 <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h2 id=\"cmakeのインストール\">cmakeのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n</code></pre></div></div>\n\n<p>他にもmakeとかbuild-essentialとか要るけど、<a href=\"/memoBlog/2019/06/27/pyenv.html\">ここ</a>\nでインストールしたやつがあれば大丈夫っぽい。</p>\n\n<h2 id=\"初期化スクリプトの変更\">初期化スクリプトの変更</h2>\n\n<p>~/.bashrc の最後に以下を追加。<br />\nここでは<code class=\"language-plaintext highlighter-rouge\">${VINO_DIR_TMP}</code>使っちゃダメよ~。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOの設定</span>\n<span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<h2 id=\"初期化スクリプトの変更を反映\">初期化スクリプトの変更を反映</h2>\n\n<p>シリアルコンソールやSSHでlog inしてる場合は、ここで一旦log offして再log in。<br />\nX使ってるならターミナル開きなおす。<br />\nもちろん、<code class=\"language-plaintext highlighter-rouge\">source</code>するだけでも良いけど。<br />\nいちお、.bashrcにちゃんと書けてるか確認の意味で一旦log off or ターミナル開きなおしするのがいいかな。  <br />\n(.bashrcの変更だけなので、再起動までは必要ない) <br />\nlog in時 or 新しいターミナルを開いた時に <code class=\"language-plaintext highlighter-rouge\">[setupvars.sh] OpenVINO environment initialized</code> と表示されることを確認。</p>\n\n<h2 id=\"グループの追加\">グループの追加</h2>\n\n<p>ユーザがグループusersを持っているか確認。(デフォルトなら持ってるハズ) 持ってなかったら追加。<br />\n次のコマンドで追加してくれるっぽいけど。。。</p>\n\n<h2 id=\"udevルールの追加\">udevルールの追加</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sh <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n\n<h2 id=\"いよいよncstick2の登場だ\">いよいよNCStick2の登場だ~~~</h2>\n\n<p>NCStick2をUSBポートにぶっ挿す。<br />\nデカくて他のポートに干渉するので、必要なら延長ケーブルを使ってちょ。</p>\n\n<p>で、認識されたか確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n<span class=\"c\"># こんな感じで表示されるハズ。XXX部分は ぶっ挿したUSBポートで変わる。</span>\n・・・\nBus XXX Device XXX: ID 03e7:2485 Intel Movidius MyriadX\n・・・\n</code></pre></div></div>\n\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n\n<p>とりあえず、ワークディレクトリは<code class=\"language-plaintext highlighter-rouge\">/work/NCS2/</code>を使ってる。<br />\nhome に色々ぶち込むの嫌いなので。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">/work</code>は作成済みで<code class=\"language-plaintext highlighter-rouge\">chown</code>済みとする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ワークディレクトリの作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/sample\n<span class=\"nb\">cd</span> /work/NCS2/sample\n\n<span class=\"c\"># cmakeの実行</span>\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a\"</span> <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/deployment_tools/inference_engine/samples\n\n<span class=\"c\"># makeの実行</span>\nmake <span class=\"nt\">-j2</span> object_detection_sample_ssd\n\n<span class=\"c\"># ネットワークデータの取得</span>\n<span class=\"c\"># shell変数の設定時はスペース入れちゃダメだよ~</span>\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R2/20190716_170000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n\n<span class=\"c\"># 入力ファイルをどっかから持ってきて、<<入力ファイル>>.jpgとしてカレントディレクトリに保存しておく</span>\n<span class=\"c\"># 顔検出のデモなので、人物が何人か写ってる画像を用意してね。</span>\n\n<span class=\"c\"># サンプル実行</span>\n./armv7l/Release/object_detection_sample_ssd  <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> <<入力ファイル>>.jpg\n\n<span class=\"c\"># out_0.bmpができる</span>\n</code></pre></div></div>\n\n<h2 id=\"結果の確認\">結果の確認</h2>\n\n<p>out_0.bmpをテキトーに表示。<br />\n人物の顔が四角で囲まれていることを確認。</p>\n\n<h2 id=\"インストールと動作確認完了\">インストールと動作確認完了</h2>\n\n<p>めでたしめでたし。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WebIOPiをRaspbian Busterで動かす</title>\n  </head>\n  <body>\n    <header>\n      <h1>WebIOPiをRaspbian Busterで動かす</h1>\n      <p>WebIOPiをRaspbian Busterで動かす</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"背景\">背景</h1>\n\n<p>知人がWebIOPiをRaspbian Busterで動かそうとして、Raspbian Stretch では動いたが、Raspbian Busterだと動かないと言っていたので、\n興味本位でデバッグしてみた。</p>\n\n<p>私はこれを使おうと思ってないので、「鳴かぬなら鳴かせてみせようホトトギス」なだけなので、詳しい使い方とかは調べてません。</p>\n\n<h1 id=\"参照\">参照</h1>\n\n<p>そもそものインストール手順は、<br />\n<a href=\"https://www.hiramine.com/physicalcomputing/raspberrypi3/webiopi_install.html\">WebIOPi のインストール</a><br />\n<a href=\"https://www.fabshop.jp/%E9%96%8B%E7%99%BA%E3%81%8C%E7%B5%82%E4%BA%86%E3%81%97%E3%81%9Fwebiopi%E3%82%92%E6%9C%80%E6%96%B0%E3%81%AEraspbian%E3%81%A7%E5%8B%95%E4%BD%9C%E3%81%95%E3%81%9B%E3%82%88%E3%81%86%E3%80%82/?fbclid=IwAR1u1Hq0wSqnDhPnKDeoyf1b2AmrdpO99TLSevUTZ237D5Ny97pliLjlOwU\">開発が終了したWebIOPiを最新のRaspbianで動作させよう。</a><br />\nあたりを参考にしてちょ。</p>\n\n<h1 id=\"いきなり結論\">いきなり結論</h1>\n\n<p>で、まぁ結論から言うと、根本原因は、BusterのPython3がPython3.7にバージョンアップされたこと。<br />\nちなみに、StretchのPython3はPython3.5 。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">python/webiopi/utils/thread.py</code> 内の 関数 <code class=\"language-plaintext highlighter-rouge\">runLoop()</code>の中で<code class=\"language-plaintext highlighter-rouge\">async</code>を変数に使っていたため、SyntaxErrorが発生していた模様。<br />\nPythom3.7では(正確にはPython3.6から)<code class=\"language-plaintext highlighter-rouge\">async</code>は予約語になっているため、エラーとなっていた。</p>\n\n<p>で、変数名を<code class=\"language-plaintext highlighter-rouge\">async</code>からそれ以外(例えば<code class=\"language-plaintext highlighter-rouge\">async_Flag</code>)に変更すれば良い。</p>\n\n<h1 id=\"でpatchファイル\">で、patchファイル</h1>\n\n<p>修正内容のpatchファイルがこちら。<br />\nついでにCプログラムのコンパイルの際に出るワーニングも消すようにちょこっと修正しときました。(こっちの修正は、かなりヤッツケ…)</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/cpuinfo.c WebIOPi-0.7.1/python/native/cpuinfo.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/cpuinfo.c\t2019-09-03 00:04:59.959369913 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/cpuinfo.c\t2019-09-02 23:55:16.207501342 +0900\n</span><span class=\"p\">@@ -35,7 +35,8 @@</span> char *get_cpuinfo_revision(char *revisio\n       return 0;\n \n    while(!feof(fp)) {\n<span class=\"gd\">-      fgets(buffer, sizeof(buffer) , fp);\n</span><span class=\"gi\">+      char* aaa = fgets(buffer, sizeof(buffer) , fp);\n+      aaa = aaa;\n</span>       sscanf(buffer, \"Hardware\t: %s\", hardware);\n       if (strcmp(hardware, \"BCM2708\") == 0)\n          rpi_found = 1;\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/gpio.c WebIOPi-0.7.1/python/native/gpio.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/gpio.c\t2019-09-03 00:04:59.969368480 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/gpio.c\t2019-09-02 23:58:58.757767098 +0900\n</span><span class=\"p\">@@ -23,6 +23,7 @@</span> SOFTWARE.\n #include <stdio.h>\n #include <stdint.h>\n #include <stdlib.h>\n<span class=\"gi\">+#include <unistd.h>\n</span> #include <string.h>\n #include <fcntl.h>\n #include <sys/mman.h>\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/webiopi/utils/thread.py WebIOPi-0.7.1/python/webiopi/utils/thread.py\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/webiopi/utils/thread.py\t2019-09-03 00:04:44.520586361 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/webiopi/utils/thread.py\t2019-09-02 23:54:10.087479478 +0900\n</span><span class=\"p\">@@ -33,14 +33,14 @@</span> def stop(signum=0, frame=None):\n             task.stop()\n                 \n \n<span class=\"gd\">-def runLoop(func=None, async=False):\n</span><span class=\"gi\">+def runLoop(func=None, async_Flag=False):\n</span>     global RUNNING\n     RUNNING = True\n     signal.signal(signal.SIGINT, stop)\n     signal.signal(signal.SIGTERM, stop)\n \n     if func != None:\n<span class=\"gd\">-        if async:\n</span><span class=\"gi\">+        if async_Flag:\n</span>             TASKS.append(Task(func, True))\n         else:\n             while RUNNING:\n</code></pre></div></div>\n\n<p>これを<code class=\"language-plaintext highlighter-rouge\">webiopi-buster.patch</code>として保存し、以下のコマンドを実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch <span class=\"nt\">-p1</span> <span class=\"nt\">-i</span> webiopi-buster.patch\n</code></pre></div></div>\n\n<p>で後は<code class=\"language-plaintext highlighter-rouge\">settup.sh</code>を実行して、その後は参照ページの通り進めれば良い。</p>\n\n<h1 id=\"めでたしめでたし\">めでたしめでたし</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その1)</h1>\n      <p>Node-REDのインストール他のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDをインストールや、フローを作成する際の手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"ubuntu-に-node-red-をインストールする\">ubuntu に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejsとnpmのインストール\">Node.jsとnpmのインストール</h2>\n\n<p>自動起動とかやらないなら、Node.js は nodenv とか使っても良い気がするが、\n念のためシステムに直接インストールしておく。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">apt install</code> だと古いバージョンになってしまうので、<br />\nnコマンド をインストールし、<br />\nnコマンドで安定版をインストールする。<br />\nその後、<code class=\"language-plaintext highlighter-rouge\">apt</code> でインストールしたNode.jsは削除。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n\n<span class=\"c\"># nコマンドのインストール</span>\n<span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> n\n\n<span class=\"c\"># 安定版のインストール</span>\n<span class=\"nb\">sudo </span>n stable\n\n<span class=\"c\"># aptでインストールしたnode.jsをアンインストール</span>\n<span class=\"nb\">sudo </span>apt purge <span class=\"nt\">-y</span> nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h2 id=\"node-redのインストール\">Node-REDのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> <span class=\"nt\">--unsafe-perm</span> node-red node-red-admin\n</code></pre></div></div>\n\n<p>どうも、ノードの追加とかすると、npmのキャッシュをアクセスするときにpermission deniedと言われてしまうみたいなので、\n以下のコマンドで .npm ディレクトリ以下の所有権を自分にしておく。<br />\n(キャッシュだから削除しても良い気がするが)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> ~/.npm\n</code></pre></div></div>\n\n<h2 id=\"起動\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"停止\">停止</h2>\n\n<p>CTRL-Cで停止する。</p>\n\n<h2 id=\"参考\">参考</h2>\n\n<p><a href=\"https://qiita.com/seibe/items/36cef7df85fe2cefa3ea\">https://qiita.com/seibe/items/36cef7df85fe2cefa3ea</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"windows10-に-node-red-をインストールする\">Windows10 に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npmの-インストール\">Node.js と npmの インストール</h2>\n\n<ul>\n  <li><a href=\"https://nodejs.org/ja/\">Node.jsのサイト</a>からWindows版をダウンロードします。\n  推奨版(2019/09/16現在、10.16.3 LTS)をダウンロードしてください。<br />\n  (もし、別のプラットフォームのものが必要なら上部のメニューの「ダウンロード」からダウンロードします)</li>\n  <li>ダウンロードしたnode-vXX.XX.XX-YY.msiを実行してインストーラを起動し、インストールします。\n  特に迷うところはないと思います。大体、そのまま「次へ」で大丈夫。</li>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell を起動します。\n  念のため、<code class=\"language-plaintext highlighter-rouge\">node -v</code> を実行して、<code class=\"language-plaintext highlighter-rouge\">v10.16.3</code>と表示されることを確認します。\n  次にnpmのアップデートを行います。以下のコマンドを実行してください。( 2019/09/16現在、6.11.3 でした)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g npm\n</code></pre></div></div>\n<h2 id=\"node-redのインストール-1\">Node-REDのインストール</h2>\n\n<ul>\n  <li>コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してインストールします。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g --unsafe-perm node-red\n</code></pre></div></div>\n\n<ul>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してNode-REDを起動します。<br />\n実行したウィンドウは閉じないでください。閉じるとNode-REDが終了してしまいます。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>なお、初めてNode-REDを起動したとき、\n『このアプリの機能のいくつかがWindows Defender ファイアウォールでブロックされています』\nと警告が表示されることがある。</p>\n\n<p>この場合、\n「通信を許可するネットワーク」を選択して「アクセスを許可する」をクリック\nすれば良い。</p>\n\n<h2 id=\"ちょっとヒトコトメモ\">ちょっとヒトコトメモ</h2>\n\n<p>(ぜんぜんヒトコトじゃないけど。。。)</p>\n\n<p>Node-REDを起動したPCからのアクセス(ブラウザ接続など)は成功するのに、\n外部PCやRaspberryPi(もちろん、同一サブネット上の)からのアクセス(ブラウザやWebsocket接続)が失敗する場合がある。</p>\n\n<p>考えられる原因は色々あるが、最も多そうな原因のひとつにファイアウォールでのブロックが考えられる。<br />\n上の警告ダイアログでアクセス許可した際に、プライベートネットワークのみに通信を許可していて、\nかつ、現在接続されているネットワークがパブリックネットワークである場合である。</p>\n\n<p>ファイアウォールでのブロックされているかは<strong>Node-REDを起動した状態</strong>で以下のコマンドで確認できる。</p>\n\n<ul>\n  <li>RaspberryPiの場合</li>\n</ul>\n\n<p>以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 《IPアドレス》 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 192.168.1.2 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、コマンドが終了しないので、CTRL+Cで終了する。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">Connection to 《IPアドレス》 《ポート番号》port [tcp/*] succeeded!</code>と表示される。</p>\n\n<ul>\n  <li>Windowsの場合</li>\n</ul>\n\n<p>Windows Poewrshellで(コマンドプロンプトでは不可)以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 《IPアドレス》  <span class=\"nt\">-port</span> 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 192.168.1.2 <span class=\"nt\">-port</span> 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : False</code>と表示される。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : True</code>と表示される。</p>\n\n<p>これを解決するには、Node-REDを実行しているWindows PCで<br />\n「コントロールパネル」→「Windows Defender ファイアウォール」を開き、<br />\n左側のリストから「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック<br />\n「設定の変更」をクリック\n下のリストから「Node.js: Server-side JavaScript」の右側 パブリックのチェックボックスにチェックを入れる<br />\n「OK」をクリック</p>\n\n<p>この状態で再度RaspberryPi または PCからファイアウォールでのブロックの確認を実行し、ブロックされていないことを確認してください。</p>\n\n<h1 id=\"raspbian-に-node-red-をインストールする\">Raspbian に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npm-と-node-red-のインストール\">Node.js と npm と Node-RED のインストール</h2>\n\n<p>インストールスクリプトを実行すればイッパツで解決。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストールスクリプトの取得</span>\nwget  https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered\n\n<span class=\"c\"># 必要なら中身確認してね</span>\n\n<span class=\"c\"># インストールスクリプトの実行</span>\nbash update-nodejs-and-nodered \n</code></pre></div></div>\n\n<h2 id=\"起動-1\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-start \n</code></pre></div></div>\n<p>CTRL-Cでログ表示のみ止まる(Node-RED自体は動作したまま)</p>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"ログ表示\">ログ表示</h2>\n\n<p>Node-RED で console.log などを実行したときは、ログに表示される。<br />\n<code class=\"language-plaintext highlighter-rouge\">node-red-start</code>したままなら表示されるが、CTRL-Cでログ表示を止めていた場合は\n以下のコマンドでログ表示を再開できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-log\n</code></pre></div></div>\n\n<h2 id=\"停止-1\">停止</h2>\n\n<p>Node-RED自体を停止する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-stop\n</code></pre></div></div>\n\n<h2 id=\"参考-1\">参考</h2>\n\n<p><a href=\"https://qiita.com/utaani/items/7155c62d6c5e96822afb\">https://qiita.com/utaani/items/7155c62d6c5e96822afb</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"フローの操作\">フローの操作</h1>\n\n<h2 id=\"フローを保存するエクスポート\">フローを保存する(エクスポート)</h2>\n\n<p>作成したフローは保存することができます。<br />\nしばらく使わないフローを削除したり、別の環境にコピーする場合に保存しておくと良いでしょう。</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「書き出し」→「クリップボード」をクリック →書き出しダイアログが表示される\n    <ul>\n      <li>書き出す範囲を「現在のタブ」「すべてのタブ」から選択。(フローの一部を選択していた場合は「選択したフロー」も選択可能)</li>\n      <li>その下にはその時のJSONファイルの内容が表示されていますので、ここから</li>\n      <li>さらにその下で出力形式を「インデントのないJSONフォーマット」「インデント付きのJSONフォーマット」から選択。多少ファイルサイズが増減しますが、どちらを選んでも特に問題になるようなことはないでしょう。「インデント付き」の方が目視で確認しやすいと思います。</li>\n      <li>「ダウンロード」をクリックすると、ブラウザのファイル保存(ダウンロード)ダイアログが開くので、保存処理を行う(このときのファイル名はflows.json固定なので、必要に応じて保存後リネームしてください)</li>\n      <li>または、「書き出し」をクリックすると、クリップボードへコピーされるので、直接 別の環境の読み込みダイアログやエディタへペーストすることも可能</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"フローを読み込むインポート\">フローを読み込む(インポート)</h2>\n\n<p>保存したフローは読み込んで使用することができます(当然か)</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「読み込み」→「クリップボード」をクリック →読み込みダイアログが表示される\n    <ul>\n      <li>「読み込むファイルを選択してください」をクリックして読み込むファイルを選択 → ファイルの内容がその下のエディットボックスに表示される</li>\n      <li>または、その下のエディットボックスにJSONデータをペースト</li>\n      <li>読み込み先を「現在のタブ」「新規のタブ」から選択(「選択したフロー」で保存してないとどっちでも同じ気がする)</li>\n      <li>「読み込み」をクリック</li>\n    </ul>\n  </li>\n  <li>読み込まれるので、内容を確認。必要なら修正。</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"フローを削除する\">フローを削除する</h2>\n\n<p>使用しなくなったフローをいつまでも残しておくとトラブルの元ですから、削除しましょう。<br />\n(念のため保存しておくのを忘れずに)</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、削除したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>左上の「削除」をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(次回デプロイするまで処理は残っているので注意)</li>\n</ul>\n\n<h2 id=\"フローを一時的に停止する\">フローを一時的に停止する</h2>\n\n<p>後で使うから削除したくはないけど、今デバッグしてる作業の邪魔になる、というような場合、\n作成したフローを削除せずに一時的に停止することができます。</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、停止したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>状態を「無効」にする</li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(デプロイしないといつまで経っても停止しないので注意)</li>\n</ul>\n\n<p>再開する場合は上記手順と同じで、状態を「有効」にする。</p>\n\n<h2 id=\"フローを全削除する\">フローを全削除する</h2>\n\n<p>色々フローを作成したけど、一回チャラにしてやりなおしたいときは、\n一旦Node-REDを停止(ブラウザ切断だけじゃなく、サーバプログラムを停止)して\n以下の2つのファイルを削除する</p>\n\n<ul>\n  <li>~/.node-red/flows_《ホスト名》.json</li>\n  <li>~/.node-red/.flows_《ホスト名》.json.backup</li>\n</ul>\n\n<p>もちろん、念のためバックアップ取っておくのが好ましい。<br />\nバックアップから復元すれば元通りになるはず。</p>\n\n<p>その後、Node-Redを起動すると、フローが綺麗さっぱり消えているハズ。</p>\n\n<h2 id=\"その2以降のフローの例について\">その2以降の「フローの例」について</h2>\n\n<p>「フローの例」に書かれたJSONコードはテスト用に作成したフローをエクスポート(書き出し)したものです。<br />\nこのコードの表示部分にマウスを乗せると、右上に「Copy」ボタンが表示されますので、このボタンをクリックしてください。JSONコードがクリップボードにコピーされます(マウスをドラッグしての選択は不要)。</p>\n\n<p>この状態で、上記<strong>フローを読み込む(インポート)</strong>に示した方法でフローをインポートするとフローがコピーされます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n複数のフローをインポートした場合、既に存在するノードと同名のノードは別のノードとして生成されます。このとき、名前に「(_1)」などの別ノードを識別できるような記号は付きません。<br />\n特に、WebsocketのノードやDashboardのタブ/グループはシステムの動作や見た目に影響しますので、注意してください。<br />\n自動でよしなにする方法はありませんので、手動でチマチマと修正してください。<br />\nサイドバー(右側のペイン)の「▼」ボタンをクリックし、ノードの設定を表示でノードの設定を表示し、<br />\n各ノードの右側の数字をクリックすると、そのノードを参照しているノードの一覧が表示されます。<br />\nさらにそのノード一覧の各ノードをダブルクリックすると、そのノードが点滅表示されるので、そのノードのプロパティで参照先を変更すれば良いでしょう。</p>\n\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その2)</h1>\n      <p>Node-REDのメモ GPIO & I2C編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIO操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDはRaspberryPiで起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"raspberrypiでgpio出力\">RaspberryPiでGPIO出力</h1>\n<ul>\n  <li>パレット(左側のペイン)の「Raspberry Pi」の下の「rpi gpio」(出力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で出力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「出力形式」で「デジタル出力」を選択</li>\n      <li>デプロイしたときに端子状態を初期化したい場合は「端子の状態を初期化」をチェック\n        <ul>\n          <li>「端子の初期状態レベル」を選択</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「LED_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>トリガノードはGPIOから出力する値(0 または 1)を出力する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"51e0a206.805964\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_OUT\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"597df548.0311f4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"89834ee2.89e27\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b020b32.e26818\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"21621e60.e300ba\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_1\",\n        \"pin\": \"22\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"87abb89b.307418\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7ae7810.959a88\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 220,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでgpio入力\">RaspberryPiでGPIO入力</h1>\n\n<ul>\n  <li>パレットの「Raspberry Pi」の下の「rpi gpio」(入力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で入力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「抵抗」で端子に接続するプルアップ/ダウン種別を選択\n        <ul>\n          <li>端子の初期化時に内部のプルアップ/ダウン抵抗のどちらを有効にするかを選択</li>\n          <li>ボード上で処理してれば「なし」を選ぶ</li>\n        </ul>\n      </li>\n      <li>デバウンスにチャタリング除去時間を設定</li>\n      <li>デプロイしたときに端子状態を読み込みたい場合は「~初期状態を読み込む」をチェック</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「SWITCH_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力信号を処理するノードを接続\n    <ul>\n      <li>処理ノードへはGPIOから入力された値(0 または 1)が入力される</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1385085c.ab8648\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_IN\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"e9177a48.70b74\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"932b0e92.05cdd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"932b0e92.05cdd8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f31f20e.4b6d28\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW1\",\n        \"pin\": \"16\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d27c860d.7de3a8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d27c860d.7de3a8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 160,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでi2cを使用する\">RaspberryPiでI2Cを使用する</h1>\n\n<h2 id=\"事前準備\">事前準備</h2>\n\n<p>以下はターミナルやコンソールでの作業</p>\n\n<ul>\n  <li>I2Cを有効化する\n    <ul>\n      <li>リブートは不要らしい</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config\n    5 Interfacing Options\n        P5 I2C\n            Would you like the ARM I2C interface to be enabled?\n            に対して<はい>を選択\n            The ARM I2C interface is enabled\n            と表示されるので<了解>\n    <Finish>\n</code></pre></div></div>\n<ul>\n  <li>I2Cデバイスアクセス用ツールをインストールする</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>i2c-tools\n</code></pre></div></div>\n\n<ul>\n  <li>i2cバスをスキャンしてみる(RasbberryPi2/3のI2Cバスはバス1が出てる。古いのだと0のもあるらしい)</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#   ↓結果(例)</span>\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00:          <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n10: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n20: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n30: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n40: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n50: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n60: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n70: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> 76 <span class=\"nt\">--</span>\n<span class=\"c\"># 76がBME280(Bosch温湿度センサ)</span>\n</code></pre></div></div>\n\n<ul>\n  <li>I2Cデバイスのレジスタをリードしてみる</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cget <span class=\"nt\">-y</span> 1 0x76 0xd0\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ↓ 結果</span>\n0x60\n<span class=\"c\"># レジスタ 0xd0(CHIP ID)をリードするとデバイスのID 0x60が読める</span>\n</code></pre></div></div>\n\n<h2 id=\"bme280用ノードをインストールする\">BME280用ノードをインストールする</h2>\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「bme280」と入力</li>\n  <li>下に検索結果が出るので。「node-red-contrib-bme280」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\n2019/09/13現在、何やらインストール時にエラーになるが、<br />\nモジュールのコンパイル時にwarning/noteが出ているだけのようなので、インストール自体はできているようだ。<br />\nとりあえず下記サンプルは動いているので、大丈夫でしょう。</p>\n</blockquote>\n\n<h2 id=\"bme280を使用するフローを作成する\">BME280を使用するフローを作成する</h2>\n<ul>\n  <li>パレットの「入力」の下の「Bme280」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Bme280」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略するとBme280が表示される</li>\n        </ul>\n      </li>\n      <li>Bus# にバス番号(1)を設定</li>\n      <li>I2C Address にI2Cアドレス(0x76)を設定</li>\n      <li>Topicが必要なら設定(デフォルトはbme280)</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>信号を処理するノードを出力側に接続\n    <ul>\n      <li>Bme280ノードの出力メッセージの内容は以下の通り</li>\n    </ul>\n  </li>\n</ul>\n\n<table>\n  <thead>\n    <tr>\n      <th>変数名</th>\n      <th>値の例</th>\n      <th>項目</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>msg.topic</td>\n      <td>“bme280”</td>\n      <td>ノードの設定で設定したTopic</td>\n    </tr>\n    <tr>\n      <td>msg.payload.temperature_C</td>\n      <td>34.23</td>\n      <td>温度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.humidity</td>\n      <td>54.402349427117336</td>\n      <td>湿度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.pressure_hPa</td>\n      <td>1013.9016246356634</td>\n      <td>気圧</td>\n    </tr>\n    <tr>\n      <td>msg.payload.model</td>\n      <td>“BME280”</td>\n      <td>センサ名</td>\n    </tr>\n  </tbody>\n</table>\n\n<ul>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n    {\n        \"id\": \"e4065603.3c6dc\",\n        \"type\": \"tab\",\n        \"label\": \"BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c0602bca.110b8\",\n        \"type\": \"Bme280\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"8b845ce5.ec2fd\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b845ce5.ec2fd\",\n        \"type\": \"debug\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 630,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"cdbf55ce.3aa94\",\n        \"type\": \"inject\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"c0602bca.110b8\"\n            ]\n        ]\n    }\n]\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その3)</h1>\n      <p>Node-REDのメモ TCP通信編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでTCP通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"udpで送信\">UDPで送信</h1>\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「送信」で出力するメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト)/「ブロードキャストメッセージ」/「マルチキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で送信先ポート番号を設定\n        <ul>\n          <li>受信プログラムが待ち受けしているポート番号を指定</li>\n        </ul>\n      </li>\n      <li>「アドレス」に送信先アドレス(名前 or IPアドレス)を指定</li>\n      <li>さらにその右で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>特定のポートから送信したいときは「ローカルポートを使用」を選択し、その右に送信元ポート番号を指定する\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n          <li>通常は「ローカルポートをランダムに使用」で大丈夫</li>\n        </ul>\n      </li>\n      <li>入力データがBase64エンコードされたBufferオブジェクトの場合は「Base64形式のペイロードを複合」にチェックを入れる\n        <ul>\n          <li>入力データがBase64文字列かをチェックするだけで、ここでデータを変換するわけではない(?)</li>\n          <li>通常はチェックしないでOK</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると送信先アドレスとポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>送信データを作成するノードを接続\n    <ul>\n      <li>UDPノードはmsg.payloadを送信する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"udpで受信\">UDPで受信</h1>\n<ul>\n  <li>パレットの「入力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「待ち受け」で受信待ちするするメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト or マルチキャスト)/「ブロードキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で受信待ちポート番号を設定\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n        </ul>\n      </li>\n      <li>「種類」で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>「出力」で受信したデータをどのような形式で次段のノードに出力するかを選択する\n        <ul>\n          <li>「バイナリバッファ」を選択すると受信したデータをそのままbufferオブジェクトとして出力</li>\n          <li>「文字列」を選択すると受信したデータをStringオブジェクトにデコードする</li>\n          <li>「Base64文字列」を選択すると受信したデータをBase64 Stringオブジェクトにデコードする</li>\n          <li>「Base64文字列」と「文字列」は内部でtoStringのencodingに’base64’を指定するか’utf8’を指定するかの違い(?)</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると受信待ちポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>受信データを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"2506be7d.1b5332\",\n        \"type\": \"tab\",\n        \"label\": \"UDP\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"44364ec0.0b59b8\",\n        \"type\": \"udp out\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"addr\": \"localhost\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"outport\": \"\",\n        \"base64\": false,\n        \"multicast\": \"false\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"20cee006.2fee4\",\n        \"type\": \"inject\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"\",\n        \"payloadType\": \"date\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 150,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"44364ec0.0b59b8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"eb875fd8.7aa5f8\",\n        \"type\": \"udp in\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"multicast\": \"false\",\n        \"group\": \"\",\n        \"datatype\": \"utf8\",\n        \"x\": 160,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"a6b72636.514e2\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a6b72636.514e2\",\n        \"type\": \"debug\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 140,\n        \"wires\": []\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"httpでrest-api\">HTTPでREST API</h1>\n\n<h2 id=\"http入力ノードの作成\">HTTP入力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「入力」の下の「http」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「メソッド」でメソッド種別を選択\n        <ul>\n          <li>ここでは「GET」で設定を進める(他のメソッドは他所で調べてね)</li>\n        </ul>\n      </li>\n      <li>「URL」でエンドポイント(要はパス)を設定</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとメソッドとURLが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>レスポンスを作成するノード(下記)を接続</li>\n</ul>\n\n<h2 id=\"レスポンス生成ノードの作成\">レスポンス生成ノードの作成</h2>\n\n<p>ここでは、簡単にfunctionノードで固定文字列を返すものを作っています。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると空欄になるので、なるべく識別できる名前を付けましょう</li>\n        </ul>\n      </li>\n      <li>「コード」に処理するプログラムを記述\n        <ul>\n          <li>msg.payloadに表示するページの本文を設定する</li>\n          <li>例えば以下</li>\n        </ul>\n      </li>\n      <li>「名前」の横のアイコンをクリックすると作成したノードの保存/読み込みが出来る\n        <ul>\n          <li>コードは <code class=\"language-plaintext highlighter-rouge\">~/.node-red/lib/functions/</code> に指定したフォルダとファイル名で保存される</li>\n          <li>保存したコードは別のノードで読み込むことができる</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"dl\">\"</span><span class=\"s2\"><h1> ぼ~っと生きてんじゃね~よ! </H1></span><span class=\"dl\">\"</span><span class=\"p\">;</span>\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h2 id=\"http出力ノードの作成\">HTTP出力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「出力」の下の「http response」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「http」と表示される</li>\n        </ul>\n      </li>\n      <li>必要なら「状態コード」を設定</li>\n      <li>必要なら「ヘッダ」を設定</li>\n      <li>シンプルな処理の場合、何も設定しなくてもOK</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"入力レスポンス生成出力を接続\">入力、レスポンス生成、出力を接続</h2>\n\n<ul>\n  <li>上記で作成したノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"ブラウザでアクセス接続\">ブラウザでアクセス接続</h2>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/《HTTP入力ノードに設定したURL》 に接続\n    <ul>\n      <li>ブラウザにレスポンス生成ノードで作成したメッセージが表示される</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"7508e635.c8bf48\",\n        \"type\": \"tab\",\n        \"label\": \"HTTP_REST\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c7938d8a.3ae9d\",\n        \"type\": \"http in\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"url\": \"/rest_api_1\",\n        \"method\": \"get\",\n        \"upload\": false,\n        \"swaggerDoc\": \"\",\n        \"x\": 160,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"fb01d5fd.b76918\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fb01d5fd.b76918\",\n        \"type\": \"function\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"ぼ~っと生きてんじゃね~よ!\",\n        \"func\": \"msg.payload = \\\"<h1> ぼ~っと生きてんじゃね~よ! </H1>\\\";\\nreturn msg;\\n\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 430,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"8d3518af.f9da7\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d3518af.f9da7\",\n        \"type\": \"http response\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"statusCode\": \"\",\n        \"headers\": {},\n        \"x\": 690,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"86c0f820.b0a56\",\n        \"type\": \"debug\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 700,\n        \"y\": 120,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"websocketでデータを送受信\">Websocketでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにwscatを使うこととします。<br />\nwscat は 以下のコマンドでインストールできます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> wscat\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信クライアント\">Websocketでデータ送信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「種類」 で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「URL」 でサーバのURLを設定(例: ws://PiDev25.local:5000/ws/data01)</li>\n          <li>「送信/受信」でペイロードのみ送受信するか、メッセージ全体を送受信するかを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5000で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5000\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5000 (press CTRL+C to quit)\nclient connected\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"75e44664.73e018\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"49b725b6.0e0934\",\n        \"type\": \"websocket out\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"99ad88ce.8bcf7\",\n        \"x\": 600,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"762ccf62.73a48\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fe2498d8.71c17\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47ef3c99.d6eefc\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f97b4d60.afc278\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6d15d519.6289ec\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"87c94e6f.db3458\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"175e465.15aaa3a\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e7c2219c.07acf8\",\n        \"type\": \"debug\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"99ad88ce.8bcf7\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5000/ws/data01\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信サーバ\">Websocketでデータ送信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata1 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest1で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wstest1\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-3\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"22d6d63b.99a952\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"d64e2a6a.27ead8\",\n        \"type\": \"websocket out\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"server\": \"d7536de3.b48578\",\n        \"client\": \"\",\n        \"x\": 520,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"79358fcc.5a5a68\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"cd6acb87.0a77\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7991d417.429124\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ee88046b.37b298\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7eac2c2e.6fa39c\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"650517e9.5e34a8\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d197151e.8b01e\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5871022e.6bbb1c\",\n        \"type\": \"debug\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d7536de3.b48578\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wstest1\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信クライアント\">Websocketでデータを受信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>URL でサーバのURLを設定(例: ws://PiDev25.local:5002/ws/wsdata2)</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-2\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5002で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5002\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5002 (press CTRL+C to quit)\nclient connected\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-4\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a45bd125.622fb8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"24a93730.cf2a7\",\n        \"type\": \"websocket in\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"server\": \"45ba6028.84fc88\",\n        \"client\": \"\",\n        \"x\": 220,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"15576052.1536\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"15576052.1536\",\n        \"type\": \"debug\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"45ba6028.84fc88\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5002/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信サーバ\">Websocketでデータを受信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata2 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-3\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest2で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wsdata2\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-5\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"15604b9.9721eb4\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"80f59585.469758\",\n        \"type\": \"websocket in\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"server\": \"11528a5d.783b0e\",\n        \"client\": \"\",\n        \"x\": 140,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"f37c8fe9.6307c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f37c8fe9.6307c\",\n        \"type\": \"debug\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"11528a5d.783b0e\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その4)</h1>\n      <p>Node-REDのメモ Dashboard編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでDashboardでUIを作成するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"dashboardをインストールする\">Dashboardをインストールする</h1>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-dashboard」と入力</li>\n  <li>下に検索結果が出るので。「node-red-dashboard」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するボタン\">Dashboard のUIを作成する(ボタン)</h1>\n\n<ul>\n  <li>パレット(左側のペイン)の「dashboard」の下の「button」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「button」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「名前」は適当に設定</li>\n          <li>「タブ」 で「新規に ui_tab を追加…」を選択してその右の編集ボタンをクリック\n            <ul>\n              <li>適当に値を設定する</li>\n              <li>右上の「追加」をクリック</li>\n            </ul>\n          </li>\n          <li>または、既存のタブを選択</li>\n          <li>右上の「追加」をクリック</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Icon」「Tooltip」「Colour」「Background」はオプションなので空欄のままで可</li>\n      <li>「Payload」 に クリックされたときに送信するデータを設定</li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"ブラウザでdashboardのuiに接続する\">ブラウザでDashboardのUIに接続する</h1>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/ui に接続\n    <ul>\n      <li>Dashboardが表示されるハズ\n        <ul>\n          <li>複数のタブがある場合、左上の3本線メニュー(≡)から切り替えられる</li>\n        </ul>\n      </li>\n      <li>ボタンをクリックしたらフローが動作する。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するスライダ\">Dashboard のUIを作成する(スライダ)</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「slider」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「slider」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Tooltip」はオプションなので空欄のままで可</li>\n      <li>「Range」に値の最小値、最大値、刻みを設定</li>\n      <li>「Output」を設定\n        <ul>\n          <li>「continuously while sliding」:操作中、一定時間ごとにメッセージを出力</li>\n          <li>「only on release」:スライダを離したとき(値を確定したとき)にメッセージを出力</li>\n        </ul>\n      </li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"dashboardでゲージグラフを表示する\">Dashboardでゲージグラフを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「guage」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「guage」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>デフォルトの<code class=\"language-plaintext highlighter-rouge\">{{value}}</code>では受信したデータのpayload(<code class=\"language-plaintext highlighter-rouge\">msg.payload</code> )が使用される</li>\n          <li>payloadがobjectの場合、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.XXX}}</code>のように指定すると特定の変数が表示できる</li>\n          <li>このとき、<code class=\"language-plaintext highlighter-rouge\">{{</code> と <code class=\"language-plaintext highlighter-rouge\">}}</code> は波括弧を2つ重ねたもの。波括弧1つだと正常に処理されないので、注意</li>\n          <li>表示する数値の有効桁数を設定したい場合は以下のようにフィルタを設定\n            <ul>\n              <li>小数点以下1桁まで表示:<code class=\"language-plaintext highlighter-rouge\">{{value | number:1 }}</code></li>\n              <li>整数部のみ表示:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:0 }}</code></li>\n              <li>10の位へ丸める:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:-1 }}</code></li>\n            </ul>\n          </li>\n          <li>単位を表示するなど、決まった文字列を追加したい場合は「<code class=\"language-plaintext highlighter-rouge\">{{・・・}}℃</code>」のように波括弧の外側に追加</li>\n        </ul>\n      </li>\n      <li>「units」 で単位を設定する。温度なら「℃」など。これは数値表示には表示されず、グラフ内部の単位情報として表示される</li>\n      <li>「Range」 でグラフの値の範囲を指定する。「-20」~「40」など。\n        <ul>\n          <li>入力値が範囲外になった場合はグラフが上下限に張り付くだけで、エラーなどにはならない。また値そのものは数値表示される</li>\n        </ul>\n      </li>\n      <li>「Colour gradient」 でグラフの色を指定する。3つの色は下で設定するSectors の範囲に対応する</li>\n      <li>「Sectors」 で 上で指定した色を表示する範囲を設定する\n        <ul>\n          <li>これはオプションなので設定しなくても良い。指定しなかった場合は上の「Range」で指定した値の範囲を3等分して使用される</li>\n        </ul>\n      </li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nValue formatのフィルタの詳細は<a href=\"https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters\">https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters</a>を見ろと書かれていましたが、残念ながら私にはよく分かりませんでした…</p>\n</blockquote>\n\n<h1 id=\"dashboardでテキストを表示する\">Dashboardでテキストを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「text」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「text」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>上記参照</li>\n        </ul>\n      </li>\n      <li>「Layout」でレイアウトを選択。お好みで</li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a226513f.c36b1\",\n        \"type\": \"tab\",\n        \"label\": \"Dashboard_1\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"160486fa.dc7159\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e89b8821.ec65e8\",\n        \"type\": \"debug\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 580,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d4346336.cf1228\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e403fdac.aa3748\",\n        \"type\": \"ui_slider\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"label\": \"温度\",\n        \"tooltip\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 4,\n        \"width\": 0,\n        \"height\": 0,\n        \"passthru\": true,\n        \"outs\": \"all\",\n        \"topic\": \"\",\n        \"min\": \"-30\",\n        \"max\": \"50\",\n        \"step\": 1,\n        \"x\": 140,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"78c10ecb.1eb67\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"78c10ecb.1eb67\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 6,\n        \"width\": 4,\n        \"height\": 4,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{value}}℃\",\n        \"min\": \"-20\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 570,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"84bd2adf.3b5df8\",\n        \"type\": \"ui_text\",\n        \"z\": \"a226513f.c36b1\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 560,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1127e563.00001b\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"6547952b.517b34\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"6547952b.517b34\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ1\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"dashboard-のレイアウトを修正する\">Dashboard のレイアウトを修正する</h1>\n\n<p>ボタンのサイズを小さくしたり、複数のボタンを横に並べたい場合はレイアウトの修正を行う。</p>\n\n<ul>\n  <li>サイドバー(右側のペイン)の「dashboard」ボタン(グラフのアイコン)をクリック</li>\n  <li>配置タブをクリック</li>\n  <li>タブの部分(「ホーム」など)をマウスでポイントし、「レイアウト」をクリック\n    <ul>\n      <li>表示領域の幅を変更するには、右上の「幅」の設定値を変更する。(単位はグリッド数)</li>\n      <li>各要素をドラッグすると、表示位置を入れ替えられる。</li>\n      <li>各要素のサイズを変更するには、\n        <ul>\n          <li>右上の鍵アイコンをクリックして閉じた状態にする(鍵が開いた状態では表示領域幅に一致するように自動変更される)</li>\n          <li>右下に矢印アイコンが表示されるので、これをつまんでサイズを変更</li>\n        </ul>\n      </li>\n      <li>各要素を横並びにしたい場合は、各要素をドラッグして移動する(表示幅に収まらない場合は移動できない)</li>\n      <li>各要素のサイズ/位置はグリッド単位でのみ可能</li>\n      <li>右上の完了をクリック\nー デプロイする</li>\n    </ul>\n  </li>\n</ul>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その5)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをWebsocketで飛ばして、Dashboardでグラフ表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"bme280データをwebsocketで送信raspberrypi\">BME280データをWebsocketで送信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>BME280を使用するフローを作成する</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、送信されるデータはmsg.payloadなので、文字列ではなく、object。<br />\n  (WebsocketのパケットにはobjectをJSON文字列化したものが入る)</p>\n  </li>\n  <li>BME280のデータを送信するためのトリガとなるノードをBME280ノードの入力に接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"411d9021.cb1948\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"72021e21.cce078\",\n        \"type\": \"Bme280\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"571951b6.480168\",\n        \"type\": \"websocket out\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"f24a6df3.ed0608\",\n        \"x\": 660,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4ce01eb0.f1d438\",\n        \"type\": \"debug\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 570,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"480f869f.968e18\",\n        \"type\": \"function\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"DummyData\",\n        \"func\": \"msg.payload = {\\n\\t\\t\\\"temperature_C\\\": Math.floor((Math.random() * (  40 - (-30)) * 100) / 100) + (-30),\\n\\t\\t\\\"humidity\\\":      Math.floor((Math.random() * ( 100 -    0 ) * 100) / 100) +    0,\\n\\t\\t\\\"pressure_hPa\\\":  Math.floor((Math.random() * (1100 -  800 ) * 100) / 100) +  800,\\n\\t\\t\\\"model\\\":\\\"DUMMY\\\"\\n}\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 310,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"c6ba67a3.1c69c\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"72021e21.cce078\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ab623444.9c5148\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"480f869f.968e18\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f24a6df3.ed0608\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/bme280\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからbme280データを受信サーバ\">WebsocketからBME280データを受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノード</li>\n</ul>\n\n<p>これだけでWebsocketからデータは受信できる。<br />\nこのとき、Websocketの受信ノードのmag.payloadはJSON文字列なので、objectに変換してやらないと後段で使用できない。<br />\nそのため、Websocketのノードの出力をjsonノードで変換してやる必要がある。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「json」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「json」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「動作」で「常にJavascriptオブジェクトに変換」を選択</li>\n      <li>プロパティは「msg.payload」を設定(デフォルトのまま)</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとjsonが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力側にWebsocketのノードを接続</li>\n  <li>\n    <p>出力側に受信データを処理するノードを接続</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>この状態でRaspberryPi側でBME280のデータ送信をトリガすれば、受信したデータで処理ノードが実行される</p>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その1サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その1)(サーバ)</h1>\n\n<p>上記、<strong>WebsocketからBME280データを受信(サーバ)</strong>の処理ノードとして</p>\n<ul>\n  <li><strong>その4</strong> の <strong>Dashboardでゲージグラフを表示する</strong>の手順で作成したノードを接続すれば良い。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nこれで理屈的には大丈夫なハズなんだけど、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.pressure_hPa}}</code>を指定すると、値は正常に表示されるけど、グラフが正常に表示されないことがある。。。<br />\nどうやら、この形で指定すると、値が1000を超えるとグラフ表示がおかしくなるようだ。バグか?<br />\n下の(その2)の方法で回避可能。</p>\n</blockquote>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"61238c01.1e1fdc\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"2163c454.8e4654\",\n        \"type\": \"json\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"8a687382.d3a38\",\n                \"54ecaf20.30611\",\n                \"1e9e6439.3de04c\",\n                \"54f5a1ee.e4fb5\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"de53f105.be0bb\",\n        \"type\": \"websocket in\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"2163c454.8e4654\",\n                \"8a687382.d3a38\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8a687382.d3a38\",\n        \"type\": \"debug\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 530,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54ecaf20.30611\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{msg.payload.temperature_C | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 510,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1e9e6439.3de04c\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度\",\n        \"label\": \"%\",\n        \"format\": \"{{msg.payload.humidity| number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 510,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54f5a1ee.e4fb5\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧\",\n        \"label\": \"hPa\",\n        \"format\": \"{{msg.payload.pressure_hPa| number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 510,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"9912b800.6921d8\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その2サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その2)(サーバ)</h1>\n\n<p><strong>(その1)</strong>での不具合を回避するため、msg.payloadのオブジェクト内のそれぞれの変数をバラすfunctionノードを追加する</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「function」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら名前にノード名を設定</li>\n      <li>コードを設定(下記参照)</li>\n      <li>出力数に「3」を設定</li>\n      <li>右上の「完了」をクリック。</li>\n    </ul>\n  </li>\n  <li>これでfunctionノードの出力端子が3個になり、上から温度、湿度、気圧データが出力される。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>// make deep copy\nvar msg_temp  <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_hum   <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_press <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\n\nmsg_temp.topic    <span class=\"o\">=</span> <span class=\"s2\">\"temperature_C\"</span><span class=\"p\">;</span>\nmsg_temp.payload  <span class=\"o\">=</span> msg.payload.temperature_C<span class=\"p\">;</span>\nmsg_hum.topic     <span class=\"o\">=</span> <span class=\"s2\">\"humidity\"</span><span class=\"p\">;</span>\nmsg_hum.payload   <span class=\"o\">=</span> msg.payload.humidity<span class=\"p\">;</span>\nmsg_press.topic   <span class=\"o\">=</span> <span class=\"s2\">\"pressure_hPa\"</span><span class=\"p\">;</span>\nmsg_press.payload <span class=\"o\">=</span> msg.payload.pressure_hPa<span class=\"p\">;</span>\n\n<span class=\"k\">return</span> <span class=\"o\">[</span>msg_temp, msg_hum, msg_press]<span class=\"p\">;</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">var msg_temp  = msg;</code>などとしてはいけない。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">msg_temp</code>は<code class=\"language-plaintext highlighter-rouge\">msg</code>の浅いコピーとなってしまうため、その下で<code class=\"language-plaintext highlighter-rouge\">msg_temp.payload</code>を変更すると、<code class=\"language-plaintext highlighter-rouge\">msg.payload</code>も変更されてしまうことになる。<br />\nこれを防ぐため、深いコピーを作成している。これには<code class=\"language-plaintext highlighter-rouge\">msg</code>をJSON文字列化して、再度パースすることで対応している。</p>\n</blockquote>\n\n<p>フローエディタ上で、どの端子がどの信号か分からなくなるのを防ぐため、端子に名前を付けることができる。<br />\n(付けなくても動作上は問題ない)</p>\n\n<ul>\n  <li>「function」ノードをダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>右上の「完了」ボタンの下にある「外観」ボタン(ウィンドウ表示のアイコン)をクリック</li>\n      <li>ポートラベルの下の出力の下、1、2、3に対して、それぞれ分かりやすい名前を付ける</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>functionノードの入力にjsonノードの出力を接続</li>\n  <li>functionノードのそれぞれの出力にそれぞれを表示するゲージグラフノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"9c09bf08.8c36a8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280_2\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1e53a14c.4133a7\",\n        \"type\": \"json\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"855491ee.723a88\",\n                \"3cee4c1c.c6861c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ada05d07.d2d8b\",\n        \"type\": \"websocket in\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"1e53a14c.4133a7\",\n                \"855491ee.723a88\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"855491ee.723a88\",\n        \"type\": \"debug\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 690,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"51b57ef4.80809\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度2\",\n        \"label\": \"℃\",\n        \"format\": \"{{value | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 670,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"be7cac56.7bcc4\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度2\",\n        \"label\": \"%\",\n        \"format\": \"{{value | number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 670,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"f36e338d.e77e6\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧2\",\n        \"label\": \"hPa\",\n        \"format\": \"{{value | number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 670,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3cee4c1c.c6861c\",\n        \"type\": \"function\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"BME280\",\n        \"func\": \"// make deep copy\\nvar msg_temp  = JSON.parse(JSON.stringify(msg));\\nvar msg_hum   = JSON.parse(JSON.stringify(msg));\\nvar msg_press = JSON.parse(JSON.stringify(msg));\\n\\nmsg_temp.topic    = \\\"temperature_C\\\";\\nmsg_temp.payload  = msg.payload.temperature_C;\\nmsg_hum.topic     = \\\"humidity\\\";\\nmsg_hum.payload   = msg.payload.humidity;\\nmsg_press.topic   = \\\"pressure_hPa\\\";\\nmsg_press.payload = msg.payload.pressure_hPa;\\n\\nreturn [msg_temp, msg_hum, msg_press];\",\n        \"outputs\": 3,\n        \"noerr\": 0,\n        \"x\": 460,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"51b57ef4.80809\"\n            ],\n            [\n                \"be7cac56.7bcc4\"\n            ],\n            [\n                \"f36e338d.e77e6\"\n            ]\n        ],\n        \"inputLabels\": [\n            \"BME280データ\"\n        ],\n        \"outputLabels\": [\n            \"温度\",\n            \"湿度\",\n            \"気圧\"\n        ]\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"34e8ddba.6c67fa\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ2\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>モバイル ホットスポットでRaspberryPiをネットに接続</title>\n  </head>\n  <body>\n    <header>\n      <h1>モバイル ホットスポットでRaspberryPiをネットに接続</h1>\n      <p>Windows10のモバイル ホットスポットでRaspberryPiをネットに接続する手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>お出かけ先でも RaspberryPi を、常に同じWi-Fi AP で接続できるような方法を考える。</p>\n\n<p>一つの案として、Windows10のモバイル ホットスポットを経由して RaspberryPi をネットワークにつなげる。\nこの場合、PCと RaspberryPi はセットで持ち歩くものと考えれば、 \nRaspberryPi は常にPCのモバイル ホットスポットのAPに接続すれば良いことになる。</p>\n\n<p>一つのWi-Fiアダプタを通常接続用とモバイル ホットスポット用でシェアすることはできないので、<br />\nUSBドングルを追加して使用する。</p>\n\n<ul>\n  <li>内蔵Wi-Fi → 通常接続用</li>\n  <li>USBドングル → モバイル ホットスポット用</li>\n</ul>\n\n<p>USBドングルは BUFFALO WLI-UC-GNM2S で確認\nWindowsはWindows10 ver.1903 で確認</p>\n\n<h1 id=\"windows側の事前準備\">Windows側の事前準備</h1>\n\n<p>内蔵Wi-Fi は 通常通り ルータに接続しておく。<br />\nこのとき、どのルータに繋いでいるかは考慮しなくて良いはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPCのルータ接続ダウン時、モバイル ホットスポットは使えない</p>\n</blockquote>\n\n<p>USBドングル BUFFALO WLI-UC-GNM2S はあらかじめドライバをインストールしてWindowsに認識させておく。<br />\n接続先は設定しなくて大丈夫。</p>\n\n<ul>\n  <li>Windowsで「設定」→「ネットワークとインターネット」→「モバイル ホットスポット」を開く\n    <ul>\n      <li>「インターネット接続を共有する」で、ルータに接続しているアダプタを選択</li>\n      <li>「Wi-Fi」を選択</li>\n      <li>「ネットワーク名」と「ネットワーク パスワード」をメモっておく</li>\n      <li>この状態で一番上のスイッチを「オン」にする\n        <ul>\n          <li>スイッチがアクティブカラーになったら準備完了</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"raspberrypi側の事前準備\">RaspberryPi側の事前準備</h1>\n\n<h2 id=\"etcwpa_supplicantwpa_supplicantconf-の修正\">/etc/wpa_supplicant/wpa_supplicant.conf の修正</h2>\n\n<p>モバイル ホットスポットか通常のルータか、どちらか生きてる方に接続にいくように設定する。<br />\n(いつもの環境ならモバイル ホットスポット使わなくて良いように)</p>\n\n<p>以下の「モバイルホットスポットのSSID名」「パスワード」は<br />\n上記でメモった「ネットワーク名」と「ネットワーク パスワード」を記入する。<br />\nダブルクォーテーションで囲むのを忘れないこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">ctrl_interface</span><span class=\"o\">=</span><span class=\"nv\">DIR</span><span class=\"o\">=</span>/var/run/wpa_supplicant <span class=\"nv\">GROUP</span><span class=\"o\">=</span>netdev\n<span class=\"nv\">update_config</span><span class=\"o\">=</span>1\n<span class=\"nv\">country</span><span class=\"o\">=</span>JP\n\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"デフォルトのSSID名\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span><span class=\"s2\">\"パスワード\"</span>\n        <span class=\"nv\">priority</span><span class=\"o\">=</span>3\n<span class=\"o\">}</span>\n\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"モバイルホットスポットのSSID名\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span><span class=\"s2\">\"パスワード\"</span>\n        <span class=\"nv\">priority</span><span class=\"o\">=</span>5\n<span class=\"o\">}</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npriority設定値は大きい方が優先される。<br />\n上記の場合、モバイルホットスポットが生きていればそちらが優先される</p>\n</blockquote>\n\n<h2 id=\"ap再接続用スクリプト\">AP再接続用スクリプト</h2>\n\n<p>モバイル ホットスポット の Enable/Disable を切り替えたとき、<br />\n(RaspberryPiを起動してからモバイルホットスポットを有効にするのを忘れていたことに気がついたなど)\nRaspberryPiのネットワーク設定は自動的に新しい環境に切り替わらない。<br />\nコマンドをチマチマ入力するのも面倒なので、コマンド イッパツで再接続処理するようにしておく。</p>\n\n<p>まず、 ~/wifi_reconnect.sh を以下の内容で作成する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo </span>wlan0 down..\n<span class=\"nb\">sudo </span>ifconfig wlan0 down\n<span class=\"nb\">sleep </span>1\n\n<span class=\"nb\">echo </span>wlan0 up..\n<span class=\"nb\">sudo </span>ifconfig wlan0 up\n<span class=\"nb\">sleep </span>3\n\n<span class=\"nb\">echo </span>re-get IP address...\n<span class=\"nb\">sudo </span>dhcpcd <span class=\"nt\">-k</span>\n<span class=\"nb\">sleep </span>3\n<span class=\"nb\">sudo </span>dhcpcd <span class=\"nt\">-n</span>\n<span class=\"nb\">sleep </span>15\n\n<span class=\"nb\">echo </span>DONE!!\n</code></pre></div></div>\n\n<p>スクリプトファイルに実行属性をつける。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod</span> +x ~/wifi_reconnect.sh\n</code></pre></div></div>\n\n<p>再接続したいタイミングで <code class=\"language-plaintext highlighter-rouge\">~/wifi_reconnect.sh</code>を実行する。<br />\nDHCPのアドレス確定時間分を待っているので、コマンド実行には20秒強かかる。</p>\n\n<h1 id=\"raspberrypiの起動\">RaspberryPiの起動</h1>\n\n<p>上記の準備が整ったら、RaspberryPiを起動する。<br />\n起動後、<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>(他のコマンドでも良いけど)でIPアドレスを確認する。</p>\n\n<ul>\n  <li>192.168.137.XXX になっていればOK</li>\n</ul>\n\n<p>また、PC側で「設定」→「ネットワークとインターネット」→「モバイル ホットスポット」の<br />\n「接続されているデバイス」にRaspberryPiが表示されているハズ。</p>\n\n<h1 id=\"問題点\">問題点</h1>\n\n<h2 id=\"windows10-pcがルータにつながっていないと使えない\">Windows10 PCがルータにつながっていないと使えない</h2>\n\n<p>ルータにつながっていないと、そもそもモバイル ホットスポット がオンできない。<br />\nこれは、ネットワーク環境がまったくない場合(つまりPCとRaspberryPiだけで箱庭環境だけ作りたいとき)は使えない。<br />\n回避策としては、スマホのテザリングでネットワークにつなぐ?\n間違って外部にアクセスしちゃったら、パケ死しそう。。。</p>\n\n<h2 id=\"pcの外側ルータのサブネット内からraspberrypiにアクセスできない\">PCの外側(ルータのサブネット内)からRaspberryPiにアクセスできない</h2>\n\n<p>モバイル ホットスポットのサブネットとルータのサブネットは別なので、<br />\nモバイル ホットスポットのサブネットの外側から内側へのアクセスはできない。<br />\nもちろん、ルータの外側からもアクセスできない。<br />\nRaspberryPiにアクセスできるのはモバイル ホットスポットを提供しているPCのみ。</p>\n\n<h2 id=\"mdnsが使えない\">mDNSが使えない</h2>\n\n<p>モバイル ホットスポットのサブネットとルータのサブネットは別なので、\nルータを超えられないmDNSは名前を取得できない。<br />\n回避策としては、/etc/hosts を名前エラーが出るたびに名前追加するか?</p>\n\n<p>なお、WindowsPCからRaspberryPiへのmDNS参照はできるが、RaspberryPiからWindowsPCへのmDNS参照はできない。</p>\n\n<h1 id=\"結論\">結論</h1>\n\n<p>とりあえず、RaspberryPiにアクセスするのはWindowsPC 1台のみで、<br />\nRaspberryPiからアクセスするはルータの外側のみ、という条件なら使えそう。</p>\n\n<p>う~ん、良いところまで行くんだけど、微妙に不満の残る結果に。。。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その6)</h1>\n      <p>Node-REDのメモ MQTT編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでMQTT通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"mqttでデータを送受信\">MQTTでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにmosquitto broker および mosquitto client toolsを使うこととします。<br />\nこれらは以下のコマンドでインストールできます。</p>\n\n<p>Ubuntuで動作確認。RaspberryPiでも大丈夫なはず。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mosquitto mosquitto-clients\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータ送信publish\">MQTTでデータ送信(Publish)</h2>\n\n<p>MQTTでデータを送信してみます</p>\n\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要なら「名前」を設定\n            <ul>\n              <li>省略するとサーバアドレスとポート番号が表示される</li>\n            </ul>\n          </li>\n          <li>「サーバ」 でブローカのアドレス(またはホスト名)を設定(例: PiDev25.local)</li>\n          <li>「ポート」 でポート番号を設定(一般的な設定なら1883のままで大丈夫)</li>\n          <li>SSL/TLS接続を使用する場合は「SSL/TLS接続を使用」のチェックを入れる</li>\n          <li>クライアントIDを指定したい場合は「クライアント」に設定。通常は空欄で大丈夫</li>\n          <li>キープアライブ時間を「キープアライブ時間」に設定</li>\n          <li>「セッションの初期化」?とりあえず初期設定のままで</li>\n          <li>「旧MQTT 3.1のサポート」?とりあえず初期設定のままで</li>\n          <li>「セキュリティ」タブ、「メッセージ」タブの内容は必要なら設定する。設定しなくても大丈夫</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に送信するトピックを設定\n        <ul>\n          <li>省略すると、トリガノードの出力に設定されているtopicが使用される</li>\n        </ul>\n      </li>\n      <li>「QoS」を「0」/「1」/「2」から選択</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される\n            <ul>\n              <li>トピックも省略されている場合はmqttと表示される</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のようにsubscriberコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> 《トピック》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカからすべてのトピック(“#”)を取得するよう指定しています。<br />\n-v 指定により、対象メッセージのトピックも表示されます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> Pidev25.local <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> <span class=\"s2\">\"#\"</span>\n</code></pre></div></div>\n<p>Node-RED側で mqttの送信をトリガするとmosquitto_subの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>test_data 0\ntest_data 1\ntest_data true\ntest_data false\ntest_data 文字列\ntest_data {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"f580f01a.f771f\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_publish\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"33450bad.82764c\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ea6d9236.74e038\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d7baa4c.08385\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"82148e63.4b97e\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d0b1ac7f.0ac0b\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7e6180b5.f29098\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"test_data\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6f26fe46.a01f58\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"バッファ\",\n        \"topic\": \"test_data\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 140,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d5a5b2db.83462\",\n        \"type\": \"debug\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 500,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"e6218cda.844308\",\n        \"type\": \"mqtt out\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"\",\n        \"qos\": \"\",\n        \"retain\": \"\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 570,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータを受信subscribe\">MQTTでデータを受信(subscribe)</h2>\n\n<p>MQTTでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に受信するトピックを設定\n        <ul>\n          <li>すべてのトピックを受信するには#を設定</li>\n          <li>省略することはできない</li>\n        </ul>\n      </li>\n      <li>「QoS」を設定</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>デプロイ後、ターミナル or コンソールで以下のようにpublisherコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-t</span> 《トピック》 <span class=\"nt\">-m</span> 《メッセージ》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカへ、トピック test_data で、メッセージ test を送信しています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> PiDev25.local <span class=\"nt\">-t</span> <span class=\"s2\">\"test_data\"</span> <span class=\"nt\">-m</span> <span class=\"s2\">\"test\"</span>\n</code></pre></div></div>\n\n<p>コマンドを実行するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"13f22fdd.2e009\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_subscribe\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1760f49a.fd2d3b\",\n        \"type\": \"debug\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 420,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"30229cea.13aba4\",\n        \"type\": \"mqtt in\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"#\",\n        \"qos\": \"2\",\n        \"datatype\": \"auto\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 150,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"1760f49a.fd2d3b\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian Buster Lite版のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian Buster Lite版のインストール</h1>\n      <p>Raspbian Buster with desktopのインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspbian Buster Lite」 の 「DownloadZIP」でダウンロードする。<br />\n以下の手順は、RaspberryPi Zero W、「Version: July 2019」 で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>は表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nframebuffer_width=1280\nframebuffer_height=720\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"ロケールやらタイムゾーンやらの設定\">ロケールやらタイムゾーンやらの設定</h1>\n\n<p>日本語表示や時刻を日本時間に設定するための設定を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    4 Localisation Options\n        I1 Change Locale\n            [ ] ja_JP.UTF-8 UTF-8     でスペースを押して[*] にする\n            TABを押して<Ok>を選んでリターン\n                Default locale for~ と聞かれるので、\n                ja_JP.UTF-8          を選択\n                TABを押して<Ok>を選んでリターン\n    4 Localisation Options\n        I2 Change Timezon\n            Asia\n                Tokyo\n    <Finish>\n</code></pre></div></div>\n\n<p>設定変更を有効にするにはrebootが必要。</p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"c\"># export PYENV_ROOT=/proj/.pyenv</span>\n<span class=\"c\"># export PATH=$PYENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(pyenv init -)\"</span>\n<span class=\"c\"># eval \"$(pyenv virtualenv-init -)\"</span>\n\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"c\"># export NODENV_ROOT=/proj/.nodenv</span>\n<span class=\"c\"># export PATH=$NODENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(nodenv init -)\"</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nSSHなら関係ないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"hdmiコンソール用日本語入力表示環境構築\">HDMIコンソール用日本語入力&表示環境構築</h1>\n\n<p>デフォルトのままだと、HDMIコンソールは日本語の入力はおろか、表示もできない。<br />\nそこで、日本語入力&表示環境を整備する。<br />\nHDMIコンソールで日本語を使わないなら本章は設定不要。</p>\n\n<h2 id=\"フォントのインストール\">フォントのインストール</h2>\n\n<p>フォントをインストールしないと表示できないのでまずはフォントのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk \n</code></pre></div></div>\n\n<h2 id=\"ターミナルエミュレータのインストール\">ターミナルエミュレータのインストール</h2>\n\n<p>デフォルトのターミナルは日本語を表示できないので、日本語対応のターミナルエミュレータを使う。<br />\nネット上にはjfbtermを使用する記事が多いが、jfbtermはイマイチらしいのでfbtermを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fbterm\n</code></pre></div></div>\n\n<h2 id=\"日本語変換システムのインストール\">日本語変換システムのインストール</h2>\n\n<p>日本語入力のためのプログラム。Windowsで言うところのMS-IMEやATOKに相当するもの。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>uim-fep uim-anthy\n</code></pre></div></div>\n\n<h2 id=\"fbtermの設定\">fbtermの設定</h2>\n\n<p>fbtermの設定は、 ~/.fbtermrc で行う。<br />\n<strong>HDMIコンソールから</strong> fbtermを一度起動すると ~/.fbtermrc ができるので、設定変更するときはこれを書き換える。<br />\n例えばこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>font-size<span class=\"o\">=</span>18\n</code></pre></div></div>\n\n<p>fbtermを起動したときに<code class=\"language-plaintext highlighter-rouge\">[input] can’t change kernel keymap table ~</code>と表示されるときは以下を実行すると良い。(表示されるだけで実害はないらしい)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>setcap <span class=\"s1\">'cap_sys_tty_config+ep'</span> /usr/bin/fbterm\n</code></pre></div></div>\n\n<p>または、以下でも良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chmod </span>u+s /usr/bin/fbterm\n</code></pre></div></div>\n\n<p>参考: <a href=\"https://qiita.com/mtomoaki_96kg/items/e5a946fd38f7318d3758?fbclid=IwAR2d8ekXNiD9cqvpqycdfinDZMHZ0OcTmaETTsci1UA9T-aDtc3LvfOiaa0\">https://qiita.com/mtomoaki_96kg/items/e5a946fd38f7318d3758?fbclid=IwAR2d8ekXNiD9cqvpqycdfinDZMHZ0OcTmaETTsci1UA9T-aDtc3LvfOiaa0</a></p>\n\n<h2 id=\"uim日本語変換システムの設定\">uim(日本語変換システム)の設定</h2>\n\n<p>uimでCTRL+SPACEでFEPの切り替えの設定。\n~/.uim に以下の内容を記述(なければ新規作成)。<br />\n参考: <a href=\"https://qiita.com/tukiyo3/items/376e3a2895a71ff9bfc7\">https://qiita.com/tukiyo3/items/376e3a2895a71ff9bfc7</a></p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>(define default-im-name 'anthy)\n(define-key generic-on-key? '(\"<Control> \" \"`\"))\n(define-key generic-off-key? '(\"<Control> \" \"`\"))\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n各行のシングルクォーテーションは1個だけ。文字列として区切っている訳ではない。<br />\n余計なシングルクォーテーションを入れると動かなくなるので注意!!</p>\n</blockquote>\n\n<h2 id=\"起動時にfbtermを起動する\">起動時にfbtermを起動する</h2>\n\n<p>起動時にfbtermを起動するには以下を ~/.profile 、 ~/.bashrc に追加</p>\n\n<h3 id=\"profile\">~/.profile</h3>\n\n<p>最後に以下の内容を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"o\">=</span> <span class=\"s2\">\"linux\"</span> <span class=\"o\">]</span>\n<span class=\"k\">then</span>\n<span class=\"c\">#   FBTERM=1 exec fbterm -- uim-fep</span>\n   <span class=\"nv\">FBTERM</span><span class=\"o\">=</span>1 fbterm <span class=\"nt\">--</span> uim-fep\n   <span class=\"nb\">exit\n</span><span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<p>本当はコメントアウトされてる方の exec を使うようにしないといけないが、現状うまく動かないらしい。<br />\n(Strechでは動いていたと思う)<br />\n仕方ないので、fbtermをbashの子プロセスとして実行するようにしてある。<br />\nこれだとうまく動いている(当然、メモリ消費量は増えるけど)。</p>\n\n<p>また、ログアウトの際にCTRL+Dを2回入力しないといけなくなる(fbtermからのexitとbashからのexit)のを回避するため、 fbterm終了時にexitコマンドを実行している。</p>\n\n<h3 id=\"bashrc\">~/.bashrc</h3>\n\n<p>最後に(でなくてもいいけど)、以下を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>linux<span class=\"p\">)</span>\n        <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$FBTERM</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"nb\">export </span><span class=\"nv\">TERM</span><span class=\"o\">=</span>fbterm\n        <span class=\"p\">;;</span>\n    fbterm<span class=\"p\">)</span>\n        <span class=\"c\"># 何もしない</span>\n        <span class=\"p\">;;</span>\n    <span class=\"k\">*</span><span class=\"p\">)</span>\n        <span class=\"c\"># 何もしない</span>\n        <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n</code></pre></div></div>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian SDカードイメージファイルの縮小</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian SDカードイメージファイルの縮小</h1>\n      <p>Raspbian SDカードイメージファイルの縮小</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2020/10/25/Jetson_nano_backup.html\">Jetson nano のSDカードをバックアップする</a> \nに改訂版を公開しました。そちらを参照してください。</p>\n\n<h1 id=\"イメージファイルの縮小\">イメージファイルの縮小</h1>\n\n<h3>『イメージファイルの縮小』はUbuntuで実行することを前提に書いてあります。</h3>\n\n<p>SDカードに作成した、RaspberryPiのオリジナルのカスタムブートディスク\n(<a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\">Raspbian Busterのインストール</a>、\n<a href=\"/memoBlog/2019/09/13/raspbian_buster_2.html\">Raspbian Buster Lite版のインストール</a>参照)\nは、イメージファイルにバックアップしておくと、\n再度カスタマイズ作業を行わなくても同じ環境を作成できる。</p>\n\n<p>ただ、このイメージファイルはSDカードを丸ごとファイル化するので、元のSDカードより小さなSDカードにコピーできない。<br />\n(スペック上同じ容量のSDカードでも微妙にサイズが違ったりするので入らないことがある)</p>\n\n<p>そこで、イメージファイルを縮小しておけば、小さなSDカードにもコピーできる(コピー時間も短縮できて一石二鳥)。<br />\nこのとき、ディスクイメージ内部のパーティション情報/ファイルシステム情報をきちんと縮小処理しておかないと\nファイルシステムエラーになってしまうので、注意が必要。</p>\n\n<p>今回はSDカードから作成したイメージファイルを<strong>Ubuntuで</strong>縮小処理するスクリプトを書いてみた。<br />\nとりあえず、手元の環境では動いているが、詳細評価したわけではないので、\n実行する場合は自己責任で。</p>\n\n<p>また、途中<strong>エラーチェックは行っていない</strong>ので、エラーが発生していないか、実行結果を注意深く確認すること。</p>\n\n<h2 id=\"virtualbox-共有フォルダのマウント\">Virtualbox 共有フォルダのマウント</h2>\n\n<p>SDカードのイメージファイルは大きいので、共有フォルダを使ってWindows側のフォルダをアクセスできるようにしておけばディスク領域を圧迫しなくて済む。<br />\nVirtualbox側で共有フォルダ「Share」を作成済みで、/Shareディレクトリにマウントする場合は以下のコマンドで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> vboxsf Share /Share/\n</code></pre></div></div>\n\n<h2 id=\"ツールのインストール\">ツールのインストール</h2>\n\n<p>イメージファイル内のパーティションをそれぞれloopデバイスに割り当てるツールを使用する。<br />\n以下のコマンドでインストールできる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>kpartx\n</code></pre></div></div>\n\n<h2 id=\"スクリプト\">スクリプト</h2>\n\n<p>以下のスクリプトを適当な名前(例えば<code class=\"language-plaintext highlighter-rouge\">shrink_img.sh</code>)で保存し、実行する(<code class=\"language-plaintext highlighter-rouge\">bash shrink_img.sh</code>)。<br />\n実行する前に使用するファイル名を設定すること。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: left\">変数</th>\n      <th style=\"text-align: left\">内容</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: left\">WORK_IMG_FILE</td>\n      <td style=\"text-align: left\">作業用イメージファイルのファイル名</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: left\">NEW_IMG_FILE</td>\n      <td style=\"text-align: left\">小さくしたイメージファイルのファイル名</td>\n    </tr>\n  </tbody>\n</table>\n\n<p>WORK_IMG_FILE で指定したファイルは書き変えられるので、オリジナルのイメージファイルは 別途残しておくこと。</p>\n\n<p>内部で<code class=\"language-plaintext highlighter-rouge\">sudo</code>を実行しているので、パスワードを聞かれたら入力する。</p>\n\n<p>途中、『警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?』と聞かれたら「y」を入力する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># イメージファイル</span>\n<span class=\"nv\">WORK_IMG_FILE</span><span class=\"o\">=</span>/Share/tmp.img            <span class=\"c\"># 作業ファイル</span>\n<span class=\"nv\">NEW_IMG_FILE</span><span class=\"o\">=</span>/Share/shrink.img          <span class=\"c\"># 縮小した(作成する)ファイル</span>\n\n<span class=\"c\"># イメージファイルをマッピング(マッピング済みでも問題ない) </span>\n<span class=\"c\"># 前回の操作が終わるのを待つため-sを付けておく</span>\n<span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-asv</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span>\n\n<span class=\"c\"># loopデバイス名を取得</span>\n<span class=\"c\"># 前回の操作が終わるのを待つため-sを付けておく</span>\n<span class=\"nv\">tmp_var</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-ls</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">LOOP_DEV</span><span class=\"o\">=</span>/dev/mapper/<span class=\"k\">${</span><span class=\"nv\">tmp_var</span><span class=\"p\">[6]</span><span class=\"k\">}</span>          <span class=\"c\"># 結果の位置は決め打ちで(姑息だけど)</span>\n\n<span class=\"c\"># 要求するブロックサイズの取得</span>\n<span class=\"nv\">tmp_var</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>resize2fs <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">req_fs_block</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">tmp_var</span><span class=\"p\">[-1]</span><span class=\"k\">}</span>                 <span class=\"c\"># サイズは結果の最後に入っている</span>\n\n<span class=\"c\"># パーティション情報の取得</span>\n<span class=\"nv\">part_info</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>parted <span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> unit B print<span class=\"sb\">`</span>\n<span class=\"c\"># 1行毎に分割</span>\n<span class=\"nv\">line</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">part_info</span><span class=\"p\">//;/ </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># ext4のパーティション番号を探す</span>\n<span class=\"nv\">part_number</span><span class=\"o\">=</span>0\n<span class=\"nv\">part_start</span><span class=\"o\">=</span>0\n<span class=\"nv\">target_type</span><span class=\"o\">=</span><span class=\"s2\">\"ext4\"</span>\n<span class=\"k\">for </span>l <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span> <span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各要素に分割</span>\n    <span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">l</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n    <span class=\"nv\">elm_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[0]</span><span class=\"k\">}</span>             <span class=\"c\"># パーティション番号</span>\n    <span class=\"nv\">elm_start</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[1]//B/</span><span class=\"k\">}</span>          <span class=\"c\"># ついでに最後のBを取り除いておく</span>\n    <span class=\"nv\">elm_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>               <span class=\"c\"># ファイルシステムタイプ</span>\n    <span class=\"c\"># echo $elm_number $elm_start $elm_type</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n        if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n            <span class=\"c\"># 対象のパーティションが見つかった</span>\n            <span class=\"nv\">part_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_number</span><span class=\"k\">}</span>\n            <span class=\"nv\">part_start</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_start</span><span class=\"k\">}</span>\n            <span class=\"nb\">break\n        </span><span class=\"k\">fi\n    fi\ndone\nif</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"o\">=</span> 0 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"s2\">\"のパーティションが見つかりませんでした\"</span>\n<span class=\"k\">else</span>\n    <span class=\"c\"># 新しいパーティション終了位置を計算</span>\n    <span class=\"nv\">new_fs_block</span><span class=\"o\">=</span><span class=\"k\">$((</span>req_fs_block <span class=\"o\">+</span> <span class=\"m\">100000</span><span class=\"k\">))</span>             <span class=\"c\"># 少し余裕(100000block=390MB)を持たせる</span>\n    <span class=\"nv\">new_fs_byte</span><span class=\"o\">=</span><span class=\"k\">$((</span>new_fs_block <span class=\"o\">*</span> <span class=\"m\">4096</span><span class=\"k\">))</span>                <span class=\"c\"># byteに換算</span>\n    <span class=\"nv\">part_end</span><span class=\"o\">=</span><span class=\"k\">$((</span>part_start <span class=\"o\">+</span> new_fs_byte <span class=\"o\">+</span> <span class=\"m\">2048</span><span class=\"k\">))</span>       <span class=\"c\"># さらに少し余裕を持たせる</span>\n    <span class=\"nv\">img_size_mb</span><span class=\"o\">=</span><span class=\"k\">$((</span><span class=\"o\">(</span>part_end <span class=\"o\">/</span> <span class=\"o\">(</span><span class=\"m\">1024</span> <span class=\"o\">*</span> <span class=\"m\">1024</span><span class=\"k\">))</span> + 10<span class=\"o\">))</span>    <span class=\"c\"># MBに換算 ついでにしつこいくらいに余裕を持たせる </span>\n\n    <span class=\"nb\">set</span> <span class=\"nt\">-x</span>          <span class=\"c\">#--------------------------------------</span>\n\n    <span class=\"c\"># ファイルシステムとパーティションの縮小</span>\n    <span class=\"nb\">sudo </span>e2fsck <span class=\"nt\">-f</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span> \n    <span class=\"nb\">sudo </span>resize2fs <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">new_fs_block</span><span class=\"k\">}</span>\n    parted <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> unit B resizepart <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">part_end</span><span class=\"k\">}</span>\n\n    <span class=\"c\"># 縮小コピー</span>\n    <span class=\"nb\">dd </span><span class=\"k\">if</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> <span class=\"nv\">of</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">NEW_IMG_FILE</span><span class=\"k\">}</span> <span class=\"nv\">count</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">img_size_mb</span><span class=\"k\">}</span> <span class=\"nv\">bs</span><span class=\"o\">=</span>1M\n\n    <span class=\"nb\">set</span> +x          <span class=\"c\">#--------------------------------------</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># マッピング解除</span>\n<span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-d</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span>\n \n</code></pre></div></div>\n\n<h1 id=\"新しいイメージファイルでブートsdを作る\">新しいイメージファイルでブートSDを作る</h1>\n\n<p>縮小したイメージファイルから作成したSDカードはSDカードの容量をすべて使用できるようになっていない。<br />\nそこで、コピーしたSDカードでブートした後、パーティションを拡張する必要がある。</p>\n\n<h2 id=\"sdカードへの書き込みは通常通り\">SDカードへの書き込みは通常通り</h2>\n\n<h2 id=\"書き込んだsdカードでブートする\">書き込んだSDカードでブートする</h2>\n\n<h2 id=\"sdカードのパーティション拡張\">SDカードのパーティション拡張</h2>\n\n<p>色々手順がめんどっちいので、スクリプト作成してみた。<br />\nとりあえず、手元の環境では動いているが、詳細評価したわけではないので、\n実行する場合は自己責任で。</p>\n\n<p>以下のスクリプトを適当な名前(例えば<code class=\"language-plaintext highlighter-rouge\">expand_partition.sh</code>)で保存し、実行する(<code class=\"language-plaintext highlighter-rouge\">bash expand_partition.sh</code>)<br />\n成功したらリブートすること。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># ターゲットのデバイス</span>\n<span class=\"nv\">target_device</span><span class=\"o\">=</span>/dev/mmcblk0\n\n<span class=\"c\"># パーティション情報の取得</span>\n<span class=\"nv\">part_info</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>parted <span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span> unit s print free<span class=\"sb\">`</span>\n\n<span class=\"c\"># 1行毎に分割</span>\n<span class=\"nv\">line</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">part_info</span><span class=\"p\">//;/ </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 最終行</span>\n<span class=\"c\"># declare -i last_index=${#line[@]}-1</span>\n<span class=\"c\"># last_line=${line[$last_index]}</span>\n<span class=\"nv\">last_line</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[</span><span class=\"k\">$((${#</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span><span class=\"o\">-</span><span class=\"m\">1</span><span class=\"k\">))</span><span class=\"p\">]</span><span class=\"k\">}</span>\n\n<span class=\"c\"># :で区切られた各要素に分割</span>\n<span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">last_line</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 変数名付け替え</span>\n<span class=\"c\"># last_number=${elm[0]}</span>\n<span class=\"c\"># last_start=${elm[1]}</span>\n<span class=\"nv\">last_end</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[2]</span><span class=\"k\">}</span>\n<span class=\"c\"># last_size=${elm[3]}</span>\n<span class=\"nv\">last_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>\n\n<span class=\"c\"># 確認</span>\n<span class=\"c\"># echo last_number=  $last_number</span>\n<span class=\"c\"># echo last_start=   $last_start</span>\n<span class=\"c\"># echo last_end=     $last_end</span>\n<span class=\"c\"># echo last_size=    $last_size</span>\n<span class=\"c\"># echo last_type=    $last_type</span>\n\n<span class=\"c\"># 最後のパーティションがfreeか確認</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">last_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> free <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># ext4のパーティション番号を探す</span>\n    <span class=\"nv\">part_number</span><span class=\"o\">=</span>0\n    <span class=\"nv\">target_type</span><span class=\"o\">=</span><span class=\"s2\">\"ext4\"</span>\n    <span class=\"k\">for </span>l <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span> <span class=\"p\">;</span> <span class=\"k\">do</span>\n        <span class=\"c\"># 各要素に分割</span>\n        <span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">l</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n        <span class=\"nv\">elm_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[0]</span><span class=\"k\">}</span>\n        <span class=\"nv\">elm_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n            <span class=\"c\"># echo $elm_number $elm_type</span>\n            <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n                </span><span class=\"nv\">part_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_number</span><span class=\"k\">}</span>\n                <span class=\"nb\">break\n            </span><span class=\"k\">fi\n        fi\n    done\n    if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"o\">=</span> 0 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"ext4のパーティションが見つかりませんでした\"</span>\n    <span class=\"k\">else</span>\n        <span class=\"c\"># リサイズの実行</span>\n        <span class=\"nb\">set</span> <span class=\"nt\">-x</span>\n        <span class=\"nb\">sudo </span>parted <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span> resizepart <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">last_end</span><span class=\"k\">}</span>\n        <span class=\"nb\">sudo </span>resize2fs <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span>p2\n        <span class=\"nb\">set</span> +x\n        <span class=\"nb\">echo</span> <span class=\"s2\">\"リブートしてください\"</span>\n    <span class=\"k\">fi\nelse\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"最終パーティションがfreeではありません\"</span>\n<span class=\"k\">fi</span>\n \n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その7)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その7)</h1>\n      <p>Node-REDのメモ 応用編 GPIO+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIOの入出力データをWebsocketで飛ばして、Dashboardから操作/Dashboardで表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"gpio入出力データをwebsocketで送受信raspberrypi\">GPIO入出力データをWebsocketで送受信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>RaspberryPiでGPIO出力</strong>、<strong>RaspberryPiでGPIO入力</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>、<strong>Websocketでデータを受信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、GPIO入力データをそのまま送信すると、受け取り側で「0はON?それともOFF?」となってしまうので、GPIO入力の0/1をON/OFFの文字列に変換するファンクションノードを追加している。\n  また、GPIO出力側も同様に、送信側から送られてきたON/OFFの文字列をGPIO出力データの1/0の数値に変換するファンクションノードを挿入している。<br />\n  ターゲットボードの正論理/負論理が変更になった場合はこれらのファンクションノードで調整すれば良い。</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"6e229d5a.774af4\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"109b9bce.e015e4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 730,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4834db5b.5c24d4\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": true,\n        \"x\": 190,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"3ff59514.52c732\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7d90bda.d7b4b8\",\n        \"type\": \"websocket in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"47e24d88.c603e4\",\n        \"x\": 280,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"a38bd8a1.0a5bd8\",\n                \"5e99ea44.cfdac4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9bc37a7.e1e9808\",\n        \"type\": \"websocket out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"c4985621.1edb48\",\n        \"x\": 830,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"a38bd8a1.0a5bd8\",\n        \"type\": \"debug\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 730,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3ff59514.52c732\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"1/0→OFF/ON\",\n        \"func\": \"if (msg.payload) {\\n    msg.payload = 'OFF';\\n}\\nelse {\\n    msg.payload = 'ON';\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"9bc37a7.e1e9808\",\n                \"a38bd8a1.0a5bd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5e99ea44.cfdac4\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"OFF/ON→0/1\",\n        \"func\": \"if (msg.payload == 'OFF') {\\n    msg.payload = 0;\\n}\\nelse {\\n    msg.payload = 1;\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"109b9bce.e015e4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47e24d88.c603e4\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/led0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"c4985621.1edb48\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/sw0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからgpio入出力データを送受信サーバ\">WebsocketからGPIO入出力データを送受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータ送信(サーバ)</strong>、<strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノードに<strong>その4</strong> の <strong>Dashboard のUIを作成する(ボタン)</strong>、<strong>Dashboardでテキストを表示する</strong>で作成したノードを接続すれば良い。</li>\n</ul>\n\n<p>この状態でRaspberryPi側でスイッチをON/OFFすると、Dashboardの「SW」の文字列のON/OFFが切り替わる。\nまた、DashboardのLLED_ON/LED_OFFのボタンをクリックすると、LEDが点灯/消灯する</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"ca6a740f.4d43b8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_GPIO\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"ac19aeee.9f8f5\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 260,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"2098e31e.e6832c\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 270,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8db70b6.86a1178\",\n        \"type\": \"ui_text\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 610,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f45af19.269e\",\n        \"type\": \"websocket in\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"fad64a63.6141a\",\n        \"client\": \"\",\n        \"x\": 270,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"8db70b6.86a1178\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"299e8287.226e6e\",\n        \"type\": \"websocket out\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"d7b33218.4a1f28\",\n        \"client\": \"\",\n        \"x\": 630,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"95b08556.d2cce\",\n        \"type\": \"debug\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 610,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"b7e42e0e.52bdb\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"1b4acf7b.a194c9\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"fad64a63.6141a\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/sw0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"d7b33218.4a1f28\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/led0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"1b4acf7b.a194c9\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ3\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node.jsでGoogle spreadsheet にデータを書き込む</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node.jsでGoogle spreadsheet にデータを書き込む</h1>\n      <p>Node.jsでGoogle spreadsheet にデータを書き込む</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Node.jsでGoogle spreadsheet にデータを書き込む方法。<br />\nサンプルプログラムを<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>に置きました。</p>\n\n<p>Google Drive API を サービスアカウントで操作する方法を取りました。</p>\n\n<p>OAuth認証を使う方法は事前準備がめんどっちいので、パス。<br />\nAPIキー認証はリードはできたけど、ライトが出来んかった。あと、シートを公開しないといけないが、やな感じだった。</p>\n\n<h1 id=\"詳細\">詳細</h1>\n\n<p>詳細は\n<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>\nのREADME おひび ソースコードを参照してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その8)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その8)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Google spreadsheet</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをGoogle spreadsheet に記録するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"google-spreadsheet用ノードのインストール\">Google spreadsheet用ノードのインストール</h2>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-contrib-viseo-google-」と入力</li>\n  <li>下に検索結果が出るので、「node-red-contrib-viseo-google-authentication」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら続けて「node-red-contrib-viseo-google-spreadsheet」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h2 id=\"googleの準備\">Googleの準備</h2>\n\n<p><a href=\"https://techblog.lclco.com/entry/2018/11/30/120000\">具体的な手順はこちらを参考にしてくだされ。</a> (コードの実装の手前まで)  <br />\nただし、<span style=\"color: red; \">有効にするAPI</span>は「Google Drive API」ではなく、「<span style=\"color: red; \">Google Sheets API</span>」なので、注意!!</p>\n\n<h3 id=\"認証情報の作成\">認証情報の作成</h3>\n\n<ul>\n  <li><a href=\"https://console.developers.google.com/project\">Google Developers Console</a> でプロジェクトを作成</li>\n  <li>Google Sheets APIを有効化</li>\n  <li>認証情報(サービスアカウント キー)を作成</li>\n  <li>保存された認証情報の秘密鍵をダウンロード<br />\n  このファイルはセキュリティ上 <strong>超重要</strong> なので、まちがって公開しないように!!!!<br />\n  ・・・・公開して後悔…なんちゃって(^^ゞ</li>\n</ul>\n\n<h3 id=\"記録用スプレッドシートの作成\">記録用スプレッドシートの作成</h3>\n\n<ul>\n  <li><a href=\"https://drive.google.com/drive/u/0/my-drive\">Google Drive</a>から記録するスプレッドシートを作成する(マイドライブからgoogleスプレッドシートを選択すると新規ファイルが作成される)</li>\n  <li>作成されたスプレッドシートに共有ユーザ(サービスアカウントキーのメールアドレス)を追加。権限を編集者、通知のチェックははずしてOKする</li>\n  <li>必要ならシートの追加や名前の変更を行っておく(以下ではシート名が「BME280」になっているものとして説明)</li>\n  <li>1行目に項目名を入れておく。ここではA列から「epoch」「日付」「温度」「湿度」「気圧」としている</li>\n  <li>B列(「日付」の列)を選択し、メニューから「表示形式」→「数値」→「日時」を選択(これをやらないと時刻が見えない))</li>\n  <li>作成されたスプレッドシートのID(URLの docs.google.com/spreadsheets/d/<span style=\"color: red; \">この部分</span>/edit~)をメモしておく</li>\n</ul>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"bme280ノード\">BME280ノード</h3>\n\n<ul>\n  <li><strong>その2</strong>の<strong>BME280を使用するフローを作成する</strong>と同様の手順でBME280ノードを作成する</li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>出力側にFunctionノードを接続\n  コードは以下。<br />\n  あとで時刻を使用しやすいようにエポック時刻で記録するようにしている。<br />\n  また、エポック時刻のままだとスプレッドシーで見たときに日時が分かり難いので、エポック時刻から日時に変更する計算式を入れておく。(ここで直接文字列にすることもできるが)<br />\n  また、Google Sheetsノードの入力はArrayである必要があるようで、Ayyayでラップしておく。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">var</span> <span class=\"nx\">date</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">epoch</span> <span class=\"o\">=</span> <span class=\"nx\">date</span><span class=\"p\">.</span><span class=\"nx\">getTime</span><span class=\"p\">();</span>\n<span class=\"c1\">// msg.payload.date  = date.toString();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">date</span>  <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">=indirect(\"R[0]C[-1]\", false) / (1000*60*60*24) + (9/24) + DATE(1970, 1, 1)</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">];</span>\n\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に上でメモっておいたスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:z」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>set dataのときは使用されないようだ</li>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n        </ul>\n      </li>\n      <li>「Action」に「Set Data」を選択し、その右は「Append」を選択</li>\n      <li>「input」は「msg」を選択し、「payload」を入力</li>\n      <li>「Fields」で「Select」を選択</li>\n      <li>その下に「key」と入力欄が表示されるので、「epoch」と入力し、「追加」をクリック</li>\n      <li>「date」と入力し、「追加」をクリック</li>\n      <li>「temperature_C」と入力し、「追加」をクリック</li>\n      <li>「humidity」と入力し、「追加」をクリック</li>\n      <li>「pressure_hPa」と入力\n        <ul>\n          <li>このデータの並びが入力のプロパティ名とスプレッドシートのセルの並びに対応する</li>\n        </ul>\n      </li>\n      <li>outputもよー分からんけど、とりあえず「msg」を選択し、「_output」にしておく\n        <ul>\n          <li>set dataのときは処理結果が入るようだ</li>\n          <li>get dataのときはリード結果が入るようだ</li>\n        </ul>\n      </li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>このノードの入力にファンクションノードの出力を接続</li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、温度等を測定、スプレッドシートに送信される。<br />\nスプレッドシートを確認すれば、そのデータが記録されているハズである。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1a4f21c6.53e09e\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+spreadsheet\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"b4e73f33.99aec8\",\n        \"type\": \"Bme280\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 220,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"a54ed898.2a114\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"b74c37d3.63a48\",\n        \"type\": \"inject\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 90,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"b4e73f33.99aec8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a54ed898.2a114\",\n        \"type\": \"function\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"データ整形\",\n        \"func\": \"var date = new Date();\\nmsg.payload.epoch = date.getTime();\\n// msg.payload.date  = date.toString();\\n// msg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\",false)/1000/60/60/24 + 9/24 + DATE(1970,1,1)';\\nmsg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\", false) / (1000*60*60*24) + (9 / 24) + DATE(1970, 1, 1)';\\n\\nmsg.payload = [msg.payload];\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 390,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"6a4f8cc4.882e54\",\n                \"adad9a.88697a68\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6a4f8cc4.882e54\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:z\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"set\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": false,\n        \"fields\": \"select\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"epoch\",\n            \"date\",\n            \"temperature_C\",\n            \"humidity\",\n            \"pressure_hPa\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"payload\",\n        \"output\": \"__output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 620,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"93209cb1.cd86\"\n            ],\n            [\n                \"9a8717a8.88bae8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"93209cb1.cd86\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9a8717a8.88bae8\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 220,\n        \"wires\": []\n    },\n    {\n        \"id\": \"adad9a.88697a68\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 850,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その9)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その9)</h1>\n      <p>Node-REDのメモ 応用編 Google spreadsheet Read</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGoogle spreadsheet からデータを取得したときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><strong>その8</strong> に従って準備済みであるものとする。</p>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で作成済みの認証情報を選択するか、「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に操作対象のスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:zzz」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n          <li>Rangeのフォーマットはシート名!開始セル:終了セル\n            <ul>\n              <li>開始セルと終了セルを両方省略することは可能(片方のみ省略は不可のよう)。<br />\nこの場合、シート全体が取得される。ただし、↑のように特定のシート名はダメかもしれない。</li>\n              <li>開始セル/終了セルはカラム名と行番号で構成されるが、カラム名か行番号は省略可能。\nたぶん、こんな感じ。\n                <ul>\n                  <li>開始カラム名を省略するとAが指定されたとみなす</li>\n                  <li>開始行番号を省略すると1が指定されたとみなす</li>\n                  <li>終了カラム名を省略すると最終カラム(zzz?)が指定されたとみなす</li>\n                  <li>終了行番号を省略すると最終行が指定されたとみなす</li>\n                </ul>\n              </li>\n              <li>大きな範囲を指定しても、以降空白セルであった場合は無視される(有効なデータがある範囲だけ読み込まれる)</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n          <li>プロパティ名はシート名_開始セル_終了セル</li>\n          <li>globalに記録しておけば、キャッシュとして使用出来て、なんども同じデータを読まなくて済む、という使い方かな?</li>\n        </ul>\n      </li>\n      <li>\n        <p>「Action」に「Get Data」を選択し、その右は「By line」を選択</p>\n      </li>\n      <li>「Labels」の「First line for labels」を選択しすると、outputの型がDictionaryになる。指定したセル範囲の開始カラム(シート全体の開始カラムではない)がキー名となる。<br />\n 選択しなければ、outputの型がArrayになる</li>\n      <li>「Labels」の「First column for labels」を選択しすると、outputの各要素の型がDictionaryになる。指定したセル範囲の開始行(シート全体の開始行ではない)の内容がキー名となる。<br />\n 選択しなければ、outputの各要素の型がArrayになる</li>\n      <li>\n        <p>この2つ、なんか逆な気もするけど…</p>\n      </li>\n      <li>outputにリード結果が入る。とりあえず「msg」を選択し、「_output」にしておく\n内容は「Labels」の設定内容によって変わる</li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>設定内容と取得内容の関係はよくワカランので、色々試してみてください。<br />\n現実的には、細かくデータを取得してどうこうするより、シート全体を取得して処理するような使い方になるのかな??</p>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、スプレッドシートの内容が取得されるハズ。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"5eb2475f.ea747\",\n        \"type\": \"tab\",\n        \"label\": \"spreadsheet_read\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"60d62f37.80a8a\",\n        \"type\": \"inject\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"bba510f2.5bb2d8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e183b4f0.c372f\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"37bd743e.1ca96c\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"bba510f2.5bb2d8\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"spreadsheet read\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:zzz\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"get\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": true,\n        \"fields\": \"all\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"\",\n        \"output\": \"_output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 290,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"e183b4f0.c372f\"\n            ],\n            [\n                \"37bd743e.1ca96c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PythonでIntel NCStick2</title>\n  </head>\n  <body>\n    <header>\n      <h1>PythonでIntel NCStick2</h1>\n      <p>PythonでIntel NCStick2を操作する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"事前準備\">事前準備</h1>\n<p>何はなくともPythonが必要。<br />\n実際には3.7.4を使用して動作確認。</p>\n\n<p>Pythonはpyenvでインストールしておくのが便利。インストール方法は \n<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a> を参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\npyenvとの相性が悪いらしく、pyenvで3.7.xがインストールされていると\n(python3.7コマンド自体は存在するので;実行自体はエラーで返ってくるが)、\nsetupvars.shでPYTHONPATHにpython3.7用pathが設定されてしまう。\nプログラム中で<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>でpathを追加しても、sys.pathの末尾に追加されてしまい、\n先に設定された3.7用モジュールがインポートされてしまう。\nもし、他のバージョンのpythonで実行する場合は<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">sys.path.insert</code>で\npathの先頭に追加するようにしないといけないようだ(試してないけど)。</p>\n\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n    <span class=\"err\">↓</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>ということで、下のプログラムソースの<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>の行は不要。</p>\n</blockquote>\n\n<h2 id=\"モジュールのインストール\">モジュールのインストール</h2>\n\n<p>必要なモジュール類をインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgfortran-6-dev\npip <span class=\"nb\">install </span>numpy\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h2 id=\"ワークディレクトリ\">ワークディレクトリ</h2>\n\n<p>色々共通で使いたいサイズのでっかいファイルがあるので、ワークディレクトリを以下の構成で作成しておく。<br />\n以降のopenVINO関連の投稿もこのディレクトリ構成を使うようにする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># C++プログラム湯尾</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++\n<span class=\"c\"># pythonプログラム用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/python\n<span class=\"c\"># モデルデータ用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP16\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP32\n</code></pre></div></div>\n\n<h1 id=\"参考\">参考</h1>\n\n<p><del>パクった</del> 参考にしたのは以下のあたり<br />\n解説や実行方法などはこっちを参照してちょ(相変わらずの他力本願ぶり…))</p>\n\n<ul>\n  <li><a href=\"http://jellyware.jp/openvino/\">JELLYWARE ゼロから学ぶディープラーニング推論</a>\n    <ul>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c07_ie_emotion.html\">Inference Engineを学んで感情分類</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c08_face_detection.html\">リアルタイム顔検出</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c09_emotion_app.html\">リアルタイム感情分析アプリ</a></li>\n    </ul>\n  </li>\n</ul>\n\n<p>顔検出+感情分類の参照元はカメラキャプチャした画像を処理しているけど、手元に適当なカメラがなかったので、JPEGファイルで実行するようにしてある(こっちの方が余計な処理なくて分かりやすいかな、と思ったのもある)。</p>\n\n<h1 id=\"感情分類\">感情分類</h1>\n\n<p>感情分類のプログラムを試す。</p>\n\n<h3 id=\"準備\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/emotions-recognition-retail-0003/FP16/emotions-recognition-retail-0003\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する顔画像(顔部分のみ切り出し)をPHOTO/face.jpgとして保存しておく。</p>\n\n<h3 id=\"プログラム\">プログラム</h3>\n\n<p>試したソースはこちら。<br />\nPCのubuntuで実行するための処理も追加済み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/face.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 結果取り出し\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>\n<span class=\"c1\"># 結果の最大値を持つインデックスを取得\n</span><span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 結果表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">結果'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">index_max</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"c1\"># 結果の詳細表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">詳細'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'スコア:</span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出\">顔検出</h1>\n\n<p>顔検出のプログラムを試す。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-1\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-1\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n\n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-1\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_detect.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_detect.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_detect.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出感情分類\">顔検出+感情分類</h1>\n\n<p>上の2つを合体させ、顔検出した結果に感情分類を実行する。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-2\">準備</h3>\n\n<p>モデルデータは上の2つをそのまま使用。</p>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-2\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出 + 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n# 日本語表示にはPillow使うとかしないといけないので、英語で。\n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# バウンティングボックスとラベルを表示する関数\n</span><span class=\"k\">def</span> <span class=\"nf\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ラベル領域サイズ\n</span>    <span class=\"n\">LABEL_W</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">12</span>    <span class=\"c1\"># 等幅フォントじゃないので正確ではないけど、大体こんな感じ\n</span>    <span class=\"n\">LABEL_H</span> <span class=\"o\">=</span> <span class=\"mi\">14</span>                <span class=\"c1\"># こっちもトライアンドエラーで微調整\n</span>    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">IMAGE_W</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">IMAGE_H</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># バウンディングボックス表示 \n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ラベル表示位置(X)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">IMAGE_W</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">IMAGE_W</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_W</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">xmin</span>\n    \n    <span class=\"c1\"># ラベル表示位置(Y)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span>\n    \n    <span class=\"c1\"># 文字列背景描画(塗りつぶし)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">label_x</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 文字列描画(座標は文字の左下)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX_SMALL</span><span class=\"p\">,</span> <span class=\"mf\">0.8</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n    \n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。特にminは補正しないとエラーになる\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 顔領域のみ切り出し \n</span>    <span class=\"n\">frame_face</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">[</span> <span class=\"n\">ymin</span><span class=\"p\">:</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">:</span><span class=\"n\">xmax</span> <span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 入力データフォーマットへ変換 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame_face</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span>   <span class=\"c1\"># サイズ変更 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">img_face</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img_face</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>    \n    <span class=\"c1\"># 推論実行 \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img_face</span><span class=\"p\">})</span>\n    \n    <span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>    \n    <span class=\"c1\"># 出力値が最大のインデックスを得る \n</span>    <span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"c1\"># print(list_emotion[index_max])\n</span>    <span class=\"n\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-2\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<h1 id=\"考察\">考察</h1>\n\n<p>基本パターンはこんな感じ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># モジュールのロード\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># 初期化\n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"s\">\"MYRIAD\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み\n</span><span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"s\">'xmlファイル'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"s\">'binファイル'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 推論実行 \n# imgは入力データ、Numpy配列 ndarray型\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># outが出力データ、Numpy配列 ndarray型\n</span>\n</code></pre></div></div>\n\n<p>入出力データの並びは読み込んだモデルに依存する。<br />\n入力データのサイズやRGB並び順などを合わせる。<br />\n(モデルに入力する際にリサイズすれば、元の画像ファイルのサイズは任意で良い。)<br />\n出力データはそのままでは「何のこっちゃ?」なので、きちんと整形してやる必要がある。</p>\n\n<p>ここに学習済みデータが色々登録されているらしい。<br />\n<a href=\"https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html\">https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html</a></p>\n\n<p>TensorflowやCaffeで作成した学習済みデータを変換することもできるらしいが、やり方はこれから調査。</p>\n\n<h1 id=\"参考情報\">参考情報</h1>\n<p><a href=\"https://software.intel.com/en-us/articles/OpenVINO-RelNotes\">openVINO toolkit リリースノート</a><br />\n<a href=\"https://git.uni-paderborn.de/rnagle/dldt/tree/noctua_plugin_develop\">openVINO toolkit リポジトリ</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>改訂版はこちら→<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></p>\n\n<p>caffeモデルなどをopenVINOへ変換するには、フルパッケージが必要らしい。<br />\nでもって、フルパッケージはRaspberryPiでは使用できなくて、WindowsやLinux、macOSが必要。<br />\nということで、openVINO フルパッケージをubuntu 18.04にインストールする。 <br />\n(16.04でも大丈夫かもしれないけど、今回は18.04を使う。LTSじゃないのはやめといた方が良さそう)</p>\n\n<h1 id=\"ダウンロード--インストール前半\">ダウンロード & インストール前半</h1>\n\n<p>ダウンロードはこの辺を参考に。。。<br />\n<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758</a><br />\nなにやら登録しないといけないらしい。</p>\n\n<p>ダウンロードしたら、てきとーなところに展開して、インストーラを実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\n2910.10 「2019 R3.1」がリリースされた。ファイル名は「l_openvino_toolkit_p_2019.3.376.tgz」</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf /Share/l_openvino_toolkit_p_2019.3.334.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2019.3.334\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n\n<p>nextをクリックしていけば大丈夫(Agreeするとこはあるけど)。<br />\nあとで色々インストールしろと言われるけど、あとでやるので無視して大丈夫<br />\n・・・・しばらく待つ・・・・<br />\nいったんFinishするとブラウザが表示される<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h1 id=\"インストール後半--動作確認\">インストール後半 & 動作確認</h1>\n\n<h2 id=\"install-external-software-dependenciesとな\">「Install External Software Dependencies」とな?</h2>\n\n<p>なんか実行してインストールしろってことらしい。<br />\nroot権限で実行しないとエラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh\n</code></pre></div></div>\n\n<p>なんか色々インストールされるっぽい。<br />\n中身はOSのディストリビューションとバージョンでインストールパッケージを切り替えてインストールしてるらしい。</p>\n\n<h2 id=\"set-the-environment-variablesとな\">「Set the Environment Variables」とな?</h2>\n\n<p>環境変数の設定らしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<p>~/.bashrcに追加しておくと良いとのことなので、そうする。</p>\n\n<h2 id=\"configure-the-model-optimizerとな\">「Configure the Model Optimizer」とな?</h2>\n\n<p>モデルオプティマイザの設定。<br />\nこれが欲しかったのよ。</p>\n\n<p>必要なpipモジュールをインストールするらしい。<br />\n必要なものだけインストールすることもできるけど、一括でインストールしといた方が手間がかからないでしょう。</p>\n\n<p>pyenvを使ってると、<code class=\"language-plaintext highlighter-rouge\">sudo pip3</code>されると、systemのpip3が動いてしまい、pyenv環境にモジュールがインストールされない。<br />\nスクリプトの中で必要なコマンドだけ実行する(随分スッキリしちゃったなぁ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\n</code></pre></div></div>\n\n<p>バージョン不一致とか言われたら、適宜バージョン合わせてアップグレードorダウングレードしてちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nsetuptoolsは<code class=\"language-plaintext highlighter-rouge\">pip install -U setuptools</code>でOKなはず。<br />\nnumpyは<code class=\"language-plaintext highlighter-rouge\">mxnet 1.3.1 has requirement numpy<1.15.0,>=1.8.2, but you'll have numpy 1.17.3 which is incompatible.</code>と言われるのだけど、tensorflow 1.15.0だとnumpy 1.16.0以上を要求する。<br />\nとりあえず、tenssorflowを1.13.1にしてnumpyを1.14.6にしてみて様子見。<br />\n現状のバージョン一覧は以下。これを<code class=\"language-plaintext highlighter-rouge\">requirements.txt</code>として保存し、<code class=\"language-plaintext highlighter-rouge\">pip install -r requirements.txt</code>するとこのバージョンでそろえてくれるはず。</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.8.1\nastor==0.8.0\ncertifi==2019.9.11\nchardet==3.0.4\ndecorator==4.4.0\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.1.7\ngraphviz==0.8.4\ngrpcio==1.24.3\nh5py==2.10.0\nidna==2.8\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.0\nMarkdown==3.1.1\nmock==3.0.5\nmxnet==1.3.1\nnetworkx==2.3\nnumpy==1.14.6\nonnx==1.6.0\nopt-einsum==3.1.0\npipdeptree==0.13.2\nprotobuf==3.6.1\nrequests==2.22.0\nsix==1.12.0\ntensorboard==1.13.1\ntensorflow==1.13.1\ntensorflow-estimator==1.13.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4\nurllib3==1.25.6\nWerkzeug==0.16.0\nwrapt==1.11.2\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nオリジナルの方法はこちら</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"run-the-verification-scripts-to-verify-installationとな\">「Run the Verification Scripts to Verify Installation」とな?</h2>\n\n<p>なになに、実行必須?たしかにapt installが実行される。<br />\nなら、タイトルに “to Verify Installation” とか書くなよ!</p>\n\n<p>build前に<code class=\"language-plaintext highlighter-rouge\">apt install</code> と <code class=\"language-plaintext highlighter-rouge\">pip install</code>が走る。</p>\n\n<p>こっちもpyenv使ってるとpipで悲しいことになるので、先にpipだけ実行しておく。<br />\nスクリプト側でもpipが走ってsystemのモジュールが追加されるが、悪影響はないと思うので、そのままにしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div></div>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n./demo_squeezenet_download_convert_run.sh\n</code></pre></div></div>\n\n<p>・・・・こんなことをやってるらしい・・・・</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">target_precision</code> は FP16 になっている</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">apt install</code> で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pip install</code>で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/open_model_zoo/tools/downloaderdownloader.py</code>でモデルのダウンロードを行う\n    <ul>\n      <li>ダウンロード済みならスキップ»</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/model_optimizer/mo.py</code>でモデル変換を行う\n    <ul>\n      <li>変換済みならスキップ»</li>\n    </ul>\n  </li>\n  <li>サンプルプログラムのbuild</li>\n  <li>サンプルプログラム(classification_sample_async)の実行<br />\n  実行結果はこんな感じ</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./classification_sample_async -d CPU -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/openvino_models/ir/FP16//public/squeezenet1.1/squeezenet1.1.xml \n\n[ INFO ] InferenceEngine: \n\tAPI version ............ 2.1\n\tBuild .................. custom_releases/2019/R3_cb6cad9663aea3d282e0e8b3e0bf359df665d5d0\n\tDescription ....... API\n[ INFO ] Parsing input parameters\n[ INFO ] Parsing input parameters\n[ INFO ] Files were added: 1\n[ INFO ]     /opt/intel/openvino/deployment_tools/demo/car.png\n[ INFO ] Creating Inference Engine\n\tCPU\n\tMKLDNNPlugin version ......... 2.1\n\tBuild ........... 30677\n\n[ INFO ] Loading network files\n[ INFO ] Preparing input blobs\n[ WARNING ] Image is resized from (787, 259) to (227, 227)\n[ INFO ] Batch size is 1\n[ INFO ] Loading model to the device\n[ INFO ] Create infer request\n[ INFO ] Start inference (10 asynchronous executions)\n[ INFO ] Completed 1 async request execution\n[ INFO ] Completed 2 async request execution\n[ INFO ] Completed 3 async request execution\n[ INFO ] Completed 4 async request execution\n[ INFO ] Completed 5 async request execution\n[ INFO ] Completed 6 async request execution\n[ INFO ] Completed 7 async request execution\n[ INFO ] Completed 8 async request execution\n[ INFO ] Completed 9 async request execution\n[ INFO ] Completed 10 async request execution\n[ INFO ] Processing output blobs\n\nTop 10 results:\n\nImage /opt/intel/openvino/deployment_tools/demo/car.png\n\nclassid probability label\n------- ----------- -----\n817     0.8364176   sports car, sport car\n511     0.0945683   convertible\n479     0.0419195   car wheel\n751     0.0091233   racer, race car, racing car\n436     0.0068038   beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon\n656     0.0037315   minivan\n586     0.0025940   half track\n717     0.0016044   pickup, pickup truck\n864     0.0012045   tow truck, tow car, wrecker\n581     0.0005833   grille, radiator grille\n\n[ INFO ] Execution successful\n\n[ INFO ] This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool\n</code></pre></div></div>\n\n<ul>\n  <li>終了</li>\n</ul>\n\n<p>もういっちょでも実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh\n</code></pre></div></div>\n\n<p>やってることは前のと同じ。<br />\nこっちはopenVINOのモデルをダウンロードするので、モデル変換はない。<br />\n最終的に実行しているデモプログラムはこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./security_barrier_camera_demo -d CPU -d_va CPU -d_lpr CPU -i /opt/intel/openvino/deployment_tools/demo/car_1.bmp -m ~/openvino_models/ir/FP16/intel/vehicle-license-plate-detection-barrier-0106/FP16/vehicle-license-plate-detection-barrier-0106.xml -m_lpr ~/openvino_models/ir/FP16/intel/license-plate-recognition-barrier-0001/FP16/license-plate-recognition-barrier-0001.xml -m_va ~/openvino_models/ir/FP16/intel/vehicle-attributes-recognition-barrier-0039/FP16/vehicle-attributes-recognition-barrier-0039.xml \n</code></pre></div></div>\n\n<h2 id=\"gpuやncstick使わないから以下スキップ\">GPUやNCStick使わないから以下スキップ</h2>\n\n<!--\n## 「Run a Sample Application」\n\nNCStickなどVPUベースの環境で実行するにはFP16モデルが必要\nデフォルトはFP32\n\nFP16: 16bit浮動小数点\nFP32: 32bit浮動小数点\n====\nmkdir ~/squeezenet1.1_FP16\ncd ~/squeezenet1.1_FP16\npython3 /opt/intel/openvino/deployment_tools/model_optimizer/mo.py --input_model ~/openvino_models/models/FP32/classification/squeezenet/1.1/caffe/squeezenet1.1.caffemodel --data_type FP16 --output_dir .\n\n====\n\n\n\n\n./classification_sample_async -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/squeezenet1.1_FP16/squeezenet1.1.xml -d CPU\n-->\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openCV で MPEG再生</title>\n  </head>\n  <body>\n    <header>\n      <h1>openCV で MPEG再生</h1>\n      <p>python + openCV でMPEGファイルを再生する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>python + openCV で MPEGファイルを再生するには、以下のようにread→imshowを繰り返せば良い。<br />\nしかし、これではフレームレートを考慮していないため、実際の時間とは異なる速度で再生されてしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n<span class=\"k\">while</span> <span class=\"n\">true</span><span class=\"p\">:</span>\n    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"k\">break</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>そこで、フレーム間に待ち時間を確保し、実際の時間と同じになるように再生する方法を考える。</p>\n\n<h1 id=\"フレーム間の待ち時間を決め打ちで待つパターン一番シンプルなパターン\">フレーム間の待ち時間を決め打ちで待つパターン(一番シンプルなパターン)</h1>\n\n<p>最も簡単な方法は、フレーム間に決め打ちでwait処理を挿入する方法である。<br />\nフレームレートは一定であるため、待ち時間も一定になる。<br />\n再生中にキー入力による中止を検出したいので、<code class=\"language-plaintext highlighter-rouge\">time.sleep()</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">cv2.waitKey(delay)</code>を使用している。<br />\n試した環境では、<code class=\"language-plaintext highlighter-rouge\">cv2.waitKey()</code> は 25くらいを指定すると大体30fpsに合うくらいの間隔になる(ちょっと早いかも)。<br />\n設定値はトライ&エラーで設定値を探るしかない。</p>\n\n<p>しかし、MPEG再生しか行わない場合はこれでも問題ないが、フレーム間に他の処理を行うと待ち時間が変わってきてしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./video.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 現在時刻\n</span>    <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"n\">index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># delay = 1         # 最速再生\n</span>    <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"mi\">25</span>          <span class=\"c1\"># それっぽい再生速度になるように決め打ちで\n</span>    \n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">delay</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"前回の時刻からフレーム間の待ち時間を決めるパターン\">前回の時刻からフレーム間の待ち時間を決めるパターン</h1>\n\n<p>前回の表示時刻を覚えておき、今回の表示時刻との間隔がフレームレートに一致するように待ち時間を調整する。<br />\nこれなら、フレーム間に他の処理を挿入しても(その処理時間が一定でなくても)、その処理時間を除いて待ち時間を設定できる。</p>\n\n<p>しかし、挿入した処理がフレームレートを超えてしまうと、回復する術がなく、どんどん遅れていってしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./video.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n        <span class=\"n\">tmp_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 現在時刻\n</span>    <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"n\">index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># 待ち時間計算用起点からの差分とsec/frameから待ち時間決定\n</span>    <span class=\"n\">delta_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">tmp_time</span>\n    <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">sec_per_frame</span> <span class=\"o\">-</span> <span class=\"n\">delta_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(f'delta =  {int(delta_time*1000)}    {delay}')\n</span>    <span class=\"c1\"># 待ち時間がsec/frameを超えてたら最小値に設定\n</span>    <span class=\"k\">if</span> <span class=\"n\">delay</span> <span class=\"o\"><</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n\n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">delay</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># 待ち時間計算用起点\n</span>    <span class=\"n\">tmp_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"経過時間から表示すべきフレームを求めて移動しながら表示するパターン\">経過時間から表示すべきフレームを求めて移動しながら表示するパターン</h1>\n\n<p>現在時刻と再生開始時刻の差から表示すべきフレーム番号を求め、必要であれば<code class=\"language-plaintext highlighter-rouge\">cap.set(cv2.CAP_PROP_POS_FRAMES, index)</code>で読み込みフレームを移動して現在時刻とフレームの同期をとる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">cap.set()</code>は処理に時間がかかるので、無条件で実行すると再生フレームレートが遅くなるため、フレーム飛びが発生したときのみ実行するようにする。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n# filepath = os.path.abspath(\"./video.mp4\") \n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./stopwatch.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 前回表示フレーム番号の更新\n</span>    <span class=\"n\">prev_index</span> <span class=\"o\">=</span> <span class=\"n\">index</span>\n    \n    <span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 現在時刻\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        \n        <span class=\"c1\"># 表示するフレーム位置の取得\n</span>        <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">sec_per_frame</span><span class=\"p\">)</span>\n        <span class=\"c1\"># print(f\"{prev_time}    {cur_time}    {prev_index}    {index}\")\n</span>        <span class=\"k\">if</span> <span class=\"n\">prev_index</span> <span class=\"o\">==</span> <span class=\"n\">index</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 前回と同じフレーム番号ならちょっと待つ\n</span>            <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.001</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"k\">break</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># 表示するフレーム位置が連続するフレームでなければ移動\n</span>    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">!=</span> <span class=\"n\">prev_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># 動作確認0.5秒待ってみる\n</span>    <span class=\"c1\"># time.sleep(0.5)\n</span>\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>YOLOv3を試す</title>\n  </head>\n  <body>\n    <header>\n      <h1>YOLOv3を試す</h1>\n      <p>Native & python でYOLOv3を実行してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"yolov3を試す\">YOLOv3を試す</h1>\n\n<p>YOLOv3をubuntu上で実行してみた。<br />\nopneVINOやNCStickは使用していない。<br />\n単にYOLOv3の動作確認したかった&python実装を探してたら見つかったサイトをトレースしてみただけの話。<br />\npyhton のバージョンは3.7.4</p>\n\n<p>元ネタはこちら→ <a href=\"https://qiita.com/massie_g/items/a2bcfac4fed66b1b0717#yolo-v3-tiny-%E3%83%A2%E3%83%87%E3%83%AB\">https://qiita.com/massie_g/items/a2bcfac4fed66b1b0717#yolo-v3-tiny-%E3%83%A2%E3%83%87%E3%83%AB</a></p>\n\n<p>とりあえず動かしてみた後にpythonのソース読んでみた。<br />\nイメージの読み込みも、結果の描画も、保存もNativeなライブラリをコールしてるだけだ… <br />\n完全なwrapperだ。。。<br />\nやりたかったこととちょっと違う。。。orz….</p>\n\n<p>darknetは色々な処理(jpegファイルの操作とか)を自前で実装しているので、\n色々ライブラリをインストールしなくて良いのは助かるんだけど、\n他の処理系に移植するのはめんどくさそうなんだな。。。</p>\n\n<p>ということで、さくっと試した手順だけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">WORKDIR</span><span class=\"o\">=</span>/work1/YOLO\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>\ngit clone https://github.com/pjreddie/darknet.git\n<span class=\"nb\">cd </span>darknet\nwget https://pjreddie.com/media/files/yolov3.weights\nwget https://pjreddie.com/media/files/yolov3-tiny.weights\n<span class=\"nb\">cd</span> ..\ngit clone https://github.com/mganeko/python3_yolov3.git\n<span class=\"nb\">cp</span> ./python3_yolov3/darknet-tiny-label.py ./darknet/python/\n<span class=\"nb\">cd </span>darknet\nmake\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>/darknet/libdarknet.so /usr/lib/libdarknet.so\n\n<span class=\"c\"># YOLOv3 native版の実行</span>\n./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg\n<span class=\"c\"># predictions.jpg が認識結果</span>\n<span class=\"nb\">mv </span>predictions.jpg predictions_yolo.jpg \n\n<span class=\"c\"># tinyYOLOv3 native版の実行</span>\n./darknet detect cfg/yolov3-tiny.cfg yolov3-tiny.weights data/dog.jpg\n<span class=\"c\"># predictions.jpg が認識結果</span>\n<span class=\"nb\">mv </span>predictions.jpg predictions_tiny.jpg\n\n<span class=\"c\"># tinyYOLOv3 python版の実行</span>\npython python/darknet-tiny-label.py \n<span class=\"c\"># detect_result.jpg が認識結果</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO</h1>\n      <p>darknetのモデルデータをopenVINOのモデルデータに変換し、tinyYOLOで画像認識を行う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOの2019 R3.1 がリリー(2019.10.29現在、ubuntu用のみ)スされ、YOLOのサンプルプログラムが用意されていたので、tinyYOLOを実行してみた。</p>\n\n<p>参考:<a href=\"https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html\">https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html</a></p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"darknetのモデルデータをopenvinoのモデルデータに変換\">darknetのモデルデータをopenVINOのモデルデータに変換</h1>\n\n<p>上記参考サイトの手順に従って、darknetのtinyYOLOモデルデータをopenVINOのモデルデータに変換する。</p>\n\n<h2 id=\"darknet--tensorflow-変換のためのプログラム取得\">darknet → tensorflow 変換のためのプログラム取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2\ngit clone https://github.com/mystic123/tensorflow-yolo-v3.git\n<span class=\"nb\">cd </span>tensorflow-yolo-v3/\ngit checkout ed60b90\n</code></pre></div></div>\n\n<h2 id=\"darknet-tinyyoloモデルデータ取得\">darknet tinyYOLOモデルデータ取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://raw.githubusercontent.com/pjreddie/darknet/master/data/coco.names\nwget https://pjreddie.com/media/files/yolov3-tiny.weights\n</code></pre></div></div>\n\n<h1 id=\"darknet--tensorflow-モデルデータ変換\">darknet → tensorflow モデルデータ変換</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python convert_weights_pb.py <span class=\"nt\">--class_names</span> coco.names <span class=\"nt\">--data_format</span> NHWC <span class=\"nt\">--weights_file</span> yolov3-tiny.weights <span class=\"nt\">--tiny</span>\n<span class=\"nb\">mv </span>frozen_darknet_yolov3_model.pb yolo_v3_tiny.pb\n</code></pre></div></div>\n\n<h2 id=\"モデルデータを変換\">モデルデータを変換</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP16 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div></div>\n\n<p>/work/NCS2/openvino_models/FP16ディレクトリに yolo_v3_tiny.bin yolo_v3_tiny.mapping yolo_v3_tiny.xml の3つが出来る</p>\n\n<blockquote>\n  <p>[!NOTE]\nFP32で計算する場合はこちら<br />\nNCStick使用時はFP16のみサポートなので、FP16で作っておくと使い回しできて楽。<br />\nそんなに認識精度が変わるわけでもなさそうだし。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP32\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP32 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"ラベルデータもコピー\">ラベルデータもコピー</h2>\n\n<p>pbファイルにはラベルデータが入っているはずだが、この後の変換でラベルデータは欠落するらしい。<br />\n後のプログラムのためにファイル名変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>coco.names <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels\n</code></pre></div></div>\n\n<h2 id=\"デモプログラムをコピー\">デモプログラムをコピー</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ..\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_yolov3_async <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>object_detection_demo_yolov3_async/\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>MP4ファイルのパスが絶対パスでないと正常にオープンできない対策(ubuntuではやらなくても大丈夫)</li>\n  <li>1フレームあたりの処理時間の計測と表示処理を追加</li>\n  <li>認識枠の表示色変更(ちょっと見難かったので)</li>\n  <li>計測データ表示処理の並べ替え(ソースが見難かったので。フレーム時間の追加以外の動作は変更なし)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py.org\t2019-10-29 05:08:34.982999999 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"p\">@@ -210,7 +210,8 @@</span>\n     else:\n         labels_map = None\n \n<span class=\"gd\">-    input_stream = 0 if args.input == \"cam\" else args.input\n</span><span class=\"gi\">+    # input_stream = 0 if args.input == \"cam\" else args.input\n+    input_stream = 0 if args.input == \"cam\" else os.path.abspath(args.input)\n</span> \n     is_async_mode = True\n     cap = cv2.VideoCapture(input_stream)\n<span class=\"p\">@@ -234,6 +235,8 @@</span>\n     next_request_id = 1\n     render_time = 0\n     parsing_time = 0\n<span class=\"gi\">+    frame_time = 0\n+    prev_time = time()\n</span> \n     # ----------------------------------------------- 6. Doing inference -----------------------------------------------\n     log.info(\"Starting inference...\")\n<span class=\"p\">@@ -263,6 +266,8 @@</span>\n \n         # Start inference\n         start_time = time()\n<span class=\"gi\">+        frame_time = start_time - prev_time         # 1フレームの処理時間\n+        prev_time = start_time\n</span>         exec_net.start_async(request_id=request_id, inputs={input_blob: in_frame})\n         det_time = time() - start_time\n \n<span class=\"p\">@@ -303,8 +308,9 @@</span>\n             # Validation bbox of detected object\n             if obj['xmax'] > origin_im_size[1] or obj['ymax'] > origin_im_size[0] or obj['xmin'] < 0 or obj['ymin'] < 0:\n                 continue\n<span class=\"gd\">-            color = (int(min(obj['class_id'] * 12.5, 255)),\n-                     min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span><span class=\"gi\">+            # color = (int(min(obj['class_id'] * 12.5, 255)),\n+            #          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n+            color = (255, 128, 128)\n</span>             det_label = labels_map[obj['class_id']] if labels_map and len(labels_map) >= obj['class_id'] else \\\n                 str(obj['class_id'])\n \n<span class=\"p\">@@ -322,16 +328,17 @@</span>\n         # Draw performance stats over frame\n         inf_time_message = \"Inference time: N\\A for async mode\" if is_async_mode else \\\n             \"Inference time: {:.3f} ms\".format(det_time * 1e3)\n<span class=\"gi\">+        frame_time_message = \"Frame time: {:.3f} ms\".format(frame_time * 1e3)\n</span>         render_time_message = \"OpenCV rendering time: {:.3f} ms\".format(render_time * 1e3)\n         async_mode_message = \"Async mode is on. Processing request {}\".format(cur_request_id) if is_async_mode else \\\n             \"Async mode is off. Processing request {}\".format(cur_request_id)\n         parsing_message = \"YOLO parsing time is {:.3f}\".format(parsing_time * 1e3)\n \n<span class=\"gd\">-        cv2.putText(frame, inf_time_message, (15, 15), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200, 10, 10), 1)\n-        cv2.putText(frame, render_time_message, (15, 45), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n-        cv2.putText(frame, async_mode_message, (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5,\n-                    (10, 10, 200), 1)\n-        cv2.putText(frame, parsing_message, (15, 30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n</span><span class=\"gi\">+        cv2.putText(frame, inf_time_message,    (15, 15),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, parsing_message,     (15, 30),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, render_time_message, (15, 45),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, frame_time_message,  (10, int(origin_im_size[0] - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, async_mode_message,  (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n</span> \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n</code></pre></div></div>\n\n<p>上のパッチ内容をa.patchとして保存したとして、以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch object_detection_demo_yolov3_async.py a.patch \n\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\n入力ファイルをmp4に変えるだけ。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしいが、カメラないので未確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>RaspberryPi用はopenVINO 2019R3のまま(2019.10.29現在、R3.1はリリースされていない)だけど、問題なし。</p>\n\n<p>ubuntuで作成した object_detection_demo_yolov3_async ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"静止画の場合-1\">静止画の場合</h2>\n\n<p>実行コマンドは以下。  ubuntuの実行コマンドと比べて、以下の変更がある。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--device MYRIAD</code>を追加</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">--cpu_extension</code>を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合-1\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\nこちらも入力ファイルをmp4に変えるだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p>openCVではMP4ファイルを保存することができる。<br />\nobject_detection_demo_yolov3_async.py に以下の変更を加えることで、認識結果をMP4ファイルに保存することができる。</p>\n\n<p>以下の修正ファイルは簡易的に保存する処理を追加したため、保存ファイル名は決め打ち。 <br />\n汎用的にするなら、オプションで指定できるようにしてもいいかもね。</p>\n\n<p>ただし、実際に保存するタイミングとMP4ファイルのタイムインデックスが一致するわけではないので、\n処理時の見た目と保存ファイルを再生したときの見た目は異なるので注意が必要。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"gi\">+++ record.py\t2019-10-29 11:35:37.296005608 +0900\n</span><span class=\"p\">@@ -218,6 +218,18 @@</span>\n     number_input_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n     number_input_frames = 1 if number_input_frames != -1 and number_input_frames < 0 else number_input_frames\n \n<span class=\"gi\">+    # =====================================================================================\n+    # 幅と高さを取得\n+    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n+    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n+    size = (width, height)\n+    # フレームレート(1フレームの時間単位はミリ秒)の取得\n+    frame_rate = int(cap.get(cv2.CAP_PROP_FPS))\n+    # フォーマット\n+    fmt = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')\n+    writer = cv2.VideoWriter('./outtest.mp4', fmt, frame_rate, size)\n+    # =====================================================================================\n+\n</span>     wait_key_code = 1\n \n     # Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n<span class=\"p\">@@ -342,6 +354,9 @@</span>\n \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n<span class=\"gi\">+        # =====================================================================================\n+        writer.write(frame)\n+        # =====================================================================================\n</span>         render_time = time() - start_time\n \n         if is_async_mode:\n<span class=\"p\">@@ -359,6 +374,10 @@</span>\n             is_async_mode = not is_async_mode\n             log.info(\"Switched to {} mode\".format(\"async\" if is_async_mode else \"sync\"))\n \n<span class=\"gi\">+    # =====================================================================================\n+    writer.release()\n+    # =====================================================================================\n+\n</span>     cv2.destroyAllWindows()\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO(C++版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO(C++版)</h1>\n      <p>tinyYOLOのC++版デモプログラムのbuildと実行</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nのpythonで実行したデモプログラムのC++版をbuild&実行してみる。</p>\n\n<h1 id=\"ubuntu環境での実行\">ubuntu環境での実行</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h2 id=\"デモのソースプログラム\">デモのソースプログラム</h2>\n\n<p>ドライバのインストール先 <code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/deployment_tools/open_model_zoo/demos</code> にあるので、そのまま参照しても良いが、\nソース修正に備えて、ソースをコピっておく(オーナーも変更)と何かと便利。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++/openvino_demo <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos <span class=\"nb\">.</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> demos/\n</code></pre></div></div>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>出力文字列のサイズと位置を調整</li>\n  <li>-saveオプションの追加と認識結果画像ファイルの保存処理の追加</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.hpp.org\t2019-10-31 14:39:14.757039048 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.hpp\t2019-10-31 06:16:49.178945707 +0900\n</span><span class=\"p\">@@ -93,6 +93,7 @@</span>\n /// \\brief Define a flag to disable showing processed video<br>\n /// It is an optional parameter\n DEFINE_bool(no_show, false, no_show_processed_video);\n<span class=\"gi\">+DEFINE_bool(save, false, \"Optional. save image file.\");\n</span> \n /**\n * \\brief This function shows a help message\n<span class=\"p\">@@ -115,4 +116,5 @@</span>\n     std::cout << \"    -iou_t                    \" << iou_thresh_output_message << std::endl;\n     std::cout << \"    -auto_resize              \" << input_resizable_message << std::endl;\n     std::cout << \"    -no_show                  \" << no_show_processed_video << std::endl;\n<span class=\"gi\">+    std::cout << \"    -save                     \" << \"Optional. save image file.\" << std::endl;\n</span> }\n</code></pre></div></div>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.org\t2019-10-31 05:46:38.515000000 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"p\">@@ -197,6 +197,21 @@</span>\n         }\n         // -----------------------------------------------------------------------------------------------------\n \n<span class=\"gi\">+        // =====================================================================================\n+        // 動画ファイルを書き出すためのオブジェクトを宣言する\n+        cv::VideoWriter writer;\n+        // =====================================================================================\n+        // =====================================================================================\n+        if (FLAGS_save) {\n+            double fps    = cap.get(cv::CAP_PROP_FPS);\t\t\t\t// フレームレートを取得\n+            int fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v');\t\t// MP4形式を指定\n+            // * エンコード形式 \"XVID\" = AVI, \"MP4V\" = MPEG4, \"WMV1\" = WMV\n+\n+            // 動画ファイルを書き出すためのファイルをオープンする\n+            writer.open(\"result.mp4\", fourcc, fps, cv::Size(width, height));\n+        }\n+        // =====================================================================================\n+\n</span>         // --------------------------- 1. Load inference engine -------------------------------------\n         slog::info << \"Loading Inference Engine\" << slog::endl;\n         Core ie;\n<span class=\"p\">@@ -356,17 +371,17 @@</span>\n                 std::ostringstream out;\n                 out << \"OpenCV cap/render time: \" << std::fixed << std::setprecision(2)\n                     << (ocv_decode_time + ocv_render_time) << \" ms\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 25), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 255, 0));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 15), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 255, 0));\n</span>                 out.str(\"\");\n                 out << \"Wallclock time \" << (isAsyncMode ? \"(TRUE ASYNC):      \" : \"(SYNC, press Tab): \");\n                 out << std::fixed << std::setprecision(2) << wall.count() << \" ms (\" << 1000.f / wall.count() << \" fps)\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 50), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 0, 255));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 30), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 0, 255));\n</span>                 if (!isAsyncMode) {  // In the true async mode, there is no way to measure detection time directly\n                     out.str(\"\");\n                     out << \"Detection time  : \" << std::fixed << std::setprecision(2) << detection.count()\n                         << \" ms (\"\n                         << 1000.f / detection.count() << \" fps)\";\n<span class=\"gd\">-                    cv::putText(frame, out.str(), cv::Point2f(0, 75), cv::FONT_HERSHEY_TRIPLEX, 0.6,\n</span><span class=\"gi\">+                    cv::putText(frame, out.str(), cv::Point2f(0, 45), cv::FONT_HERSHEY_TRIPLEX, 0.4,\n</span>                                 cv::Scalar(255, 0, 0));\n                 }\n \n<span class=\"p\">@@ -410,7 +425,7 @@</span>\n                         cv::putText(frame,\n                                 (label < static_cast<int>(labels.size()) ?\n                                         labels[label] : std::string(\"label #\") + std::to_string(label)) + conf.str(),\n<span class=\"gd\">-                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 1,\n</span><span class=\"gi\">+                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.4,\n</span>                                     cv::Scalar(0, 0, 255));\n                         cv::rectangle(frame, cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin)),\n                                       cv::Point2f(static_cast<float>(object.xmax), static_cast<float>(object.ymax)), cv::Scalar(0, 0, 255));\n<span class=\"p\">@@ -420,6 +435,11 @@</span>\n             if (!FLAGS_no_show) {\n                 cv::imshow(\"Detection results\", frame);\n             }\n<span class=\"gi\">+            // =====================================================================================\n+            if (FLAGS_save) {\n+                writer << frame;\n+            }\n+            // =====================================================================================\n</span> \n             t1 = std::chrono::high_resolution_clock::now();\n             ocv_render_time = std::chrono::duration_cast<ms>(t1 - t0).count();\n<span class=\"p\">@@ -457,6 +477,11 @@</span>\n         if (FLAGS_pc) {\n             printPerformanceCounts(*async_infer_request_curr, std::cout, getFullDeviceName(ie, FLAGS_d));\n         }\n<span class=\"gi\">+        // =====================================================================================\n+        if (FLAGS_save) {\n+            writer.release();\n+        }\n+        // =====================================================================================\n</span>     }\n     catch (const std::exception& error) {\n         std::cerr << \"[ ERROR ] \" << error.what() << std::endl;\n\n</code></pre></div></div>\n\n<h2 id=\"buildディレクトリの作成とbuild\">buildディレクトリの作成とbuild</h2>\n\n<p>cmakeの実行とbuild</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<p>ちょっと時間がかかる。</p>\n\n<h2 id=\"モデルデータ\">モデルデータ</h2>\n\n<p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nで作成したモデルデータをそのまま使用する。<br />\nラベルデータファイルのファイル名はモデルデータのxmlファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものに固定だが、モデルデータ作成時にコピー済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./intel64/Release/</code>に作成される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./intel64/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-l</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> ../../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>-save オプションを指定すると、認識結果の動画をresult.mp4(ファイル名は固定)に保存する。</p>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>デモプログラムはRasspberryPiでも動作させることができる。<br />\nソースはRaspberryPi側にはないので、ubuntuからコピーする。</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>ubuntuで作成した /work/NCS2/c++/openvino_demo/demos ディレクトリと/work/NCS2/openvino_models ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"buildディレクトリの作成とbuild-1\">buildディレクトリの作成とbuild</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a -Wno-psabi\"</span> ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./armv7l/Release/</code>に作成される。<br />\n入力ファイル(-i オプション)はフルパスで指定すること。相対パスだとファイルが見つからないと怒られる。<br />\n※ 下のパッチを当てると相対パスでも大丈夫になる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./armv7l/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-d</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> /work/NCS2/data/testvideo3.mp4 \n</code></pre></div></div>\n\n<p>なぜか-saveオプションが効かない。。。</p>\n\n<h2 id=\"入力ファイル名に相対パスを使用できるようにするためのパッチ\">入力ファイル名に相対パスを使用できるようにするためのパッチ</h2>\n\n<p>入力ファイル名をrealpath()で絶対パスに変換して使用することで対応。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.1\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-11-01 11:25:29.720856218 +0900\n</span><span class=\"p\">@@ -30,6 +30,9 @@</span>\n #include <ext_list.hpp>\n #endif\n \n<span class=\"gi\">+#include <limits.h>\n+#include <unistd.h>\n+\n</span> using namespace InferenceEngine;\n \n bool ParseAndCheckCommandLine(int argc, char *argv[]) {\n<span class=\"p\">@@ -180,7 +183,23 @@</span>\n \n         slog::info << \"Reading input\" << slog::endl;\n         cv::VideoCapture cap;\n<span class=\"gd\">-        if (!((FLAGS_i == \"cam\") ? cap.open(0) : cap.open(FLAGS_i.c_str()))) {\n</span><span class=\"gi\">+\n+        bool open_status;\n+        if (FLAGS_i == \"cam\") {\n+            open_status = cap.open(0);\n+        }\n+        else {\n+            std::string input_filename;\n+            char input_filename_char[PATH_MAX+1];\n+            if (!realpath(FLAGS_i.c_str(), input_filename_char)) {\n+                throw std::logic_error(\"Cannot get realpath\");\n+            }\n+            input_filename = input_filename_char;\n+            slog::info << \"input filename :\" + input_filename << slog::endl;\n+            open_status = cap.open(input_filename.c_str());\n+\n+        }\n+        if (!open_status) {\n</span>             throw std::logic_error(\"Cannot open input file or camera: \" + FLAGS_i);\n         }\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD</h1>\n      <p>openVINOのSSDのサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>YOLOとは別のアルゴリズムSSDで物体認識するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_ssd_async</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">models.list</code>によると、以下のモデルデータが使用できるらしい。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>face-detection-adas-????\nface-detection-adas-binary-????\nface-detection-retail-????\npedestrian-and-vehicle-detector-adas-????\npedestrian-detection-adas-????\npedestrian-detection-adas-binary-????\nperson-detection-retail-????\nvehicle-detection-adas-????\nvehicle-detection-adas-binary-????\nvehicle-license-plate-detection-barrier-????\n</code></pre></div></div>\n\n<p>ここでは、vehicle-detection-adas-binary-????を使ってみることにする。</p>\n\n<p>以下の手順でモデルデータをダウンロードする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/pedestrian-and-vehicle-detector-adas-0001/FP16/pedestrian-and-vehicle-detector-adas-0001\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>ラベルデータは用意されていないので、ラベルデータを以下の内容で、<code class=\"language-plaintext highlighter-rouge\">${models_diir}/pedestrian-and-vehicle-detector-adas-0001.labels</code>のファイル名で作成する。<br />\nオリジナルでは<code class=\"language-plaintext highlighter-rouge\">--label</code>オプションでラベルデータファイルを指定するようになっているが、\nモデルデータファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものをデフォルトのラベルデータファイルとして認識するように変更しておいた。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>UNKNOWN\nvehicles\npedestrians\nUNKNOWN\n</code></pre></div></div>\n\n<p>どのIDが何を示すか書いてる場所を見つけられなかったんだよなぁ~。<br />\nとりあえず、結果表示から推測するしかないか。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<p>ちょっとのつもりで改造してたら、結構たくさんの変更になったので、ソース全体を掲載しておく。<br />\n(RaspberryPiにはソース入ってないし)<br />\nおもな変更点は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--save</code> <code class=\"language-plaintext highlighter-rouge\">--log</code> <code class=\"language-plaintext highlighter-rouge\">--sync</code> <code class=\"language-plaintext highlighter-rouge\">--no_disp</code> オプションの追加</li>\n  <li>結果解析部分の関数化(後でYOLOと比較しやすいように)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># print(res[out_blob].shape)\n</span>    <span class=\"c1\">#  -> (1, 1, 200, 7)        200:バウンディングボックスの数\n</span>    <span class=\"c1\"># データ構成は\n</span>    <span class=\"c1\"># https://docs.openvinotoolkit.org/2019_R1/_pedestrian_and_vehicle_detector_adas_0001_description_pedestrian_and_vehicle_detector_adas_0001.html\n</span>    <span class=\"c1\"># の「outputs」を参照\n</span>    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"n\">out_blob</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]:</span>     <span class=\"c1\"># このループは200回まわる\n</span>        <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>                       <span class=\"c1\"># confidence for the predicted class(スコア)\n</span>        <span class=\"k\">if</span> <span class=\"n\">conf</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">:</span>      <span class=\"c1\"># 閾値より大きいものだけ処理\n</span>            <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n            <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 表示色\n</span>            <span class=\"c1\"># color = (min(class_id * 12.5, 255), min(class_id * 7, 255), min(class_id * 5, 255))\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>            <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># バウンディングボックスとラベル、スコアを表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">det_label</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">conf</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">%\"</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Demo supports only single output topologies\"</span>\n\n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"c1\"># SSDのinputsは1とは限らないのでスキャンする\n</span>    <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">for</span> <span class=\"n\">blob_name</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">:</span>\n        <span class=\"c1\"># print(f'{blob_name}   {net.inputs[blob_name].shape}')\n</span>        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">4</span><span class=\"p\">:</span>\n            <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">2</span><span class=\"p\">:</span>\n            <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"nb\">RuntimeError</span><span class=\"p\">(</span><span class=\"s\">\"Unsupported {}D input layer '{}'. Only 2D and 4D input layers are supported\"</span>\n                               <span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">),</span> <span class=\"n\">blob_name</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    <span class=\"k\">if</span> <span class=\"n\">img_info_input_blob</span><span class=\"p\">:</span>\n        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">img_info_input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n\n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span>     <span class=\"o\">=</span> <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span>  <span class=\"o\">=</span> <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span> <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_ssd_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                          <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                          <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でYOLO(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でYOLO(その2)</h1>\n      <p>openVINOのYOLOのプログラムをちょこっと改変</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> のソースを\n<a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> のソースと形状を合わせたもの。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">math</span> <span class=\"kn\">import</span> <span class=\"n\">exp</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-iout\"</span><span class=\"p\">,</span> <span class=\"s\">\"--iou_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Intersection over union threshold for overlapping \"</span>\n                                                       <span class=\"s\">\"detections filtering\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-ni\"</span><span class=\"p\">,</span> <span class=\"s\">\"--number_iter\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Number of inference iterations\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pc\"</span><span class=\"p\">,</span> <span class=\"s\">\"--perf_counts\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Report performance counters\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span>\n                      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-r\"</span><span class=\"p\">,</span> <span class=\"s\">\"--raw_output_message\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Output inference results raw values showing\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">YoloParams</span><span class=\"p\">:</span>\n    <span class=\"c1\"># ------------------------------------------- Extracting layer parameters ------------------------------------------\n</span>    <span class=\"c1\"># Magic numbers are copied from yolo samples\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">param</span><span class=\"p\">,</span> <span class=\"n\">side</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"mi\">3</span> <span class=\"k\">if</span> <span class=\"s\">'num'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'num'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">=</span> <span class=\"mi\">4</span> <span class=\"k\">if</span> <span class=\"s\">'coords'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'coords'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">classes</span> <span class=\"o\">=</span> <span class=\"mi\">80</span> <span class=\"k\">if</span> <span class=\"s\">'classes'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'classes'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">10.0</span><span class=\"p\">,</span> <span class=\"mf\">13.0</span><span class=\"p\">,</span> <span class=\"mf\">16.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">33.0</span><span class=\"p\">,</span> <span class=\"mf\">23.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">61.0</span><span class=\"p\">,</span> <span class=\"mf\">62.0</span><span class=\"p\">,</span> <span class=\"mf\">45.0</span><span class=\"p\">,</span> <span class=\"mf\">59.0</span><span class=\"p\">,</span> <span class=\"mf\">119.0</span><span class=\"p\">,</span> <span class=\"mf\">116.0</span><span class=\"p\">,</span> <span class=\"mf\">90.0</span><span class=\"p\">,</span> <span class=\"mf\">156.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">198.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">373.0</span><span class=\"p\">,</span> <span class=\"mf\">326.0</span><span class=\"p\">]</span> <span class=\"k\">if</span> <span class=\"s\">'anchors'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"p\">[</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">a</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'anchors'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n\n        <span class=\"k\">if</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">:</span>\n            <span class=\"n\">mask</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">idx</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'mask'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">mask</span><span class=\"p\">)</span>\n\n            <span class=\"n\">maskedAnchors</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n            <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">mask</span><span class=\"p\">:</span>\n                <span class=\"n\">maskedAnchors</span> <span class=\"o\">+=</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"n\">maskedAnchors</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">=</span> <span class=\"n\">side</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"o\">=</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span>  <span class=\"c1\"># Weak way to determine but the only one.\n</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">log_params</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># params_to_print = {'classes': self.classes, 'num': self.num, 'coords': self.coords, 'anchors': self.anchors}\n</span>        <span class=\"c1\"># [log.info(\"         {:8}: {}\".format(param_name, param)) for param_name, param in params_to_print.items()]\n</span>        <span class=\"k\">pass</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">entry_index</span><span class=\"p\">(</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">coord</span><span class=\"p\">,</span> <span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">location</span><span class=\"p\">,</span> <span class=\"n\">entry</span><span class=\"p\">):</span>\n    <span class=\"n\">side_power_2</span> <span class=\"o\">=</span> <span class=\"n\">side</span> <span class=\"o\">**</span> <span class=\"mi\">2</span>\n    <span class=\"n\">n</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">//</span> <span class=\"n\">side_power_2</span>\n    <span class=\"n\">loc</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">%</span> <span class=\"n\">side_power_2</span>\n    <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">side_power_2</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">coord</span> <span class=\"o\">+</span> <span class=\"n\">classes</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">entry</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">loc</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"p\">,</span> <span class=\"n\">h_scale</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"p\">):</span>\n    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">w</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">y</span> <span class=\"o\">-</span> <span class=\"n\">h</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">w</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">+</span> <span class=\"n\">h</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"nb\">dict</span><span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"o\">=</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"o\">=</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"o\">=</span><span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"o\">=</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">blob</span><span class=\"p\">,</span> <span class=\"n\">resized_image_shape</span><span class=\"p\">,</span> <span class=\"n\">original_im_shape</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">threshold</span><span class=\"p\">):</span>\n    <span class=\"c1\"># ------------------------------------------ Validating output parameters ------------------------------------------\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    <span class=\"k\">assert</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">==</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"s\">\"Invalid size of output blob. It sould be in NCHW layout and height should \"</span> \\\n                                     <span class=\"s\">\"be equal to width. Current height = {}, current width = {}\"</span> \\\n                                     <span class=\"s\">\"\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ------------------------------------------ Extracting layer parameters -------------------------------------------\n</span>    <span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">orig_im_w</span> <span class=\"o\">=</span> <span class=\"n\">original_im_shape</span>\n    <span class=\"n\">resized_image_h</span><span class=\"p\">,</span> <span class=\"n\">resized_image_w</span> <span class=\"o\">=</span> <span class=\"n\">resized_image_shape</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">predictions</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">flatten</span><span class=\"p\">()</span>\n    <span class=\"n\">side_square</span> <span class=\"o\">=</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n\n    <span class=\"c1\"># ------------------------------------------- Parsing YOLO Region output -------------------------------------------\n</span>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">side_square</span><span class=\"p\">):</span>\n        <span class=\"n\">row</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">//</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"n\">col</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">%</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"k\">for</span> <span class=\"n\">n</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">num</span><span class=\"p\">):</span>\n            <span class=\"n\">obj_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">)</span>\n            <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">scale</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"n\">box_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n            <span class=\"c1\"># Network produces location predictions in absolute coordinates of feature maps.\n</span>            <span class=\"c1\"># Scale it to relative coordinates.\n</span>            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">col</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">0</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">row</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"c1\"># Value for exp is very big number in some cases so following construction is using here\n</span>            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">w_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n                <span class=\"n\">h_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">3</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n            <span class=\"k\">except</span> <span class=\"nb\">OverflowError</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"c1\"># Depends on topology we need to normalize sizes by feature maps (up to YOLOv3) or by input shape (YOLOv3)\n</span>            <span class=\"n\">w</span> <span class=\"o\">=</span> <span class=\"n\">w_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_w</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"n\">h</span> <span class=\"o\">=</span> <span class=\"n\">h_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_h</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">):</span>\n                <span class=\"n\">class_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span>\n                                          <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">+</span> <span class=\"n\">j</span><span class=\"p\">)</span>\n                <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"n\">scale</span> <span class=\"o\">*</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">class_index</span><span class=\"p\">]</span>\n                <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                    <span class=\"k\">continue</span>\n                <span class=\"n\">objects</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">=</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">=</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"o\">=</span><span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"o\">=</span><span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">j</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">,</span>\n                                          <span class=\"n\">h_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_w</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"n\">objects</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n    <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">height_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span>\n    <span class=\"k\">if</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">height_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">*</span> <span class=\"n\">height_of_overlap_area</span>\n    <span class=\"n\">box_1_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">box_2_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">area_of_union</span> <span class=\"o\">=</span> <span class=\"n\">box_1_area</span> <span class=\"o\">+</span> <span class=\"n\">box_2_area</span> <span class=\"o\">-</span> <span class=\"n\">area_of_overlap</span>\n    <span class=\"k\">if</span> <span class=\"n\">area_of_union</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"mi\">0</span>\n    <span class=\"k\">return</span> <span class=\"n\">area_of_overlap</span> <span class=\"o\">/</span> <span class=\"n\">area_of_union</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>                 <span class=\"c1\"># 冒頭でinputは一つでなければエラーになってるので決め打ちで[0]\n</span>    <span class=\"n\">in_frame_shape</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">:]</span>       <span class=\"c1\"># HWC→BCHWに変更してあるので、height/widthはshape[2:]で取得\n</span>    <span class=\"k\">for</span> <span class=\"n\">layer_name</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">.</span><span class=\"n\">items</span><span class=\"p\">():</span>\n        <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">parents</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]].</span><span class=\"n\">shape</span><span class=\"p\">)</span>\n        <span class=\"n\">layer_params</span> <span class=\"o\">=</span> <span class=\"n\">YoloParams</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n        <span class=\"c1\"># log.info(\"Layer {} parameters: \".format(layer_name))\n</span>        <span class=\"n\">layer_params</span><span class=\"p\">.</span><span class=\"n\">log_params</span><span class=\"p\">()</span>\n        <span class=\"n\">objects</span> <span class=\"o\">+=</span> <span class=\"n\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">out_blob</span><span class=\"p\">,</span> \n                                        <span class=\"n\">in_frame_shape</span><span class=\"p\">,</span>\n                                        <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">],</span> \n                                        <span class=\"n\">layer_params</span><span class=\"p\">,</span>\n                                        <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Filtering overlapping boxes with respect to the --iou_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">sorted</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">,</span> <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"k\">lambda</span> <span class=\"n\">obj</span> <span class=\"p\">:</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">reverse</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">iou_threshold</span><span class=\"p\">:</span>\n                <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># Drawing objects with respect to the --prob_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">obj</span> <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span> <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">Detected boxes for batch {}:\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">))</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\" Class ID | Confidence | XMIN | YMIN | XMAX | YMAX | COLOR \"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">origin_im_size</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Validation bbox of detected object\n</span>        <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"c1\"># color = (int(min(obj['class_id'] * 12.5, 255)),\n</span>        <span class=\"c1\">#          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span>        <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n        <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]]</span> <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"ow\">and</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">>=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]</span> <span class=\"k\">else</span> \\\n            <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">])</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span>\n                <span class=\"s\">\"{:^9} | {:10f} | {:4} | {:4} | {:4} | {:4} | {} \"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">det_label</span><span class=\"p\">,</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">color</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]),</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span>\n                    <span class=\"s\">\"#\"</span> <span class=\"o\">+</span> <span class=\"n\">det_label</span> <span class=\"o\">+</span> <span class=\"s\">' '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"s\">' %'</span><span class=\"p\">,</span>\n                    <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.6</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"c1\"># YOLOのoutputsは1ではない\n</span>    \n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Sample supports only YOLO V3 based single input topologies\"</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>     <span class=\"c1\"># inputは一つだけなので決め打ちで[0]\n</span>    \n    <span class=\"c1\">#  Defaulf batch_size is 1\n</span>    <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n    \n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n        \n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span> <span class=\"o\">=</span>      <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span> <span class=\"o\">=</span>   <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span>  <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_yolov3_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                             <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                             <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                             <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-iout</span> IOU_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-ni</span> NUMBER_ITER] <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-r</span><span class=\"o\">]</span>\n                                             <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG]\n                                             <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n  <span class=\"nt\">-iout</span> IOU_THRESHOLD, <span class=\"nt\">--iou_threshold</span> IOU_THRESHOLD\n                        Optional. Intersection over union threshold <span class=\"k\">for\n                        </span>overlapping detections filtering\n  <span class=\"nt\">-ni</span> NUMBER_ITER, <span class=\"nt\">--number_iter</span> NUMBER_ITER\n                        Optional. Number of inference iterations\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_counts</span>    Optional. Report performance counters\n  <span class=\"nt\">-r</span>, <span class=\"nt\">--raw_output_message</span>\n                        Optional. Output inference results raw values showing\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WindowsでX-serve</title>\n  </head>\n  <body>\n    <header>\n      <h1>WindowsでX-serve</h1>\n      <p>WindowsでX-serveを使用するためにVcXsrvを使う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>SSH ログインしたLinuxマシンからX-Windowプログラムを実行したときに、ウィンドウをWindoesマシンに表示する方法。<br />\nUbuntu、RaspberryPiともにOK。</p>\n\n<h1 id=\"vcxsrvのインストール\">VcXsrvのインストール</h1>\n\n<p>このあたりを参考に(といっても、ダウンロードしてインストーラ実行するだけだけど)。<br />\n<a href=\"https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html\">https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html</a></p>\n\n<h1 id=\"設定のメモ\">設定のメモ</h1>\n\n<h2 id=\"リモートマシンからの要求を受け付ける\">リモートマシンからの要求を受け付ける</h2>\n\n<p>リモートマシンからの要求を受け付けるには、起動時に3ページ目で”Disable access control” にチェックを入れる。</p>\n\n<blockquote>\n  <p>[!NOTE]\nC:\\Program Files\\VcXsrv\\X0.hosts にクライアント(Linuxマシン)のIPアドレスを書いておくと、”Disable access control”にチェックを入れなくても良いらしい。<br />\nしかし、サブネット全体を指定するために「192.168.1.」とやってもうまく動かない。。。<br />\n個別に「192.168.1.5」と書いておくとOK</p>\n</blockquote>\n\n<h2 id=\"逐一設定するのがめんどい\">逐一設定するのがめんどい</h2>\n\n<p>4ページ目で”Save configuration”\tをクリックして保存した設定ファイル(拡張子は”.xlaunch”)を実行すれば設定済みの状態で起動できる。</p>\n\n<h2 id=\"linux側の設定\">Linux側の設定</h2>\n\n<p>Linux側では~/.bashrcに以下を追加しておくと、SSHでlog inしたときに自動でDISPLAY変数を設定してくれる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n\t</span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XXX.XXX:0.0\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h2 id=\"その他注意事項\">その他注意事項</h2>\n\n<p>VcXsrvを起動するとキーボードが勝手に変わることがあるらしい。<br />\n日本語入力できなくなったらWindows+SPACEで確認すること。</p>\n\n<h2 id=\"愚痴\">愚痴</h2>\n\n<p>コマンドラインオプションで設定できないか調べてみたが、見つからない。<br />\n「Addituinal parameters」という設定項目があるので、何かしら設定できるはずなんだけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbianのディスクイメージのアーカイブ</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbianのディスクイメージのアーカイブ</h1>\n      <p>Raspbianのディスクイメージのアーカイブのありかをすぐ忘れてしまうのでメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"メモ\">メモ</h1>\n\n<p>Raspbianのディスクイメージのアーカイブは以下にある。<br />\n各バージョン(日付)別にディレクトリ分けされている。<br />\nミラーサイトが爆速なのでおススメ。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>項目</th>\n      <th>URL</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>最新版</td>\n      <td><a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(本家)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_armhf/images/\">https://downloads.raspberrypi.org/raspios_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Full版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_full_armhf/images/\">https://downloads.raspberrypi.org/raspios_full_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_lite_armhf/images/\">https://downloads.raspberrypi.org/raspios_lite_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(ミラーサイト)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Full版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(2020/02以前版)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspbian/images/\">https://downloads.raspberrypi.org/raspbian/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspbian_lite/images/\">https://downloads.raspberrypi.org/raspbian_lite/images/</a></td>\n    </tr>\n  </tbody>\n</table>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO で顔検出(特定人物識別)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO で顔検出(特定人物識別)</h1>\n      <p>openVINOの顔検出(特定人物識別)のサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOで顔検出(特定人物識別)するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"ソースをワークディレクトリにコピー\">ソースをワークディレクトリにコピー</h1>\n\n<p>ファイルのオーナがrootなので、編集しやすいようにワークディレクトリにソースをコピーし、そこで作業する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>face_recognition_demo/\n</code></pre></div></div>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p>いくつかのモデルデータが必要になるので、ダウンロードする。<br />\nワイルドカードでファイル指定したかったので、wgetでなくcurlを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/landmarks-regression-retail-0009/FP16/landmarks-regression-retail-0009.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-reidentification-retail-0095/FP16/face-reidentification-retail-0095.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\n<span class=\"nb\">cd</span> ..\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ncurlは「カレントディレクトリにターゲットと同じファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-O</code> と 「任意のファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-o</code>オプションしかなく、\nwgetの「ターゲットと同じファイル名で保存先ディレクトリを指定して保存」の<code class=\"language-plaintext highlighter-rouge\">-P</code>に相当するオプションがないので、\nカレントディレクトリを保存先に移動してから<code class=\"language-plaintext highlighter-rouge\">-O</code> オプションでコマンドを実行する。</p>\n</blockquote>\n\n<h1 id=\"足りないモジュールのインストール\">足りないモジュールのインストール</h1>\n\n<p>使用するモジュールでこれまでのお試しで未インストールのモジュールがあるのでインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>scipy\n</code></pre></div></div>\n\n<h1 id=\"ソースの修正\">ソースの修正</h1>\n\n<p>ソースはそのままで問題ないが、ちょっと修正しておく。</p>\n\n<p>主な変更内容は以下の通り。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code> オプションの追加と関連処理</li>\n  <li>Unknownと識別できた場合で検出枠の色を変える</li>\n  <li>入力ファイルを絶対パスに変換(不具合対策)</li>\n  <li>出力ファイルのフォーマットのmp4対応を追加(オリジナルはaviのみ対応)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur face_recognition_demo.org/face_recognition_demo.py face_recognition_demo/face_recognition_demo.py\n</span><span class=\"gd\">--- face_recognition_demo.org/face_recognition_demo.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/face_recognition_demo.py\t2019-11-27 06:29:07.507574900 +0900\n</span><span class=\"p\">@@ -62,6 +62,10 @@</span>\n     gallery.add_argument('--run_detector', action='store_true',\n                          help=\"(optional) Use Face Detection model to find faces\" \\\n                          \" on the face images, otherwise use full images.\")\n<span class=\"gi\">+    gallery.add_argument('--run_detector_no_save', action='store_true',\n+                         help=\"(optional) Use Face Detection model to find faces\" \\\n+                         \" on the face images, otherwise use full images.\" \\\n+                         \" not save detected face image.\")\n</span> \n     models = parser.add_argument_group('Models')\n     models.add_argument('-m_fd', metavar=\"PATH\", default=\"\", required=True,\n<span class=\"p\">@@ -142,7 +146,7 @@</span>\n         log.info(\"Building faces database using images from '%s'\" % (args.fg))\n         self.faces_database = FacesDatabase(args.fg, self.face_identifier,\n                                             self.landmarks_detector,\n<span class=\"gd\">-                                            self.face_detector if args.run_detector else None, args.no_show)\n</span><span class=\"gi\">+                                            self.face_detector if args.run_detector or args.run_detector_no_save else None, args.no_show, args.run_detector_no_save)\n</span>         self.face_identifier.set_faces_database(self.faces_database)\n         log.info(\"Database is built, registered %s identities\" % \\\n             (len(self.faces_database)))\n<span class=\"p\">@@ -261,9 +265,8 @@</span>\n             .face_identifier.get_identity_label(identity.id)\n \n         # Draw face ROI border\n<span class=\"gd\">-        cv2.rectangle(frame,\n-                      tuple(roi.position), tuple(roi.position + roi.size),\n-                      (0, 220, 0), 2)\n</span><span class=\"gi\">+        color1 = (0, 220, 0) if identity.id == FaceIdentifier.UNKNOWN_ID else (0, 0, 220)\n+        cv2.rectangle(frame, tuple(roi.position), tuple(roi.position + roi.size), color1, 2)\n</span> \n         # Draw identity label\n         text_scale = 0.5\n<span class=\"p\">@@ -398,19 +401,17 @@</span>\n         try:\n             stream = int(path)\n         except ValueError:\n<span class=\"gd\">-            pass\n</span><span class=\"gi\">+            # 数字でなければ絶対パスに変換\n+            stream = osp.abspath(path)\n</span>         return cv2.VideoCapture(stream)\n \n     @staticmethod\n     def open_output_stream(path, fps, frame_size):\n         output_stream = None\n         if path != \"\":\n<span class=\"gd\">-            if not path.endswith('.avi'):\n-                log.warning(\"Output file extension is not 'avi'. \" \\\n-                        \"Some issues with output can occur, check logs.\")\n</span><span class=\"gi\">+            forcc = cv2.VideoWriter.fourcc(*'mp4v') if path.endswith('.mp4') else cv2.VideoWriter.fourcc(*'MJPG')\n</span>             log.info(\"Writing output to '%s'\" % (path))\n<span class=\"gd\">-            output_stream = cv2.VideoWriter(path,\n-                                            cv2.VideoWriter.fourcc(*'MJPG'), fps, frame_size)\n</span><span class=\"gi\">+            output_stream = cv2.VideoWriter(path, forcc, fps, frame_size)\n</span>         return output_stream\n \n \n<span class=\"gh\">diff -ur face_recognition_demo.org/faces_database.py face_recognition_demo/faces_database.py\n</span><span class=\"gd\">--- face_recognition_demo.org/faces_database.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/faces_database.py\t2019-11-20 06:31:13.481819754 +0900\n</span><span class=\"p\">@@ -36,10 +36,11 @@</span>\n         def cosine_dist(x, y):\n             return cosine(x, y) * 0.5\n \n<span class=\"gd\">-    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False):\n</span><span class=\"gi\">+    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False, no_db_save=False):\n</span>         path = osp.abspath(path)\n         self.fg_path = path\n         self.no_show = no_show\n<span class=\"gi\">+        self.no_db_save = no_db_save\n</span>         paths = []\n         if osp.isdir(path):\n             paths = [osp.join(path, f) for f in os.listdir(path) \\\n<span class=\"p\">@@ -96,7 +97,7 @@</span>\n                     self.add_item(descriptor, label)\n \n     def ask_to_save(self, image):\n<span class=\"gd\">-        if self.no_show:\n</span><span class=\"gi\">+        if self.no_show or self.no_db_save:\n</span>             return None\n         save = False\n         label = None\n<span class=\"p\">@@ -209,12 +210,14 @@</span>\n             match = len(self.database)-1\n         else:\n             filename = \"{}-{}.jpg\".format(label, len(self.database[match].descriptors)-1)\n<span class=\"gd\">-        filename = osp.join(self.fg_path, filename)\n-\n-        log.debug(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n-        if osp.exists(filename):\n-            log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n-        cv2.imwrite(filename, image)\n</span><span class=\"gi\">+        \n+        if name :\n+            filename = osp.join(self.fg_path, filename)\n+            log.info(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n+            if osp.exists(filename):\n+                log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n+            else :\n+                cv2.imwrite(filename, image)\n</span>         return match\n \n     def add_item(self, desc, label):\n</code></pre></div></div>\n\n<h1 id=\"前準備\">前準備</h1>\n\n<p>識別したい顔の画像を適当なディレクトリに保存しておく。ファイル形式はjpgまたはpng。<br />\n一人ずつ1画像で顔部分のみ切り出しておく。<br />\n複数の人の顔を識別したい場合はそれぞれ別々に保存しておく。</p>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"実行用スクリプトの作成\">実行用スクリプトの作成</h2>\n\n<p>実行コマンドが長ったらしくて入力が面倒なので、以下のスクリプト(demo.sh)を作成しておく。<br />\nUbuntuとRaspberrypiを識別して自動でコマンドオプションを変更するようにしてある。 \n作成したら実行属性を付与しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/bin/bash</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"face_recognition_demo.py\"</span>\n\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"       -m_fd models/face-detection-retail-0004.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_lm models/landmarks-regression-retail-0009.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_reid models/face-reidentification-retail-0095.xml\"</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"o\">==</span> <span class=\"s2\">\"armv7l\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Raspberry Pi\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_fd MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_lm MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_reid MYRIAD\"</span>\n<span class=\"k\">else\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Ubuntu\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> --cpu_lib /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so\"</span>\n<span class=\"k\">fi\n\n\nif</span> <span class=\"o\">[</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 0 <span class=\"nt\">-o</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 1 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n\t<span class=\"c\"># パラメータなし/1個はエラー</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\n</span><span class=\"s2\">==== usage ====\"</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"nv\">$0</span><span class=\"s2\"> database_dir input_file [other option(s)]</span><span class=\"se\">\\n\\n\\n</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">exit </span>1\n<span class=\"k\">else\n    </span><span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -fg </span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\"> --input </span><span class=\"k\">${</span><span class=\"nv\">2</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    <span class=\"c\"># 3番目以降すべてのパラメータを追加</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"p\">@</span>:3:<span class=\"p\">(</span><span class=\"nv\">$#-2</span><span class=\"p\">)</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi\n</span><span class=\"nb\">echo</span> <span class=\"s2\">\"python </span><span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\npython <span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n\n<p>第1パラメータに識別子する顔画像を保存したディレクトリ、第2パラメータに入力ビデオファイル名を指定する。<br />\nこれらのパラメータは省略不可。<br />\n追加でオプションを指定したい場合は第3パラメータ以降に指定する。<br />\nたとえば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo.sh data data/video.mp4  <span class=\"nt\">--output</span> result.mp4\n</code></pre></div></div>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python face_recognition_demo.py <span class=\"nt\">-h</span>\nusage: face_recognition_demo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-i</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-o</span> PATH] <span class=\"o\">[</span><span class=\"nt\">--no_show</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-tl</span><span class=\"o\">]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-cw</span> CROP_WIDTH] <span class=\"o\">[</span><span class=\"nt\">-ch</span> CROP_HEIGHT] <span class=\"nt\">-fg</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">--run_detector</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--run_detector_no_save</span><span class=\"o\">]</span>\n                                <span class=\"nt\">-m_fd</span> PATH <span class=\"nt\">-m_lm</span> PATH <span class=\"nt\">-m_reid</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-l</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-c</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]]\n                                <span class=\"o\">[</span><span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]] <span class=\"o\">[</span><span class=\"nt\">-exp_r_fd</span> NUMBER]\n                                <span class=\"o\">[</span><span class=\"nt\">--allow_grow</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit\n\n</span>General:\n  <span class=\"nt\">-i</span> PATH, <span class=\"nt\">--input</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to the input video <span class=\"o\">(</span><span class=\"s1\">'0'</span> <span class=\"k\">for </span>the\n                        camera, default<span class=\"o\">)</span>\n  <span class=\"nt\">-o</span> PATH, <span class=\"nt\">--output</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to save the output video to\n  <span class=\"nt\">--no_show</span>             <span class=\"o\">(</span>optional<span class=\"o\">)</span> Do not display output\n  <span class=\"nt\">-tl</span>, <span class=\"nt\">--timelapse</span>      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Auto-pause after each frame\n  <span class=\"nt\">-cw</span> CROP_WIDTH, <span class=\"nt\">--crop_width</span> CROP_WIDTH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this width\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n  <span class=\"nt\">-ch</span> CROP_HEIGHT, <span class=\"nt\">--crop_height</span> CROP_HEIGHT\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this height\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n\nFaces database:\n  <span class=\"nt\">-fg</span> PATH              Path to the face images directory\n  <span class=\"nt\">--run_detector</span>        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images.\n  <span class=\"nt\">--run_detector_no_save</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images. not save\n                        detected face image.\n\nModels:\n  <span class=\"nt\">-m_fd</span> PATH            Path to the Face Detection model XML file\n  <span class=\"nt\">-m_lm</span> PATH            Path to the Facial Landmarks Regression model XML file\n  <span class=\"nt\">-m_reid</span> PATH          Path to the Face Reidentification model XML file\n\nInference options:\n  <span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Detection model\n                        <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Facial Landmarks\n                        Regression model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Reidentification\n                        model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> PATH, <span class=\"nt\">--cpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For MKLDNN <span class=\"o\">(</span>CPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to a shared library with custom layers\n                        implementations\n  <span class=\"nt\">-c</span> PATH, <span class=\"nt\">--gpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For clDNN <span class=\"o\">(</span>GPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to the XML file with descriptions of the\n                        kernels\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> Be more verbose\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_stats</span>     <span class=\"o\">(</span>optional<span class=\"o\">)</span> Output detailed per-layer performance stats\n  <span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Probability threshold <span class=\"k\">for </span>face\n                        detections<span class=\"o\">(</span>default: 0.6<span class=\"o\">)</span>\n  <span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Cosine distance threshold between two\n                        vectors <span class=\"k\">for </span>face identification <span class=\"o\">(</span>default: 0.3<span class=\"o\">)</span>\n  <span class=\"nt\">-exp_r_fd</span> NUMBER      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Scaling ratio <span class=\"k\">for </span>bboxes passed to face\n                        recognition <span class=\"o\">(</span>default: 1.15<span class=\"o\">)</span>\n  <span class=\"nt\">--allow_grow</span>          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Allow to grow faces gallery and to dump on\n                        disk. Available only <span class=\"k\">if</span> <span class=\"nt\">--no_show</span> option is off.\n</code></pre></div></div>\n\n<p>主なオプションの意味は以下の通り。</p>\n\n<h3 id=\"-m_fd\"><code class=\"language-plaintext highlighter-rouge\">-m_fd</code></h3>\n\n<p>必須。<br />\n顔位置検出モデルファイル</p>\n\n<h3 id=\"ーm_lm\"><code class=\"language-plaintext highlighter-rouge\">ーm_lm</code></h3>\n\n<p>必須。<br />\n顔特徴点検出モデルファイル</p>\n\n<h3 id=\"-m_reid\"><code class=\"language-plaintext highlighter-rouge\">-m_reid</code></h3>\n\n<p>必須。<br />\n顔識別モデルファイル</p>\n\n<h3 id=\"-d_fd\"><code class=\"language-plaintext highlighter-rouge\">-d_fd</code></h3>\n\n<p>顔位置検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_lm\"><code class=\"language-plaintext highlighter-rouge\">-d_lm</code></h3>\n\n<p>顔特徴点検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_reid\"><code class=\"language-plaintext highlighter-rouge\">-d_reid</code></h3>\n\n<p>顔識別に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"--cpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--cpu_lib</code></h3>\n\n<p>CPU用カスタムレイヤライブラリ(?)ファイル</p>\n\n<h3 id=\"--gpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--gpu_lib</code></h3>\n\n<p>GPU用カスタムレイヤライブラリ(?)ファイル(使ったことないからワカラン)</p>\n\n<h3 id=\"-fg\"><code class=\"language-plaintext highlighter-rouge\">-fg</code></h3>\n\n<p>必須。<br />\n識別する顔画像を格納したディレクトリ<br />\nこのディレクトリ内のjpg、pngファイルのみ抽出してくれるので、他のファイルが混在しても大丈夫。</p>\n\n<h3 id=\"--input\"><code class=\"language-plaintext highlighter-rouge\">--input</code></h3>\n\n<p>必須。<br />\n入力ファイル(動画ファイル)を指定する。 <br />\n静止画でもエラーにならないが、一瞬で消えるので、オプション –timelapse でキー入力待ちにするか、\nオプション –outputでファイル出力すると確認できる。<br />\n省略時はカメラが指定される。</p>\n\n<h3 id=\"--output\"><code class=\"language-plaintext highlighter-rouge\">--output</code></h3>\n\n<p>認識結果をファイルに出力する。<br />\n指定しなければファイルは作成されない(表示のみ)。 \n拡張子がmp4のときはMP4(追加した処理)。<br />\nそれ以外はMJPEGで保存(aviにするのが望ましい。それ以外だとffmpegがなんか言うがファイルはできてるっぽい)。</p>\n\n<h3 id=\"--no_show\"><code class=\"language-plaintext highlighter-rouge\">--no_show</code></h3>\n\n<p>画像表示しない。<br />\n通常は–outputと組み合わせて使う。</p>\n\n<h3 id=\"--timelapse\"><code class=\"language-plaintext highlighter-rouge\">--timelapse</code></h3>\n\n<p>1フレーム表示するごとにキー入力待ちになる。</p>\n\n<h3 id=\"--crop_width--crop_height\"><code class=\"language-plaintext highlighter-rouge\">--crop_width</code>、<code class=\"language-plaintext highlighter-rouge\">--crop_height</code></h3>\n\n<p>入力画像を指定したサイズに切り取る。切り取る場所は元画像の中心。<br />\n両方指定しないと無効。</p>\n\n<h3 id=\"--run_detector\"><code class=\"language-plaintext highlighter-rouge\">--run_detector</code></h3>\n\n<p>オプションを指定するとデータベース作成時に顔検出して新たに顔画像を作成してくれる。<br />\nデータベースファイルが全身画像だったり、複数人数が一緒に写っていてもOK。<br />\n1回指定すれば画像が残っているので以降は指定しなくても良い。</p>\n\n<h3 id=\"--run_detector_no_save\"><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code></h3>\n\n<p>追加したオプション<br />\n指定するとデータベース作成時に顔検出するが、顔画像の保存はしない。</p>\n\n<h3 id=\"--verbose\"><code class=\"language-plaintext highlighter-rouge\">--verbose</code></h3>\n\n<p>指定するとloglevelがDEBUGになる</p>\n\n<h3 id=\"--perf_stats\"><code class=\"language-plaintext highlighter-rouge\">--perf_stats</code></h3>\n\n<p>指定するとフレーム毎にパフォーマンスステータスを表示する</p>\n\n<h3 id=\"-t_fd\"><code class=\"language-plaintext highlighter-rouge\">-t_fd</code></h3>\n\n<p>顔位置検出に使用する閾値。省略時は0.6。</p>\n\n<h3 id=\"-t_reid\"><code class=\"language-plaintext highlighter-rouge\">-t_reid</code></h3>\n\n<p>顔識別に使用する閾値。省略時は0.3。</p>\n\n<h3 id=\"-exp_r_fd\"><code class=\"language-plaintext highlighter-rouge\">-exp_r_fd</code></h3>\n\n<p>顔位置検出した枠のサイズを何倍にするか。ギリギリだとうまく行かないから?省略時は1.15</p>\n\n<h3 id=\"--allow_grow\"><code class=\"language-plaintext highlighter-rouge\">--allow_grow</code></h3>\n\n<p>認識画像で知らない顔が出てきたらその都度登録するか確認する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD(その2)</h1>\n      <p>openVINOのSSDのサンプルプログラムのモデルデータを変更してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> でSSDを動かしてみたが、\n検出できるオブジェクトの種類が少なくてちょっと寂しかったので、別のモデルがないか探してみた。</p>\n\n<p>で、調べてみると、openCVのopen_model_zoo以外にもTensorFlowの公式モデルなどをダウンロードして変換するスクリプトが用意されていた。<br />\nで、以下手順。</p>\n\n<h1 id=\"モデルのダウンロードモデルのirへの変換\">モデルのダウンロード&モデルのIRへの変換</h1>\n\n<h4 id=\"テンポラリディレクトリの作成移動\">テンポラリディレクトリの作成&移動</h4>\n\n<p>とりあえず作業用のディレクトリを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/temp\n<span class=\"nb\">cd</span> /work/temp\n</code></pre></div></div>\n\n<h3 id=\"使用できるモデルの一覧を表示\">使用できるモデルの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py  <span class=\"nt\">--print_all</span>\n</code></pre></div></div>\n\n<p>ちなみに、モデル毎の設定は以下にあるので、雰囲気で解読してちょ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>${INTEL_OPENVINO_DIR}/deployment_tools/open_model_zoo/models/public/${modelname}/model.yml\n</code></pre></div></div>\n\n<h3 id=\"このへんのモデルを使ってみる\">このへんのモデルを使ってみる</h3>\n\n<p>なんとなく、mobilenetが小さそうなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssd_mobilenet_v2_coco\n</code></pre></div></div>\n\n<p>または</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssdlite_mobilenet_v2\n</code></pre></div></div>\n\n<p>ssdlightの方がモデルデータが小さい。その分精度は落ちるらしい。<br />\n検出できるオブジェクトの種類は同じ。<br />\n出力は90種類だが、途中欠番があるみたいなので実質80種類くらい。<br />\n変わったところでは「テディベア」なんてのもある。試してみたらちゃんと認識した(あたりまえか…)。<br />\ncocoデータセット<a href=\"http://cocodataset.org/#home\">http://cocodataset.org/#home</a>なので、有名どころですね。<br />\nあ、「80 object categories 91 stuff categories」ってちゃんと書いてある…</p>\n\n<h3 id=\"ダウンロード\">ダウンロード</h3>\n\n<p>まずはダウンロード。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/</code>にモデルがダウンロードされる。</p>\n\n<h3 id=\"モデルデータをirファイルへ変換\">モデルデータをIRファイルへ変換</h3>\n\n<p>もとのモデルデータはTensorFlowで使用するProtocolBuffer形式なので、openVINOで使用できるIR形式に変換する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/converter.py <span class=\"nt\">--precisions</span> FP16 <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/FP16/</code>にIRモデルが出来る。</p>\n\n<h3 id=\"そのままの場所で使用しても良いが他のモデルとまとめておく\">そのままの場所で使用しても良いが、他のモデルとまとめておく</h3>\n\n<p>モデルがあちこちにあると管理しずらくなるので、他のモデルと同じところに置いておく。<br />\n必要なのはxmlとbin。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>public/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>/FP16/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>.<span class=\"o\">{</span>xml,bin<span class=\"o\">}</span> /work/NCS2/openvino_models/FP16/\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">.{xml,bin}</code>のところにスペースなどを入れてしまうとうまく動かないので注意。<br />\n結構「あとで読みやすいように」と入れてしまいがち(特にスクリプト書くとき)なので注意。</p>\n\n<h3 id=\"ラベルファイルの作成\">ラベルファイルの作成</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/work/NCS2/openvino_models/FP16/${modelname}.labels</code>にラベルデータを作成しておく。<br />\nなくても可。<br />\n作り方は後述。</p>\n\n<h3 id=\"実行\">実行</h3>\n\n<p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> の「デモ実行」と同じ手順で\nモデルファイルを差し替えて(<code class=\"language-plaintext highlighter-rouge\">--model</code>オプション)実行すれば良い。</p>\n\n<h1 id=\"ラベルファイルの作成方法\">ラベルファイルの作成方法</h1>\n\n<p>ラベルデータはモデルデータには含まれていないようなので、作成する方法を検討してみた。</p>\n\n<h3 id=\"tensorflowのmodelsモジュールをダウンロード\">tensorflowのmodelsモジュールをダウンロード</h3>\n\n<p>まず、モデルデータの作成情報のあるモジュールをダウンロードしておく。<br />\ngitでなくてもzipをダウンロードして展開しておいても可(ちょっとデカいので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git models_tf\n</code></pre></div></div>\n\n<h3 id=\"作業ディレクトリに移動\">作業ディレクトリに移動</h3>\n\n<p>あとでpythonプログラムを作成するときに色々面倒がないので、作業ディレクトリはココで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models_tf/research\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">object_detection/samples/configs</code>から対応するconfigファイルを探して(なんとなく雰囲気で探せ!)表示<br />\n<code class=\"language-plaintext highlighter-rouge\">label_map_path</code>に記載されたファイルがlabel_mapファイル<br />\nこのとき、PATH_TO_BE_CONFIGURED は <code class=\"language-plaintext highlighter-rouge\">object_detection/data</code> に読み替えること</p>\n\n<p>ssd_mobilenet_v2_cocoの場合は以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/samples/configs/ssd_mobilenet_v2_coco.config\n</code></pre></div></div>\n\n<p>上記ファイルの場合、label_mapは以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/data/mscoco_label_map.pbtxt\"\n</code></pre></div></div>\n\n<p>こにファイルにIDとラベルが定義されているが、そのままラベルファイルとしては認識できない。<br />\nIDには途中抜けがあるので注意(そのままgrepで抜き出してはダメ)</p>\n\n<h2 id=\"ラベルデータ変換プログラムを作成する\">ラベルデータ変換プログラムを作成する</h2>\n\n<p>label_map.pbtxtからラベル一覧を取得するのを手作業で行うのは大変なので、プログラムを作成する。</p>\n\n<h3 id=\"protocのインストール\">protocのインストール</h3>\n\n<p>まずは必要なモジュールのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n</code></pre></div></div>\n\n<h3 id=\"protoファイルからpythonモジュールを作成する\">protoファイルからpythonモジュールを作成する</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>protoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"変換プログラムのソース\">変換プログラムのソース</h3>\n\n<p>label_mapからテーブルを作成するスクリプト(labelmap2labels.py)をカレントディレクトリに作成する。<br />\nやっつけ仕事なので、かなりテキトー(笑)、、、</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">object_detection.utils</span> <span class=\"kn\">import</span> <span class=\"n\">label_map_util</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"==== USAGE ====\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"    python </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> label_map_file\"</span><span class=\"p\">)</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># パラメータが1個でない\n</span>    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_map_file = \"object_detection/data/mscoco_complete_label_map.pbtxt\"\n</span><span class=\"n\">label_map_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># 第一パラメータのファイルが存在しない\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"error: '</span><span class=\"si\">{</span><span class=\"n\">label_map_file</span><span class=\"si\">}</span><span class=\"s\">' not exist</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_mapからカテゴリインデックスを作成\n</span><span class=\"n\">category_index</span> <span class=\"o\">=</span> <span class=\"n\">label_map_util</span><span class=\"p\">.</span><span class=\"n\">create_category_index_from_labelmap</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span>\n\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># print(i)\n</span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">category_index</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">\"name\"</span><span class=\"p\">]</span>\n    <span class=\"k\">except</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'{name}\\t# {i}')\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n    \n<span class=\"c1\"># 個数確認のためにダミーを出力\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スクリプトの実行\">スクリプトの実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.py label_map_file\n</code></pre></div></div>\n\n<p>結果は標準出力へ出力されるので、ファイルにcastして使用する</p>\n\n<p>例:</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.pyobject_detection/data/mscoco_complete_label_map.pbtxt <span class=\"o\">></span> mscoco_complete.labels\n</code></pre></div></div>\n\n<p>出来上がったlabelsファイルを必要なところへコピーして使ってちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>UbuntuをNative環境にインストールする(18.04)</title>\n  </head>\n  <body>\n    <header>\n      <h1>UbuntuをNative環境にインストールする(18.04)</h1>\n      <p>Ubunt(18.04)をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntu-をnative環境virtualboxではなくにインストールする\">Ubuntu をNative環境(Virtualboxではなく)にインストールする</h1>\n\n<p><a href=\"/memoBlog/2019/06/26/install1804.html\">Ubuntu 18.04のインストール</a>ではVirtualbox環境にUbuntuをインストールする手順を書いたが、ここではNative環境にインストールする手順を説明する。</p>\n\n<p>ハードウェア構成としては、Ubuntuを外付けHDDにインストールし、内蔵ディスクのWindowsは消さずにデュアルブート環境にする。<br />\n手順はPCはNECのLavie all-in-oneタイプ(ちょっと古い奴)で確認している。<br />\nBIOS関連など、PC固有の機能に左右される部分は機種によって異なるので注意。</p>\n\n<h2 id=\"前準備\">前準備</h2>\n\n<h3 id=\"hddをgpt化\">HDDをGPT化</h3>\n<p>インストールするHDDのパーティションがMBRだとEFIブートができないので、<br />\n対象ハードディスクのパーテイションテーブルをGPTに変更<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://pc-karuma.net/windows-10-convert-mbr-gpt-disk/\">Windows10 - MBRディスク ⇔ GPTディスクに変換(変更)</a></li>\n</ul>\n\n<h3 id=\"インストールメディアでインストーラ起動\">インストールメディアでインストーラ起動</h3>\n<p>インストールメディアはブータブルUSBメモリを作成すると便利<br />\nブータブルUSBメモリの作成は以下を参照</p>\n<ul>\n  <li><a href=\"https://forest.watch.impress.co.jp/library/software/rufus/?fbclid=IwAR0Ry5oRt3jOegmkkswUQmudtvuleLCkH44-Tx8brnS0VYQJLQLBmGtT5Lw\">窓の杜 Rufus</a></li>\n  <li><a href=\"https://pc-freedom.net/software/how-to-use-rufus/?fbclid=IwAR1bXsLVQviiwpcQSZapci1vgJKF4rFv1nmIh7knZkrdQDJkGh7BLTrcXi4\">RufusでLinuxのインストールメディアを作る</a></li>\n  <li><a href=\"https://rufus.ie/\">本家</a></li>\n</ul>\n\n<p>ダウンロードしたファイルはインストーラではなく、ポータブル版の実行ファイル。<br />\n大体直感的に使えるけど、<strong><em>UEFI モードで起動できるようにするにはパーティション構成でGPTを選択しないといけない</em></strong>らしい。<br />\nGPT にしておけば、UEFI モードでブートするPCのbootデバイスの優先順位をUSBをHDDより高くしておけば対象のHDDからブートできる。</p>\n\n<p>これで逐一CD-Rを焼かなくて済む。<br />\nまた、起動もCD-Rより高速。</p>\n\n<h2 id=\"対象ハードディスクにインストール\">対象ハードディスクにインストール</h2>\n<p>以下を参照。</p>\n<ul>\n  <li><a href=\"https://linuxfan.info/ubuntu-18-04-install-guide\">Ubuntu 18.04 LTSインストールガイド【スクリーンショットつき解説】</a></li>\n</ul>\n\n<h2 id=\"再起動してbiosセットアップメニューを起動\">再起動してBIOSセットアップメニューを起動</h2>\n<p>NEC LAVIEの場合、電源ON時にF2キーを連打し、BIOSセットアップメニューを表示<br />\n「Boot」の「Boot Priority Order」の起動順序で「Ubuntu」を「Windows」の上に持ってくる。<br />\nその後、 saveしてreset。</p>\n\n<h2 id=\"基本的な初期設定\">基本的な初期設定</h2>\n<p>Virtualbox版の手順の<a href=\"/memoBlog/2019/06/26/install1804.html\">Ubuntu 18.04のインストール</a>を参照。<br />\n基本的にこれと同じで大丈夫(GuestAdditionのインストール、grub-pcのインストール先情報の変更を除く)</p>\n\n<h3 id=\"もっと簡単に設定する方法があった\">もっと簡単に設定する方法があった</h3>\n<p>以下の項目はもっと簡単に設定する方法があったのでメモ。</p>\n\n<ul>\n  <li>「ウィンドウが勝手に最大化するのをやめる」</li>\n  <li>「ウィンドウにマウスを乗せるとフォーカスされるようにする」</li>\n  <li>「デスクトップからゴミ箱とホームを消す」</li>\n</ul>\n\n<p>これらの設定はdconf-editorでなく、gnome-tweaksを使うと簡単(dconf-editorでもOK)</p>\n\n<p>gnome-tweaksのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\ngnome-tweaks\n</code></pre></div></div>\n<ul>\n  <li>「ウィンドウにマウスを乗せるとフォーカスされるようにする」\n    <ul>\n      <li>「ウィンドウ」で「ウィンドウフォーカス」を「Sloppy」にする</li>\n    </ul>\n  </li>\n  <li>「デスクトップからゴミ箱とホームを消す」\n    <ul>\n      <li>「デスクトップ」で選択</li>\n    </ul>\n  </li>\n  <li>「CTRLとCapsLockの入れ替えを行う」(Virtualboxではホスト側で入れ替えてたので不要だった)\n    <ul>\n      <li>「キーボードとマウス」で「追加のレイアウトオプション」をクリック\n        <ul>\n          <li>Ctrl position」の「CapsLockをCtrlとして扱う」を選択する。\n            <ul>\n              <li>「CtrlとCapsLockを入れ替える」だとうまく動かないので注意。</li>\n              <li>UnityとGNOME Flashbackでは設定は別らしい。</li>\n              <li>GNOME Flashbackでは「CtrlとCapsLockを入れ替える」でもOK。</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>「ウィンドウが勝手に最大化するのをやめる」\n    <ul>\n      <li>設定項目が見当たらないので、dconf editorで設定する。\n        <ul>\n          <li>dconf editor起動して以下を変更\n            <ul>\n              <li>/org/gnome/metacity/edge-tiling false</li>\n              <li>/org/gnome/mutter/edge-tiling false</li>\n              <li>/org/gnome/shell/overrides/edge-tiling false</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"sshのインストール\">sshのインストール</h1>\n<p>WindowsPCにあるデータをubuntuPCにキーボードで打ち込むのは効率が悪いので、最も簡単なsshでリモートログインできるようにしてみる。</p>\n\n<p>以下のコマンドでsshサーバをインストールし、サーバを開始する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n<p>クライアントからTeraTermなどでsshで対象マシンのポート22に接続する</p>\n\n<h1 id=\"vncで画面共有する\">vncで画面共有する</h1>\n\n<p>sshリモートログインよりもうちょっと使いやすくしたいので、vncで画面共有するようにしてみる。</p>\n\n<p>chrome リモートデスクトップ等とは異なり、コンソールに表示している画面を共有して操作するもの。<br />\n使用したクライアント(VNC-Viewer)がヘボいからなのか、ちょっと反応鈍いけど、<br />\nコンソールで作業していた実行状況を確認したり<br />\n会社でトラブった人のリモートサポートなんかに使えるかも。</p>\n\n<p>やり方自体はとてもシンプル。<br />\n特にインストールとかも必要ない。<br />\n(クライアント側はVNC viewerなどを実行する必要があるけど、こっちもインストールは不要(単体実行))</p>\n\n<p>例によって手順の説明は他力本願(^^ゞ<br />\n参照:</p>\n<ul>\n  <li><a href=\"https://www.yokoweb.net/2019/12/09/ubuntu-18_04-desktop-vnc-remote/\">【Ubuntu 18.04 Desktop】WinやMacパソコンからVNCでリモート接続し画面共有する </a></li>\n</ul>\n\n<p>そのままトレースすればできるけど、ちょっと「ん?」と思ってしまうエラーが。<br />\n同じページの<a href=\"https://www.yokoweb.net/2019/12/09/ubuntu-18_04-desktop-vnc-remote/#toc5\">ココ</a>に解決策がかかれているけど、ちゃんと前もって書いておいてほしいもんだ(笑)。<br />\n解決策の要約は以下の通り。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false</span>\n<span class=\"c\"># 実行後再起動必要</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ndconf editor でも設定可能。<br />\nなので、dconf editorとの設定操作とバッティングしないように注意<br />\ndconf editorで設定する場合は以下<br />\n   /org/gnome/desktop/remote-access/require-encryption</p>\n</blockquote>\n\n<p>あくまで共有なのでコンソール側でGUIログインしてないとつながらない。<br />\n反応鈍いので、普段使いにはちょっとストレスかも。<br />\nchrome リモートデスクトップ使えるならそっち使ったほうがいいかな。</p>\n\n<h1 id=\"chromeリモートデスクトップのインストール\">chromeリモートデスクトップのインストール</h1>\n\n<p>chromeリモートデスクトップ による接続は画面の共有ではなく、新しいセッションによる接続となる(Xclientみたいなもん?)。<br />\nwindowsマシンに接続した場合は表示画面のミラーリングだったが。</p>\n\n<p>chromeのインストール&リモートデスクトップのインストールはWindowsとほぼ同じ。<br />\n以下参考ページ</p>\n<ul>\n  <li><a href=\"https://www.google.com/chrome/\">Google Chrome フェブブラウザ</a></li>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>パソコンでリモート アクセスを設定する</li>\n      <li>パソコンにリモート アクセスする</li>\n    </ul>\n  </li>\n</ul>\n\n<p>接続すると、開始するセッションの選択画面になるので、「Ubuntu」を選択。GNOME Flashbackだとつながらない…なんで??</p>\n\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。このダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></li>\n</ul>\n\n<p>要約すると\n<code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下を入力</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n<h2 id=\"コンソール画面を共有したい場合\">コンソール画面を共有したい場合</h2>\n\n<p>chromeリモートデスクトップでvnc同様のコンソール画面の共有をすることも可能。<br />\n設定方法は以下を参照。</p>\n<ul>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>他のユーザとパソコンを共有する</li>\n    </ul>\n  </li>\n</ul>\n\n<p>この方法だと、アクセスコードの生成(コンソール側)/アクセスコードの入力(リモート側)/アクセス許可(コンソール側)と手続きが少々煩雑(毎回必要)。<br />\n画面共有で操作するにはvncのほうが簡単かな?</p>\n\n<h1 id=\"biosセットアップメニューでのブートマネージャの表示名を変更する\">BIOSセットアップメニューでのブートマネージャの表示名を変更する</h1>\n\n<p>ubuntu をインストールした後、BIOSセットアップメニューでブート優先順位を指定しようとすると<br />\nubuntuのブートマネージャが2つ表示されて、どちらを選べばよいのか見分けがつかない。<br />\n(機種によってはpathが表示されて見分けられるものもあるらしいが、私のPCはそうなってない)</p>\n\n<p>そこで、表示名を変更して見分けがつくようにしてみる。</p>\n\n<p>以下、参考ページ</p>\n<ul>\n  <li><a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1383uefinvnm/uefinvnm.html\">bcdeditでUEFIのブート・エントリの名前を変更する</a></li>\n</ul>\n\n<p>まず、Windowsを起動し、管理者権限でコマンドプロンプト(cmd.exe)を実行する。\nPowerShellではちょっとテクニックが要る(というほど大げさではないが)みたいなので、\nコマンドプロンプトで実行するのが無難。</p>\n\n<p>現在の状態の確認</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /enum firmware\n</code></pre></div></div>\n\n<p>実行結果</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ファームウェアのブート マネージャー\n--------------------------------\nidentifier              {fwbootmgr}\ndisplayorder            {bootmgr}\n                        {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\n                        {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ntimeout                 1\n\nWindows ブート マネージャー\n--------------------------------\n《省略》\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\ubuntu\\shimx64.efi\ndescription             ubuntu\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\Ubuntu\\grubx64.efi\ndescription             ubuntu\n</code></pre></div></div>\n\n<p>表示名を変更する<br />\n指定するuuidは現状の確認で確認したuuidに置き換えること。<br />\ndescriptionが表示名なので、これを好みの名前に変更する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /set {9b7f627e-7edc-11ea-84b2-806e6f6e6963} description  \"ubuntu shimx64\"\nbcdedit /set {9b7f627f-7edc-11ea-84b2-806e6f6e6963} description  \"ubuntu grubx64\"\n</code></pre></div></div>\n\n<p>結果を確認する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /enum firmware\n</code></pre></div></div>\n\n<p>実行結果</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ファームウェアのブート マネージャー\n--------------------------------\nidentifier              {fwbootmgr}\ndisplayorder            {bootmgr}\n                        {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\n                        {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ntimeout                 1\n\nWindows ブート マネージャー\n--------------------------------\n《省略》\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\ubuntu\\shimx64.efi\ndescription             ubuntu shimx64\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\Ubuntu\\grubx64.efi\ndescription             ubuntu grubx64\n</code></pre></div></div>\n\n<p>ちなみに、shimx64.efi と grubx64.efi の違いは、セキュアブートの対応/非対応の違いである。<br />\n通常(セキュアブート有効のハズ)はshimx64.efiで良いと思われる。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://netlog.jpn.org/r271-635/2019/08/uefi_windows10_ubuntu_install.html\">UEFIのWindows 10マシンにUbuntu 18.04を追加インストールしデュアルブート化する</a>\n    <ul>\n      <li>「UbuntuがUEFIのブートメニューに登録されていることを確認」のあたり</li>\n    </ul>\n  </li>\n</ul>\n\n<p>この設定はbuntuを再インストールすると上書きされてしまうので、再度変更する必要がある。</p>\n\n<h1 id=\"grubのboot-menuの表示などの変更方法\">GRUBのboot menuの表示などの変更方法</h1>\n\n<p>デフォルトのubuntuインストール状態では、GRUBのブートメニューが表示されない。<br />\nそこで、ブートメニューを表示するように変更してみる。<br />\nついでに、設定する箇所が同じなので、</p>\n\n<ul>\n  <li>タイムアウトまでの時間の変更(あっ?と思った瞬間にブートされちゃうと悲しいので)</li>\n  <li>スプラッシュスクリーンを表示しなくする(ちゃんとブートしてるか心配なので(笑))</li>\n</ul>\n\n<p>も設定しておく。</p>\n\n<p>まず、ubuntuを起動してターミナル起動</p>\n\n<p>rootでないとできないことなので、rootでbashを実行しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>bash                                     \n</code></pre></div></div>\n\n<p>設定ファイル <code class=\"language-plaintext highlighter-rouge\">/etc/default/grub</code> を以下の内容で変更する</p>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- grub.org\t2020-05-08 06:16:59.908079737 +0900\n</span><span class=\"gi\">+++ grub\t2020-05-08 06:17:13.540255464 +0900\n</span><span class=\"p\">@@ -3,11 +3,11 @@</span>\n # For full documentation of the options in this file, see:\n #   info -f grub -n 'Simple configuration'\n \n<span class=\"gd\">-GRUB_DEFAULT=0\n-GRUB_TIMEOUT_STYLE=hidden\n-GRUB_TIMEOUT=10\n</span><span class=\"gi\">+GRUB_DEFAULT=saved\n+GRUB_TIMEOUT_STYLE=menu\n+GRUB_TIMEOUT=30\n</span> GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`\n<span class=\"gd\">-GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash\"\n</span><span class=\"gi\">+GRUB_CMDLINE_LINUX_DEFAULT=\n</span> GRUB_CMDLINE_LINUX=\"\"\n \n # Uncomment to enable BadRAM filtering, modify to suit your needs\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">GRUB_DEFAULT</code> がデフォルトの選択項目。 <code class=\"language-plaintext highlighter-rouge\">saved</code> は前回選択項目。rebootのときだけ??動きがイマイチわからんかった。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_TIMEOUT_STYLE</code> がメニュー表示形式。<code class=\"language-plaintext highlighter-rouge\">hidden</code> は表示しない、<code class=\"language-plaintext highlighter-rouge\">menu</code> はメニューを表示する。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_TIMEOUT</code> がタイムアウトまでの時間。単位は秒。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_CMDLINE_LINUX_DEFAULT</code> がLinux起動時のコマンドラインオプション。<code class=\"language-plaintext highlighter-rouge\">quiet splash</code> を指定すると起動メッセージを表示せず、スプラッシュスクリーンを表示する。これを削除することで起動メッセージが表示される</p>\n\n<p>変更した設定をcfgファイルに反映する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>grub-mkconfig <span class=\"nt\">-o</span> /boot/grub/grub.cfg            \n</code></pre></div></div>\n\n<p>これで、次回起動時からGRUBのブートメニューが変更される</p>\n\n<p>以下、参考ページ:</p>\n<ul>\n  <li><a href=\"http://www.usupi.org/sysad/202.html\">いますぐ実践! Linux システム管理</a></li>\n</ul>\n\n<p>この項目と直接関係ないけど、起動時にのfsckを実行する方法の参考ページ。</p>\n<ul>\n  <li><a href=\"https://linux.just4fun.biz/?Linux%E7%92%B0%E5%A2%83%E8%A8%AD%E5%AE%9A/%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E9%96%93%E9%9A%94%E3%81%AE%E7%A2%BA%E8%AA%8D\">Linux環境設定/起動時のファイルシステムチェック間隔の確認 </a></li>\n</ul>\n\n<h1 id=\"usb-hdd接続-ubuntuのboot未接続windowsのbootにする方法\">USB-HDD接続→ Ubuntuのboot、未接続→Windowsのbootにする方法</h1>\n\n<p>ubuntuがインストールされたUSB-UDDが接続されていたらubuntuが、接続されていなければ内蔵HDDのWindowsが自動的に起動するようにしてみる。<br />\n(デフォルトのインストール状態だとブート優先順位を変更しないと切り替えられない)<br />\nちょうどFDDブートのような感じ。</p>\n\n<p>BIOSセットアップにより、ブートモードはUEFIブートで、ブート優先順位はubuntuの方を高く設定しておく。</p>\n\n<p>まず、ubuntuを起動する</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/boot/efi/EFI/ubuntu/grub.cfg</code> を以下のように変更する。<br />\nrootでないとアクセスできないので、<code class=\"language-plaintext highlighter-rouge\">sudo bash</code>  して rootでshellを動かして作業するのが良い。</p>\n\n<ul>\n  <li>元のファイル\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>search.fs_uuid 60c491cd-126d-4f4a-a321-84bb2e0d9068 root hd1,gpt1 \nset prefix=($root)'/boot/grub'\nconfigfile $prefix/grub.cfg\n</code></pre></div>    </div>\n  </li>\n  <li>変更後のファイル\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>if search.fs_uuid 60c491cd-126d-4f4a-a321-84bb2e0d9068 root hd1,gpt1 ;then\n set prefix=($root)'/boot/grub'\n configfile $prefix/grub.cfg\nelse\n set timeout_style=menu\n set timeout=0\n menuentry 'Windows Boot Manager (on /dev/sda2)' --class windows --class os $menuentry_id_option 'osprober-efi-2A43-3D28' {\n    insmod part_gpt\n    insmod fat\n    set root='hd0,gpt2'\n    if [ x$feature_platform_search_hint = xy ]; then\n       search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  2A43-3D28\n    else\n       search --no-floppy --fs-uuid --set=root 2A43-3D28\n    fi\n    chainloader /EFI/Microsoft/Boot/bootmgfw.efi\n}\nfi\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>メモ:</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">60c491cd-126d-4f4a-a321-84bb2e0d9068</code>  は ubuntuのインストールされたパーティションのuuidなので、接続したUSB-HDDDのuuidに合わせて変更する。\n    <ul>\n      <li>パーティションのuuidは以下で確認可能。\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"s1\">' \\/boot\\/efi '</span> /etc/mtab         <span class=\"c\"># デバイスファイルを確認する</span>\n<span class=\"nb\">sudo </span>blkid /dev/sda2                   <span class=\"c\"># 確認したデバイスファイルを指定する</span>\n</code></pre></div>        </div>\n      </li>\n      <li>あるいは、元のファイルのuuidをコピるのでもOK。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">2A43-3D28</code>はEFIシステムパーティションのuuidなので、環境に合わせて変更する。\n    <ul>\n      <li>パーティションのuuidは以下で確認可能。\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"s1\">' \\/ '</span> /etc/mtab                  <span class=\"c\"># デバイスファイルを確認する</span>\n<span class=\"nb\">sudo </span>blkid /dev/sdb1                   <span class=\"c\"># 確認したデバイスファイルをしてする</span>\n</code></pre></div>        </div>\n      </li>\n      <li>あるいは、<code class=\"language-plaintext highlighter-rouge\">/boot/grub/grub.cfg</code> の <code class=\"language-plaintext highlighter-rouge\">menuentry 'Windows Boot Manager ~</code>  の部分をパクってきても可。</li>\n    </ul>\n  </li>\n  <li>このファイルはbuntuを再インストールすると上書きされてしまうので、再度編集する必要がある。</li>\n</ul>\n\n<p>処理の解説:<br />\n元のgrub.cfgではUSB-HDDが接続されていなければ <code class=\"language-plaintext highlighter-rouge\">$prefix/grub.cfg</code>  が見つからないので、GRUBメニューが表示されない。<br />\nそこで、<code class=\"language-plaintext highlighter-rouge\">search.fs_uuid</code> の実行結果により、ディスクが見つかったら従来通りの処理、<br />\n見つからなかったらWindows Boot Managerを起動するようにしている。</p>\n\n<h3 id=\"参考情報\">参考情報</h3>\n<p>WindowsからEFIシステムパーティションのファイルを編集するには、このあたりを参考に。</p>\n<ul>\n  <li><a href=\"https://bi.biopapyrus.jp/os/win/dualboot-fix-bootmenu.html\">デュアルブートから Ubuntu を削除する方法</a><br />\nマウントする部分だけね。</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その1</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その1</h1>\n      <p>Google Coral USB Acceleratorのインストールメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<p>参考サイト:\n<a href=\"https://qiita.com/rhene/items/7b34f60b73645d430789\">RaspberryPi 4でCoral USB TPU Accelerator(EdgeTPU)をとりあえず使う</a></p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<h2 id=\"edgetpu用ライブラリのインストール\">EdgeTPU用ライブラリのインストール</h2>\n\n<p>下記コマンドを実行して、EdgeTPU用ライブラリ(ドライバ類)をインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/coral-edgetpu.list\ncurl https://packages.cloud.google.com/apt/doc/apt-key.gpg | <span class=\"nb\">sudo </span>apt-key add -\n\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># 通常版をインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libedgetpu1-std\n<span class=\"c\"># または、最大クロック版</span>\n<span class=\"c\"># sudo apt install libedgetpu1-max</span>\n</code></pre></div></div>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 coral\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral\n<span class=\"nb\">cd</span> /work/coral\npyenv <span class=\"nb\">local </span>coral \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<p>numpyのinstallで失敗するので、以下を実行しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n</code></pre></div></div>\n\n<h2 id=\"tfliteモジュールのインストール\">TFLiteモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install  </span>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nどれをインストールするかは<a href=\"https://www.tensorflow.org/lite/guide/python\">Python quickstart</a>で確認<br />\n========= 例えば、ubuntu/raspbianのときはpythonのバージョンに応じて以下のどれかを指定 ==============</p>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (x86-64)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl</td>\n      </tr>\n    </tbody>\n  </table>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (ARM 32)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl</td>\n      </tr>\n    </tbody>\n  </table>\n</blockquote>\n\n<h2 id=\"coral-usb-acceleratorの接続と確認\">Coral USB Acceleratorの接続と確認</h2>\n\n<p>USBポートに Coral USB Accelerator を接続する</p>\n\n<p>認識されたことを確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下の表示があったら正常に認識されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>«省略»\nBus XXX Device YYY: ID 1a6e:089a Global Unichip Corp. \n«省略»\n</code></pre></div></div>\n\n<h1 id=\"動作確認サンプルプログラム\">動作確認(サンプルプログラム)</h1>\n\n<h2 id=\"サンプルソースのインストール\">サンプルソースのインストール</h2>\n\n<p>Githubからソースをダウンロードする</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/\ngit<span class=\"k\">**</span> clone https://github.com/google-coral/tflite.git\n</code></pre></div></div>\n\n<h2 id=\"サンプルプログラムの実行その1-classification\">サンプルプログラムの実行(その1) classification</h2>\n\n<h3 id=\"プログラムディレクトリへの移動\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/classification/\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh \n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py \n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n<p>結果の例は以下。<br />\n結果は「Ara macao(コンゴウインコ)」と表示されている。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference on Edge TPU is slow because it includes loading the model into Edge TPU memory.\n12.4ms\n4.2ms\n4.1ms\n4.2ms\n4.2ms\n-------RESULTS--------\nAra macao (Scarlet Macaw): 0.77734\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n\n<p><a id=\"CPUonlydiff\"> </a></p>\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合もCoral USB Acceleratorを接続しておかないとエラーになる。<br />\n接続しなくても実行できるようにするには以下のパッチを適用し、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">-cpu</code>オプションを指定する。</p>\n\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/python/examples/classification/classify_image.py b/python/examples/classification/\n</span><span class=\"gi\">> classify_image.py\n</span><span class=\"gh\">index 75f1d76..44fb798 100644\n</span><span class=\"gd\">--- a/python/examples/classification/classify_image.py\n</span><span class=\"gi\">+++ b/python/examples/classification/classify_image.py\n</span><span class=\"p\">@@ -12,7 +12,7 @@</span>\n<span class=\"err\">#</span> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n # See the License for the specific language governing permissions and\n # limitations under the License.\n<span class=\"gd\">-r\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span><span class=\"gi\">+\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span>\n    To run this code, you must attach an Edge TPU attached to the host and\n    install the Edge TPU runtime (`libedgetpu.so`) and `tflite_runtime`. For\n<span class=\"p\">@@ -64,9 +64,12 @@</span> def load_labels(path, encoding='utf-8'):\n       return {index: line.strip() for index, line in enumerate(lines)}\n\n\n<span class=\"gd\">-def make_interpreter(model_file):\n</span><span class=\"gi\">+def make_interpreter(model_file, cpu=False):\n</span>   model_file, *device = model_file.split('@')\n<span class=\"gd\">-  return tflite.Interpreter(\n</span><span class=\"gi\">+  if cpu :\n+    return tflite.Interpreter(model_path=model_file)\n+  else :\n+    return tflite.Interpreter(\n</span>       model_path=model_file,\n       experimental_delegates=[\n           tflite.load_delegate(EDGETPU_SHARED_LIB,\n<span class=\"p\">@@ -92,11 +95,19 @@</span> def main():\n   parser.add_argument(\n       '-c', '--count', type=int, default=5,\n       help='Number of times to run inference')\n<span class=\"gi\">+  parser.add_argument(\n+      '--cpu', action='store_true',\n+      help='use cpu only(default:use with TPU)')\n</span>   args = parser.parse_args()\n\n+  if args.cpu :\n<span class=\"gi\">+    print('**** USE CPU ONLY!! ****')\n+  else :\n+    print('**** USE WITH TPU ****')\n+\n</span>   labels = load_labels(args.labels) if args.labels else {}\n\n-  interpreter = make_interpreter(args.model)\n<span class=\"gi\">+  interpreter = make_interpreter(args.model, args.cpu)\n</span>   interpreter.allocate_tensors()\n\n   size = classify.input_size(interpreter)\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"サンプルプログラムの実行その2-detection\">サンプルプログラムの実行(その2) detection</h2>\n\n<h3 id=\"プログラムディレクトリへの移動-1\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/detection\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール-1\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh\n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行-1\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<p>結果の例は以下。<br />\n以下の表示と同時に認識結果の画像が別ウィンドウで表示される。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference is slow because it includes loading the model into Edge TPU memory.\n27.90 ms\n11.59 ms\n11.36 ms\n11.89 ms\n11.10 ms\n-------RESULTS--------\ntie\n  id:     31\n  score:  0.83984375\n  bbox:   BBox(xmin=226, ymin=417, xmax=290, ymax=539)\nperson\n  id:     0\n  score:  0.83984375\n  bbox:   BBox(xmin=2, ymin=5, xmax=507, ymax=590)\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行-1\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションを指定すると、結果画像を保存するとともに、表示を行う。<br />\n指定しなければ認識だけ行う(結果の画像表示もしない)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションによる出力ファイルの形式は指定した拡張子で決定される。jpgやbmpなど。<br />\nrawデータで出力した場合(拡張子rgb)は、以下のコマンドでjpgやbmpに変換できる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.jpg\n</code></pre></div>  </div>\n\n  <p>または</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.bmp\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合でCoral USB Acceleratorを接続していなくてエラーになる場合は<br />\n<a href=\"#CPUonlydiff\">こちら</a>を参照</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その2</h1>\n      <p>Google Coral USB Accelerator で SSD(Single Shot MultiBox Detector)を実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n一部を除き、基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<h1 id=\"tflite-の-モデルファイルをedgetpu使用モデルに変換する方法\">tflite の モデルファイルをEdgeTPU使用モデルに変換する方法</h1>\n<p>通常のtfliteのモデルファイルはCPUのみ(またはCPU+GPU)を使用するように構成されていて、\nそのまま実行してもEdge-TPUは使用されない。<br />\nそこで、Edge-TPU使用モデルに変換するため、edgetpu_compilerを使用する必要がある。<br />\n(ただし、Ubuntuのみ。RasPi不可。)</p>\n\n<h2 id=\"edgetpu_compiler-のインストール\">edgetpu_compiler のインストール</h2>\n\n<p>CPU使用モデルからEdge-TPU使用モデルに変換するツール<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code>をインストールする。<br />\naptリポジトリの登録はTPUライブラリインストール時に行っているので不要(以下ではコメントアウトしてある)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -</span>\n<span class=\"c\"># echo \"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list</span>\n<span class=\"c\"># sudo apt update</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>edgetpu-compiler\n</code></pre></div></div>\n\n<h2 id=\"使用方法\">使用方法</h2>\n<p>基本的に以下。<br />\ntfliteファイルを喰わせるとファイル名に<code class=\"language-plaintext highlighter-rouge\">_edgetpu</code>を付加したファイルが作成される。<br />\nこれがEdge-TPU使用するモデルファイル。<br />\n詳細は<a href=\"https://coral.ai/docs/edgetpu/compiler/\">Edge TPU Compiler</a> を参照。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>edgetpu_compiler [options] model...\n</code></pre></div></div>\n\n<h1 id=\"事前準備\">事前準備</h1>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n\n<p>openCVをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"ssdを実行してみる\">SSDを実行してみる</h1>\n\n<h2 id=\"作業用ディレクトリの作成移動\">作業用ディレクトリの作成&移動</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral/ssd/\n<span class=\"nb\">cd</span> /work/coral/ssd/\n</code></pre></div></div>\n\n<h2 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h2>\n\n<p>用意されているSSDのモデルをダウンロードし、Edge-TPU使用モデルを作成する。<br />\n実行が終了すると、<code class=\"language-plaintext highlighter-rouge\">models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite</code> ができる。</p>\n\n<ul>\n  <li>ダウンロード元: <a href=\"https://www.tensorflow.org/lite/models/object_detection/overview\">Object detection</a>\nの 「Get Started」の「Download starter model and labels」</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl <span class=\"nt\">-O</span> https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip\nunzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip \n<span class=\"nb\">mv </span>detect.tflite coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># リネームしなくてもいいけど、後でわからなくならないようにリネームしておく</span>\n<span class=\"nb\">mv </span>labelmap.txt coco_ssd_mobilenet_v1_1.0_quant.labels   <span class=\"c\"># 同上</span>\nedgetpu_compiler coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># EdgeTPU使用モデルに変換</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"テスト用画像の準備\">テスト用画像の準備</h2>\n\n<p>適当な画像を<code class=\"language-plaintext highlighter-rouge\">image</code>ディレクトリに用意しておく。<br />\n使用できるファイル形式は<code class=\"language-plaintext highlighter-rouge\">jpg</code>と<code class=\"language-plaintext highlighter-rouge\">mp4</code></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>images\n<span class=\"nb\">cd </span>images/\n<span class=\"c\"># 適当な画像ファイルをダウンロードする</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"ssdのプログラムソース\">SSDのプログラムソース</h2>\n\n<p>以下の内容を<code class=\"language-plaintext highlighter-rouge\">object_detection_demo_ssd.py</code>として保存しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">tflite_runtime.interpreter</span> <span class=\"k\">as</span> <span class=\"n\">tflite</span>\n\n<span class=\"c1\"># shared library\n</span><span class=\"n\">EDGETPU_SHARED_LIB</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n  <span class=\"s\">'Linux'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.so.1'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Darwin'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.1.dylib'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Windows'</span><span class=\"p\">:</span> <span class=\"s\">'edgetpu.dll'</span>\n<span class=\"p\">}[</span><span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">system</span><span class=\"p\">()]</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># interpreter の生成\n</span><span class=\"k\">def</span> <span class=\"nf\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">):</span>\n    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"o\">=</span><span class=\"n\">model_file</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span>\n                <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">model_file</span><span class=\"p\">,</span>\n                <span class=\"n\">experimental_delegates</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n                    <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">load_delegate</span><span class=\"p\">(</span><span class=\"n\">EDGETPU_SHARED_LIB</span><span class=\"p\">)</span>\n                <span class=\"p\">])</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    \n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">output_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_output_details</span><span class=\"p\">()</span>\n    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n\n    <span class=\"n\">tflite_results1</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Locations (Top, Left, Bottom, Right)\n</span>    <span class=\"n\">tflite_results2</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Classes (0=Person)\n</span>    <span class=\"n\">tflite_results3</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Scores\n</span>    <span class=\"n\">tflite_results4</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Number of detections\n</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">tflite_results4</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])):</span>\n        <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        \n        <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>        <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n\n        <span class=\"n\">prob</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results3</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">prob</span> <span class=\"o\">>=</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'Class=</span><span class=\"si\">{</span><span class=\"n\">class_name</span><span class=\"si\">:</span><span class=\"mi\">15</span><span class=\"si\">}</span><span class=\"s\">    Probability=</span><span class=\"si\">{</span><span class=\"n\">prob</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    Location=(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)-(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n            <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span>    <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span>   <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span>  <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 表示色\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 対象物の枠とラベルの描画\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"n\">bottom</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">20</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"o\">+</span><span class=\"mi\">160</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"s\">\"{} ({:.3f})\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">class_name</span><span class=\"p\">,</span> <span class=\"n\">prob</span><span class=\"p\">),</span>\n                        <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># interpreterの構築\n</span>    <span class=\"n\">interpreter</span> <span class=\"o\">=</span> <span class=\"n\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">allocate_tensors</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">input_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()</span>\n    \n    <span class=\"c1\"># 入力データ\n</span>    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">org_frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>                 <span class=\"c1\"># オリジナルのフレームレート\n</span>    <span class=\"n\">org_frame_time</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span> <span class=\"o\">/</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>                <span class=\"c1\"># オリジナルのフレーム時間\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">org_frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルの読み込み\n</span>        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルがない場合\n</span>        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># フレーム数\n</span>    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 実行時間測定用変数の初期化\n</span>    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n    <span class=\"c1\"># フレーム測定用タイマ\n</span>    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># モデルの入力サイズ\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># 画像の前処理 =============================================================================\n</span>        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                          <span class=\"c1\"># 前処理開始時刻\n</span>        \n        <span class=\"c1\"># 画像の読み込み\n</span>        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレームを作成\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># モデル入力用にリサイズ\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>   <span class=\"c1\"># input size of coco ssd mobilenet?\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">]]</span>                          <span class=\"c1\"># BGR -> RGB\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">in_frame</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>                 <span class=\"c1\"># 3D -> 4D\n</span>        \n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>     <span class=\"c1\"># 前処理にかかった時間\n</span>        \n        <span class=\"c1\"># 推論実行 =============================================================================\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"c1\"># 推論本体\n</span>        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">set_tensor</span><span class=\"p\">(</span><span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">],</span> <span class=\"n\">in_frame</span><span class=\"p\">)</span>\n        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">invoke</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>                          <span class=\"c1\"># 推論処理にかかった時間\n</span>        \n        <span class=\"c1\"># 検出結果の解析 =============================================================================\n</span>        <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                               <span class=\"c1\"># 解析処理開始時刻\n</span>        <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n        <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>                    <span class=\"c1\"># 解析処理にかかった時間\n</span>        \n        <span class=\"c1\"># 結果の表示 =============================================================================\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 表示処理開始時刻\n</span>        \n        <span class=\"c1\"># 測定データの表示\n</span>        <span class=\"n\">frame_number_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'frame_number   : </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span>\n        <span class=\"k\">if</span> <span class=\"n\">frame_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span>  <span class=\"s\">'Frame time     : ---'</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Frame time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms    </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> fps'</span>\n        <span class=\"n\">inf_time_message</span>        <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Inference time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">render_time_message</span>     <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Rendering time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">parsing_time_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'parse time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        \n        <span class=\"c1\"># 結果の書き込み\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_number_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>     <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>   <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像の保存\n</span>        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>                 <span class=\"c1\"># 表示処理にかかった時間\n</span>        \n        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"c1\"># フレーム処理終了 =============================================================================\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_key_code</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"make_interpretermodel_file\">make_interpreter(model_file)</h3>\n\n<p>interpreter(認識エンジン)を構築する処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>モデルファイル内に<code class=\"language-plaintext highlighter-rouge\">\"edgetpu-custom-op\"</code>という文字列が含まれていたらTPU使用モデルと判定してTPU使用のための共有ライブラリをダウンロードして初期化する。<br />\nそうでなければCPUのみ使用モデルなので、 共有ライブラリなしで初期化する。</p>\n\n<p>もっと単純にモデルファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>が含まれていたらTPU使用モデルと判定しても良いかもしれない(<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code> は出力ファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>を付加するので)。</p>\n\n<h3 id=\"parse_resultinterpreter-frame-labels_map-args\">parse_result(interpreter, frame, labels_map, args)</h3>\n\n<p>認識結果の解析と結果の表示(検出枠とラベルの描画)</p>\n\n<p>認識結果から検出した座標、クラスID、スコアを取得し、出力画像に描画している。</p>\n\n<p>出力データの構成は<a href=\"https://www.tensorflow.org/lite/models/object_detection/overview#output\">ここ</a>を参照。</p>\n\n<p>どうやらこのモデルは検出個数が10個に設定されているようだ。</p>\n\n<h3 id=\"main\">main()</h3>\n\n<p>メインルーチン</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>タイミング調整部分は、認識処理が速かった場合に結果表示画像の表示時間を実際の入力画像の表示時間に合わせるため、ちょっと小細工を入れてある。</p>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--help</span>\nusage: object_detection_demo_ssd.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT <span class=\"o\">[</span><span class=\"nt\">-l</span> LABELS]\n                                    <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> LABELS, <span class=\"nt\">--labels</span> LABELS\n                        Optional. Labels mapping file\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合edge-tpu使用\">静止画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合edge-tpu使用\">動画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n再生が終了するか、画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n<h2 id=\"静止画の場合cpuのみ\">静止画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合cpuのみ\">動画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その3</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その3</h1>\n      <p>Tensorflow 2.2.0をインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Edge-TPUを直接操作するわけではないが、Tensorflowで作成されたモデルファイルをtflite用に変換する準備として<br />\ntensorflowをインストールする。<br />\nここではVersion 2.2.0を使用する。</p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<p>coral環境に追加インストールでも良いが、今回は別の環境を用意する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_2.2.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_2.2.0\n<span class=\"nb\">cd</span> /work/tf_2.2.0\npyenv <span class=\"nb\">local </span>tf_2.2.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"tensorflow-220-のインストール\">tensorflow 2.2.0 のインストール</h1>\n\n<p>インストールするパッケージはGPUを使わないので-cpu付きパッケージを選択する。<br />\nTensorflowはバージョンによって機能差が激しいので、インストールするバージョンを指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>2.2.0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その4</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その4</h1>\n      <p>tensorflowのモデルファイル(*.pbや*.tflite)の可視化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>tensorflowのモデルファイル( <code class=\"language-plaintext highlighter-rouge\">*.pb</code> や <code class=\"language-plaintext highlighter-rouge\">*.tflite</code> )を可視化する方法について。<br />\n<code class=\"language-plaintext highlighter-rouge\">tensorboard</code> を使う方法などもあるが、最もお手軽と思われる <code class=\"language-plaintext highlighter-rouge\">netron</code> を使用する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれやらなくても、<a href=\"https://lutzroeder.github.io/netron/\">https://lutzroeder.github.io/netron/</a> にアクセスすれば使える。</p>\n</blockquote>\n\n<h1 id=\"netron-の-インストール\">netron の インストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code>をインストールする。<br />\n<code class=\"language-plaintext highlighter-rouge\">netron</code> はtensorflowのバージョンに依存しない(そもそもtensorflow自体に依存してない)のでTensorflow1系、Tenorflow2系 どちらの環境にインストールしてもよい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>netron\n</code></pre></div></div>\n\n<h1 id=\"netron-の-実行\">netron の 実行</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code> を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>netron <span class=\"nt\">--host</span> 0.0.0.0 <span class=\"o\">[</span><span class=\"nt\">--port</span> xxxx]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--host</code> オプションを指定しないとlocalhostからしか接続できないので、他のマシンから接続するときは指定する。<br />\n<code class=\"language-plaintext highlighter-rouge\">--port</code> オプションのデフォルトは8080なので、変更したいときは指定する。</p>\n\n<h1 id=\"モデルファイルの表示\">モデルファイルの表示</h1>\n\n<p>ブラウザ(Winマシンからで可)で実行したマシンのポート8008(またはオプションで指定したxxxx)に接続。<br />\n例:<code class=\"language-plaintext highlighter-rouge\">http://ncc-1701u.local:8080/</code></p>\n\n<p>表示された画面でOpen Model…をクリックして表示するモデルファイルを選ぶ。<br />\nしばらく待つと表示される。<br />\nモデルファイルはブラウザからアップロードするので、ブラウザから参照できる場所になければならない(サーバ側にあってもダメ)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">*.pb</code> ファイルが大きいとうまく表示できないみたい。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その5</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その5</h1>\n      <p>Tensorflow v1.15のインストールとソースからのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はUbuntuだけ。</p>\n\n<h1 id=\"tensorflow-115-のインストール\">Tensorflow 1.15 のインストール</h1>\n\n<p>Tensorflow1系でないと動かない環境とかサンプルとかあるので、<br />\nTensorflow v1.15をインストールする。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_1.15.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_1.15.0\n<span class=\"nb\">cd</span> /work/tf_1.15.0\npyenv <span class=\"nb\">local </span>tf_1.15.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"tensorflow-115-ライブラリのインストール\">Tensorflow 1.15 ライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>1.15\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nGPU使わないので-cpu付きパッケージを選択する</p>\n</blockquote>\n\n<h1 id=\"tensorflow-115-のbuild\">Tensorflow 1.15 のbuild</h1>\n\n<p>Tensorflowのpythonライブラリは<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできるが、\nソースからbuildしないと使えないツールもあるのでbuild環境を整える。</p>\n\n<p>参考: <a href=\"https://www.tensorflow.org/install/source?hl=ja\">ソースからのビルド | Tensorflow</a></p>\n\n<h2 id=\"bazelのインストール\">Bazelのインストール</h2>\n\n<p>Tensorflow をソースからbuildするには<code class=\"language-plaintext highlighter-rouge\">bazel</code>が必要なので、インストールしておく。</p>\n<blockquote>\n  <p>[!NOTE]\nBazelはVer.0.26.1 以下 を使用しないといけない<br />\nVer. 0.26.1はaptでインストールできない</p>\n</blockquote>\n\n<p>参考: <a href=\"https://docs.bazel.build/versions/0.26.0/install-ubuntu.html\">Installing Bazel on Ubuntu</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/bazelbuild/bazel/releases/download/0.26.1/bazel-0.26.1-installer-linux-x86_64.sh\n<span class=\"nb\">chmod</span> +x bazel-0.26.1-installer-linux-x86_64.sh\n./bazel-0.26.1-installer-linux-x86_64.sh <span class=\"nt\">--user</span>\n</code></pre></div></div>\n\n<p>実行ファイルは、<code class=\"language-plaintext highlighter-rouge\">~/bin/bazel</code> になるので、pathが~/binに通ってない場合は、一旦 ログアウトして 再ログイン\n(pathが通ってない場合、configureでエラーになる)</p>\n\n<h2 id=\"必要なpipパッケージのインストール\">必要なpipパッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>six numpy wheel mock <span class=\"s1\">'future>=0.17.1'</span>\npip <span class=\"nb\">install </span>keras_applications <span class=\"nt\">--no-deps</span>\npip <span class=\"nb\">install </span>keras_preprocessing <span class=\"nt\">--no-deps</span>\n</code></pre></div></div>\n\n<h2 id=\"tennsorflowのソースを取得\">tennsorflowのソースを取得</h2>\n\n<p>githubからcloneして V1.15.3 をチェックアウトしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/\ngit clone https://github.com/tensorflow/tensorflow.git\n<span class=\"nb\">cd </span>tensorflow\ngit checkout <span class=\"nt\">-b</span> v1.15.3 refs/tags/v1.15.3\n</code></pre></div></div>\n\n<h1 id=\"buildの設定\">buildの設定</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\n./configure\n<span class=\"c\"># いくつか質問されるので、すべてデフォルト(リターン)を入力</span>\n</code></pre></div></div>\n\n<h1 id=\"buildの実行\">buildの実行</h1>\n<h2 id=\"実行のひな形\">実行のひな形</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build //《対象ディレクトリ》:《ターゲット》\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n※ 対象ディレクトリはカレントディレクトリからの相対パス<br />\n※ ターゲットは対象ディレクトリのBUILDファイルで確認</p>\n</blockquote>\n\n<h2 id=\"例えばこんな感じ\">例えばこんな感じ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel build //tensorflow/lite/toco:toco\nbazel build //tensorflow/python/tools:freeze_graph\nbazel build //tensorflow/tools/graph_transforms:summarize_graph\nbazel build //tensorflow/tools/graph_transforms:transform_graph\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRAMは4GB以上必要かな?<br />\nオプション<code class=\"language-plaintext highlighter-rouge\">--local_ram_resources=2048</code>を指定すると使用するRAMを2GBに限定できる(指定する数値はMB単位)。<br />\n使用するPCのスペックによってかかる時間はマチマチ。<br />\nNativeなUbuntuで4コア8スレッドでも3~4時間程度かかる。<br />\nVirtualboxで1コア使用だと24時間とかかかることも。</p>\n</blockquote>\n\n<h2 id=\"buildしたファイルの実行\">buildしたファイルの実行</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">bazel run</code> で実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nオプションをbazelではなく実行するコマンドに渡すため、<code class=\"language-plaintext highlighter-rouge\">--</code> を入れる必要がある。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel run //tensorflow/lite/toco:toco <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:summarize_graph <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:transform_graph <span class=\"nt\">--</span> «オプション»\n</code></pre></div></div>\n\n<p>絶対パスで実行するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph «オプション»\n</code></pre></div></div>\n\n<p>パスが長いので、以下を設定しておくと便利。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">alias            </span><span class=\"nv\">toco</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">summarize_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">transform_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph'</span>\n</code></pre></div></div>\n\n<h2 id=\"おまけ\">おまけ</h2>\n\n<p>フツーはこっちがメインだが…(^^ゞ<br />\npipでインストールすれば必要ないが、Tensorflowのpipパッケージを作成するにはこちら。<br />\n(オプション変更したいときとか)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build <span class=\"nt\">--config</span><span class=\"o\">=</span>v1 //tensorflow/tools/pip_package:build_pip_package\n./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg\npip <span class=\"nb\">install</span> /tmp/tensorflow_pkg/tensorflow-1.15.3-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール(改訂版)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2020.3対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a>で\nubuntuへのインストール手順を書いたが、今読み返すと結構分かりにくかったので改訂版を書いとく。<br />\n今回はNCS2をubuntuで使えるようにしたので、その手順も追加。<br />\nついでに、今日(2020/06/16)現在の最新版Ver.2020.3での手順確認したので、反映しておく。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<p>参考 :<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">AIを始めよう!OpenVINOのインストールからデモの実行まで[R4対応]</a></p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>何やら登録しないとダウンロードさせてくれないらしい。</p>\n<ul>\n  <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download.html\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a> <br />\nLinux* (supports Ubuntu, CentOS, and Yocto Project)を選択\n    <ul>\n      <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download/linux.html\">Free Download</a>  <br />\n<span style=\"border: 1px solid;\">Register & Download</span>をクリック\n        <ul>\n          <li><a href=\"https://software.seek.intel.com/openvino-toolkit?os=linux\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a><br />\n必要事項を記入して<span style=\"border: 1px solid;\">Submit</span>をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>openVINO用のpython環境を用意しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work1/\npyenv virtualenv 3.7.7 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p>あとで「入ってない」って言われるので先にインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev\n</code></pre></div></div>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>ダウンロードしたファイルを展開してインストールスクリプトを実行する。<br />\n今回はバージョン 2020.3 で確認した。<br />\n最新版は <a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html</a> を参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf l_openvino_toolkit_p_<version>.tgz\n<span class=\"nb\">cd </span>l_openvino_toolkit_p_<version>/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n<p>GUIで次へを押していく。</p>\n\n<p>完了したらこれが表示されるので、したがって進める。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<h3 id=\"install-external-software-dependencies\">Install External Software Dependencies</h3>\n<p>依存パッケージのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh \n</code></pre></div></div>\n\n<h3 id=\"set-the-environment-variables\">Set the Environment Variables</h3>\n<p>環境変数の設定<br />\n~/.bashrc に以下の一文を追加。これでこの後開くコンソールでは環境変数が設定される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>source /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<p>現在のターミナルでも使えるように以下のコマンドを実行しておく。コンソール開きなおしてもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<h3 id=\"configure-the-model-optimizer\">Configure the Model Optimizer</h3>\n<p>モデルオプティマイザのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh \n</code></pre></div></div>\n\n<p>上記スクリプトではsystemのpython3にpipモジュールがインストールされてしまうので、<br />\npyenv環境にも必要なpipモジュールをインストールしておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell openVINO                       <span class=\"c\"># python環境を固定したいので</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\npyenv shell <span class=\"nt\">--unset</span>                        <span class=\"c\"># python環境を戻しておく</span>\n</code></pre></div></div>\n\n<h3 id=\"run-the-verification-scripts-to-verify-installation\">Run the Verification Scripts to Verify Installation</h3>\n<p>デモ実行<br />\n「Verify Installation」って書いてあるけど、実行必須。</p>\n\n<ul>\n  <li>デモ用ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo/\n</code></pre></div>    </div>\n  </li>\n  <li>sudoでpyenvが使えないので、代わりに <code class=\"language-plaintext highlighter-rouge\">/work1</code>  で作成した <code class=\"language-plaintext highlighter-rouge\">.python-version</code>をコピーしておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /work1/.python-version <span class=\"nb\">.</span>\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境にデモ環境で必要なpipモジュールをインストールしておく 。Systemのpython使うときは↓のスクリプト実行時にインストールされる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その1\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/demo1.log\n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その2\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/dem2.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"steps-for-intel-processor-graphics-gpu\">Steps for Intel® Processor Graphics (GPU)</h3>\n<p>今回はGPUを使わないのでスキップ</p>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>NCS2の準備<br />\n色々書いてあるけど、これ一発でOK。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n中ではこんなことをやってます。<br />\nグループusersに自分を追加<br />\n(ログアウト & 再ログインするまで追加は反映されません)<br />\nudevルールの作成と再ロード</p>\n</blockquote>\n\n<p>NCS2をUSBポートにブッ挿すして認識したか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下があったら認識できてる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ID 03e7:2485\n</code></pre></div></div>\n\n<h3 id=\"steps-for-intel-vision-accelerator-design-with-intel-movidius-vpus\">Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPUs</h3>\n<p>今回はVPUを使わないのでスキップ</p>\n\n<p>デモプログラムの実行で動作確認</p>\n\n<p>で、Run a Sample Application に行く前に、ログアウト&再ログインでいいはずだけど、念のためリブート。</p>\n\n<h3 id=\"run-a-sample-application\">Run a Sample Application</h3>\n<p>リブートして開いてたページが分からなくなるといけないので、念のためURL貼っとく。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample</a></p>\n\n<ul>\n  <li>デモ実行ディレクトリに移動。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~/inference_engine_samples_build/intel64/Release\n</code></pre></div>    </div>\n  </li>\n  <li>CPUでデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> CPU\n</code></pre></div>    </div>\n  </li>\n  <li>NCS2でデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> MYRIAD\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>このページの手順はここでおしまい。</p>\n\n<h1 id=\"他のサンプルも試してみよう\">他のサンプルも試してみよう。</h1>\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n<h3 id=\"前準備\">前準備</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work1/NCS/sample <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work1/NCS/sample/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release /opt/intel/openvino_2020.3.194/deployment_tools/inference_engine/samples/cpp/\n</code></pre></div></div>\n\n<h3 id=\"ssdを試してみよう\">SSDを試してみよう</h3>\n<h4 id=\"build\">build</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">-j2</span> object_detection_sample_ssd\n</code></pre></div></div>\n<h4 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R4/20200117_150000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n</code></pre></div></div>\n\n<h4 id=\"実行\">実行</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./intel64/Release/object_detection_sample_ssd <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> /work/data/data2/z_20141013051441.jpg \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nコマンド実行時の<code class=\"language-plaintext highlighter-rouge\">-i</code>オプションは入力画像ファイル。<br />\n人の顔が写っているjpegファイルを指定しましょう。 \n顔が写ってなければ顔検出できません(^^ゞ</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[ INFO ] Execution successful</code>と表示されたら実行成功だと思う。</p>\n\n<h4 id=\"結果画像を表示してみる\">結果画像を表示してみる。</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>eog out_0.bmp \n</code></pre></div></div>\n\n<h4 id=\"おーーーー\"><strong><em>おーーーー</em></strong></h4>\n\n<h1 id=\"ここまでの作業でインストールしたpipパッケージ一覧\">ここまでの作業でインストールしたpipパッケージ一覧</h1>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.9.0\nastor==0.8.1\ncertifi==2020.4.5.2\nchardet==3.0.4\ndecorator==4.4.2\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.2.0\ngraphviz==0.8.4\ngrpcio==1.29.0\nh5py==2.10.0\nidna==2.9\nimportlib-metadata==1.6.1\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.2\nMarkdown==3.2.2\nmxnet==1.5.1\nnetworkx==2.4\nnumpy==1.18.5\nonnx==1.7.0\nopt-einsum==3.2.1\nprotobuf==3.6.1\nPyYAML==5.3.1\nrequests==2.23.0\nsix==1.15.0\ntensorboard==1.15.0\ntensorflow==1.15.3\ntensorflow-estimator==1.15.1\ntermcolor==1.1.0\ntyping-extensions==3.7.4.2\nurllib3==1.25.9\nWerkzeug==1.0.1\nwrapt==1.12.1\nzipp==3.1.0\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その6</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その6</h1>\n      <p>tensorflow lite で色々なSSDモデルを使う手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はソースが大半なので、githubにリポジトリ作った。<br />\n内容は各ディレクトリのREADME.mdを見てチョ。<br />\n<a href=\"https://github.com/ippei8jp/tflite_trial\">https://github.com/ippei8jp/tflite_trial</a></p>\n\n<p>順序は <code class=\"language-plaintext highlighter-rouge\">download_models</code> → <code class=\"language-plaintext highlighter-rouge\">mk_tflite_ssd</code> → <code class=\"language-plaintext highlighter-rouge\">images</code> → <code class=\"language-plaintext highlighter-rouge\">ssd</code> が良いと思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>csvファイルをエクセルファイルに変換する</title>\n  </head>\n  <body>\n    <header>\n      <h1>csvファイルをエクセルファイルに変換する</h1>\n      <p>pythonでcsvファイルをエクセルファイルに変換する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonでcsvファイルをエクセルファイルに変換する方法。<br />\nぐぐったらすぐ出てくるけど、自分のとこにもメモしとく。<br />\nついでに、おまけとしてcsvファイルを読んで、各列の平均値を出力する処理も載せとく。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p>必要なモジュールをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>pandas openpyxl\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pandas</span> <span class=\"k\">as</span> <span class=\"n\">pd</span>\n\n<span class=\"c1\"># コマンドラインパラメータ\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span>\n\n<span class=\"c1\"># エラーチェックは省略\n# 入力ファイル(csv形式、拡張子は任意)の拡張子をxlsxに変更したファイルとして出力する\n</span>\n<span class=\"n\">input_file</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>                                        <span class=\"c1\"># 入力ファイル名\n</span><span class=\"n\">output_file</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">input_file</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".xlsx\"</span>     <span class=\"c1\"># 出力ファイル名\n</span> \n<span class=\"c1\"># CSVファイルの読み込み\n</span><span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">pd</span><span class=\"p\">.</span><span class=\"n\">read_csv</span><span class=\"p\">(</span><span class=\"n\">input_file</span><span class=\"p\">,</span> <span class=\"n\">index_col</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>     <span class=\"c1\"># 1行目がヘッダ、1列目がインデックスとする\n</span>\n<span class=\"c1\"># Excel形式で出力\n</span><span class=\"n\">data</span><span class=\"p\">.</span><span class=\"n\">to_excel</span><span class=\"p\">(</span><span class=\"n\">output_file</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s\">'utf-8'</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<p>csvファイルを読んで、各列の平均値を出力する処理をワンライナーで。<br />\n(前提:1行目がヘッダ、1列目がインデックス)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import sys; import pandas as pd; data = pd.read_csv(sys.argv[1], index_col=0); ave=data.mean(); print(ave)\"</span> «csvファイル»\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git の差分比較ツールにWinMergeを使用する</title>\n  </head>\n  <body>\n    <header>\n      <h1>git の差分比較ツールにWinMergeを使用する</h1>\n      <p>git の差分比較ツールに WinMerge を使用する方法</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows上のgit-の差分比較ツールに-winmerge-を使用する方法\">Windows上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows限定だが、git の差分比較ツールに WinMerge を使用する方法のメモ<br />\n参考: <a href=\"https://qiita.com/kobake@github/items/fb317b4fdacad718a4b2?fbclid=IwAR1eO6ENMKDeeY3PmGJWrKLf_n1rgC8NVPBF60xKMiG02yAFgCFS6ceC7IE\">git の差分比較・マージを WinMerge で行う</a><br />\n↑参考というよりパクリだが(^^ゞ</p>\n\n<p>git の差分比較の <code class=\"language-plaintext highlighter-rouge\">git diff</code> で見ると見難いので、WinmMergeを使えるようにしてみた。<br />\n普段はVS Code 使ってるけど…</p>\n\n<p>手順は、 <code class=\"language-plaintext highlighter-rouge\">C:\\Users\\〇〇\\.gitconfig</code> に以下を追記するだけ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n[difftool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -f \\\"*.*\\\" -e -u -r \\\"$LOCAL\\\" \\\"$REMOTE\\\"\n[merge]\n    tool = WinMerge\n[mergetool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -e -u \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$MERGED\\\"\n[alias]\n    windiff = difftool -y -d -t WinMerge\n    winmerge = mergetool -y -t WinMerge\n</code></pre></div></div>\n\n<p>差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力すれば良い。</p>\n\n<p>差分はファイル書き換えても自動的にアップデートされなので、都度<code class=\"language-plaintext highlighter-rouge\">git windiff</code> する必要がある。<br />\n(あくまでスナップショットでの比較を表示してるだけ)</p>\n\n<p>比較対象の指定とか、マージとかもできるみたいだけど、使ってないので、詳しくは↑の参考先を見てね。(^^ゞ</p>\n\n<h1 id=\"wsl上のgit-の差分比較ツールに-winmerge-を使用する方法\">WSL上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows上の場合とほぼ同じ。<code class=\"language-plaintext highlighter-rouge\">~/.gitconfig</code>に以下を追加しておき、差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力する。<br />\nマージは使わないので、diffだけ設定。<br />\n(上の方法をwslpathでLinux上のpath→Windows上のpath 変換してるだけ、かな?)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n\n[difftool]\n    prompt = false\n\n[difftool \"WinMerge\"]\n    cmd = '/mnt/c/Program Files/WinMerge/WinMergeU.exe' -e -r -u -wl -dl Local -wr -dr Remote \\\"`wslpath -wa $LOCAL`\\\" \\\"`wslpath -wa $REMOTE`\\\"\n    trustExitCode = false\n\n[alias]\n    windiff = difftool -y -d --no-symlinks -t WinMerge\n</code></pre></div></div>\n<p>参考:<a href=\"https://qiita.com/forest1/items/334b5d756b5696c63331\">WSL(Ubuntu 18.04)環境のgitでWinMergeを使う方法</a></p>\n\n<p>参考先ではUbuntu18.04となっているが、20.04でも問題なし。<br />\nまた、<code class=\"language-plaintext highlighter-rouge\">/mnt/c/Users/username</code>以下で作業と書いてあるが、どこで作業しても大丈夫。テンポラリパスの変更も不要。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ガラクタ置き場</title>\n  </head>\n  <body>\n    <header>\n      <h1>ガラクタ置き場</h1>\n      <p>COCO データセットから適当にファイルを取得する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ガラクタ\">ガラクタ</h1>\n<p>SSDなどの動作確認に使えるかなぁ~?と思ってCOCO データセットから適当にいくつかの画像ファイルを取得するスクリプトを作ってみた。<br />\n結局使わなかったけど、せっかくなのでガラクタ置き場に置いておく。(^^ゞ</p>\n\n<p>今回はリポジトリ作るほどではないので、ここにソース貼っとく。<br />\n解説するほどでもないので、使い方はソース見てチョ!←   テヌキ…</p>\n\n<h2 id=\"ソース\">ソース</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"s\">'''\nCOCOデータセットから適当にファイルを取得する\n'''</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">glob</span>\n<span class=\"kn\">import</span> <span class=\"nn\">shutil</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">RawTextHelpFormatter</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">urllib.request</span>\n<span class=\"kn\">import</span> <span class=\"nn\">zipfile</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n\n<span class=\"n\">COCO_2014</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>       <span class=\"c1\"># COCO 2014のminivalデータセット を使用する場合はTrueにする\n</span>\n<span class=\"c1\"># パラメータ\n</span><span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n    <span class=\"n\">DOWNLOAD_URL</span> <span class=\"o\">=</span> <span class=\"s\">'https://dl.dropboxusercontent.com/s/o43o90bna78omob/instances_minival2014.json.zip?dl=0'</span>\n    <span class=\"n\">JSON_FILE</span>    <span class=\"o\">=</span> <span class=\"s\">'instances_minival2014.json'</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">DOWNLOAD_URL</span> <span class=\"o\">=</span> <span class=\"s\">'http://images.cocodataset.org/annotations/image_info_test2017.zip'</span>\n    <span class=\"n\">JSON_FILE</span>    <span class=\"o\">=</span> <span class=\"s\">'annotations/image_info_test2017.json'</span>\n\n<span class=\"c1\"># zipファイル展開のための一時ファイル\n</span><span class=\"n\">TEMP_ZIP</span>     <span class=\"o\">=</span> <span class=\"s\">'temp.zip'</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">formatter_class</span><span class=\"o\">=</span><span class=\"n\">RawTextHelpFormatter</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--num'</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロードするファイル数\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--margin'</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">30</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロードエラーのためのマージン数\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--clean'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロード済みのファイルを削除して終了します</span><span class=\"se\">\\n</span><span class=\"s\">(ダウンロードは行いません)\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n\n<span class=\"c1\"># コマンドラインパーサの生成&解析\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">clean</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"==== CLEAN!! ====\"</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">):</span>\n        <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n            <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">shutil</span><span class=\"p\">.</span><span class=\"n\">rmtree</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">dirname</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">),</span> <span class=\"n\">ignore_errors</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">for</span> <span class=\"nb\">file</span> <span class=\"ow\">in</span> <span class=\"n\">glob</span><span class=\"p\">.</span><span class=\"n\">glob</span><span class=\"p\">(</span><span class=\"s\">'*.jpg'</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">):</span>\n            <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ファイル数設定\n</span><span class=\"n\">num_files</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num</span>\n<span class=\"n\">num_margin</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">margin</span>\n\n<span class=\"c1\"># JSONファイルがなければダウンロードする\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ダウンロードを実行\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">DOWNLOAD_URL</span><span class=\"si\">}</span><span class=\"s\"> をダウンロード中...'</span><span class=\"p\">)</span>\n    <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">urlretrieve</span><span class=\"p\">(</span><span class=\"n\">DOWNLOAD_URL</span><span class=\"p\">,</span> <span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 展開\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">TEMP_ZIP</span><span class=\"si\">}</span><span class=\"s\"> を展開中...'</span><span class=\"p\">)</span>\n    <span class=\"k\">with</span> <span class=\"n\">zipfile</span><span class=\"p\">.</span><span class=\"n\">ZipFile</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">zf</span><span class=\"p\">:</span>\n        <span class=\"n\">zf</span><span class=\"p\">.</span><span class=\"n\">extractall</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># テンポラリファイルの削除\n</span>    <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># JSONファイルの読み込み\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">JSON_FILE</span><span class=\"si\">}</span><span class=\"s\">の読み込み中...'</span><span class=\"p\">)</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_json</span> <span class=\"p\">:</span>\n    <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f_json</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ個数(5000のハズ)\n</span><span class=\"n\">data_len</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">])</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'DATA_LENGTH = </span><span class=\"si\">{</span><span class=\"n\">data_len</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 内容をダンプ\n# print(json.dumps(data[\"images\"], indent=2))\n</span>\n<span class=\"c1\"># ダウンロード数のチェック\n</span><span class=\"k\">if</span> <span class=\"n\">num_files</span> <span class=\"o\">+</span> <span class=\"n\">num_margin</span> <span class=\"o\">></span> <span class=\"n\">data_len</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'ERROR : ファイル数とマージンの合計がデータ個数を超えています'</span><span class=\"p\">)</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ダウンロードするインデックスを乱数で決定(エラー発生時のためにマージンを積んどく)\n</span><span class=\"n\">download_indexs</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">(</span><span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">data_len</span><span class=\"p\">),</span> <span class=\"n\">num_files</span> <span class=\"o\">+</span> <span class=\"n\">num_margin</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># ダウンロード完了個数\n</span><span class=\"n\">num_downloaded</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n<span class=\"n\">num_error</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># ダウンロードループ\n</span><span class=\"k\">for</span> <span class=\"nb\">id</span> <span class=\"ow\">in</span> <span class=\"n\">download_indexs</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ファイル名\n</span>    <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"file_name\"</span><span class=\"p\">]</span>\n    <span class=\"c1\"># URL\n</span>    <span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n        <span class=\"n\">url</span>      <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"url\"</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">url</span>      <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"coco_url\"</span><span class=\"p\">]</span>\n    <span class=\"c1\"># ダウンロード\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">filename</span><span class=\"si\">}</span><span class=\"s\">をダウンロード中...'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'ID : </span><span class=\"si\">{</span><span class=\"nb\">id</span><span class=\"si\">:</span><span class=\"mi\">3</span><span class=\"si\">}</span><span class=\"se\">\\t</span><span class=\"s\">NAME : </span><span class=\"si\">{</span><span class=\"n\">filename</span><span class=\"si\">}</span><span class=\"se\">\\t</span><span class=\"s\">URL : </span><span class=\"si\">{</span><span class=\"n\">url</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">try</span> <span class=\"p\">:</span> \n        <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">urlretrieve</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">)</span>\n    <span class=\"k\">except</span> <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">.</span><span class=\"n\">HTTPError</span> <span class=\"k\">as</span> <span class=\"n\">e</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># エラー発生\n</span>        <span class=\"n\">num_error</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'**** skip!! ****  </span><span class=\"si\">{</span><span class=\"n\">e</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ダウンロード完了\n</span>        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'---- DONE!! ----'</span><span class=\"p\">)</span>\n        <span class=\"n\">num_downloaded</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"c1\"># 所望の数に達したら終了\n</span>        <span class=\"k\">if</span> <span class=\"n\">num_downloaded</span> <span class=\"o\">>=</span> <span class=\"n\">num_files</span> <span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'ダウンロード数 : </span><span class=\"si\">{</span><span class=\"n\">num_downloaded</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'エラー数       : </span><span class=\"si\">{</span><span class=\"n\">num_error</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">num_error</span> <span class=\"o\">></span> <span class=\"n\">num_margin</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'warning : エラー数がマージンを越えました'</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<p>今後、なんかに使えると良いなぁ~(笑)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのバグ??</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのバグ??</h1>\n      <p>pyenvのバグ??</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>バグかどうかわからんけど、思った通りの動作をしなかったので、メモ。</p>\n\n<h1 id=\"現象\">現象</h1>\n\n<p>pyenv を使う環境で、</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    python script.py <span class=\"nt\">--option</span> /path/to/file\n</code></pre></div></div>\n\n<p>と実行した場合、カレントディレクトリと<code class=\"language-plaintext highlighter-rouge\">/path/to/file</code>の存在するディレクトリで使用するpythonのバージョンが異なる場合、<br />\n(どちらか片方 or 両方で <code class=\"language-plaintext highlighter-rouge\">pyenv local</code>が指定されている)<br />\nカレントディレクトリではなく、/path/to/fileの存在するディレクトリで使用するpythonのバージョンが指定されてしまうらしい。</p>\n\n<p>問題が発生するシチュエーションは そんなに多くないと思うけど、 双方のバージョンでインストールしてるモジュールが違ったりすると困ったことになる。</p>\n\n<h1 id=\"原因\">原因</h1>\n\n<p>色々試行錯誤してみてわかったことを結論だけ。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> を見ると、<br />\nコマンドラインをサーチして最初に見つかったファイルの属する<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読むらしい。<br />\n(以下の部分)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    ・・・\n    <span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"k\">in</span>\n        <span class=\"nt\">-c</span><span class=\"k\">*</span> <span class=\"p\">|</span> <span class=\"nt\">--</span> <span class=\"p\">)</span> <span class=\"nb\">break</span> <span class=\"p\">;;</span>\n        <span class=\"k\">*</span>/<span class=\"k\">*</span> <span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-f</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n                </span><span class=\"nb\">export </span><span class=\"nv\">PYENV_FILE_ARG</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span>\n                <span class=\"nb\">break\n            </span><span class=\"k\">fi</span>\n            <span class=\"p\">;;</span>\n    <span class=\"k\">esac</span>\n    ・・・\n</code></pre></div></div>\n<p>本来ならスクリプトファイルのあるディレクトリの<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読んでほしいはずなのに…<br />\n<code class=\"language-plaintext highlighter-rouge\">*/* )</code> でなく、<code class=\"language-plaintext highlighter-rouge\">*)</code> じゃないのかな? なんか深い訳があるのかもしれんけど…</p>\n\n<h1 id=\"対処方法\">対処方法</h1>\n\n<p>で、以下のいずれかの方法で対処できる。</p>\n\n<ul>\n  <li>オプションの場合は、オプションとオプションパラメータの間をスペースでなく、<code class=\"language-plaintext highlighter-rouge\">=</code>にする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  python script.py <span class=\"nt\">--option</span><span class=\"o\">=</span>/path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>ただし、パーサが<code class=\"language-plaintext highlighter-rouge\">argparse.ArgumentParser</code>など、オプションとオプションパラメータの区切りに<code class=\"language-plaintext highlighter-rouge\">=</code>が使えるものでなければダメ。</li>\n      <li>しかも、そもそもオプションパラメータでなくコマンドパラメータだったらどうしようもない…orz…</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pyenv shell</code>で使用するバージョンを指定する\n    <ul>\n      <li>メンドクサイ…</li>\n    </ul>\n  </li>\n  <li>スクリプトファイルの前に<code class=\"language-plaintext highlighter-rouge\">--</code>を追加してやる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">--</span> script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> では<code class=\"language-plaintext highlighter-rouge\">-c</code>か<code class=\"language-plaintext highlighter-rouge\">--</code>が見つかったら<code class=\"language-plaintext highlighter-rouge\">PYENV_FILE_ARG</code>を探すループを抜けてくれるので。</li>\n      <li>ちょっとめんどくさい…</li>\n    </ul>\n  </li>\n  <li>スクリプト名の前に./を追加する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ./script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>これが一番シンプルかな?</li>\n      <li>てか、コレしかないっしょ。 常に<code class=\"language-plaintext highlighter-rouge\">./</code>付けるクセ付ければいいし。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"免責のツモリ\">免責(のツモリ)</h1>\n\n<p>あくまで自分のメモなんで、、、  ゴニョゴニョ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>githubによるセキュリティチェック</title>\n  </head>\n  <body>\n    <header>\n      <h1>githubによるセキュリティチェック</h1>\n      <p>githubによるセキュリティチェックによるpullリクエストが来た場合の対処方法</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>githubによるセキュリティチェックによるpullリクエストが来た場合の対処方法</p>\n\n<p>例えば、tensorflow 1.15 を使用するような設定が書かれていた場合、2.1.0に変更しろと言ってくる。<br />\nでも、変更したら動かなくなるし…</p>\n\n<h1 id=\"対処方法\">対処方法</h1>\n\n<p>こんな場合は しかたないので、アラート無視するよう言い訳する。<br />\nやり方:<a href=\"https://blog.tmd45.jp/entry/2019/11/26/162157\">GitHub Security Alert の Dismiss 言い訳</a></p>\n\n<p>でもって、自動で作成されたpullリクエストをcloseすると勝手に作成されたブランチも消えるらしい。<br />\nやり方: <a href=\"https://help.github.com/ja/github/collaborating-with-issues-and-pull-requests/closing-a-pull-request\">プルリクエストをクローズする</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットをキャプチャするときの注意事項</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットをキャプチャするときの注意事項</h1>\n      <p>WiresharkでUSBパケットをキャプチャしようとしてちょっとハマったのでメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>WiresharkでUSBパケットをキャプチャするための準備(Linux版)<br />\nWindows版はちょっと異なると思うけど試してないので、ググってね😅。</p>\n\n<h1 id=\"wiresharkのインストール実行\">Wiresharkのインストール&実行</h1>\n\n<p>ふつーに<code class=\"language-plaintext highlighter-rouge\">apt install</code>するだけ。<br />\nWindows版と異なり、USBパケットキャプチャのために別途USBキャプチャプログラムをインストールする必要はない。<br />\nついでに<code class=\"language-plaintext highlighter-rouge\">sudo</code>しなくても実行できるように自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>グループを追加しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>wireshark\n<span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> wireshark \n</code></pre></div></div>\n\n<p>ここで一旦ログアウト&再ログイン or 再起動。</p>\n\n<p>このままだとUSBパケットキャプチャのためのプログラム(<code class=\"language-plaintext highlighter-rouge\">usbmon</code>)が動いてないので、動かす必要がある。<br />\n<strong>起動の度に</strong>ターミナルから以下のコマンドを実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbmon\n</code></pre></div></div>\n\n<p>Wiresharkの実行は、ターミナルから<code class=\"language-plaintext highlighter-rouge\">wireshark</code>を実行するか、メニューの「インターネット」→「Wireshark」を選択します。<br />\n(自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>`グループを追加してあるので、メニューからでも実行できます)</p>\n\n<p>起動の度に<code class=\"language-plaintext highlighter-rouge\">usbmon</code>を起動するのは面倒な場合は、以下の手順で自動化できます。</p>\n\n<ol>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/udev/rules.d/99-usbmon.rules</code>を以下の内容で作成\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>SUBSYSTEM==\"usbmon\", GROUP=\"wireshark\", MODE=\"640\"\n</code></pre></div>    </div>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/modules</code> に以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbmon\n</code></pre></div>    </div>\n  </li>\n  <li>リブート</li>\n</ol>\n\n<h1 id=\"wiresharkの使い方\">Wiresharkの使い方</h1>\n\n<p>あちこちのホームページに詳しく解説されているので、ぐぐってちょ(←なんて他力本願…😅)。<br />\nRaspberryPi4の場合、USBのインタフェースはusbmon1とusbmon2があるが、どっちをキャプチャするかは、接続した機器がUSB2.0かUSB3.0による。<br />\nたぶん、usbmon1がUSB2.0(外側/内側)、usbmon2がUSB3.0(内側のみ)だと思う。<br />\n<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)がusbmonYのYにあたるとだと推測。</p>\n\n<h1 id=\"wiresharkでパケット解析\">Wiresharkでパケット解析</h1>\n\n<p>USBのパケットの表示フィルタの書き方がネット上でもなかなか見つからなかったので、簡単なものだけメモ。</p>\n\n<h2 id=\"特定のusb機器のパケットだけ表示\">特定のUSB機器のパケットだけ表示</h2>\n\n<p>実際にはエンドポイントまで指定しているので、複数のエンドポイントを同時に表示したければ、OR(<code class=\"language-plaintext highlighter-rouge\">||</code>)で条件つなげてください。\n(<code class=\"language-plaintext highlighter-rouge\">1.5.*</code>みたいな書き方が出来るのかは不明 )</p>\n\n<p>この例の<code class=\"language-plaintext highlighter-rouge\">1.5.1</code>の<br />\n左の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)、 <br />\n中央の<code class=\"language-plaintext highlighter-rouge\">5</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のデバイス番号(<code class=\"language-plaintext highlighter-rouge\">Device YYY</code>の部分の数字)(<strong>挿抜の度に変わる</strong>)、 <br />\n右の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb -D /dev/bus/usb/XXX/YYY</code>(XXX、YYYは上記のバス番号、デバイス番号。0は省略不可) で表示される情報の <br />\n<code class=\"language-plaintext highlighter-rouge\">bEndpointAddress</code>で確認できるけど、これは機器内部で固定されてるはず。<br />\nと、難しく調べんでも、一度全部キャプチャしたものを表示して欲しいパケットを探してみてそこのアドレスを見れば分かる。</p>\n\n<p>USBホストの吐合は<code class=\"language-plaintext highlighter-rouge\">\"host\"</code>になる。</p>\n\n<h3 id=\"特定の機器の送信パケットだけ表示\">特定の機器の送信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\"\n</code></pre></div></div>\n<h3 id=\"特定の機器の受信パケットだけ表示\">特定の機器の受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n<h3 id=\"特定の機器の送受信パケットだけ表示\">特定の機器の送受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\" || usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要--背景\">概要 & 背景</h1>\n\n<p>WiresharkでUSBパケットをキャプチャしたとき、実際に転送されてるデータの中身が見たいというニッチな要求があった。<br />\n(送ったデータがちゃんとUSBバスに出てるよね~、という確認がしたいなどの用途)</p>\n\n<p>Wiresharkのセーブデータ渡して「Wiresharkで見てね~」と言ったら「見方が分からん!」と…<br />\nで、Excelで一覧表にしてあげようと思い、エクスポートできんかな~と探してみるも、適当な機能が見つからず…<br />\nしかたなく、変換スクリプトかましてCSVに出力してExcelで読み込んでみよう、と試した時のメモ。</p>\n\n<p>今回はisochronous転送のデータの中身をダンプしている。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<ol>\n  <li>最初に解析したいパケットをキャプチャしておく(これをやらなきゃ始まらん…)。</li>\n  <li>必要なら表示フィルタで解析したいパケットだけ選び出す。</li>\n  <li>それらのパケットの一部だけ(最初の1秒だけ など)解析したい場合はそのパケット群を選択する。<br />\n   RaspberryPiでのやり方が分からん…Windows版なら他のアプリ同様、先頭で左クリック→最後でshift押しながら左クリックでOK。<br />\n   どうしても出来なかったら、RaspberryPiでキャプチャしたのを保存して、そのファイル(pcapngファイル)をWindowsにコピーして、\n   Windows上のWiresharkで読み込んでくだされ…😅</li>\n  <li>メニューの「ファイル」→「パケット解析をエクスポート」→「JSONとして」を選択</li>\n  <li>ファイル操作ダイアログが表示される\n    <ul>\n      <li>真ん中の「ファイル名」を入力</li>\n      <li>左下の「パケットの範囲」で\n        <ul>\n          <li>「表示されたパケット」を選択</li>\n          <li>「すべてのパケット」または「選択されたパケットのみ」を選択<br />\n (ここで「範囲」を選んで入力すれば選択しなくてもいいのかな?試してないので不明)</li>\n        </ul>\n      </li>\n      <li>「保存」をクリック</li>\n    </ul>\n  </li>\n</ol>\n\n<p>これでJSONファイルが保存される。</p>\n\n<h1 id=\"csvファイルに変換\">CSVファイルに変換</h1>\n\n<p>さぁ、このJSONファイルを読み込んで必要な部分を取り出すスクリプトを書けばOKじゃん?と思ったが、<br />\nそうは問屋がおろしてくれない😢<br />\nじつはWiresharkがエクスポートするJSONファイルはJSONファイルの文法からはずれた部分があるのだ…<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">/_source/layers/usb</code> の配下に複数のキー<code class=\"language-plaintext highlighter-rouge\">usb</code>があって、すべてのUSBデータを読み込めない。<br />\n(JSONの仕様では同一階層に複数の同じキーの存在を許さない。pythonのJSONモジュールでは複数あるデータのうち、一つだけが読み込まれる)<br />\nここが配列になってればOKだと気が付いて、チカラワザで変換する処理を追加してみた。</p>\n\n<p>で、pyshonで書いたスクリプトがこちら。<br />\nWindows/RaspberryPi どっちでも大丈夫と思うけど、Windowsでしか試してない。<br />\npythonは3.6以降が必要。3.7.7で動作確認。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  json_read.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"c1\"># テンポラリファイル名\n</span><span class=\"n\">tmp_file</span> <span class=\"o\">=</span> <span class=\"s\">'tmp.json'</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'==== USAGE ========================='</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'    </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> <JSON file> <CSV file>'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'===================================='</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">json_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">csv_file</span>  <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'Error: JSON file not exist!!'</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># \"usb\" キーが複数あるので、これをリストに変換したJSONファイルを作成する\n# かなり力技...\n</span><span class=\"k\">def</span> <span class=\"nf\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_json</span><span class=\"p\">,</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_tmp</span><span class=\"p\">:</span>\n        <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        \n        <span class=\"k\">while</span> <span class=\"n\">line</span><span class=\"p\">:</span>\n            <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"n\">line_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>           <span class=\"c1\"># 行番号\n</span>            <span class=\"c1\"># line = line.rstrip('\\r\\n')              # CRLFを削除\n</span>            <span class=\"k\">if</span> <span class=\"n\">find_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">'\"usb\": '</span><span class=\"p\">,</span> <span class=\"s\">''</span><span class=\"p\">)</span>      <span class=\"c1\"># key名称 \"usb\"を削除\n</span>                <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'START: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          \"usb_data\": [</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">+</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'{'</span><span class=\"p\">)</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">-</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'}'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">brackets</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'END: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          ]</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb.iso.numdesc\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">f_pos</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">tell</span><span class=\"p\">()</span>\n                    <span class=\"n\">next_line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>        <span class=\"c1\"># 次の行を読み込んで\n</span>                    <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"n\">f_pos</span><span class=\"p\">)</span>                   <span class=\"c1\"># ファイル位置を戻す\n</span>                    <span class=\"k\">if</span> <span class=\"n\">next_line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                    <span class=\"c1\"># 括弧の数\n</span>            <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">line</span><span class=\"p\">)</span>\n            <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># JSONファイルの修正\n</span><span class=\"n\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># パケット解析用変数\n</span><span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n<span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># JSONファイルの読み込み\n</span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n    <span class=\"n\">json_load</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(json_load)\n</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">csv_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_csv</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ヘッダの出力\n</span>    <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">'PacketNo,Date,Relative_time,Delta_time,Packet Size,Video Stream Size,Video Stream offset,Frame No,Stream No,Stream Data</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">json_data</span> <span class=\"ow\">in</span> <span class=\"n\">json_load</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フレームデータ\n</span>        <span class=\"n\">frame_data</span>          <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"frame\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_index</span>         <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.number\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_epoc</span>     <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_epoch\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_delta</span>    <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_delta_displayed\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_relative</span> <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_relative\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_dt</span>       <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">fromtimestamp</span><span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">frame_time_epoc</span><span class=\"p\">))</span>\n        <span class=\"n\">frame_time</span>          <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_time_dt</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_len</span>           <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.len\"</span><span class=\"p\">]</span>\n        <span class=\"c1\"># print(f'{frame_index},\"\\'{frame_time}\",{frame_len},', end='')\n</span>        <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_index</span><span class=\"si\">}</span><span class=\"s\">,\"</span><span class=\"se\">\\'</span><span class=\"si\">{</span><span class=\"n\">frame_time</span><span class=\"si\">}</span><span class=\"s\">\",</span><span class=\"si\">{</span><span class=\"n\">frame_time_relative</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_time_delta</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_len</span><span class=\"si\">}</span><span class=\"s\">,'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># USBデータ\n</span>        <span class=\"n\">usb_datas</span>  <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"usb\"</span><span class=\"p\">][</span><span class=\"s\">\"usb_data\"</span><span class=\"p\">]</span>\n        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"k\">for</span> <span class=\"n\">usb_data</span> <span class=\"ow\">in</span> <span class=\"n\">usb_datas</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f',,,,,', end='')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">',,,,,'</span><span class=\"p\">)</span>\n            <span class=\"n\">iso_len</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_len'</span><span class=\"p\">])</span>\n            <span class=\"n\">iso_off</span>  <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_off'</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">iso_len</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">\"usb.iso.data\"</span><span class=\"p\">]</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"s\">'0x'</span><span class=\"o\">+</span><span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">':'</span><span class=\"p\">,</span> <span class=\"s\">',0x'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">stream_number</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_number</span><span class=\"p\">)</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"s\">''</span>\n                \n                <span class=\"c1\"># print(f'{iso_len},{iso_off},{stream_number},{iso_data}')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_number_str</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">stream_number</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_data</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x02'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x03'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"n\">stream_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f'{iso_len},{iso_off},,')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,,</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># テンポラリファイルの削除\n</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。(RaspberryPiだと<code class=\"language-plaintext highlighter-rouge\">python3</code>にしてちょ)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python json_read.py «入力JSONファイル» «出力CSVファイル»\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>やっつけスクリプトなので、エラーチェックはかなりいい加減…</p>\n\n<p>関数<code class=\"language-plaintext highlighter-rouge\">modify_json()</code> が 前述のJSONファイルの不具合をチカラワザで修正する処理。</p>\n\n<p>テンポラリファイルとしてカレントディレクトリに<code class=\"language-plaintext highlighter-rouge\">tmp.json</code>を作成するので、注意。\nファイル名を変更したければ、8行目の<code class=\"language-plaintext highlighter-rouge\">tmp_file</code>を変更。<br />\nこのファイルはスクリプトの最後で削除している。<br />\n作成したテンポラリファイルを残しておきたければ最後の<code class=\"language-plaintext highlighter-rouge\">os.remove(tmp_file)</code>をコメントアウト。</p>\n\n<p>71~72行目で修正したJSONファイルを読み込み。</p>\n\n<p>75行目で書き出すCSVファイルをオープン。</p>\n\n<p>78行目~のforループで各JSONレコードを読み込みながら処理。</p>\n\n<p>82,85~86行目でframe.time_epochから時刻文字列を作成。<br />\n時刻は<code class=\"language-plaintext highlighter-rouge\">frame.time</code>を使用する手もあるが、ここはプラットフォームによって変化するらしいので同じ表示にするためにエポックタイムから生成している。<br />\nその他時刻関連データでは、<code class=\"language-plaintext highlighter-rouge\">frame.time_delta_displayed</code>で「前のパケットからの相対時間」、\n<code class=\"language-plaintext highlighter-rouge\">frame.time_relative</code>で「最初のパケットからの相対時間」を取得している。</p>\n\n<p>94行目~のforループがデータを取り出す部分。<br />\nisochronous転送のデータではないデータを取り出したい場合は、所望のデータのキーに置き換えて取り出せば良い。<br />\n<code class=\"language-plaintext highlighter-rouge\">frame_number</code>と<code class=\"language-plaintext highlighter-rouge\">stream_number</code>は私の解析用の補助データなので気にしないでネ。</p>\n\n<p>あとは、エクスポートされたJSONファイルとスクリプトを見比べてちゃぶだい。(^^ゞ</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>あとは、csvファイルをExcelで読み込むなり、pandasとかを使った別のスクリプトで加工するなりしてちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順はWiresharkで色々操作しないといけないのがめんどっちいので、スクリプトで自動化してみた。</p>\n\n<p>WiresharkのCUI版である、tsharkを使うと出来るらしいとの情報があったので、試してみたときのメモ。<br />\n今回はRaspberryPiだけ。Windowsは対応してません。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_1.html\">WiresharkでUSBパケットをキャプチャするときの注意事項</a> \nの準備は出来ているものとする。(Wiresharkは入ってなくても大丈夫。もちろん 入ってても良いよ。)</p>\n\n<p>tsharkは以下のコマンドイッパツでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tshark \n</code></pre></div></div>\n\n<p>で、あとは以下のスクリプトを\n<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの<code class=\"language-plaintext highlighter-rouge\">json_read.py</code>と同じディレクトリに作成し、実行するだけ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cap.sh\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/usr/bin/env bash</span>\n\n<span class=\"c\"># 第一引数でキャプチャ期間(sec)</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-z</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n  <span class=\"c\"># 引数なしだと2secに設定</span>\n  <span class=\"nv\">period</span><span class=\"o\">=</span>2\n<span class=\"k\">else</span>\n  <span class=\"c\"># 引数のチェック</span>\n  <span class=\"k\">if </span><span class=\"nb\">expr</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> : <span class=\"s1\">'[0-9]*'</span> <span class=\"o\">></span> /dev/null <span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># 数値</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nv\">$1</span> <span class=\"nt\">-lt</span> 1 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n      <span class=\"c\"># 1未満の数値</span>\n      <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n      <span class=\"nb\">exit\n    </span><span class=\"k\">else</span>\n      <span class=\"c\"># 1以上の数値(OK)</span>\n      <span class=\"nv\">period</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span>\n    <span class=\"k\">fi\n  else</span>\n    <span class=\"c\"># 数値でない</span>\n    <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n    <span class=\"nb\">exit\n  </span><span class=\"k\">fi\nfi</span>\n\n<span class=\"c\"># 現在時刻</span>\n<span class=\"nv\">cur_time</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">date</span> <span class=\"s2\">\"+%y%m%d_%H%M%S\"</span><span class=\"sb\">`</span>\n<span class=\"c\"># ファイル名生成</span>\n<span class=\"nv\">fname_base</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span>_<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># USBパケットキャプチャ</span>\n<span class=\"nb\">echo</span> <span class=\"s2\">\"Capture USB packets for </span><span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span><span class=\"s2\"> second from </span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\ntshark <span class=\"nt\">-i</span> usbmon1 <span class=\"nt\">-w</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-a</span> duration:<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># バス番号、デバイス番号の抽出</span>\n<span class=\"nv\">tmp_str</span><span class=\"o\">=</span><span class=\"sb\">`</span>lsusb | <span class=\"nb\">grep </span>WebCam<span class=\"sb\">`</span>\n<span class=\"nv\">bus_and_dev</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">tmp_str</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/Bus </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">Device </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">: ID.*/</span><span class=\"se\">\\1</span><span class=\"s2\"> </span><span class=\"se\">\\2</span><span class=\"s2\">/g\"</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">bus</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[0]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">dev</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[1]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">endpoint</span><span class=\"o\">=</span>1\n<span class=\"nv\">addr</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">bus</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">dev</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">endpoint</span><span class=\"k\">}</span>\n<span class=\"c\"># echo ${addr}</span>\n\n<span class=\"c\"># JSONファイルをエクスポート</span>\n<span class=\"nb\">echo </span>JSON data save to <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json...\ntshark <span class=\"nt\">-r</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-Y</span> <span class=\"s2\">\"usb.src==</span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">addr</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span> <span class=\"nt\">-T</span> json <span class=\"o\">></span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json\n\n<span class=\"c\"># JSON->CSV 変換</span>\npython json_read.py <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.csv\n\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。キャプチャ時間を秒で設定する。省略時は2秒。<br />\n出力されるファイル名は実行時の時刻で作成された文字列に各拡張子を付加したもの。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash cap.sh <span class=\"o\">[</span>キャプチャ時間<span class=\"o\">(</span>sec<span class=\"o\">)]</span>\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>なんかパラメータチェックが一番長いなぁ…😅</p>\n\n<p>33行目でパケットキャプチャ実行。</p>\n\n<p>35~41行目で対象USB機器のアドレス(バス番号、デバイス番号)を取得している。<br />\n36行目の<code class=\"language-plaintext highlighter-rouge\">grep</code>のパラメータは対象となるUSB機器に合わせて変更してちょ。<br />\nエンドポイント番号は対象機器によって固定なので、調べてね。\n分からなかったら、キャプチャしたデータをWiresharkで読み込んで確認してちょ。</p>\n\n<p>46行目でキャプチャしたファイルをJSONファイルにエクスポート。</p>\n\n<p>49行目でJSON→CSV変換。</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>これで<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順をスクリプトイッパツで完了できる。<br />\nま、特定環境でしか試してないから、どんな環境でも使えるとは限らないけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージ(2021.1)をインストール(追加)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージ(2021.1)をインストール(追加)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2021.1対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a>で\nubuntuへopenVINO 2020.3のインストールしたが、今回は 2021.1 を追加インストールしたのでメモ。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>前に登録したときに通知されたURLから「Choose Version」でバージョン選んでダウンロードできる。<br />\n新しく登録しなても大丈夫(登録方法は<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>参照)。</p>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>これは前回と同じ。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫だが、<br />\ncmakeは<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたバージョンだと古くてNGといわれてしまうので、<br />\n別途本家からダウンロードしてインストールする(ubuntu 18.04の場合。20.04だとたぶん<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたので大丈夫)。</p>\n\n<ul>\n  <li>既に<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストール済みの場合は、アンインストールする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt purge <span class=\"nt\">--auto-remove</span> cmake\n</code></pre></div>    </div>\n  </li>\n  <li>本家からダウンロードして展開\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/Kitware/CMake/releases/download/v3.18.4/cmake-3.18.4-Linux-x86_64.tar.gz  \n<span class=\"nb\">tar </span>xzvf cmake-3.18.4-Linux-x86_64.tar.gz \n</code></pre></div>    </div>\n  </li>\n  <li>/opt ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv </span>cmake-3.18.4-Linux-x86_64 /opt/\n</code></pre></div>    </div>\n  </li>\n  <li>/usr/bin ディレクトリにシンボリックリンク作成\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /opt/cmake-3.18.4-Linux-x86_64/bin/<span class=\"k\">*</span> /usr/bin/\n</code></pre></div>    </div>\n  </li>\n  <li>バージョン確認\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">--version</span> \n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>インストール手順も<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫。</p>\n\n<p>完了したらこれが表示されるページのURLは以下に変更されている。<br />\n<a href=\"https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<p>2020.3インストール済みだと端折っても大丈夫かと思ったけど、微妙にパッケージ増えてたりするので、再度やった方が良い。<br />\n環境変数の設定のために、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に記述する処理は以下に変更(<code class=\"language-plaintext highlighter-rouge\">openvino</code>→<code class=\"language-plaintext highlighter-rouge\">openvino_2021</code>)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\n<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を実行すると、再度<code class=\"language-plaintext highlighter-rouge\">apt</code>で<code class=\"language-plaintext highlighter-rouge\">cmake</code>がインストールされてしまいます。<br />\nopenVINOのインストール完了後であれば<code class=\"language-plaintext highlighter-rouge\">cmake</code>のバージョンが古くても大丈夫ですが、<br />\n気になるなら、再度アンインストールとシンボリックリンクの作成を行います。<br />\n(実行前に<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を編集してcmake消しておいても良いけど)</p>\n</blockquote>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>これは2020.3インストール済みだと端折ってもOK。<br />\n初めてインストールなら<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>を参照。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をセットアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をセットアップする</h1>\n      <p>Jetson nano をセットアップする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>本稿はJetoack4.4での手順です。<br />\nJetpack4.6のときのメモは<a href=\"/memoBlog/2021/09/13/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする(Jetpack4.6)</a> にあります。</p>\n\n<p>Nvidiaの<a href=\"https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/\">Jetson nano</a>をセットアップしたときのメモ</p>\n\n<h1 id=\"参照先\">参照先</h1>\n<ul>\n  <li><a href=\"https://monoist.atmarkit.co.jp/mn/articles/1905/30/news029.html\">「Jetson Nano」の電源を入れて立ち上げる</a>\n    <ul>\n      <li>わりと詳しく書いてある</li>\n    </ul>\n  </li>\n  <li><a href=\"https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit\">Getting Started With Jetson Nano Developer Kit </a>\n    <ul>\n      <li>本家</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"sdカードの作成\">SDカードの作成</h1>\n<p>参照先の通り。</p>\n\n<p>ただし、参照先のSDカードイメージへのリンクは古いので、は以下から最新版をダウンロードする(古いのも下の方を探せば出てくる)</p>\n<ul>\n  <li><a href=\"https://developer.nvidia.com/embedded/downloads\">Jetson Download Center</a></li>\n</ul>\n\n<p>SDカード書き込みは記事に書かれた balenaEtcher でなく WIN32DiskImager でも大丈夫だが、<br />\nbalenaEtcher は zipファイルを解凍せずにSDカードに書き込めるので便利。<br />\nちなみに、<em>balena</em> はイタリア語で <em>鯨</em> の意味らしい…全然関係ないけど…</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストール先のSDカードは32GB必須みたい。<br />\n16GBだとインストールしただけで「残り少ない」と言われてしまう。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSDカードスロットが分かりにくいところにある(開発ボード側ではなく、モジュール側の裏側)。<br />\nシリアルコンソール繋いでるとケーブルが邪魔で特に挿抜しにくい…</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\n一度このイメージを書き込んだSDカードは、以後Windowsから認識されなくなる。<br />\nよって、SDフォーマッタやディスクイメージ書き込みツールから新たに書き込みできなくなってしまう。\nこれは書き込んだSDカードにFATのパーティションが存在しないためのよう。<br />\n(RaspberryPiはbootパーティションとしてFATパーティションを持っているので認識されるようだ)</p>\n\n  <p>コントロールパネル→管理ツール→コンピュータの管理を起動して、<br />\n記憶域の下のディスクの管理からSDカード上の不明なパーティションを解放し、<br />\nそこに新たにFATパーティションを作成すればWindowsから認識されるようになる。<br />\nもちろん、他のUbuntuマシンで書き換えちゃうのもアリだけど。。。</p>\n</blockquote>\n\n<h1 id=\"シリアルコンソールの使用\">シリアルコンソールの使用</h1>\n<p>シリアルコンソールが必要なら接続できる。<br />\n特に設定等は必要ない。  <br />\n接続端子は以下を参照</p>\n<ul>\n  <li><a href=\"https://www.jetsonhacks.com/2019/04/19/jetson-nano-serial-console/\">Jetson Nano – Serial Console</a>\nの 「Wiring」の下の「Jetson Nano B01」を参照。</li>\n</ul>\n\n<p>シリアルポートの設定は115200bps/8bit/none/1bit/none</p>\n\n<blockquote>\n  <p>[!WARNING]\nJ41(RaspberryPi互換の40pinヘッダ)のUART端子はコンソールとして動作していないみたい。<br />\ngettyが動いてないみたいなので。  <br />\nたぶん、<code class=\"language-plaintext highlighter-rouge\">/etc/systemd/nvgetty.sh</code> に<code class=\"language-plaintext highlighter-rouge\">ttyTHS2</code>の設定を追加すればできるようになる感じだけど、試してないので詳細不明。<br />\nJ41のUARTを汎用UARTとして使用するには、以下を参照。</p>\n  <ul>\n    <li><a href=\"https://www.jetsonhacks.com/2019/10/10/jetson-nano-uart/\">Jetson Nano – UART</a></li>\n  </ul>\n</blockquote>\n\n<p>その他、コネクタ類の配置が分かりにくい場合は、\n<a href=\"https://developer.download.nvidia.com/assets/embedded/secure/jetson/Nano/docs/NV_Jetson_Nano_Developer_Kit_User_Guide.pdf?yIbsUqvBKxI1G6r3WW7cOdheZGv2-eSfaFW_kMt3dSgi0NJ7h77OwFHr5b-rquc3IX7Tyrt8FV6IKD4DHqvP4_LzhWt55tb071gqXlNGwBPYCOC5pnEKAla8D-B82bPjhQMykANFyn-EhxZRHC8AIBYWuVwwwXVPWtCOjs34Tg50oBdN0vBNoyUlZMRFXLNJ2to\">JETSON NANO DEVELOPER KIT</a>\nのP22 に<strong>Developer kit module and carrier board: rev B01 top view</strong>として配置図が掲載されているので参照のこと。</p>\n\n<h1 id=\"firstboot\">FirstBoot</h1>\n<p>最初のブートでUbuntuのセットアップを行う。<br />\nこれも参照先の通り。<br />\n終わったら、何はともあれ最新版にアップデート。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ここで一旦リブートしておく。</p>\n\n<p>その他こまごました設定はこちらが参考になるかも。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/05/08/ubuntu_native.html\">UbuntuをNative環境にインストールする(18.04)</a></li>\n</ul>\n\n<p>インストールしたパッケージ\ngnome-tweaks\ndconf-editor\nsamba</p>\n<blockquote>\n  <p>[!NOTE]\nmin/max/closeボタンがウィンドウ右側に移動できない…\nちょっとストレス…</p>\n</blockquote>\n\n<h1 id=\"その他設定\">その他設定</h1>\n<h2 id=\"ウィンドウマネージャをunityからubuntuに変更する\">ウィンドウマネージャをUnityからubuntuに変更する</h2>\n<p>Unityは使いにくくて嫌(個人の見解デス)なので、Ubuntuに変更する(変更しなくても良い)。\n自動ログインしている場合は、一旦ログアウトして、<br />\n再ログインする際に、「サインイン」ボタンの左にある歯車アイコンをクリック→Ubuntuを選択してから<br />\nログインすると、ウィンドウマネージャがUbuntuに変更されている。<br />\n次回ログイン(自動ログインでも)は何もしなくても前回のウィンドウマネージャが選択される。</p>\n<blockquote>\n  <p>[!NOTE]\nUbuntuに変えると min/max/closeボタンがウィンドウ右側に移動できてる。<br />\n結果オーライ😅</p>\n</blockquote>\n\n<h2 id=\"sshでの接続\">SSHでの接続</h2>\n<p>特に設定などは必要ない。<br />\nTeraTermなどで接続すれば良い。\nUbuntuではmDNSが動いているので、«マシン名».localでアクセスできる。</p>\n\n<p>コマンドは以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\"C:\\Program Files (x86)\\teraterm\\ttermpro.exe\" /auth=password /user=«ユーザ名» /passwd=«パスワード» «JetsonのIPアドレス or マシン名.local»\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nSSHやmDNSは立ち上がるまで少し時間がかかるみたいなので、<br />\n起動後数十秒程度待ってから接続した方が良い。</p>\n</blockquote>\n\n<h3 id=\"ssh接続がタイムアウトする対策\">SSH接続がタイムアウトする対策</h3>\n<p>SSH接続したターミナルを触らずにしばらく置いておくと、タイムアウトしてクローズされてしまう。\nこれを防ぐにはクライアント側からkeep-aliveパケットを定期的に送信してやれば良いらしい。</p>\n\n<p>Teratermの場合、「設定」→「SSH」→「ハートビート(keep-alive)」を「8」とかに設定し、保存。\n次回接続時はこの保存した設定ファイルを読み込む</p>\n\n<h3 id=\"シリアルコンソールssh接続でguiウィンドウを表示できるようにする\">シリアルコンソール/SSH接続でGUIウィンドウを表示できるようにする</h3>\n<p>シリアルコンソール/SSH接続でGUIウィンドウを表示できるようにするには、\nWindowsPCなどでX-Serverを動作させておき、<br />\nそこに出力するようにすればよい。<br />\nJetson側は<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加しておく。<br />\nここのIPアドレスはX-Serverが動作しているマシンのIPアドレスに変更すること。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XX.XX:0.0\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"リモートデスクトップの設定\">リモートデスクトップの設定</h1>\n<p>TigerVNC はちょっと動作があやしいので、やめておいて、Desktop Sharing(Vino)を使うことにする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f#%E6%96%B9%E6%B3%952-desktop-sharingvino%E3%82%92%E4%BD%BF%E3%81%86\">Jetson Nanoにリモートデスクトップ(VNC)環境を用意する</a></li>\n  <li><a href=\"https://www.hackster.io/news/getting-started-with-the-nvidia-jetson-nano-developer-kit-43aa7c298797\">Getting Started with the NVIDIA Jetson Nano Developer Kit</a> の 「Enabling Desktop Sharing」</li>\n</ul>\n\n<p>この手順はウィンドウマネージャがUnityで実行しています。 ウィンドウマネージャをUbuntuに変更していると少し手順が違うかもしれませんので、\nウィンドウマネージャをUbuntuに変更している場合はUnityに戻してから設定してください。<br />\n設定完了後はUbuntuに再変更しても問題ありません。</p>\n\n<p>以下手順の再掲。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml</code>に以下のパッチを当てる</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- org.gnome.Vino.gschema.xml.org      2020-10-19 06:21:32.034728957 +0900\n</span><span class=\"gi\">+++ org.gnome.Vino.gschema.xml  2020-10-19 06:22:30.887994965 +0900\n</span><span class=\"p\">@@ -154,5 +154,14 @@</span>\n       </description>\n       <default>true</default>\n     </key>\n<span class=\"gi\">+    <key name='enabled' type='b'>\n+      <summary>Enable remote access to the desktop</summary>\n+        <description>\n+          If true, allows remote access to the desktop via the RFB\n+          protocol. Users on remote machines may then connect to the\n+          desktop using a VNC viewer.\n+        </description>\n+      <default>false</default>\n+    </key>\n</span>   </schema>\n </schemalist>\n</code></pre></div></div>\n<ul>\n  <li>以下のコマンドを実行(これで「システム設定」に「デスクトップの共有」アイコンが表示されるようになる)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>glib-compile-schemas /usr/share/glib-2.0/schemas\n</code></pre></div>    </div>\n  </li>\n  <li>GUI画面から「システム設定」→「デスクトップの共有」(ユーザ向けカテゴリの中にある)\n    <ul>\n      <li>「Sharing」カテゴリ\n        <ul>\n          <li>「Allow other users to view your desktop」にチェックを<em>入れる</em></li>\n          <li>「Allow other users to control your desktop」にチェックを<em>入れる</em></li>\n        </ul>\n      </li>\n      <li>「セキュリティ」カテゴリ\n        <ul>\n          <li>「You must confirm each access to this machine」のチェックを<em>はずす</em></li>\n          <li>「Requwire the user to enter this password」にチェックを<em>入れて</em>パスワード設定</li>\n          <li>「Automatically configure UPnP router to open and forward ports」のチェックを<em>はずす</em></li>\n        </ul>\n      </li>\n      <li>「Show Notification Area Icon」カテゴリ\n        <ul>\n          <li>「Only when someone is connected」を選択\n            <blockquote>\n              <p>[!NOTE]\nウィンドウマネージャがUbuntuの時は「設定」で設定する。\n左側の「共有」カテゴリを選択、「画面共有」をクリック</p>\n              <ul>\n                <li>「このスクリーンの操作する接続を許可する」をチェック</li>\n                <li>「アクセスオプション」で「パスワードを要求する」を選択し、パスワード設定</li>\n                <li>「ネットワーク」で「有線接続1」のスライドスイッチで「オン」を選択\n左上のスライドスイッチで「オン」を選択\nで出来ると思うけど、出来なかったらUnityで上の方法で設定した後、再度Ubuntuに切り替えてちょ。</li>\n              </ul>\n            </blockquote>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>「自動起動するアプリケーション」を起動\n    <blockquote>\n      <p>[!NOTE]\n「コンピュータを検索」で「自動」または「session」と入力すると出てくる\n日本語環境だと「startup」で出てこないみたい…</p>\n    </blockquote>\n    <ul>\n      <li>「追加」ボタンをクリック\n        <ul>\n          <li>名前に「Vino」</li>\n          <li>コマンドに「/usr/lib/vino/vino-server」</li>\n          <li>説明に「VNC server」\nー と入力して「追加」をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>以下のコマンドを実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.Vino prompt-enabled <span class=\"nb\">false</span>\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\nこれはVinoの暗号化方式がWindowsと互換性がないための措置で、<br />\n暗号化を無効化しているらしい。<br />\ndconf-editorでも設定できる。</p>\n    </blockquote>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nVNC使う場合は自動ログインをONしておかないといけない<br />\n設定箇所はぐぐってちゃぶだい…😅</p>\n</blockquote>\n\n<ul>\n  <li>リブートする</li>\n  <li>ホストPCからRealVNCのVNC ViewerやUltraVNC viewerなどで接続する</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nVNCは反応速度が鈍いので、ちょっと使いにくい。<br />\n普段はSSHとsambaとホスト側のX-Serverで動かすのが良いかも…</p>\n</blockquote>\n\n<h1 id=\"追加情報\">追加情報</h1>\n<p>ipv6を無効にしたい(ネットワーク環境によっては無効にした方が良い)場合は、<br />\n<a href=\"/memoBlog/2020/05/26/ubuntu_koneta.html\">ubuntu 小ネタ集</a>の\n「ubuntu 18.04 で IPv6を無効にする方法」 にしたがって設定する。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano のSDカードをバックアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano のSDカードをバックアップする</h1>\n      <p>Jetson nano のSDカードをバックアップする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2020/10/23/Jetson_nano_install.html\">Jetson nano をセットアップする</a> \nでセットアップしたSDカードをバックアップしておけば逐一セットアップ作業を行わなくても環境を復元できます。</p>\n\n<p>ただ、そのままSDカードをイメージファイル化しただけでは復元するSDカードのサイズが微妙に小さい場合などは、復元できなくなってしまいます。<br />\nそこで、バックアップしtイメージファイル内のパーティションサイズを縮小し、イメージファイルを小さくするスクリプトを用意しました。</p>\n\n<p>この作業はubuntu PC上で行います。</p>\n\n<p>この方法、およびスクリプトはRaspberryPi用SDカードでも使用できます。</p>\n\n<h1 id=\"sdカードのバックアップ\">SDカードのバックアップ</h1>\n<blockquote>\n  <p>[!WARNING]\nJetson用SDカードはFATパーティションが存在しないため、<br />\nWindowsPCではバックアップツールがSDカードを認識できず、バックアップできません。</p>\n</blockquote>\n\n<ul>\n  <li>ubuntu PCにバックアップしたいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>SDカードイメージをファイルにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">of</span><span class=\"o\">=</span>«出力ファイル» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n  <li>ubuntu PCからSDカードを抜去</li>\n</ul>\n\n<h1 id=\"ディスクイメージファイルの縮小\">ディスクイメージファイルの縮小</h1>\n\n<p>バックアップしたイメージファイルはSDカード容量と同じサイズになっています。<br />\nディスクイメージを縮小するために <a href=\"/memoBlog/misc/stock/diskimage_shrink.sh\">このスクリプト</a> をダウンロードして実行します。</p>\n\n<p>まず、必要なツールをインストールしておきます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install </span>kpartx\n</code></pre></div></div>\n\n<p>ダウンロードしたスクリプトを実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash diskimage_shrink.sh «入力イメージファイル» «出力イメージファイル» \n</code></pre></div></div>\n<p>出力イメージファイルが既に存在する場合は、上書きするか聞かれますので、yまたはnで指定してください。</p>\n\n<p>最初に入力イメージファイルから出力イメージファイルへコピーを行います。<br />\nコピーが終了すると、<code class=\"language-plaintext highlighter-rouge\">sudo</code>実行するためのパスワードを聞かれますので、入力してください。<br />\n縮小するパーティションサイズを計算した後、\n現在のパーティションサイズと縮小後のパーティションサイズが表示されます。<br />\n各サイズが正しければ、yを入力してパーティションサイズの修正を行いますが、\n一般的に危険な処理なので、「警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?」と再度確認されます。<br />\nyを入力して実行してください。</p>\n\n<p>その後、さらに ファイルサイズを切り詰めます。</p>\n\n<p>処理が終了すると、以下のメッセージが表示されますので、これにしたがって後の処理を行ってください。<br />\nRaspberryPi用SDカードはMBRパーティションなので<code class=\"language-plaintext highlighter-rouge\">gdisk</code>の処理は不要です。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n<p>実行例を以下に示します。<br />\n入力コマンドは<code class=\"language-plaintext highlighter-rouge\"># =========</code>で囲んであります。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># =========================================================================\n/work2$ bash diskimage_shrink.sh jetson_sd_20201022_2.img XXXX.img\n# =========================================================================\nCopy image file...\n>f+++++++++ jetson_sd_20201022_2.img\n 30,953,963,520 100%   26.97MB/s    0:18:14 (xfr#1, to-chk=0/1)\nGet partition info...\n対象パーティション番号 : 1\nImage file mapping...\n[sudo] <<ユーザ>> のパスワード: «パスワードを入力»\nadd map loop18p1 (253:0): 0 60313600 linear 7:18 28672\nadd map loop18p2 (253:1): 0 256 linear 7:18 2048\nadd map loop18p3 (253:2): 0 896 linear 7:18 4096\nadd map loop18p4 (253:3): 0 1152 linear 7:18 6144\nadd map loop18p5 (253:4): 0 128 linear 7:18 8192\nadd map loop18p6 (253:5): 0 384 linear 7:18 10240\nadd map loop18p7 (253:6): 0 768 linear 7:18 12288\nadd map loop18p8 (253:7): 0 128 linear 7:18 14336\nadd map loop18p9 (253:8): 0 896 linear 7:18 16384\nadd map loop18p10 (253:9): 0 896 linear 7:18 18432\nadd map loop18p11 (253:10): 0 1536 linear 7:18 20480\nadd map loop18p12 (253:11): 0 128 linear 7:18 22528\nadd map loop18p13 (253:12): 0 160 linear 7:18 24576\nadd map loop18p14 (253:13): 0 256 linear 7:18 26624\nLOOP device : /dev/mapper/loop18p1\n現在のパーティションサイズ   : 29450MiB\n縮小後のパーティションサイズ : 15637MiB\nパーティションを縮小しますか? [y/N]: y\nPartition shrinking...\ne2fsck 1.44.1 (24-Mar-2018)\nPass 1: Checking iノードs, blocks, and sizes\nPass 2: Checking ディレクトリ structure\nPass 3: Checking ディレクトリ connectivity\nPass 4: Checking reference counts\nPass 5: Checking グループ summary information\n/dev/mapper/loop18p1: 199065/1881264 files (0.2% non-contiguous), 3701166/7539200 blocks\nresize2fs 1.44.1 (24-Mar-2018)\nResizing the filesystem on /dev/mapper/loop18p1 to 4003167 (4k) blocks.\nBegin pass 2 (max = 55)\nRelocating blocks             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nBegin pass 3 (max = 231)\nScanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nThe filesystem on /dev/mapper/loop18p1 is now 4003167 (4k) blocks long.\n\n警告: 管理者権限がありません。パーミッションに注意してください。\n警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?\nはい(Y)/Yes/いいえ(N)/No? y                                               \nTruncate image file size...\nReleas image file mapping...\nloop deleted : /dev/loop18\n******** Done!! ********\n\n\n\n対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\n\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n\n\n\n# =========================================================================\n/work2$ gdisk XXXX.img \n# =========================================================================\nGPT fdisk (gdisk) version 1.0.3\n\nWarning! Disk size is smaller than the main header indicates! Loading\nsecondary header from the last sector of the disk! You should use 'v' to\nverify disk integrity, and perhaps options on the experts' menu to repair\nthe disk.\nCaution: invalid backup GPT header, but valid main header; regenerating\nbackup header from main header.\n\nWarning! Error 25 reading partition table for CRC check!\nWarning! One or more CRCs don't match. You should repair the disk!\n\nPartition table scan:\n  MBR: protective\n  BSD: not present\n  APM: not present\n  GPT: damaged\n\n****************************************************************************\nCaution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\nverification and recovery are STRONGLY recommended.\n****************************************************************************\n\nCommand (? for help): b\nEnter backup filename to save: backup.gpt\nThe operation has completed successfully.\n\nCommand (? for help): r\n\nRecovery/transformation command (? for help): d\n\nRecovery/transformation command (? for help): w\nCaution! Secondary header was placed beyond the disk's limits! Moving the\nheader, but other problems may occur!\n\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\nPARTITIONS!!\n\nDo you want to proceed? (Y/N): y\nOK; writing new GUID partition table (GPT) to XXXX.img.\nWarning: The kernel is still using the old partition table.\nThe new table will be used at the next reboot or after you\nrun partprobe(8) or kpartx(8)\nThe operation has completed successfully.\n\n\n\n# =========================================================================\n/work2$ sudo parted -m XXXX.img unit GiB print\n# =========================================================================\nBYT;\n/work2/XXXX.img:15.3GiB:file:512:512:gpt::;\n2:0.00GiB:0.00GiB:0.00GiB::TBC:;\n3:0.00GiB:0.00GiB:0.00GiB::RP1:;\n4:0.00GiB:0.00GiB:0.00GiB::EBT:;\n5:0.00GiB:0.00GiB:0.00GiB::WB0:;\n6:0.00GiB:0.01GiB:0.00GiB::BPF:;\n7:0.01GiB:0.01GiB:0.00GiB::BPF-DTB:;\n8:0.01GiB:0.01GiB:0.00GiB::FX:;\n9:0.01GiB:0.01GiB:0.00GiB::TOS:;\n10:0.01GiB:0.01GiB:0.00GiB::DTB:;\n11:0.01GiB:0.01GiB:0.00GiB::LNX:;\n12:0.01GiB:0.01GiB:0.00GiB::EKS:;\n13:0.01GiB:0.01GiB:0.00GiB::BMP:;\n14:0.01GiB:0.01GiB:0.00GiB::RP4:;\n1:0.01GiB:15.3GiB:15.3GiB:ext4:APP:;\n\n\n\n# =========================================================================\n/work2$ ls -la jetson_sd_20201022_2.img y.img \n# =========================================================================\n-rw-r--r-- 1 user  user 30953963520 10月 22 15:42 jetson_sd_20201022_2.img\n-rw-r--r-- 1 user  user 16422139904 10月 25 07:00 y.img\n</code></pre></div></div>\n\n<h1 id=\"新しいsdカードにバックアップを復元\">新しいSDカードにバックアップを復元</h1>\n\n<p>イメージファイルからSDカードへのコピーはWindowsマシンで行っても良いですが、ここではubuntu PCで行う方法について記載します。</p>\n\n<ul>\n  <li>ubuntu PCに新しいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>バックアップしたイメージファイルをSDカードにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«入力ファイル» <span class=\"nv\">of</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h1 id=\"新しいsdカードのパーティションを拡張\">新しいSDカードのパーティションを拡張</h1>\n\n<p>バックアップした際にパーティションサイズを縮小してあるため、そのままのSDカードではディスクの残り容量がわずかしかありません。<br />\nそこで、パーティションサイズを拡張して容量を増加させます。</p>\n\n<p>この作業はubuntu PCであらかじめ行うか、またはターゲットマシンでブートした後に行います。</p>\n\n<p>パーティション操作プログラム<code class=\"language-plaintext highlighter-rouge\">gparted</code>を使用します。<br />\nインストールされていない場合は、<code class=\"language-plaintext highlighter-rouge\">sudo apt install gparted</code>でインストールしておいてください。</p>\n\n<ul>\n  <li>gpartedを起動\n    <ul>\n      <li>Libparted Warning ダイアログで”Not all of the space available to ~”と出たらFixをクリック</li>\n      <li>Libparted Warning ダイアログで”The backup GPT table is corrupt, but the primary appears OK, so that will be used.”と出たらOKをクリック<br />\n以降も何度か出るが、以下の操作がすべて終わればbackup GPTが新たに作成されるので問題なし。<br />\n(これは、ディスクイメージを縮小したときにgdiskコマンドを実行しなかった場合に出ます)</li>\n      <li>Gparted→デバイスで<code class=\"language-plaintext highlighter-rouge\">«SDカードデバイス»</code>`を選択</li>\n      <li>図の<code class=\"language-plaintext highlighter-rouge\">«SDカードのパーティション»</code> を右クリック→「リサイズ/移動」をクリック\n        <ul>\n          <li>「新しいサイズ」の欄に上にある「最大サイズ」以下の値を入力</li>\n          <li>「リサイズ」をクリック</li>\n        </ul>\n      </li>\n      <li>「編集(E)」→「保留中の全ての操作を適用する(A)」をクリック\n        <ul>\n          <li>「本当に保留中の操作を適用してもよろしいですか?」と聞かれるので、「適用」をクリック</li>\n        </ul>\n      </li>\n      <li>処理が完了したら「閉じる」をクリック</li>\n    </ul>\n  </li>\n  <li>gpartedを終了</li>\n</ul>\n\n<p>ターゲットマシンで実行している場合は、そのまま使用できます。<br />\nubuntuマシンで実行した場合は、SDカードを取り外してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をUSBドライブからブートできるようにする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をUSBドライブからブートできるようにする</h1>\n      <p>Jetson nano をUSBドライブからブートできるようにする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>本稿はJetoack4.4での手順です。<br />\nJetpack4.6のときのメモは<a href=\"/memoBlog/2021/09/14/Jetson_usb_boot.html\" target=\"_blank\">Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</a> にあります。</p>\n\n<h1 id=\"概要\">概要</h1>\n<p>SDカードからブートすると、かなりディスクアクセスが遅いのと、ディスク容量を結構喰うので、<br />\nUSBドライブ(HDD/SSD)からブートできるようにする手順。<br />\n例によって、先人の知恵を借りるだけだけど(パクりとも言う)…(^^ゞ</p>\n\n<p>めんどくさそうだったけど、ほとんどスクリプト化されているので、意外と簡単。</p>\n\n<h1 id=\"参考\">参考</h1>\n<ul>\n  <li><a href=\"https://www.miki-ie.com/nvidiajetsonnano/nvidia-jetson-nano-usb-root/\">NVIDIA Jetson Nano USB ディスクをルート構成</a></li>\n  <li><a href=\"https://qiita.com/sgrowd/items/87d65383c0b74306ea7d\">Jetson Nanoの/をUSBドライブにしてSDカードを長生きさせる</a></li>\n  <li><a href=\"https://www.jetsonhacks.com/2019/09/17/jetson-nano-run-from-usb-drive/\">Jetson Nano – Run From USB Drive</a></li>\n</ul>\n\n<h1 id=\"手順を再掲しとく\">手順を再掲しとく</h1>\n\n<ul>\n  <li>SDカードからブート</li>\n  <li>USBドライブを接続&フォーマット</li>\n  <li>USBドライブをマウント</li>\n  <li>ツールのダウンロード\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/JetsonHacksNano/rootOnUSB.git\n<span class=\"nb\">cd </span>rootOnUSB/\n</code></pre></div>    </div>\n  </li>\n  <li>USBドライブからbootするためのinitrdを作成する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./addUSBToInitramfs.sh\n</code></pre></div>    </div>\n  </li>\n  <li>SDカードからUSBドライブへファイルをコピーする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./copyRootToUSB.sh <span class=\"nt\">-p</span> «コピー先パーティション»\n  <span class=\"c\"># 例: ./copyRootToUSB.sh -p /dev/sda1</span>\n</code></pre></div>    </div>\n  </li>\n  <li>実際にUSBドライブからブートするための設定\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/boot/extlinux/extlinux.conf</code>のバックアップをとっておく\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv</span> /boot/extlinux/extlinux.conf /boot/extlinux/extlinux.conf.org\n</code></pre></div>        </div>\n      </li>\n      <li>USBドライブのUUIDを調べる\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./diskUUID.sh\n</code></pre></div>        </div>\n        <p>→ <code class=\"language-plaintext highlighter-rouge\">XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</code>として得られる。</p>\n      </li>\n      <li><code class=\"language-plaintext highlighter-rouge\">sample-extlinux.conf</code> の <code class=\"language-plaintext highlighter-rouge\">APPEND</code>の行のUUID部分を以下のように変更する\n        <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    APPEND ${cbootargs} root=UUID=dc21871e-9db4-434c-98b4-713f55f807eb rootwait rootfstype=ext4\n                                     ↓↓↓↓↓\n    APPEND ${cbootargs} root=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rootwait rootfstype=ext4\n</code></pre></div>        </div>\n      </li>\n      <li>変更した<code class=\"language-plaintext highlighter-rouge\">sample-extlinux.conf</code>を<code class=\"language-plaintext highlighter-rouge\">/boot/extlinux/extlinux.conf</code>をコピー\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp </span>sample-extlinux.conf /boot/extlinux/extlinux.conf\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>リーブート</li>\n</ul>\n\n<p>リブート完了したらUSBドライブがrootにマウントされていることを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">mount</code>で確認しても良いけど、いっぱい出てきて鬱陶しいので<code class=\"language-plaintext highlighter-rouge\">df</code>で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">df</span> <span class=\"nt\">-h</span> /\n</code></pre></div></div>\n<p>こんな感じで行頭にマウント元が表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Filesystem      Size  Used Avail Use% Mounted on\n/dev/sda1       110G   14G   91G  13% /\n</code></pre></div></div>\n\n<h1 id=\"注意\">注意</h1>\n<p>USBドライブからブートできるようになっても、SDカードは取り外してはいけない。<br />\nu-bootからinitrdをロードするのはSDカードなので。</p>\n\n<p>ということは、<code class=\"language-plaintext highlighter-rouge\">apt update</code>でカーネルアップデートされても古いカーネルが使われちゃうなぁ…<br />\nそれはそのとき考えよう…<br />\nそんなに変わるもんでもないだろう。</p>\n\n<h1 id=\"独り言\">独り言</h1>\n<p>u-bootの環境変数見ると、そのままUSBブート出来そうな感じだったけど、<br />\n実際に<code class=\"language-plaintext highlighter-rouge\">usb start</code>してみたらエラーになる。<br />\nどうやらu-bootにはUSBドライバが入ってないらしい…<br />\nそんな環境変数残しとくな!!</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano に pyenv をインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano に pyenv をインストールする</h1>\n      <p>Jetson nano に pyenvをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>systemのpythonを使うのはちょっと嫌なので、仮想環境を使えるようにしておく。<br />\n<code class=\"language-plaintext highlighter-rouge\">venv</code>でもいいけど、やっぱり使い慣れた<code class=\"language-plaintext highlighter-rouge\">pyenv</code>+<code class=\"language-plaintext highlighter-rouge\">vertualenv</code>で。<br />\n基本的に<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a>と同じだけど、<br />\nJetpackでインストール済みで、<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできないパッケージがあるなど、<br />\nJetson nano 固有の設定等があるので、メモ。</p>\n\n<h1 id=\"手順再掲を含む\">手順(再掲を含む)</h1>\n\n<h2 id=\"pyenvをインストールする\">pyenvをインストールする</h2>\n<ul>\n  <li>必要なパッケージのインストール\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>pyenvとプラグインをダウンロード\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git            <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone git://github.com/pyenv/pyenv-update.git      <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境からJetpackでインストール済みのパッケージを参照できるようにしておく。<br />\n(pipでインストールできないみたいなので、お手軽な方法で解決)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/cv2          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/graphsurgeon <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/tensorrt     <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/uff          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>\n、とやりたいけど、ARM版は非対応らしいので…</p>\n    </blockquote>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>の修正<br />\n以下を追加しておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n<span class=\"c\">#jetson専用のインストール済みパッケージをコピっておく</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHONPATH</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span><span class=\"s2\">/jetson_pythonlib:</span><span class=\"nv\">$PYTHONPATH</span><span class=\"s2\">\"</span>\n</code></pre></div>    </div>\n  </li>\n  <li>ターミナル開きなおし or <code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を再読み込み</li>\n</ul>\n\n<h2 id=\"ベースとなるpythonのインストール\">ベースとなるpythonのインストール</h2>\n<p>バージョンは3.6.xでないとダメっぽい</p>\n\n<h2 id=\"python-のインストール\">python のインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.12\npyenv global 3.6.12\n</code></pre></div></div>\n<p>pip と setuptools のアップデート</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n<h2 id=\"その他\">その他</h2>\n<p>wheelが入ってると仮想環境を変えて同じモジュールをインストールするときに早いので、<br />\nインストールしておきたいが、各仮想環境に逐一インストールするのも面倒なので<br />\n共通に参照できるディレクトリにインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>wheel <span class=\"nt\">-t</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google spreadsheet にREST APIを追加(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google spreadsheet にREST APIを追加(その1)</h1>\n      <p>HTTP GETリクエストでGoogle spreadsheetに追記する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2019/10/01/spreadsheet.html\" target=\"_blank\">Node.jsでGoogle spreadsheet にデータを書き込む</a> で\nGoogle Drive APIでGoogle spreadsheet にデータを書き込む方法を紹介しましたが、\nクライアント側の処理をもっと簡単にするためにREST APIを追加してHTTP GETリクエストでデータを書き込めるようにしてみました。</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは操作されるspreadsheetを作成します。</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> を開く</li>\n  <li>左側「新規」→ 「Googleスプレッドシート」で新しいスプレッドシートが開く</li>\n  <li>無題のスプレッドシート」をクリックして名前を入力</li>\n</ul>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n<ul>\n  <li>メニューの「ツール」→「スクリプトエディタ」をクリック</li>\n</ul>\n\n<p>新しいウィンドウでスクリプトエディタが開きます。</p>\n<ul>\n  <li>コード.gs に以下のコードを入力</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストで渡されたデータをスプレッドシートの最終行に追加する\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">AddDataToSeet start</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n\n  <span class=\"c1\">// 記録するシート(現在のスプレッドシートのアクティブなシート)</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">sheet</span> <span class=\"o\">=</span> <span class=\"nx\">SpreadsheetApp</span><span class=\"p\">.</span><span class=\"nx\">getActiveSheet</span><span class=\"p\">();</span>\n\n  <span class=\"kd\">var</span> <span class=\"nx\">dt</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>    <span class=\"c1\">// 日付</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>            <span class=\"c1\">// デフォルト値</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv0が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv1が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv2が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n\n  <span class=\"c1\">// スプレッドシートの最終行に追加</span>\n  <span class=\"nx\">sheet</span><span class=\"p\">.</span><span class=\"nx\">appendRow</span><span class=\"p\">([</span><span class=\"nx\">dt</span><span class=\"p\">,</span> <span class=\"nx\">v0</span><span class=\"p\">,</span> <span class=\"nx\">v1</span><span class=\"p\">,</span> <span class=\"nx\">v2</span><span class=\"p\">]);</span>\n\n  <span class=\"c1\">// HTML表示データを生成</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">createTextOutput</span><span class=\"p\">();</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setMimeType</span><span class=\"p\">(</span><span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">MimeType</span><span class=\"p\">.</span><span class=\"nx\">TEXT</span><span class=\"p\">);</span>\n  <span class=\"c1\">// メッセージボディ</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setContent</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">set data:</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">date=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">dt</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v0=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v0</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v1=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v1</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v2=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v2</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"cm\">/**\n * GETリクエストの処理\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">doGet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 処理本体</span>\n  <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ndoGet関数のパラメータ<code class=\"language-plaintext highlighter-rouge\">e</code>については、<a href=\"https://developers.google.com/apps-script/guides/web\" target=\"_blank\">このへん</a>を参照してください。</p>\n</blockquote>\n\n<ul>\n  <li>右上の青いボタン「デプロイ」→「新しいデプロイ」をクリック\n    <ul>\n      <li>「デプロイタイプを選択してください」と言われるので、「種類の選択」横の歯車アイコンをクリック → 「ウェブアプリ」をクリック\n        <ul>\n          <li>「説明」に説明文を入力(省略可)</li>\n          <li>「ウェブアプリ」の「次のユーザとして実行」で「自分」を選択</li>\n          <li>「アクセスできるユーザ」を適切な範囲に設定  (「全員」にすればパスワードなしでアクセスできる)\n            <blockquote>\n              <p>[!NOTE]\ncurlなどでアクセスしたい場合は、「全員」にしておかないと、認証画面に飛んでしまい、アクセスが完了しません。</p>\n            </blockquote>\n          </li>\n          <li>「デプロイ」をクリック</li>\n        </ul>\n      </li>\n      <li>「このウェブ アプリケーションを使用するには、データへのアクセスを許可する必要があります。」と言われるので「アクセスを承認」をクリック</li>\n      <li>「アカウントの選択」が表示されるので、使用するアカウントを選択</li>\n      <li>「このアプリは Google で確認されていません」と言われるので、左下「詳細」をクリック\n        <ul>\n          <li>「無題のプロジェクト(安全ではないページ)に移動」をクリック</li>\n          <li>「無題のプロジェクトがGoogle アカウントへのアクセスをリクエストしています」と言われるので、「許可」をクリック</li>\n          <li>「新しいデプロイ」が表示される</li>\n          <li>一番下の「ウェブアプリ」のUARLをコピーして使用</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<p>例えば以下のコマンドでアクセスする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>curl <span class=\"nt\">-L</span> <span class=\"s2\">\"«上でコピーしたURL»?v0=1&v1=2&v2=3\"</span>\n</code></pre></div></div>\n\n<p>実行すると、対象のスプレッドシートの最終行に以下のデータが追加されます。</p>\n<ul>\n  <li>A列: 日付と時刻</li>\n  <li>B列: v0で指定した値</li>\n  <li>C列: v1で指定した値</li>\n  <li>D列: v2で指定した値</li>\n</ul>\n\n<p>スクリプトを修正した場合、再度「新しいデプロイ」を実行する必要がある。</p>\n\n<p>または、「デプロイ」→「デプロイをテスト」で表示されるURLを使用すると、デプロイせずに現在の最新ソースで実行できる。<br />\nただし、この場合、ユーザ認証が必須になってしまうので、ブラウザ等でアクセスする必要がある。<br />\nどうしてもcurlでアクセスしたい場合は、ヘッダに<code class=\"language-plaintext highlighter-rouge\">Authorization: Bearer «アクセストークン»</code>を追加してやれば良い。(あまりおススメはしないけど)<br />\nやり方は<a href=\"https://www.ka-net.org/blog/?p=12258\" target=\"_blank\">ここらへん</a>を参考にしてください。</p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>時刻の文字列を取得した場合、知らないタイムゾーンになっていて困ったときはタイムゾーンを変更すれば良い。</p>\n\n<p>タイムゾーンを変更するにはこちら。</p>\n<ul>\n  <li>画面左の歯車アイコン「プロジェクトの設定」をクリック\n    <ul>\n      <li>「「appsscript.json」マニフェスト ファイルをエディタで表示する」にチェックを入れる</li>\n    </ul>\n  </li>\n  <li>画面左の<>アイコン「エディタ」をクリックしてエディタに戻る\n    <ul>\n      <li>ファイル一覧に「appsscript.json」が追加されているのでクリック</li>\n      <li>タイムゾーンを指定している部分を   <code class=\"language-plaintext highlighter-rouge\">\"timeZone\": \"Asia/Tokyo\",</code> に変更</li>\n      <li>保存して再度デプロイ</li>\n    </ul>\n  </li>\n</ul>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google spreadsheet にREST APIを追加(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google spreadsheet にREST APIを追加(その2)</h1>\n      <p>Google Apps Scriptのライブラリ化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">Google spreadsheet にREST APIを追加 その1</a>   では\nSpreadsheetに埋め込んだスクリプトにすべて記述しましたが、 新しいSpreadsheetを作成する度にコードをコピーするのは大変ですし、\n何らかの不具合が見つかったときに複数のファイルをメンテナンスしなければならないのは現実的ではありません。<br />\nそこで、スプレッドシートにデータを登録する部分をライブラリ化し、Spreadsheetに埋め込んだスクリプトには最低限のコードだけ記載するようにしてみます。</p>\n\n<h1 id=\"手順\">手順</h1>\n<p>まずはスクリプトライブラリを作成します</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a>   を開く</li>\n  <li>左側「新規」→ 「その他」→「Google Apps Script」で新しいスクリプトエディタが開く\n    <ul>\n      <li>「無題のプロジェクト」をクリックして名前を入力</li>\n      <li>コード.gsに以下を入力(<a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">その1</a>  の<code class=\"language-plaintext highlighter-rouge\">AddDataToSeet()</code>と同一)</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストで渡されたデータをスプレッドシートの最終行に追加する\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">AddDataToSeet start</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n\n  <span class=\"c1\">// 記録するシート(現在のスプレッドシートのアクティブなシート)</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">sheet</span> <span class=\"o\">=</span> <span class=\"nx\">SpreadsheetApp</span><span class=\"p\">.</span><span class=\"nx\">getActiveSheet</span><span class=\"p\">();</span>\n\n  <span class=\"kd\">var</span> <span class=\"nx\">dt</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>    <span class=\"c1\">// 日付</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>            <span class=\"c1\">// デフォルト値</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv0が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv1が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv2が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n\n  <span class=\"c1\">// スプレッドシートの最終行に追加</span>\n  <span class=\"nx\">sheet</span><span class=\"p\">.</span><span class=\"nx\">appendRow</span><span class=\"p\">([</span><span class=\"nx\">dt</span><span class=\"p\">,</span> <span class=\"nx\">v0</span><span class=\"p\">,</span> <span class=\"nx\">v1</span><span class=\"p\">,</span> <span class=\"nx\">v2</span><span class=\"p\">]);</span>\n\n  <span class=\"c1\">// HTML表示データを生成</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">createTextOutput</span><span class=\"p\">();</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setMimeType</span><span class=\"p\">(</span><span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">MimeType</span><span class=\"p\">.</span><span class=\"nx\">TEXT</span><span class=\"p\">);</span>\n  <span class=\"c1\">// メッセージボディ</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setContent</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">set data:</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">date=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">dt</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v0=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v0</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v1=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v1</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v2=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v2</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<ul>\n  <li>右上の青いボタン「デプロイ」→「新しいデプロイ」をクリック\n    <ul>\n      <li>「デプロイタイプを選択してください」と言われるので、\n        <ul>\n          <li>「種類の選択」横の歯車アイコンをクリック → 「ライブラリ」をクリック</li>\n          <li>「説明」に説明文を入力(省略可)</li>\n          <li>「デプロイ」をクリック</li>\n        </ul>\n      </li>\n      <li>新しいデプロイウィンドウが表示されるので、「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>画面左の歯車アイコン「プロジェクトの設定」をクリック\n    <ul>\n      <li>「プロジェクトの設定」の真ん中あたりの「スクリプトID」をメモしておく</li>\n    </ul>\n  </li>\n</ul>\n\n<p>次に操作されるspreadsheetを作成します。</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a>   を開く</li>\n  <li>左側「新規」→ 「Googleスプレッドシート」で新しいスプレッドシートが開く</li>\n  <li>無題のスプレッドシート」をクリックして名前を入力</li>\n  <li>SpreadsheetにGoogle Apps Script(GAS)を追加します。\n    <ul>\n      <li>メニューの「ツール」→「スクリプトエディタ」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<p>新しいウィンドウでスクリプトエディタが開きます。</p>\n<ul>\n  <li>「ライブラリ」の横の+マーク(ライブラリを追加)をクリック</li>\n  <li>「ライブラリの追加」ウィンドウが開くので、「スクリプトID」の欄に上でメモしたスクリプトIDを入力し、「検索」をクリック</li>\n  <li>バージョンで使用するバージョンを選択(HAEAD(開発モード)を選択すると、デプロイするまえの最新ソースが使用される)</li>\n  <li>ID を設定します。\n    <blockquote>\n      <p>[!NOTE]\nID は node.jsで言うところの、以下の部分の「変数名」に相当する</p>\n      <div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">var</span> <span class=\"nx\">変数名</span> <span class=\"o\">=</span> <span class=\"nx\">require</span><span class=\"p\">(</span><span class=\"dl\">'</span><span class=\"s1\">モジュール名</span><span class=\"dl\">'</span><span class=\"p\">)</span>\n</code></pre></div>      </div>\n    </blockquote>\n  </li>\n  <li>コード.gs に以下のコードを入力</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストの処理\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">doGet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 処理本体</span>\n  <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">MySpreadsheetLib</span><span class=\"p\">.</span><span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>以降、(<a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">その1</a> のデプロイ作業と同一です。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Apps Script で LINE Notify</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Apps Script で LINE Notify</h1>\n      <p>Google Apps Script から LINE に通知を送る</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Google Apps Script(GAS)からリアルタイムな通知を送る方法としてLINEにメッセージを送ってみる。</p>\n\n<p>LINE Notify を使うとアクセストークンを取得すれば、REST APIで簡単にメッセージを送れるので、これを使うことにした。</p>\n\n<h1 id=\"前準備\">前準備</h1>\n\n<p><a href=\"https://qiita.com/iitenkida7/items/576a8226ba6584864d95\" target=\"_blank\">[超簡単]LINE notify を使ってみる</a>  を参考に、\nLINEの設定 および LINE Notifyのアクセストークンの取得を行っておいてください。</p>\n<blockquote>\n  <p>[!NOTE]\nトークルームでなく、『1:1でLINE Notifyから通知を受け取る』を選択した場合は、ID検索で「@linenotify」を検索して友だちに追加してください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://notify-bot.line.me/ja/\" target=\"_blank\">LINE Notifyホーム</a> <br />\n<a href=\"https://notify-bot.line.me/doc/ja/\" target=\"_blank\">ドキュメント</a></p>\n</blockquote>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは<a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> で新しいGoogle Apps Scriptのプロジェクトを作成します。</p>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n\n<ul>\n  <li>新しいウィンドウでスクリプトエディタが開きます。</li>\n  <li>コード.gs に以下のコードを入力してください。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">// アクセストークン </span>\n<span class=\"kd\">const</span> <span class=\"nx\">ACCESS_TOKEN</span> <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">«取得したアクセストークン»</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n\n<span class=\"cm\">/**\n * テスト用関数\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">myFunction</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 時刻文字列取得</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">date_str</span> <span class=\"o\">=</span> <span class=\"nx\">Utilities</span><span class=\"p\">.</span><span class=\"nx\">formatDate</span><span class=\"p\">(</span><span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">(),</span><span class=\"dl\">\"</span><span class=\"s2\">JST</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">yyyy/MM/dd hh:mm:ss</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">token</span> <span class=\"o\">=</span> <span class=\"nx\">ACCESS_TOKEN</span><span class=\"p\">;</span>\n  <span class=\"nx\">LINE_notify</span><span class=\"p\">(</span><span class=\"nx\">token</span><span class=\"p\">,</span> <span class=\"nx\">date_str</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">    てすとぉぉぉ</span><span class=\"dl\">\"</span> <span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n<span class=\"cm\">/**\n * メッセージ送信処理\n *\n * @param {string} token    - アクセストークン\n * @param {string} message  - 送信するメッセージ\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">LINE_notify</span><span class=\"p\">(</span><span class=\"nx\">token</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">){</span>\n    <span class=\"kd\">const</span> <span class=\"nx\">url</span> <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">https://notify-api.line.me/api/notify</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n    <span class=\"kd\">var</span> <span class=\"nx\">headers</span> <span class=\"o\">=</span> <span class=\"p\">{</span> \n      <span class=\"dl\">'</span><span class=\"s1\">Authorization</span><span class=\"dl\">'</span><span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">Bearer </span><span class=\"dl\">'</span> <span class=\"o\">+</span> <span class=\"nx\">token</span> \n    <span class=\"p\">};</span>\n    <span class=\"kd\">var</span> <span class=\"nx\">options</span> <span class=\"o\">=</span> <span class=\"p\">{</span> \n      <span class=\"dl\">'</span><span class=\"s1\">headers</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"nx\">headers</span> <span class=\"p\">,</span>\n      <span class=\"dl\">'</span><span class=\"s1\">method</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">post</span><span class=\"dl\">'</span> <span class=\"p\">,</span>\n      <span class=\"c1\">// encodeURIComponent()はなくても大丈夫っぽい...</span>\n      <span class=\"c1\">// 'payload' : 'message=' + encodeURIComponent(message)</span>\n      <span class=\"dl\">'</span><span class=\"s1\">payload</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">message=</span><span class=\"dl\">'</span> <span class=\"o\">+</span> <span class=\"nx\">message</span><span class=\"p\">,</span> \n      <span class=\"dl\">'</span><span class=\"s1\">muteHttpExceptions</span><span class=\"dl\">'</span><span class=\"p\">:</span> <span class=\"kc\">true</span>        <span class=\"c1\">// エラーが返ってきても例外発生させない</span>\n     <span class=\"p\">};</span> \n    <span class=\"kd\">var</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n\n    <span class=\"k\">try</span> <span class=\"p\">{</span>\n      <span class=\"c1\">// メッセージを送信 </span>\n      <span class=\"kd\">var</span> <span class=\"nx\">res</span> <span class=\"o\">=</span> <span class=\"nx\">UrlFetchApp</span><span class=\"p\">.</span><span class=\"nx\">fetch</span><span class=\"p\">(</span><span class=\"nx\">url</span> <span class=\"p\">,</span><span class=\"nx\">options</span><span class=\"p\">);</span>\n\n      <span class=\"kd\">var</span> <span class=\"nx\">resCode</span> <span class=\"o\">=</span> <span class=\"nx\">res</span><span class=\"p\">.</span><span class=\"nx\">getResponseCode</span><span class=\"p\">();</span>              <span class=\"c1\">// HTTP レスポンスステータスコード</span>\n      <span class=\"kd\">var</span> <span class=\"nx\">resBody</span> <span class=\"o\">=</span> <span class=\"nx\">JSON</span><span class=\"p\">.</span><span class=\"nx\">parse</span><span class=\"p\">(</span><span class=\"nx\">res</span><span class=\"p\">.</span><span class=\"nx\">getContentText</span><span class=\"p\">());</span>   <span class=\"c1\">// レスポンス本体はJSONなのでパースする</span>\n\n      <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nx\">resCode</span> <span class=\"o\">===</span> <span class=\"mi\">200</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// レスポンスが200 → 正常終了</span>\n        <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">SUCCESS: %s</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"nx\">resBody</span><span class=\"p\">.</span><span class=\"nx\">message</span><span class=\"p\">);</span>\n      <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// それ以外→エラーレスポンス</span>\n        <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"nx\">Utilities</span><span class=\"p\">.</span><span class=\"nx\">formatString</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">ERROR: status:%d  body:%s</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"nx\">resCode</span><span class=\"p\">,</span> <span class=\"nx\">resBody</span><span class=\"p\">.</span><span class=\"nx\">message</span><span class=\"p\">));</span>\n      <span class=\"p\">}</span>\n    <span class=\"p\">}</span> <span class=\"k\">catch</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n      <span class=\"c1\">// その他のエラー(DNSエラー、タイムアウトなど)は例外が発生する</span>\n      <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">ERROR: </span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">e</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<ul>\n  <li>「実行する関数」に<code class=\"language-plaintext highlighter-rouge\">myFunction</code>を選択(エディタの上、「実行ログ」の左の▼をクリックして選ぶ)\nー 「実行」をクリック</li>\n  <li>LINEに通知が届きます</li>\n</ul>\n\n<h1 id=\"最後に\">最後に</h1>\n\n<p>これだけだと大したことできないけど、ライブラリ化して他のサービスと組み合わせて使えばなんかのPUSH通知っぽく使えるかな?</p>\n\n<blockquote>\n  <p>[!NOTE]\nSpreadsheetの時のように、ウェブアプリにしようかと思ったら、もともとREST APIだから全然意味ないので関数作るだけにしておいた。<br />\n(POST使えない場合にGETで受け付けるラッパみたいなのは考えられなくはないけど)</p>\n</blockquote>\n\n<h1 id=\"参考\">参考</h1>\n\n<p>通知回数の上限は1000回/1時間/アクセストークンです。(そんなに送ったら鬱陶しいでしょうから問題ないかな?)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Apps Script で メール送信</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Apps Script で メール送信</h1>\n      <p>Google Apps Script から メールを送信する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Google Apps Script(GAS)からメールを送信してみます。</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは<a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> で新しいGoogle Apps Scriptのプロジェクトを作成します。</p>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n\n<ul>\n  <li>新しいウィンドウでスクリプトエディタが開きます。</li>\n  <li>コード.gs に以下のコードを入力してください。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * テスト用関数\n */</span>\n <span class=\"kd\">function</span> <span class=\"nx\">myFunction</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">sendGmail</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">XXXX@gmail.com</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">TEST</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">テストだよ~ん</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n\n<span class=\"cm\">/**\n * Gmail送信処理\n *\n * @param {string|string[]} address    - 送信先アドレス\n * @param {string} subject  - サブジェクト(最大250文字)\n * @param {string} message  - 送信するメッセージ\n * \n * @note 送信先アドレスが間違っていてもここではエラーにならず、送信元アドレスにエラーメールが返る\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">sendGmail</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">,</span> <span class=\"nx\">subject</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n\n  <span class=\"c1\">// アドレスが配列だったらカンマ区切りの文字列に変換する</span>\n  <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nb\">Array</span><span class=\"p\">.</span><span class=\"nx\">isArray</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n    <span class=\"nx\">address</span> <span class=\"o\">=</span> <span class=\"nx\">address</span><span class=\"p\">.</span><span class=\"nx\">join</span><span class=\"p\">(</span><span class=\"dl\">'</span><span class=\"s1\">,</span><span class=\"dl\">'</span><span class=\"p\">);</span>\n  <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// そのまま</span>\n  <span class=\"p\">}</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">options</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"na\">name</span><span class=\"p\">:</span> <span class=\"dl\">\"</span><span class=\"s2\">てすと</span><span class=\"dl\">\"</span>        <span class=\"c1\">// 送信者名を指定したい場合は入れる</span>\n    <span class=\"c1\">// , replyTo: \"ZZZZ@gmail.com\"     // Reply-To を指定したい場合は入れる</span>\n  <span class=\"p\">};</span>\n\n  <span class=\"c1\">// メール送信</span>\n  <span class=\"nx\">GmailApp</span><span class=\"p\">.</span><span class=\"nx\">sendEmail</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">,</span> <span class=\"nx\">subject</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">,</span> <span class=\"nx\">options</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n</code></pre></div></div>\n\n<ul>\n  <li>「実行する関数」に<code class=\"language-plaintext highlighter-rouge\">myFunction</code>を選択(エディタの上、「実行ログ」の左の▼をクリックして選ぶ)</li>\n  <li>「実行」をクリック</li>\n  <li>送信先アドレスへメールが送信されます</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n送信元アドレスにはこのスクリプトを実行しているGoogleユーザ(デプロイ設定によってはそのとき実行しているGoogleユーザ)が使用されます。<br />\noptionsで「from」フィールドを指定する事が出来ますが、このアドレスは送信元アドレスのaliasである必要があります。<br />\nそうでない場合は例外 Invalid argument がthrowされます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n送信先アドレスが間違っていてもここではエラーになりません。<br />\n送信元アドレスにエラーメール(subject:「Delivery Status Notification (Failure)」)が送られてきます。</p>\n</blockquote>\n\n<h1 id=\"最後に\">最後に</h1>\n\n<p>関数化する必要もないくらい簡単ですが😅</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 20.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 20.04のインストール</h1>\n      <p>Ubuntu 20.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>VirtualBox へのインストール前提で書いてます。<br />\nでも、仮想マシンの作成以外は同じかな。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2004-インストール媒体の入手\">Ubuntu 20.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら:\n<a href=\"https://www.ubuntulinux.jp/products/JA-Localized/download\" target=\"_blank\">Ubuntu Desktop 日本語 Remixのダウンロード</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを2048MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<p>以下の説明が図付きで分かりやすい:\n<a href=\"https://qiita.com/HirMtsd/items/225c20b77a7cd5194834\" target=\"_blank\">Windows10上のVirtualBoxにUbuntu20.04をインストール</a></p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面ロック を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから「デバイス」→「クリップボードの共有」→「双方向」<br />\nを選択。\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h3 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h2>\n<blockquote>\n  <p>[!NOTE]\n前のバージョンまでは、WMをGnome Flashbackに変更してたけど、<br />\n日本語入力とかと相性悪いみたいなので、やめといた方が無難<br />\nインストールする場合はここを参考に: <a href=\"https://goto-linux.com/ja/2020/3/13/ubuntu-20.04-gnome-flashback%E3%83%86%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%95%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB/\" target=\"_blank\">Ubuntu 20.04 Gnome Flashbackデスクトップのインストール</a></p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-session-flashback\n</code></pre></div>  </div>\n  <p>「GNOME Flashback(Compiz)」はなくなったらしい</p>\n</blockquote>\n\n<h2 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h2>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nUbuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h2>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"bashの設定変更\">bashの設定変更</h2>\n\n<p>~/.bashrcに以下を追記</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h2 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h2 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h2 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nFlashbackの場合は以下らしい。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.gnome-flashback.desktop.icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.gnome-flashback.desktop.icons show-trash <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h2>\n<p>なんとなく使いにくいので好みのデザインに変更。<br />\ndconf-editorでも良いよ(しつこい…)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h2 id=\"日本語入力\">日本語入力</h2>\n<p>前は設定必要だったけど、なんか大丈夫になったみたい</p>\n<blockquote>\n  <p>[!NOTE]\n以前の設定手順<br />\n右上の「A」または「あ」と書かれたアイコンをクリック→「テキスト入力設定」を選択\n一番下の「インストールされている言語の管理」をクリック\n「言語サポートが完全にはインストールされていません」と出るので「インストール」をクリック\n一旦log offして再log in\n右上のJaまたはMoと書かれたアイコンをクリック\n    Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)\nキーボードの全角/半角キーで切り替えられるようになる</p>\n</blockquote>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h2 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h2>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h2 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h2>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a></p>\n\n<p>リブート必要だが、以下のIPv6無効化とまとめてリブートでも可。</p>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>grubメニューの更新</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hosts は書き換えられないので、手動で書き換える</p>\n</blockquote>\n\n<p>IPアドレスの変更(固定アドレスにしたい場合)</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<p>まとめて実行するならこちら。<br />\n接続名があってるかは確認しておくこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># マシン番号の設定とホスト名の設定</span>\n<span class=\"nv\">number</span><span class=\"o\">=</span>30\n<span class=\"nv\">new_hostname</span><span class=\"o\">=</span>skull<span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span>\n\n<span class=\"c\"># HOSTNAMEの変更</span>\n<span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/ubuntu-20.*</span><span class=\"nv\">$/</span><span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span><span class=\"s2\">/\"</span> /etc/hosts\n\n<span class=\"c\"># HOST ONLY ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n\n<span class=\"c\"># BRIDGE ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2 メモ</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2 メモ</h1>\n      <p>WSL2に関するメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <blockquote>\n  <p>[!NOTE]\n<strong><a href=\"https:///memoBlog/2024/07/24/WSL_memo2.html\" target=\"_blank\">改訂版</a>があります。</strong></p>\n</blockquote>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"wsl2のインストール\">WSL2のインストール</h2>\n<p>参考: <a href=\"https://itengine.seesaa.net/article/479688577.html\" target=\"_blank\">WSL2をインストールしてみた</a></p>\n\n<h2 id=\"virtualboxとの共存\">Virtualboxとの共存</h2>\n<p>参考: <a href=\"https://qiita.com/hibohiboo/items/c17459e0af84d2059d21\" target=\"_blank\">Vagrant + Virtualbox 6.1.16 と WSL2 を同時に動かしたメモ</a></p>\n\n<h1 id=\"セットアップ\">セットアップ</h1>\n\n<h2 id=\"アップデート\">アップデート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n</code></pre></div></div>\n\n<h2 id=\"日本語化\">日本語化</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 日本語ランゲージパック</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>language-pack-ja\n<span class=\"c\"># ロケールの設定</span>\n<span class=\"nb\">sudo </span>update-locale <span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF8\n<span class=\"c\"># 日本語manページのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>manpages-ja manpages-ja-dev\n</code></pre></div></div>\n\n<h2 id=\"beepを消す\">BEEPを消す</h2>\n<p>鬱陶しいのでBEEPを消しておく。<br />\n参考: <a href=\"https://linuxfan.info/bow-stop-beep\" target=\"_blank\">Bash on Windowsでビープ音を消す方法</a></p>\n\n<ul>\n  <li>ターミナルのbeepを消して画面フラッシュにする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"set bell-style visible\"</span> <span class=\"o\">>></span> ~/.inputrc\n</code></pre></div>    </div>\n  </li>\n  <li>vimのbeepを消す\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"set visualbell t_vb=\"</span> <span class=\"o\">>></span> ~/.vimrc\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalの場合、<code class=\"language-plaintext highlighter-rouge\">settings.json</code>に各プロファイルの設定に\n以下の設定を追加すればbash、vim、その他一括して変更できる。</p>\n  <div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\"> </span><span class=\"nl\">\"bellStyle\"</span><span class=\"w\"> </span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visual\"</span><span class=\"err\">,</span><span class=\"w\">\n</span></code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"デフォルトshをbashに変更\">デフォルトshをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"ツール類インストール\">ツール類インストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> /proj /work\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n<p>参考:<a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a></p>\n\n<h2 id=\"nodenvのインストール\">nodenvのインストール</h2>\n<p>参考:<a href=\"/memoBlog/2019/06/28/nodenv.html\" target=\"_blank\">nodenvのインストール</a></p>\n\n<h2 id=\"bashrcの設定\">.bashrcの設定</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\[\\e</span><span class=\"s2\">[36m</span><span class=\"se\">\\]</span><span class=\"nv\">$WSL_DISTRO_NAME</span><span class=\"se\">\\[\\e</span><span class=\"s2\">[0m</span><span class=\"se\">\\]</span><span class=\"s2\">:</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n        <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n        <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"nb\">export </span><span class=\"nv\">VIRTUAL_ENV_DISABLE_PROMPT</span><span class=\"o\">=</span>1\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h1 id=\"起動時の初期ディレクトリをホームディレクトリにするための設定\">起動時の初期ディレクトリをホームディレクトリにするための設定</h1>\n\n<p>起動時の初期ディレクトリがホームディレクトリにならないので(SSHの場合は大丈夫なはず)、以下の方法で指定する。</p>\n\n<h3 id=\"windows-terminalのsettingjsonでの設定\">Windows TerminalのSetting.jsonでの設定</h3>\n<p><a href=\"https://ryotatake.hatenablog.com/entry/2019/08/15/windows_terminal_wsl\" target=\"_blank\">Windows Terminal + WSLでターミナル起動時のディレクトリをホームディレクトリにする</a></p>\n\n<h3 id=\"wtexeのコマンドラインで指定する場合\">wt.exeのコマンドラインで指定する場合</h3>\n\n<p>settings.jsonで設定してない場合や設定とは別のディレクトリを指定する場合は-dオプションで指定する。<br />\nホームディレクトリを指定する場合は以下。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">C:\\Users\\</span><span class=\"err\"><<ユーザ名>></span><span class=\"nx\">\\AppData\\Local\\Microsoft\\WindowsApps\\wt.exe</span><span class=\"w\"> </span><span class=\"nt\">-p</span><span class=\"w\"> </span><span class=\"s2\">\"«環境登録名»\"</span><span class=\"w\"> </span><span class=\"nt\">-d</span><span class=\"w\"> </span><span class=\"s2\">\"\\\\wsl</span><span class=\"err\">$</span><span class=\"s2\">\\«仮想環境名»\\home\\<<ユーザ名>>\"</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ -p で指定するのは仮想環境名ではなく、WindowsTerminal に登録した環境名(ドロップダウンリストに表示される名前)。 -d で指定するのは仮想環境名。同一でない場合は間違えないように注意。</p>\n\n<h3 id=\"wsl-コマンドで起動する場合\">wsl コマンドで起動する場合</h3>\n\n<p>使用中のターミナルを使って起動する場合はwslコマンドで起動する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">c:\\WINDOWS\\system32\\wsl.exe</span><span class=\"w\"> </span><span class=\"nx\">~</span><span class=\"w\"> </span><span class=\"nt\">-d</span><span class=\"w\"> </span><span class=\"s2\">\"仮想環境名\"</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ wsl コマンドのパラメータに <code class=\"language-plaintext highlighter-rouge\">~</code> を追加</p>\n\n<h1 id=\"pathにwindowsのpathを引き継がせない設定\">PATHにWindowsのPATHを引き継がせない設定</h1>\n<p>仮想マシン起動語、PATHにWindows環境のPATHが引き継がれる。<br />\n便利な半面、コマンド名補完でサーチに行くと かなりの時間をくってしまい 不便。<br />\nWindowsのコマンドを仮想マシン上から起動することはあまりない(私の場合)ので、、<br />\nWindows環境のPATHを引き継がせないようにする。</p>\n\n<p>設定方法は <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に 以下の設定を追加する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>interop]\nappendWindowsPath <span class=\"o\">=</span> <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>参考: <a href=\"https://zenn.dev/o2z/articles/zenn-20210524-01\" target=\"_blank\">WSL2でWindowsのPATH設定が引き継がれるのを解除する</a></p>\n\n<h1 id=\"guiアプリを使用する\">GUIアプリを使用する</h1>\n<p>参考: <a href=\"https://qiita.com/vega77/items/f00323e8ce64bfa1fdd6\" target=\"_blank\">WSL2でGUIアプリを起動</a></p>\n\n<h1 id=\"wsl2上のサーバプログラムへのアクセス\">WSL2上のサーバプログラムへのアクセス</h1>\n<p>参考:<a href=\"https://www.atmarkit.co.jp/ait/articles/1909/09/news020.html\" target=\"_blank\">Linuxがほぼそのまま動くようになった「WSL2」のネットワーク機能</a></p>\n\n<table>\n  <thead>\n    <tr>\n      <th>向き</th>\n      <th>可否</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>HOST → WSL2</td>\n      <td>localhost でアクセスできる</td>\n    </tr>\n    <tr>\n      <td>WSL2 → HOST</td>\n      <td>localhost でアクセスできない。<br /> IPアドレス指定ならアクセスできる。</td>\n    </tr>\n  </tbody>\n</table>\n\n<h1 id=\"仮想マシンの複製\">仮想マシンの複製</h1>\n\n<h2 id=\"手順\">手順</h2>\n<p>仮想マシンは元になる仮想マシンをエクスポートして、別のディレクトリにインポートすれば複製できる。</p>\n\n<h3 id=\"仮想マシン一覧の確認\">仮想マシン一覧の確認</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>対象の仮想マシンが停止していることを確認。<br />\n停止してない場合はそれぞれのターミナルを終了するか、以下のコマンドで。<br />\nターミナルを終了してから実際に仮想マシンが停止するまで少し時間がかかる(数十秒くらい?)。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"err\">«対象の仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"エクスポート\">エクスポート</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--export</span><span class=\"w\"> </span><span class=\"err\">«エクスポート元仮想環境名»</span><span class=\"w\"> </span><span class=\"err\">«エクスポートファイル名»</span><span class=\"o\">.</span><span class=\"nf\">tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>例</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--export</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04</span><span class=\"w\"> </span><span class=\"nx\">F:\\WSL_VMs\\_Backup\\Ubuntu-20.04.tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"インポート\">インポート</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"err\">«新しい仮想環境名»</span><span class=\"w\"> </span><span class=\"err\">«インストール先ディレクトリ»</span><span class=\"w\"> </span><span class=\"err\">«エクスポートファイル名»</span><span class=\"o\">.</span><span class=\"nf\">tar</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ インストール先ディレクトリは自動で作成される</p>\n\n<p>例:</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04-1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">/Ubuntu-20.04-1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">\\_Backup\\Ubuntu-20.04.tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"削除\">削除</h3>\n<p>不要になった仮想環境は削除する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"err\">«削除する仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04-2</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"参考\">参考</h2>\n<ul>\n  <li>同一ディストリビューションの複製<br />\n<a href=\"https://qiita.com/souyakuchan/items/9f95043cf9c4eda2e1cc\" target=\"_blank\">WSL 上で同一ディストリビューションの環境を複数インストール・管理する</a></li>\n  <li>仮想環境をCドライブ以外に変更する<br />\n<a href=\"https://nosubject.io/windowsdocker-desktop-move-disk-image/\" target=\"_blank\">[Windows] Docker Desktop の ディスク領域 を Cドライブから別のドライブへ移動する方法</a></li>\n</ul>\n\n<h2 id=\"インポートした環境のデフォルトユーザを変更する\">インポートした環境のデフォルトユーザを変更する</h2>\n<p>インポートした環境では、デフォルトユーザがrootになっているため、自分に変更しておく。<br />\n方法は2つ。  <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>のほうがお手軽かな? エクスポート元で書いておけば逐一書かなくてもいいし。<br />\n両方設定した場合は<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>の設定が優先される(らしい)。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>で指定する方法。<br />\nインポートした環境を起動して、 <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>を以下の内容で作成\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>user]\n<span class=\"nv\">default</span><span class=\"o\">=</span>«デフォルトユーザ名» \n</code></pre></div>    </div>\n    <p>参考:<a href=\"https://github.com/Microsoft/WSL/issues/3974#issuecomment-576782860\" target=\"_blank\">github Microsoft/WSL/issues/3974</a>\n参考:<a href=\"https://roy-n-roy.github.io/Windows/WSL%EF%BC%86%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A/wslconfig/\" target=\"_blank\">wsl.conf と .wslconfig - roy-n-roy メモ</a></p>\n  </li>\n  <li>レジストリで設定する方法\n    <ul>\n      <li>Windowsでレジストリエディタを起動</li>\n      <li><strong><em>コンピューター\\HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Lxss</em></strong> 下の<br />\n各エントリで <strong><em>DistributionName</em></strong> が対象の名前になっているエントリを探す</li>\n      <li>そのエントリの<strong><em>DefaultUid</em></strong> を 対象のユーザIDに変更する。<br />\n対象のユーザIDはコピー元の<strong><em>DefaultUid</em></strong> に合わせれば良い。 あるいは、一旦ログインして/etc/passwd で調べる。 (大抵、1000( = 0x3e8 )のはず)</li>\n    </ul>\n  </li>\n</ul>\n\n<p>参考:<a href=\"https://roy-n-roy.github.io/Windows/WSL%EF%BC%86%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A/centos/#wsl\" target=\"_blank\">WSLでCentOS/Fedoraを利用する - roy-n-roy メモ</a></p>\n\n<h1 id=\"なんかのときに使うかも\">なんかのときに使うかも</h1>\n\n<p>試してないけど、メモっておく。</p>\n<ul>\n  <li>仮想ディスクが肥大化した場合の対処方法<br />\n<del><a href=\"https://qiita.com/386jp/items/e469333c5a74789db46d\" target=\"_blank\">WSL2を使っているパソコンのディスク容量が枯渇したときにやってみるべきこと</a></del><br />\nこっちの方が分かりやすかった。<br />\n<a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1271vhdexpcmd/vhdexpcmd.html\">仮想ディスクをコマンドラインから拡大/縮小する</a></li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>PS: XXXX> diskpart                                                 ← コマンド起動\n\nMicrosoft DiskPart バージョン 10.0.19041.964\n\nCopyright (C) Microsoft Corporation.\nコンピューター: XXXXXX\n\nDISKPART> select vdisk file=\"f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\" ← 圧縮したいvhdxファイル\n\nDiskPart により、仮想ディスク ファイルが選択されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   20 GB\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART> compact vdisk                                            ← 縮小の実行\n\n  100% 完了しました                       ← ちょっと時間がかかる\n\nDiskPart により、仮想ディスク ファイルは正常に圧縮されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   12 GB                      ← 小さくなった\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART>exit                                                      ← 終了\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu20.04 on WSL2 で openVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu20.04 on WSL2 で openVINO</h1>\n      <p>WSL2上のUbuntu20.04でopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"環境構築\">環境構築</h1>\n\n<p>WSL環境ではNCS2は使えないが、CPU演算での実行は可能。<br />\n以下インストール~デモ実行までのメモ。</p>\n\n<p>基本は以下を参考に。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></li>\n  <li><a href=\"/memoBlog/2020/10/18/openVINO_ubuntu_3.html\">openVINO フルパッケージ(2021.1)をインストール(追加)</a></li>\n</ul>\n\n<p>WSLのインストールメモはこちら:<a href=\"/memoBlog/2021/03/03/WSL_memo.html\">WSL2 メモ</a><br />\nUbuntuは20.04。<br />\n今回はopenVINO 2021.2を使用した。</p>\n\n<h2 id=\"pyenvの仮想環境を作成\">pyenvの仮想環境を作成</h2>\n<p>まずは、pythonの環境を準備。<br />\n以下ではpythonは3.7.10を使用。(3.8を使えばTensorflow2を使えるらしい(?))</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.10 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n\n<p>ubuntuのライブラリ類をインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev \n<span class=\"c\"># 他にもあるかもしれんけど、とりあえずこれだけ。</span>\n</code></pre></div></div>\n\n<p>WSLでは以下も必要(グラフィック系処理が入ってないので)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgtk-3-0\n</code></pre></div></div>\n<h2 id=\"ダウンロードしたopenvinoアーカイブの展開とインストール\">ダウンロードしたopenVINOアーカイブの展開とインストール</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/mnt/f/Download/</code>にダウンロードしたファイルがあるとして。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\n<span class=\"nb\">tar </span>xzvf /mnt/f/Download/l_openvino_toolkit_p_2021.2.185.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2021.2.185/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n<span class=\"c\"># なぜかXwindow設定しててもテキストベースになる...</span>\n<span class=\"c\"># てきとーに答えていく。</span>\n</code></pre></div></div>\n\n<p>スクリプト終了したら、以下に従い進めていく。<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html</a></p>\n\n<h2 id=\"後半のコマンド一覧と注意事項\">後半のコマンド一覧と注意事項</h2>\n\n<ul>\n  <li>環境変数の設定とpythonモジュールのインストール</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># このコマンド、~/.bashrcにも書いておくこと</span>\n<span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n\n<span class=\"c\"># このコマンド実行すると、pyenvでなくsystemのpipでモジュールがインストールされるので実行しない</span>\n<span class=\"c\"># しかも、systemのpip3が壊れる...すごい罠😡</span>\n<span class=\"c\"># cd /opt/intel/openvino_2021/deployment_tools/model_optimizer/install_prerequisites/</span>\n<span class=\"c\"># sudo -E ./install_prerequisites.sh </span>\n\n<span class=\"c\"># 代わりに以下を実行(上記スクリプトは結局これを実行しているだけなので)</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npython 3.7で実行すると、</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version >= \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われるけど、無視して良い。<br />\nこれはPython3.8未満か以上で異なるバージョンのTensorflowがインストールされるように設定されているため。<br />\nちなみに、python 3.8でやると</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version < \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nもし、<code class=\"language-plaintext highlighter-rouge\">install_prerequisites.sh</code>を実行してしまい、pip3が壊れてしまった場合は\n以下で復旧する(一旦アンインストールしてから再インストール)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove python3-pip \n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip \n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"デモ実行\">デモ実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino_2021/deployment_tools/demo\n<span class=\"nb\">sudo cp</span> /work/.python-version <span class=\"nb\">.</span>\n\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/demo1.log\n\n<span class=\"c\"># このデモはグラフィック表示可能環境で実行する必要がある。  </span>\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/dem2.log\n</code></pre></div></div>\n\n<h1 id=\"別の仮想環境を用意する場合\">別の仮想環境を用意する場合</h1>\n\n<p>別の仮想環境を用意するときは以下で新しい仮想環境下にモジュールをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2でX-serverへの表示</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2でX-serverへの表示</h1>\n      <p>WindowsTerminal上のWSL2コンソールからGUIプログラムを起動する場合の設定メモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>MobaXtermを使えば何もしなくてもGUIプログラムを表示できるけど、\nWindowsTerminalなどから表示したい場合に対応してみた。</p>\n\n<h1 id=\"windows側の設定\">Windows側の設定</h1>\n<p>VcXsrvをインストールして起動しておく。<br />\n参考:<a href=\"/memoBlog/2019/11/26/VcXsrv.html\" target=\"_blank\">WindowsでX-serve</a></p>\n\n<h1 id=\"linux側の設定\">Linux側の設定</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">.bashrc</code>に以下を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># HOSTのIPアドレス取得</span>\n<span class=\"c\"># export HOST_IP_ADDR=$(host `hostname`.mshome.net | sed -r 's/.*address (.*)$/\\1/')</span>\n<span class=\"c\"># HOSTのIPアドレス取得(アドレスが2つ以上返ってきたときは1個目だけ取り出す)</span>\n<span class=\"nb\">export </span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"o\">=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-n</span> 1p<span class=\"si\">)</span>\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"k\">}</span>:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n他の用途でホストのIPアドレス(名前でなく)を使いたいときのために別に変数作っておいた。<br />\n以下のように名前で書いて指定しても良い。<br />\nマシン名は<code class=\"language-plaintext highlighter-rouge\">hostname</code>コマンドで得られるので、別のマシンに移動しても変更の必要はない。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net:0.0\n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">.mshome.net</code>ドメインを指定するとホスト側のIPアドレスが得られるらしい。<br />\nドメインなしだと<code class=\"language-plaintext highlighter-rouge\">localhost</code>になっちゃうから注意。<br />\nぐぐると<code class=\"language-plaintext highlighter-rouge\">/etc/resolv.conf</code>を<code class=\"language-plaintext highlighter-rouge\">awk</code>でごちょごちょやるのが流行っているが<br />\n本来の設定値ではない(結果的に同じだけど)のでちゃんと設定しておくことにする。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nドメイン<code class=\"language-plaintext highlighter-rouge\">mshome.net</code>はHyper-Vのネットワークのドメインらしい。<br />\n要はWSL-Windows間の仮想ネットワークのドメイン名みたい。<br />\nちなみに、WSL2上から<code class=\"language-plaintext highlighter-rouge\">nslookup <<ホストのIPアドレス>></code>とやったら出てきた。</p>\n</blockquote>\n\n<h1 id=\"x-windowを使用するプログラムを起動\">X-Windowを使用するプログラムを起動</h1>\n<p>なんか起動してちょ。\nとりあえず<code class=\"language-plaintext highlighter-rouge\">xeyes</code>とか。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">xeyes</code> は <code class=\"language-plaintext highlighter-rouge\">sudo apt install x11-apps</code>でインストールできる。</p>\n\n<h1 id=\"wslからのgui表示が行えない場合の対処\">WSLからのGUI表示が行えない場合の対処</h1>\n\n<h2 id=\"原因\">原因</h2>\n<p>WSLのネットワークがパブリックネットワークになっており、<br />\nWSLネットワークからの接続要求がファイアウォールで はじかれている。</p>\n\n<h2 id=\"ファイアウォールの設定変更による回避\">ファイアウォールの設定変更による回避</h2>\n\n<p>VcXsrvをパブリックネットワークからの接続も受け付けるようにする \n以下手順。</p>\n\n<ul>\n  <li>コントロール パネル  →  Windows Defender ファイアウォール</li>\n  <li>左側上から2番目「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック</li>\n  <li>名前の欄から「VcXsrv windows xserver」を探す</li>\n  <li>その横のチェックボックスの「パブリック」側(右側)にもチェックを入れる(プライベート側は既にチェックが入っているはず。そっちはそのまま)。</li>\n  <li>OKボタンをクリックして終了</li>\n  <li>コントロールパネルは閉じてOK</li>\n</ul>\n\n<h2 id=\"ちなみに\">ちなみに</h2>\n\n<p>以下のような回避方法もある。</p>\n\n<h3 id=\"display変数を変更して回避\">DISPLAY変数を変更して回避</h3>\n<p>一旦WSLネットワークから外に出て接続すれば接続できる。<br />\n具体的には、DISPLAY変数をWSL側のIPアドレス(172.xxx.xxx.xxx)ではなく、<br />\nWi-Fiやイーサネットに割り当てられたアドレス(一般に 192.168.xxx.xxx)を指定する。<br />\n → WSL側から自動的にアドレスを取得できないのであまりおススメできない。<br />\n    VcXsrvがちゃんと動いているかを確認するには有効な手段かも。</p>\n\n<h3 id=\"根本的回避\">根本的回避</h3>\n<p><a href=\"https://daizo3.tumblr.com/post/150523393217/%E5%82%99%E5%BF%98%E9%8C%B2-%E5%85%88%E6%97%A5%E3%81%AE%E7%B6%9A%E3%81%8D-%E8%AD%98%E5%88%A5%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF-%E3%82%92%E3%83%97%E3%83%A9%E3%82%A4%E3%83%99%E3%83%BC%E3%83%88%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AB%E3%81%99%E3%82%8B\">備忘録 - (先日の続き) 識別されていないネットワーク をプライベートネットワークにする</a><br />\nによると、<br />\n<a href=\"https://www.atmarkit.co.jp/ait/articles/1012/24/news127.html\">Windowsで、「識別されていないネットワーク」の種類を「パブリック ネットワーク」から「プライベート ネットワーク」に変更する</a><br />\nの「レジストリによる設定」に記載された方法でも出来るらしいけど(こっちの方が根本的解決な気がする)、<br />\nレジストリ弄るのは気が引けるので、小手先対処にて。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PyPiからopenVINOをインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>PyPiからopenVINOをインストール</h1>\n      <p>PyPiで配布されているopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>openVINOを使いたいが、SDKをインストールするのは面倒というズボラさんのためのTips😅<br />\nNCS2を使うためのドライバをインストールするにはSDK必要だが(WSLだとそもそもNCS2は使えないけど)、CPUだけでさくっと使いたいときなんかは有効かな?<br />\nあと、SDKインストール済みだけど、別のバージョン試したいときとか。</p>\n\n<p>対象はWindwos(試してないけど)、Ubuntu(x86_64 の 18.04、20.04)。(macOSも対象らしいけど使ったことないのでよーわからん😅)<br />\nPython は3.6、3.7、3.8<br />\nRasoberryPiは現在のところ対象外。</p>\n\n<h1 id=\"pypiのページ\">PyPiのページ</h1>\n\n<p>PyPiは以下にページがある。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino/\" target=\"_blank\">openvino · PyPI</a></li>\n</ul>\n\n<p>ただし、現状はUbuntuでPython3.8を使用する場合は以下を使用(Ubuntu Python3.7は両方用意されているらしい)。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino-ubuntu20/\" target=\"_blank\">openvino-ubuntu20 · PyPI</a></li>\n</ul>\n\n<h1 id=\"pythonモジュールのインストール\">pythonモジュールのインストール</h1>\n<p>上記ページに記載された通りだが、大抵openCVも必要になるので、インストールしておく。 <br />\n最近はopenCVも<code class=\"language-plaintext highlighter-rouge\">pip</code>コマンドイッパツでインストールできるのでラクチン😊</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOのインストール</span>\npip <span class=\"nb\">install </span>openvino\n<span class=\"c\"># またはこちら</span>\n<span class=\"c\"># pip install openvino-ubuntu20</span>\n\n<span class=\"c\"># openCVのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<p>インストールすると、現状、以下のモジュールがインストールされる(ubuntuでpython3.7/3.8の場合)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>numpy==1.20.1\nopencv-python==4.5.1.48\nopenvino==2021.2\ntbb==2020.3.254\n</code></pre></div></div>\n\n<h1 id=\"実行前の準備\">実行前の準備</h1>\n\n<p>openVINOモジュールは<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>の設定が必要なので、\nシステムのpythonを使用するときは上記ページに記載された通りに<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>を設定する。<br />\nただし、pyenvを使用している場合は、以下のように設定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"k\">}</span>:<span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/versions/<span class=\"sb\">`</span>pyenv version-name<span class=\"sb\">`</span>/lib\n</code></pre></div></div>\n\n<p>pyenvで環境を切り替えることを考えると、<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>で設定するより、スクリプト実行ラッパで設定した方が無難かも。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Keras on tensorflow2 で SSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>Keras on tensorflow2 で SSD</h1>\n      <p>Tensorflow2上のKerasでSSDを実行を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>※ 2021.05.21 kerasをtensorflow.kerasに変更</p>\n\n<h1 id=\"概要\">概要</h1>\n\n<p>Kerasを使ってSSDを実行してみようと思ったら、Tensorflow1.x上の情報ばかり出てきて、Tensorflow2で実行するのに手間取ったのでメモ。<br />\n(最終的にopenVINOに持っていきたいなぁ、と思って試し始めたんだけど、openVINOにサクッと変換できるのはcaffeだった😅)<br />\nということで、やったけど 続きはないかも。実行遅いし…😩💨</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p><a href=\"https://smilerobo.com/papero/tips_keras_tf_ssd/\" target=\"_blank\">【実験】学習済のSSDを使ってPaPeRo i に複数種類の物体を数えさせる</a>\nを参考に、KerasをTensorflow2で動かしてみる。</p>\n\n<p>Pythonは3.8を使用した(念のため明記しておく)。</p>\n\n<p>Anaconda使ってないし、Paperoじゃないので、そのまんまじゃないけど、<br />\nとりあえずSSDを動かしてみよう。</p>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n\n<p>まずは、python仮想環境の準備をする。<br />\npyenv環境前提。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースディレクトリとpython仮想環境の準備</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/keras2/\n<span class=\"nb\">cd</span> /work/keras2/\npyenv virtualenv 3.8.8 keras2\npyenv <span class=\"nb\">local </span>keras2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># pythonモジュールのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n<span class=\"c\"># kerasはtensorflow内を直接参照にしたので不要  </span>\n<span class=\"c\"># pip install keras</span>\npip <span class=\"nb\">install </span>matplotlib\npip <span class=\"nb\">install </span>imageio\n</code></pre></div></div>\n\n<p>インストールされているpythonモジュールは以下の通り</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.2\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.4.0\ngoogle-auth==1.30.0\ngoogle-auth-oauthlib==0.4.4\ngoogle-pasta==0.2.0\ngrpcio==1.34.1\nh5py==3.1.0\nidna==2.10\nimageio==2.9.0\nkeras-nightly==2.5.0.dev2021032900\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.4.2\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.2.52\nopt-einsum==3.3.0\nPillow==8.2.0\nprotobuf==3.17.0\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nsix==1.15.0\ntensorboard==2.5.0\ntensorboard-data-server==0.6.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.5.0\ntensorflow-estimator==2.5.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==2.0.1\nwrapt==1.12.1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nKeras修正以前の状態は以下</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.1\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.3.3\ngoogle-auth==1.28.0\ngoogle-auth-oauthlib==0.4.3\ngoogle-pasta==0.2.0\ngrpcio==1.32.0\nh5py==2.10.0\nidna==2.10\nimageio==2.9.0\nKeras==2.4.3\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.3.4\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.1.48\nopt-einsum==3.3.0\nPillow==8.1.2\nprotobuf==3.15.6\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nPyYAML==5.4.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nscipy==1.6.1\nsix==1.15.0\ntensorboard==2.4.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.4.1\ntensorflow-estimator==2.4.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==1.0.1\nwrapt==1.12.1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"patchファイルの準備\">patchファイルの準備</h2>\n\n<p>参照先には色々手順が書いてあるが、めんどくさいので パッチファイル用意した(足りない修正もあるし)。<br />\n以下の内容を<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code> <code class=\"language-plaintext highlighter-rouge\">ssd_keras_2.patch</code>のファイル名で保存しておく。</p>\n\n<h3 id=\"ssd_keraspatch\">ssd_keras.patch</h3>\n\n<p>参照先の情報によるpatch</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/ssd.py b/ssd.py\nindex c0049d8..656cd83 100644\n</span><span class=\"gd\">--- a/ssd.py\n</span><span class=\"gi\">+++ b/ssd.py\n</span><span class=\"p\">@@ -2,14 +2,15 @@</span>\n \n import keras.backend as K\n from keras.layers import Activation\n<span class=\"gd\">-from keras.layers import AtrousConvolution2D\n</span><span class=\"gi\">+#from keras.layers import AtrousConvolution2D\n</span> from keras.layers import Convolution2D\n from keras.layers import Dense\n from keras.layers import Flatten\n from keras.layers import GlobalAveragePooling2D\n from keras.layers import Input\n from keras.layers import MaxPooling2D\n<span class=\"gd\">-from keras.layers import merge\n</span><span class=\"gi\">+#from keras.layers import merge\n+from keras.layers.merge import concatenate\n</span> from keras.layers import Reshape\n from keras.layers import ZeroPadding2D\n from keras.models import Model\n<span class=\"p\">@@ -34,109 +35,115 @@</span> def SSD300(input_shape, num_classes=21):\n     input_tensor = input_tensor = Input(shape=input_shape)\n     img_size = (input_shape[1], input_shape[0])\n     net['input'] = input_tensor\n<span class=\"gd\">-    net['conv1_1'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    net['conv1_1'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_1')(net['input'])\n<span class=\"gd\">-    net['conv1_2'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    \n+    net['conv1_2'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_2')(net['conv1_1'])\n<span class=\"gd\">-    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+\n+    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool1')(net['conv1_2'])\n     # Block 2\n<span class=\"gd\">-    net['conv2_1'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+    net['conv2_1'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_1')(net['pool1'])\n<span class=\"gd\">-    net['conv2_2'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+\n+    net['conv2_2'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_2')(net['conv2_1'])\n<span class=\"gd\">-    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool2')(net['conv2_2'])\n<span class=\"gi\">+\n</span>     # Block 3\n<span class=\"gd\">-    net['conv3_1'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_1'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_1')(net['pool2'])\n<span class=\"gd\">-    net['conv3_2'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_2'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_2')(net['conv3_1'])\n<span class=\"gd\">-    net['conv3_3'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_3'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_3')(net['conv3_2'])\n<span class=\"gd\">-    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool3')(net['conv3_3'])\n     # Block 4\n<span class=\"gd\">-    net['conv4_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_1')(net['pool3'])\n<span class=\"gd\">-    net['conv4_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_2')(net['conv4_1'])\n<span class=\"gd\">-    net['conv4_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_3')(net['conv4_2'])\n<span class=\"gd\">-    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool4')(net['conv4_3'])\n<span class=\"gd\">-    # Block 5\n-    net['conv5_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+# Block 5\n+    net['conv5_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_1')(net['pool4'])\n<span class=\"gd\">-    net['conv5_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_2')(net['conv5_1'])\n<span class=\"gd\">-    net['conv5_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_3')(net['conv5_2'])\n<span class=\"gd\">-    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), border_mode='same',\n</span><span class=\"gi\">+    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), padding='same',\n</span>                                 name='pool5')(net['conv5_3'])\n     # FC6\n<span class=\"gd\">-    net['fc6'] = AtrousConvolution2D(1024, 3, 3, atrous_rate=(6, 6),\n-                                     activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['fc6'] = Convolution2D(1024, (3, 3), dilation_rate=(6, 6),\n+                                     activation='relu', padding='same',\n</span>                                      name='fc6')(net['pool5'])\n     # x = Dropout(0.5, name='drop6')(x)\n     # FC7\n<span class=\"gd\">-    net['fc7'] = Convolution2D(1024, 1, 1, activation='relu',\n-                               border_mode='same', name='fc7')(net['fc6'])\n</span><span class=\"gi\">+    net['fc7'] = Convolution2D(1024, (1, 1), activation='relu',\n+                               padding='same', name='fc7')(net['fc6'])\n</span>     # x = Dropout(0.5, name='drop7')(x)\n     # Block 6\n<span class=\"gd\">-    net['conv6_1'] = Convolution2D(256, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv6_1'] = Convolution2D(256, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv6_1')(net['fc7'])\n<span class=\"gd\">-    net['conv6_2'] = Convolution2D(512, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+\n+\n+    net['conv6_2'] = Convolution2D(512, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv6_2')(net['conv6_1'])\n<span class=\"gd\">-    # Block 7\n-    net['conv7_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+        # Block 7\n+    net['conv7_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv7_1')(net['conv6_2'])\n     net['conv7_2'] = ZeroPadding2D()(net['conv7_1'])\n<span class=\"gd\">-    net['conv7_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='valid',\n</span><span class=\"gi\">+    net['conv7_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='valid',\n</span>                                    name='conv7_2')(net['conv7_2'])\n     # Block 8\n<span class=\"gd\">-    net['conv8_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv8_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv8_1')(net['conv7_2'])\n<span class=\"gd\">-    net['conv8_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['conv8_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv8_2')(net['conv8_1'])\n     # Last Pool\n     net['pool6'] = GlobalAveragePooling2D(name='pool6')(net['conv8_2'])\n     # Prediction from conv4_3\n     net['conv4_3_norm'] = Normalize(20, name='conv4_3_norm')(net['conv4_3'])\n     num_priors = 3\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv4_3_norm_mbox_loc')(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_loc'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_loc_flat')\n<span class=\"p\">@@ -144,7 +151,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv4_3_norm_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_conf'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_conf_flat')\n<span class=\"p\">@@ -155,16 +162,16 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv4_3_norm_mbox_priorbox'] = priorbox(net['conv4_3_norm'])\n     # Prediction from fc7\n     num_priors = 6\n<span class=\"gd\">-    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, 3, 3,\n-                                        border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, (3, 3),\n+                                        padding='same',\n</span>                                         name='fc7_mbox_loc')(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_loc_flat')\n     net['fc7_mbox_loc_flat'] = flatten(net['fc7_mbox_loc'])\n     name = 'fc7_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, 3, 3,\n-                                         border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, (3, 3),\n+                                         padding='same',\n</span>                                          name=name)(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_conf_flat')\n     net['fc7_mbox_conf_flat'] = flatten(net['fc7_mbox_conf'])\n<span class=\"p\">@@ -174,7 +181,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['fc7_mbox_priorbox'] = priorbox(net['fc7'])\n     # Prediction from conv6_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv6_2_mbox_loc')(net['conv6_2'])\n     net['conv6_2_mbox_loc'] = x\n     flatten = Flatten(name='conv6_2_mbox_loc_flat')\n<span class=\"p\">@@ -182,7 +189,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv6_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv6_2'])\n     net['conv6_2_mbox_conf'] = x\n     flatten = Flatten(name='conv6_2_mbox_conf_flat')\n<span class=\"p\">@@ -193,7 +200,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv6_2_mbox_priorbox'] = priorbox(net['conv6_2'])\n     # Prediction from conv7_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv7_2_mbox_loc')(net['conv7_2'])\n     net['conv7_2_mbox_loc'] = x\n     flatten = Flatten(name='conv7_2_mbox_loc_flat')\n<span class=\"p\">@@ -201,7 +208,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv7_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv7_2'])\n     net['conv7_2_mbox_conf'] = x\n     flatten = Flatten(name='conv7_2_mbox_conf_flat')\n<span class=\"p\">@@ -212,7 +219,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv7_2_mbox_priorbox'] = priorbox(net['conv7_2'])\n     # Prediction from conv8_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv8_2_mbox_loc')(net['conv8_2'])\n     net['conv8_2_mbox_loc'] = x\n     flatten = Flatten(name='conv8_2_mbox_loc_flat')\n<span class=\"p\">@@ -220,7 +227,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv8_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv8_2'])\n     net['conv8_2_mbox_conf'] = x\n     flatten = Flatten(name='conv8_2_mbox_conf_flat')\n<span class=\"p\">@@ -241,7 +248,7 @@</span> def SSD300(input_shape, num_classes=21):\n     priorbox = PriorBox(img_size, 276.0, max_size=330.0, aspect_ratios=[2, 3],\n                         variances=[0.1, 0.1, 0.2, 0.2],\n                         name='pool6_mbox_priorbox')\n<span class=\"gd\">-    if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+    if K.image_data_format() == 'channels_last':\n</span>         target_shape = (1, 1, 256)\n     else:\n         target_shape = (256, 1, 1)\n<span class=\"p\">@@ -249,42 +256,47 @@</span> def SSD300(input_shape, num_classes=21):\n                                     name='pool6_reshaped')(net['pool6'])\n     net['pool6_mbox_priorbox'] = priorbox(net['pool6_reshaped'])\n     # Gather all predictions\n<span class=\"gd\">-    net['mbox_loc'] = merge([net['conv4_3_norm_mbox_loc_flat'],\n</span><span class=\"gi\">+    net['mbox_loc'] = concatenate([net['conv4_3_norm_mbox_loc_flat'],\n</span>                              net['fc7_mbox_loc_flat'],\n                              net['conv6_2_mbox_loc_flat'],\n                              net['conv7_2_mbox_loc_flat'],\n                              net['conv8_2_mbox_loc_flat'],\n                              net['pool6_mbox_loc_flat']],\n<span class=\"gd\">-                            mode='concat', concat_axis=1, name='mbox_loc')\n-    net['mbox_conf'] = merge([net['conv4_3_norm_mbox_conf_flat'],\n</span><span class=\"gi\">+                            axis=1,\n+                                  name='mbox_loc')\n+    net['mbox_conf'] = concatenate([net['conv4_3_norm_mbox_conf_flat'],\n</span>                               net['fc7_mbox_conf_flat'],\n                               net['conv6_2_mbox_conf_flat'],\n                               net['conv7_2_mbox_conf_flat'],\n                               net['conv8_2_mbox_conf_flat'],\n                               net['pool6_mbox_conf_flat']],\n<span class=\"gd\">-                             mode='concat', concat_axis=1, name='mbox_conf')\n-    net['mbox_priorbox'] = merge([net['conv4_3_norm_mbox_priorbox'],\n</span><span class=\"gi\">+                              axis=1,\n+                              name='mbox_conf')\n+    net['mbox_priorbox'] = concatenate([net['conv4_3_norm_mbox_priorbox'],\n</span>                                   net['fc7_mbox_priorbox'],\n                                   net['conv6_2_mbox_priorbox'],\n                                   net['conv7_2_mbox_priorbox'],\n                                   net['conv8_2_mbox_priorbox'],\n                                   net['pool6_mbox_priorbox']],\n<span class=\"gd\">-                                 mode='concat', concat_axis=1,\n</span><span class=\"gi\">+                                 axis=1,\n</span>                                  name='mbox_priorbox')\n     if hasattr(net['mbox_loc'], '_keras_shape'):\n         num_boxes = net['mbox_loc']._keras_shape[-1] // 4\n     elif hasattr(net['mbox_loc'], 'int_shape'):\n<span class=\"gd\">-        num_boxes = K.int_shape(net['mbox_loc'])[-1] // 4\n</span><span class=\"gi\">+        num_boxes = net['mbox_loc'].int_shape()[-1] // 4\n+    elif hasattr(net['mbox_loc'], 'get_shape'):\n+        num_boxes = net['mbox_loc'].get_shape()[-1] // 4\n</span>     net['mbox_loc'] = Reshape((num_boxes, 4),\n                               name='mbox_loc_final')(net['mbox_loc'])\n     net['mbox_conf'] = Reshape((num_boxes, num_classes),\n                                name='mbox_conf_logits')(net['mbox_conf'])\n     net['mbox_conf'] = Activation('softmax',\n                                   name='mbox_conf_final')(net['mbox_conf'])\n<span class=\"gd\">-    net['predictions'] = merge([net['mbox_loc'],\n</span><span class=\"gi\">+    net['predictions'] = concatenate([net['mbox_loc'],\n</span>                                net['mbox_conf'],\n                                net['mbox_priorbox']],\n<span class=\"gd\">-                               mode='concat', concat_axis=2,\n</span><span class=\"gi\">+                               axis=2,\n+                               #axis = 0,\n</span>                                name='predictions')\n     model = Model(net['input'], net['predictions'])\n     return model\n<span class=\"gh\">diff --git a/ssd_layers.py b/ssd_layers.py\nindex 5e10478..41ee510 100644\n</span><span class=\"gd\">--- a/ssd_layers.py\n</span><span class=\"gi\">+++ b/ssd_layers.py\n</span><span class=\"p\">@@ -29,7 +29,8 @@</span> class Normalize(Layer):\n         Add possibility to have one scale for all features.\n     \"\"\"\n     def __init__(self, scale, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n+\n</span>             self.axis = 3\n         else:\n             self.axis = 1\n<span class=\"p\">@@ -41,7 +42,7 @@</span> class Normalize(Layer):\n         shape = (input_shape[self.axis],)\n         init_gamma = self.scale * np.ones(shape)\n         self.gamma = K.variable(init_gamma, name='{}_gamma'.format(self.name))\n<span class=\"gd\">-        self.trainable_weights = [self.gamma]\n</span><span class=\"gi\">+        self._trainable_weights = [self.gamma]\n</span> \n     def call(self, x, mask=None):\n         output = K.l2_normalize(x, self.axis)\n<span class=\"p\">@@ -81,7 +82,7 @@</span> class PriorBox(Layer):\n     \"\"\"\n     def __init__(self, img_size, min_size, max_size=None, aspect_ratios=None,\n                  flip=True, variances=[0.1], clip=True, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n</span>             self.waxis = 2\n             self.haxis = 1\n         else:\n<span class=\"p\">@@ -108,7 +109,7 @@</span> class PriorBox(Layer):\n         self.clip = True\n         super(PriorBox, self).__init__(**kwargs)\n \n<span class=\"gd\">-    def get_output_shape_for(self, input_shape):\n</span><span class=\"gi\">+    def compute_output_shape(self, input_shape):\n</span>         num_priors_ = len(self.aspect_ratios)\n         layer_width = input_shape[self.waxis]\n         layer_height = input_shape[self.haxis]\n<span class=\"gh\">diff --git a/ssd_utils.py b/ssd_utils.py\nindex 0a9ffb1..4fc7a49 100644\n</span><span class=\"gd\">--- a/ssd_utils.py\n</span><span class=\"gi\">+++ b/ssd_utils.py\n</span><span class=\"p\">@@ -1,7 +1,8 @@</span>\n \"\"\"Some utils for SSD.\"\"\"\n \n import numpy as np\n<span class=\"gd\">-import tensorflow as tf\n</span><span class=\"gi\">+import tensorflow.compat.v1 as tf\n+tf.disable_v2_behavior()\n</span> \n \n class BBoxUtility(object):\n<span class=\"gh\">diff --git a/testing_utils/videotest.py b/testing_utils/videotest.py\nindex 0cbae3c..7b2ff4f 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest.py\n</span><span class=\"p\">@@ -3,13 +3,14 @@</span>\n import cv2\n import keras\n from keras.applications.imagenet_utils import preprocess_input\n<span class=\"gd\">-from keras.backend.tensorflow_backend import set_session\n</span><span class=\"gi\">+# from keras.backend.tensorflow_backend import set_session\n</span> from keras.models import Model\n from keras.preprocessing import image \n import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-from scipy.misc import imread, imresize\n</span><span class=\"gi\">+# from scipy.misc import imread, imresize\n+from imageio import imread\n</span> from timeit import default_timer as timer\n \n import sys\n<span class=\"p\">@@ -84,8 +85,8 @@</span> class VideoTest(object):\n             \"trying to open a webcam, make sure you video_path is an integer!\"))\n         \n         # Compute aspect ratio of video     \n<span class=\"gd\">-        vidw = vid.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)\n-        vidh = vid.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)\n</span><span class=\"gi\">+        vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)\n+        vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)\n</span>         vidar = vidw/vidh\n         \n         # Skip frames until reaching start_frame\n<span class=\"gh\">diff --git a/testing_utils/videotest_example.py b/testing_utils/videotest_example.py\nindex fb4d873..27ec148 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest_example.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest_example.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import os\n+# GPU不使用を設定\n+os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n+\n</span> import keras\n import pickle\n from videotest import VideoTest\n<span class=\"p\">@@ -9,16 +13,38 @@</span> from ssd import SSD300 as SSD\n input_shape = (300,300,3)\n \n # Change this if you run with other classes than VOC\n<span class=\"gd\">-class_names = [\"background\", \"aeroplane\", \"bicycle\", \"bird\", \"boat\", \"bottle\", \"bus\", \"car\", \"cat\", \"chair\", \"cow\", \"diningtable\", \"dog\", \"horse\", \"motorbike\", \"person\", \"pottedplant\", \"sheep\", \"sofa\", \"train\", \"tvmonitor\"];\n</span><span class=\"gi\">+class_names = [ \n+                \"background\", \n+                \"aeroplane\", \n+                \"bicycle\", \n+                \"bird\", \n+                \"boat\", \n+                \"bottle\", \n+                \"bus\", \n+                \"car\", \n+                \"cat\", \n+                \"chair\", \n+                \"cow\", \n+                \"diningtable\", \n+                \"dog\", \n+                \"horse\", \n+                \"motorbike\", \n+                \"person\", \n+                \"pottedplant\", \n+                \"sheep\", \n+                \"sofa\", \n+                \"train\", \n+                \"tvmonitor\"\n+            ];\n</span> NUM_CLASSES = len(class_names)\n \n model = SSD(input_shape, num_classes=NUM_CLASSES)\n \n # Change this path if you want to use your own trained weights\n<span class=\"gd\">-model.load_weights('../weights_SSD300.hdf5') \n</span><span class=\"gi\">+model.load_weights('../../weights_SSD300.hdf5') \n</span>         \n vid_test = VideoTest(class_names, model, input_shape)\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('path/to/your/video.mkv')\n</span><span class=\"gi\">+vid_test.run('../../testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h3 id=\"ssd_keras_2patch\">ssd_keras_2.patch</h3>\n\n<p>keras修正対応</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras_2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd.py ssd_keras.tmp/ssd.py\n</span><span class=\"gd\">--- ssd_keras/ssd.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd.py\t2021-05-21 07:06:44.970000000 +0900\n</span><span class=\"p\">@@ -1,19 +1,17 @@</span>\n \"\"\"Keras implementation of SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.layers import Activation\n-#from keras.layers import AtrousConvolution2D\n-from keras.layers import Convolution2D\n-from keras.layers import Dense\n-from keras.layers import Flatten\n-from keras.layers import GlobalAveragePooling2D\n-from keras.layers import Input\n-from keras.layers import MaxPooling2D\n-#from keras.layers import merge\n-from keras.layers.merge import concatenate\n-from keras.layers import Reshape\n-from keras.layers import ZeroPadding2D\n-from keras.models import Model\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.keras.layers import Activation\n+from tensorflow.keras.layers import Convolution2D\n+from tensorflow.keras.layers import Dense\n+from tensorflow.keras.layers import Flatten\n+from tensorflow.keras.layers import GlobalAveragePooling2D\n+from tensorflow.keras.layers import Input\n+from tensorflow.keras.layers import MaxPooling2D\n+from tensorflow.keras.layers import concatenate\n+from tensorflow.keras.layers import Reshape\n+from tensorflow.keras.layers import ZeroPadding2D\n+from tensorflow.keras.models import Model\n</span> \n from ssd_layers import Normalize\n from ssd_layers import PriorBox\n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd_layers.py ssd_keras.tmp/ssd_layers.py\n</span><span class=\"gd\">--- ssd_keras/ssd_layers.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd_layers.py\t2021-05-21 06:31:11.780000000 +0900\n</span><span class=\"p\">@@ -1,8 +1,8 @@</span>\n \"\"\"Some special pupropse layers for SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.engine.topology import InputSpec\n-from keras.engine.topology import Layer\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.python.keras.engine.input_spec import InputSpec\n+from tensorflow.python.keras.engine.base_layer import Layer\n</span> import numpy as np\n import tensorflow as tf\n \n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest.py ssd_keras.tmp/testing_utils/videotest.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest.py\t2021-05-21 07:08:24.680000000 +0900\n</span><span class=\"p\">@@ -1,15 +1,13 @@</span>\n \"\"\" A class for testing a SSD model on a video file or webcam \"\"\"\n \n import cv2\n<span class=\"gd\">-import keras\n-from keras.applications.imagenet_utils import preprocess_input\n-# from keras.backend.tensorflow_backend import set_session\n-from keras.models import Model\n-from keras.preprocessing import image \n</span><span class=\"gi\">+import tensorflow.keras as keras\n+from tensorflow.keras.applications.imagenet_utils import preprocess_input\n+from tensorflow.keras.models import Model\n+from tensorflow.keras.preprocessing import image \n</span> import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-# from scipy.misc import imread, imresize\n</span> from imageio import imread\n from timeit import default_timer as timer\n \n<span class=\"p\">@@ -179,6 +177,7 @@</span>\n             cv2.putText(to_draw, fps, (3,10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0,0,0), 1)\n             \n             cv2.imshow(\"SSD result\", to_draw)\n<span class=\"gd\">-            cv2.waitKey(10)\n-            \n-        \n</span><span class=\"gi\">+            key = cv2.waitKey(1)\n+            if key == 27:\n+                # ESCキー\n+                break\n</span><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest_example.py ssd_keras.tmp/testing_utils/videotest_example.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest_example.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest_example.py\t2021-05-21 07:04:24.320000000 +0900\n</span><span class=\"p\">@@ -2,7 +2,7 @@</span>\n # GPU不使用を設定\n os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n \n<span class=\"gd\">-import keras\n</span><span class=\"gi\">+import tensorflow.keras as keras\n</span> import pickle\n from videotest import VideoTest\n \n<span class=\"p\">@@ -47,4 +47,4 @@</span>\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('../../testvideo3.mp4')\n</span><span class=\"gi\">+vid_test.run('../../images/testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h2 id=\"学習済み重みファイルのダウンロード\">学習済み重みファイルのダウンロード</h2>\n\n<p>参照先の記載にしたがって、重み学習済み重みファイルをダウンロードする。</p>\n\n<p>wgetでは取得できなかったので、ブラウザで↓ここ から weights_SSD300.hdf5 をダウンロード。<br />\n<a href=\"https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA\" target=\"_blank\">https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA</a><br />\nで、ZIPファイルをカレントディレクトリに解凍しておく。</p>\n\n<h2 id=\"ソースのダウンロードパッチをあてる\">ソースのダウンロード&パッチをあてる</h2>\n\n<p>githubからソースをダウンロードする。<br />\nこのままではエラーになるので、先ほど作成したパッチファイル<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code>でパッチをあてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/rykov8/ssd_keras.git\n<span class=\"nb\">cd </span>ssd_keras\npatch <span class=\"nt\">-p1</span> < ../ssd_keras.patch \n<span class=\"c\"># Keras修正対応パッチ</span>\npatch <span class=\"nt\">-p1</span> < ../ssd_keras_2.patch \n</code></pre></div></div>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>testing_utils/\npython videotest_example.py\n</code></pre></div></div>\n\n<p>おー。<br />\nしかし遅い…. <br />\nKerasは遅いみたい。。。orz…</p>\n\n<h1 id=\"こんなんもある\">こんなんもある</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50\" target=\"_blank\">「Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Visual Studio Code で Jupyter Notebook</title>\n  </head>\n  <body>\n    <header>\n      <h1>Visual Studio Code で Jupyter Notebook</h1>\n      <p>Visual Studio Code で Jupyter Notebookを実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Visual Studio CodeでJupyter Notebookを実行する。</p>\n\n<p>サンプルプログラムがJupyter Notebookだったりするとブラウザで動かすのめんどいので、Visual Studio Codeで動かしてみた。<br />\n参考:このあたりかな? <a href=\"https://codeaid.jp/vscode-jupyter/\" target=\"_blank\">Visual Studio CodeでJupyter Notebookを使う方法</a></p>\n\n<p>以下では、<a href=\"https://www.koi.mashykom.com/tensorflow.html\" target=\"_blank\">SSD と YOLO を用いた物体検出</a> の「Object Detection APIを用いた物体検出」を参考に進めてみる。</p>\n\n<h1 id=\"前準備\">前準備</h1>\n<p>作業ディレクトリとツール類のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Tensorflow\n<span class=\"nb\">cd</span> /work/Tensorflow\n\n<span class=\"c\"># pyenvの仮想環境作成と切り替え</span>\npyenv virtualenv 3.7.10 tensorflow\npyenv <span class=\"nb\">local </span>tensorflow\n<span class=\"c\"># お約束</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># Protocol buffers コンパイラのインストール(Jupyter Notebookの実行には関係ない)</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n\n<span class=\"c\"># Jupyter Notebook のモジュールインストール</span>\npip <span class=\"nb\">install </span>notebook\n</code></pre></div></div>\n\n<h1 id=\"modelsリポジトリのクローン\">modelsリポジトリのクローン</h1>\n<p>実行するプログラムの準備</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git\n</code></pre></div></div>\n\n<h1 id=\"visual-studio-codeの起動\">Visual Studio Codeの起動</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models/\ncode <span class=\"nb\">.</span>\n</code></pre></div></div>\n<p><strong>*** Visual Studio Code起動 ***</strong></p>\n\n<h1 id=\"visual-studio-codeでの作業\">Visual Studio Codeでの作業</h1>\n<p>以下、Visual Studio Codeで作業する</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>拡張機能から「Jupyter」と「Python」を選択し、対象マシンにインストール</p>\n\n<h2 id=\"使用するpythonを選択その1\">使用するpythonを選択その1</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n<ul>\n  <li>Python: インタプリター選択\n    <ul>\n      <li>これはどこで有効なんだろうか?念のため設定しておこう。</li>\n    </ul>\n  </li>\n  <li>Jupyter: Select interpreter to start jupyter server\n    <ul>\n      <li>たぶん、Jupyter Notebookそのものを実行するためのPython<br />\njupyter-notebookモジュールがインストールされている必要がある</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"対象ファイルをオープン\">対象ファイルをオープン</h2>\n<p>エクスプローラから<br />\n<code class=\"language-plaintext highlighter-rouge\">research/object_detection/colab_tutorials/object_detection_tutorial.ipynb</code>\nを開く<br />\n<code class=\"language-plaintext highlighter-rouge\">a notebook could execute harmful code when opened. ~</code>\nと言われるので、<code class=\"language-plaintext highlighter-rouge\">Trust</code> をクリック</p>\n\n<h2 id=\"使用するpythonを選択その2\">使用するpythonを選択その2</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する<br />\n(ipynbファイルを開かないと選べない)</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n\n<ul>\n  <li>Jupyter: Select a Kernel\n    <ul>\n      <li>たぶん、Notebook内のpythonスクリプトを実行するためのPython<br />\nシステムコマンド(!を行頭につけて指定)として実行したり、<code class=\"language-plaintext highlighter-rouge\">%%bash</code> で指定したCode cell で実行した<br />\npython スクリプト(pipコマンドなども含む)を実行した場合もこのバージョンが使用される</li>\n      <li>ipykernelモジュールをインストールしておく必要があるが、入ってなければVSCodeからインストールできるので気にしなくても大丈夫。<br />\n(Jupyter Notebook のモジュールがインストールされていれば同時にインストールされている)</li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nその1、その2で選択するバージョンはそれぞれ異なるバージョンを設定できるが、<br />\n上でpyenvで選択したバージョンで統一しておくのが混乱しなくて良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSelect a Kernel の設定内容は以下のファイルに保存されるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.vscode-server/data/User/globalStorage/ms-toolsai.jupyter/kernelSpecPaths.json</code><br />\nこの設定はシステム(ターゲットマシン)で1つのようなので、他のプロジェクトで設定を変更した場合は再度確認しておくのが良いと思う。</p>\n</blockquote>\n\n<h2 id=\"エラーになる部分の対策\">エラーになる部分の対策</h2>\n\n<h3 id=\"その1\">その1</h3>\n<p>「Get tensorflow/models or cd to parent directory of the repository.」\nの下のCode cellの最後に以下を追加</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n<span class=\"n\">cwd</span><span class=\"o\">=</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getcwd</span><span class=\"p\">()</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research/slim\"</span><span class=\"p\">)</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research\"</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"その2\">その2</h3>\n<p>以下のcellを削除(エラーになる)<br />\n(おそらく、その1で追加している処理に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>%%bash \ncd models/research\npip install .\n</code></pre></div></div>\n\n<h3 id=\"その3\">その3</h3>\n<p>「Instance Segmentation」以下はエラーになる(RCNNのモデル形状が変更された?)ので削除しておく。<br />\n(手順の本筋に関係ないので)</p>\n\n<h2 id=\"実行\">実行</h2>\n<p>最初のCode cell(Installの下)で▶(Run)をクリック<br />\nあとは、続くcellで▶(Run)をクリックしていく。</p>\n\n<p>または、ツールバーの⏩(Run all cells)をクリックする</p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<h2 id=\"ipynbファイルをpythonファイルにエクスポートする\">ipynbファイルをpythonファイルにエクスポートする。</h2>\n\n<p>Visual Studio Codeのエクスプローラペインで対象のipynbファイルを右クリックして<br />\n<code class=\"language-plaintext highlighter-rouge\">Convert a Notebook to Python Script</code>を選択すると、変換結果が新しいファイルとしてエディタに開かれる。<br />\nこれを名前を付けて保存する。</p>\n\n<p>または、コマンドラインから以下のコマンドを実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>jupyter nbconvert «対象ファイル».ipynb <span class=\"nt\">--to</span> python\n</code></pre></div></div>\n<p>デフォルトの出力ファイル名は«対象ファイル名».py(拡張子をipynb→pyに変えたもの)になる。</p>\n\n<p>ただし、単独で動かす場合は <code class=\"language-plaintext highlighter-rouge\">get_ipython()</code> で始まる行(システムコマンドを実行する部分)はエラーになるので、コメントアウトしておくこと。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tensorflowの転移学習に関するメモ</title>\n  </head>\n  <body>\n    <header>\n      <h1>tensorflowの転移学習に関するメモ</h1>\n      <p>tensorflowの転移学習を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"tensorflow-1xでのssdの転移学習の例\">tensorflow 1.XでのSSDの転移学習の例</h1>\n\n<p><a href=\"https://github.com/ippei8jp/tf1_TransferLearning\" target=\"_blank\">https://github.com/ippei8jp/tf1_TransferLearning</a></p>\n\n<h1 id=\"tensorflow-2xでのssdの転移学習の例\">tensorflow 2.XでのSSDの転移学習の例</h1>\n\n<p><a href=\"https://github.com/ippei8jp/tf2_TransferLearning\" target=\"_blank\">https://github.com/ippei8jp/tf2_TransferLearning</a></p>\n\n<h1 id=\"pascal-voc-で転移学習\">Pascal VOC で転移学習</h1>\n\n<p>ローカルマシン(Core-i7/Win10/WSL2/Ubuntu20.04/Tensorflow2.4)で試してみた手順が以下。<br />\nかなり時間がかかるけど、GPUなくても24時間もあればそれなりの回数がこなせる(5000回くらい?)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA  To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.</code> と言われているので、これらを有効にしてTensorflowを再構築すればもうちっと速くなるはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nずいぶん前にtensorflow 1.1.0でAVXを有効にしたら、MNISTの学習で実行時間が半分になった記憶もあるが、<br />\ntensorflow 1.6以降でAVXは有効になってて、AVX2,FMAの有無では10%くらいしか違わないらしい。<br />\n参考:<a href=\"https://www.acceluniverse.com/blog/developers/2019/05/tensorflowavx2-fma.html\" target=\"_blank\">TensorFlowのAVX2, FMAの有無で性能の比較をする</a><br />\ntensorflowのbuildに十何時間もかかることを考えたら 「ま、いっか」となっちゃうな…</p>\n</blockquote>\n\n<h2 id=\"実行手順\">実行手順</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">BASE_DIR</span><span class=\"o\">=</span>/work/test\n<span class=\"nv\">MODELS_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>/models\n<span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>/voc\n\n<span class=\"c\"># modelsリポジトリのclone</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>\ngit clone <span class=\"nt\">--depth</span> 1 https://github.com/tensorflow/models.git\n<span class=\"c\"># object_detectionモジュール未インストールならインストールすること</span>\n\n<span class=\"c\"># Pascal VOC データ取得</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>\nwget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar <span class=\"nt\">-O</span> - | <span class=\"nb\">tar </span>xvf -\n\n<span class=\"c\"># 学習データ(tf-record)の作成</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython create_pascal_tf_record.py <span class=\"nt\">--label_map_path</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"nt\">--data_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/VOCdevkit <span class=\"nt\">--year</span> VOC2007 <span class=\"nt\">--set</span> train <span class=\"nt\">--output_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pascal_train.record\npython create_pascal_tf_record.py <span class=\"nt\">--label_map_path</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"nt\">--data_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/VOCdevkit <span class=\"nt\">--year</span> VOC2007 <span class=\"nt\">--set</span> val <span class=\"nt\">--output_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pascal_val.record\n\n<span class=\"c\"># 元となるモデルのダウンロード</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/\nwget http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8.tar.gz <span class=\"nt\">-O</span> - | <span class=\"nb\">tar </span>xzvf -\n<span class=\"nb\">cp </span>ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/pipeline.config <span class=\"nb\">.</span>\n\n<span class=\"c\"># pipeline.config を編集(下記参照)</span>\n\n<span class=\"c\"># 学習実行</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython model_main_tf2.py <span class=\"nt\">--pipeline_config_path</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--model_dir</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--alsologtostderr</span>\n</code></pre></div></div>\n\n<h3 id=\"object_detectionモジュールのインストール方法\">object_detectionモジュールのインストール方法</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models/research\nprotoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n<span class=\"nb\">cp </span>object_detection/packages/tf2/setup.py <span class=\"nb\">.</span> \n<span class=\"c\"># ↑ tf1の場合はtf1ディレクトリを指定する</span>\n\npip <span class=\"nb\">install</span> <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"pipelineconfig-の修正例\">pipeline.config\tの修正例</h3>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/pipeline.config\t2020-07-11 09:16:11.000000000 +0900\n</span><span class=\"gi\">+++ pipeline.config\t2021-05-11 05:22:30.943865000 +0900\n</span><span class=\"p\">@@ -1,6 +1,6 @@</span>\n model {\n   ssd {\n<span class=\"gd\">-    num_classes: 90\n</span><span class=\"gi\">+    num_classes: 20\n</span>     image_resizer {\n       fixed_shape_resizer {\n         height: 320\n<span class=\"p\">@@ -132,7 +132,7 @@</span>\n   }\n }\n train_config {\n<span class=\"gd\">-  batch_size: 128\n</span><span class=\"gi\">+  batch_size: 64\n</span>   data_augmentation_options {\n     random_horizontal_flip {\n     }\n<span class=\"p\">@@ -162,19 +162,19 @@</span>\n     }\n     use_moving_average: false\n   }\n<span class=\"gd\">-  fine_tune_checkpoint: \"PATH_TO_BE_CONFIGURED\"\n-  num_steps: 50000\n</span><span class=\"gi\">+  fine_tune_checkpoint: \"/work/test/voc/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/checkpoint/ckpt-0\"\n+  num_steps: 2000\n</span>   startup_delay_steps: 0.0\n   replicas_to_aggregate: 8\n   max_number_of_boxes: 100\n   unpad_groundtruth_tensors: false\n<span class=\"gd\">-  fine_tune_checkpoint_type: \"classification\"\n</span><span class=\"gi\">+  fine_tune_checkpoint_type: \"detection\"\n</span>   fine_tune_checkpoint_version: V2\n }\n train_input_reader {\n<span class=\"gd\">-  label_map_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+  label_map_path: \"/work/test/models/research/object_detection/data/pascal_label_map.pbtxt\"\n</span>   tf_record_input_reader {\n<span class=\"gd\">-    input_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+    input_path: \"/work/test/voc/pascal_train.record\"\n</span>   }\n }\n eval_config {\n<span class=\"p\">@@ -182,10 +182,10 @@</span>\n   use_moving_averages: false\n }\n eval_input_reader {\n<span class=\"gd\">-  label_map_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+  label_map_path: \"/work/test/models/research/object_detection/data/pascal_label_map.pbtxt\"\n</span>   shuffle: false\n   num_epochs: 1\n   tf_record_input_reader {\n<span class=\"gd\">-    input_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+    input_path: \"/work/test/voc/pascal_val.record\"\n</span>   }\n }\n</code></pre></div></div>\n\n<h2 id=\"学習の中断\">学習の中断</h2>\n\n<p>学習処理を中断したい場合は、CTRL+cを入力する。<br />\nただし、中断した時点でのチェックポイントの保存は行われないので、それまでに保存されたチェックポイントが有効。<br />\nデフォルトではチェックポイントの保存は1000回毎なので、1000回未満で中断すると学習してないのと同じ(たぶん)。</p>\n\n<h2 id=\"追加学習学習の再開\">追加学習/学習の再開</h2>\n\n<p>中断した学習を再開したい場合や設定した学習回数では十分ではなかった場合の追加学習を行うには<br />\n<code class=\"language-plaintext highlighter-rouge\">model_main_tf2.py</code>を再度実行すればOK。<br />\nそれまで実行した学習結果の続きを実行してくれます。<br />\n(特に設定ファイル類を変更する必要はないみたい)</p>\n\n<p>追加学習の場合や学習回数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--num_train_steps</code>オプションで新しい学習回数を指定するか、\n<code class=\"language-plaintext highlighter-rouge\">pipeline.config</code>ファイル内の<code class=\"language-plaintext highlighter-rouge\">num_steps</code>の項目を変更します。</p>\n\n<p>また、デフォルトでは学習結果は1000回毎にセーブされるので、学習回数が1000回未満の場合や端数が出る場合、結果がセーブされません。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">--checkpoint_every_n</code>オプションで何回毎にセーブするかを指定する必要があります。</p>\n\n<p>以下に例を示します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python model_main_tf2.py <span class=\"nt\">--pipeline_config_path</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--model_dir</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--alsologtostderr</span> <span class=\"nt\">--checkpoint_every_n</span><span class=\"o\">=</span>100 <span class=\"nt\">--num_train_steps</span><span class=\"o\">=</span>2300\n</code></pre></div></div>\n<h2 id=\"モデルのエクスポート\">モデルのエクスポート</h2>\n\n<p>学習を行った結果をエクスポートしてsaved_modelを作成します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython exporter_main_v2.py <span class=\"nt\">--trained_checkpoint_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--pipeline_config_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--output_directory</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/inference_voc\n<span class=\"c\"># ラベルファイルもコピーしておく</span>\n<span class=\"nb\">cp</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/inference_voc/\n</code></pre></div></div>\n\n<h1 id=\"学習データtf-recordの確認方法\">学習データ(tf-record)の確認方法</h1>\n<h2 id=\"セットアップ\">セットアップ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tfrecord\n<span class=\"nb\">cd</span>  /work/tfrecord\n<span class=\"c\"># 仮想環境の準備</span>\npyenv virtualenv 3.8.9 tfrecord\npyenv <span class=\"nb\">local </span>tfrecord \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n<span class=\"c\"># 必要なモジュールのインストール</span>\npip <span class=\"nb\">install </span><span class=\"nv\">tensorflow</span><span class=\"o\">==</span>2.<span class=\"k\">*</span>\npip <span class=\"nb\">install </span>flask\npip <span class=\"nb\">install </span>pillow\npip <span class=\"nb\">install </span>tqdm\n</code></pre></div></div>\n\n<h2 id=\"リポジトリのclone\">リポジトリのclone</h2>\n\n<p>以下のリポジトリから</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/sulc/tfrecord-viewer.git\n<span class=\"nb\">cd </span>tfrecord-viewer/\n</code></pre></div></div>\n<h2 id=\"viewerの実行\">Viewerの実行</h2>\n\n<p>webサーバを起動する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfviewer.py «tf-recordファイル» \n</code></pre></div></div>\n\n<p>例:</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfviewer.py /work/test/train.record \n</code></pre></div></div>\n\n<p>ブラウザで以下に接続する(ポート番号は実行環境によって変わるかも)<br />\n<code class=\"language-plaintext highlighter-rouge\">http://localhost:5000/</code></p>\n\n<p>表示下部にサムネイルが表示されるので、クリックすると中央に拡大表示される。</p>\n\n<h2 id=\"元画像データの抽出\">元画像データの抽出</h2>\n\n<p>以下のパッチを当てる<br />\n(元のファイル名がディレクトリ名を含んでいるとファイル作成エラーになるので)</p>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tfrecord_to_imfolder.py b/tfrecord_to_imfolder.py\nindex 81bb764..7a0e269 100644\n</span><span class=\"gd\">--- a/tfrecord_to_imfolder.py\n</span><span class=\"gi\">+++ b/tfrecord_to_imfolder.py\n</span><span class=\"p\">@@ -41,6 +41,7 @@</span> def parse_tfrecord(record):\n     feat = example.features.feature\n\n     filename = feat[args.filename_key].bytes_list.value[0].decode(\"utf-8\")\n<span class=\"gi\">+    filename = os.path.basename(filename)\n</span>     img =  feat[args.image_key].bytes_list.value[0]\n     label = feat[args.class_label_key].bytes_list.value[0].decode(\"utf-8\")\n</code></pre></div></div>\n\n<p>以下のコマンドを実行<br />\n<code class=\"language-plaintext highlighter-rouge\">--class-label-key</code> には他にも指定できるものがあるけど、これくらいしか使わないと思う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfrecord_to_imfolder.py <span class=\"se\">\\</span>\n  <span class=\"nt\">--output_path</span> «ファイル出力ディレクトリ» <span class=\"se\">\\</span>\n  <span class=\"nt\">--class-label-key</span> image/object/class/text <span class=\"se\">\\</span>\n  <span class=\"nt\">-v</span> <span class=\"se\">\\</span>\n   «tf-recordファイル»\n</code></pre></div></div>\n\n<p>実行すると、«ファイル出力ディレクトリ»/«クラス名»/の下に画像ファイルが生成される。<br />\n(画像中に複数のクラスが含まれる場合は、一番最初のクラスが使用される)</p>\n\n<p>例:</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfrecord_to_imfolder.py <span class=\"se\">\\</span>\n  <span class=\"nt\">--output_path</span> ./hogehoge <span class=\"se\">\\</span>\n  <span class=\"nt\">--class-label-key</span> image/object/class/text <span class=\"se\">\\</span>\n  <span class=\"nt\">-v</span> <span class=\"se\">\\</span>\n  /work/test/train.record\n</code></pre></div></div>\n\n<h1 id=\"参考になるかもしれないページ\">参考になるかもしれないページ</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8c3197d11f61812546a9?fbclid=IwAR35TFl3mOK9XxXcZChP8wNkxp8cF6HZwnrWiTborZqETz7LJBZ88Dehvvs\">TensorFlowでの物体検出が超手軽にできる「Object Detection Tools」をTensorFlow 2.xに対応しました</a></p>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50?fbclid=IwAR35TFl3mOK9XxXcZChP8wNkxp8cF6HZwnrWiTborZqETz7LJBZ88Dehvvs\">Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>UbuntuをNative環境にインストールする(20.04)</title>\n  </head>\n  <body>\n    <header>\n      <h1>UbuntuをNative環境にインストールする(20.04)</h1>\n      <p>Ubunt(20.04)をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"インストール\">インストール</h1>\n<p>最初の起動まではこちらに詳しく書かれています。<br />\n<a href=\"https://qiita.com/koba-jon/items/019a3b4eac4f60ca89c9\" target=\"_blank\">Ubuntu 20.04 LTS インストール方法(外付けドライブ用)</a></p>\n\n<blockquote>\n  <p>[!WARNING]\nEFIシステムパーティションを作成するのを忘れがち。<br />\n外付けだと作成忘れると内蔵HDDのEFIシステムパーティションに追記されちゃうので注意。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\nユーザ名に英数字以外を含むとChrome remote desktop の インストール&設定でエラーになることがあるので、<br />\n英数字以外を含まないユーザ名を設定することをおススメします。</p>\n</blockquote>\n\n<h1 id=\"その後の設定手順\">その後の設定手順</h1>\n\n<h2 id=\"最新版にアップデート\">最新版にアップデート</h2>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h2 id=\"ipアドレス確認したいとき\">IPアドレス確認したいとき</h2>\n<p>SSHのクライアントからの接続先が分からないと困るので、\nIPアドレスを確認するためにnet-toolsをインストールして\nifconfigで確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\nifconfig\n</code></pre></div></div>\n\n<h2 id=\"sshのインストール\">sshのインストール</h2>\n<p>WindowsPCにあるデータをubuntuPCにキーボードで打ち込むのは効率が悪いので、最も簡単なsshでリモートログインできるようにしてみる。</p>\n\n<p>以下のコマンドでsshサーバをインストールし、サーバを開始する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n\n<p>クライアントからTeraTermなどでsshで対象マシンのポート22に接続する</p>\n\n<h2 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面ロック を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h2 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h2>\n\n<p>とりあえず入れとこう</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\n</code></pre></div></div>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが…</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h3 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>NFSサーバの再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.XX.XX:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"bashの設定変更\">bashの設定変更</h2>\n\n<p>~/.bashrcに以下を追記</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h2 id=\"guiの動作の設定変更をお好みで\">GUIの動作の設定変更をお好みで</h2>\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.mutter auto-maximize\ngsettings get org.gnome.mutter edge-tiling\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.desktop.wm.preferences auto-raise \ngsettings get org.gnome.desktop.wm.preferences focus-mode \ngsettings get org.gnome.desktop.wm.preferences raise-on-click\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.shell.extensions.desktop-icons show-home\ngsettings get org.gnome.shell.extensions.desktop-icons show-trash\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。<br />\ndconf-editorでも良いよ(しつこい…)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 ==================================</span>\n<span class=\"c\"># Dockバー上のゴミ箱表示有無</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock show-trash\n\n<span class=\"c\"># アプリケーションのDockバー上の表示位置</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock show-apps-at-top\n\n<span class=\"c\"># Dockバー表示位置</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock dock-position\n\n<span class=\"c\"># Dockバー上のアイコンサイズ</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock dash-max-icon-size\n\n<span class=\"c\"># 設定 ==================================</span>\n<span class=\"c\"># Dockバー上のゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># Dockバー上のアイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.interface cursor-size\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"capsキーをctrlキーに変更\">CAPSキーをCtrlキーに変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.input-sources xkb-options\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.input-sources xkb-options <span class=\"se\">\\[\\'</span>ctrl:nocaps<span class=\"se\">\\'\\]</span>\n\n<span class=\"c\"># 設定を有効にするにはGUIでのlogout&再loginが必要</span>\n\n</code></pre></div></div>\n\n<h2 id=\"日本語入力\">日本語入力</h2>\n<p>前は設定必要だったけど、なんか大丈夫になったみたい</p>\n<blockquote>\n  <p>[!NOTE]\n以前の設定手順<br />\n右上の「A」または「あ」と書かれたアイコンをクリック→「テキスト入力設定」を選択\n一番下の「インストールされている言語の管理」をクリック\n「言語サポートが完全にはインストールされていません」と出るので「インストール」をクリック\n一旦log offして再log in\n右上のJaまたはMoと書かれたアイコンをクリック\n    Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)\nキーボードの全角/半角キーで切り替えられるようになる</p>\n</blockquote>\n\n<h2 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h2>\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nUbuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>IPv6が動いてるとうまく行かない環境のときは無効化しておく。<br />\n参考:<a href=\"https://www.server-memo.net/ubuntu/ubuntu_disable_ipv6.html#IPv6-4\" target=\"_blank\">UbuntuでIPv6を無効化する方法</a></p>\n\n<p>sysctlで設定するのがお手軽かな?</p>\n\n<h2 id=\"システムバックアップ\">システムバックアップ</h2>\n<p>Nativeならバックアップしといた方がいいかな。<br />\n参考:<a href=\"https://gihyo.jp/admin/serial/01/ubuntu-recipe/0588\">第588回 TimeShiftでUbuntuをホットバックアップする 2019年版</a> <br />\n<code class=\"language-plaintext highlighter-rouge\">add-apt-repository</code> でリポジトリを追加しなくても大丈夫。標準リポジトリにも入ってるから。</p>\n\n<h2 id=\"chrome-remote-desktopインストール\">chrome remote desktopインストール</h2>\n\n<p>remote desktop使いたいので、インストールする。</p>\n\n<h3 id=\"chromeのインストール\">chromeのインストール</h3>\n<p><a href=\"https://www.google.com/chrome/\">Google Chrome - Google の高速で安全なブラウザをダウンロード</a>からダウンロードしてインストール。</p>\n\n<h3 id=\"おまじない\">おまじない</h3>\n<p>remote desktopのインストール時にエラーが発生するので、以下のディレクトリを作成しておく。<br />\n(インストーラのバグらしい)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/.config/chrome-remote-desktop\n</code></pre></div></div>\n\n<h3 id=\"remote-desktopのインストール\">remote desktopのインストール</h3>\n<p>以下参考ページ</p>\n<ul>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>パソコンでリモート アクセスを設定する</li>\n      <li>パソコンにリモート アクセスする</li>\n    </ul>\n  </li>\n</ul>\n\n<p>接続すると、開始するセッションの選択画面になるので、「Ubuntu」を選択。</p>\n\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。<br />\nこのダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></li>\n</ul>\n\n<p>要約すると\n<code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下の内容で作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(May 7th 2021)のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(May 7th 2021)のインストール</h1>\n      <p>Raspberry Pi OS(May 7th 2021)のインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>前にやった <a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\" target=\"_blank\">Raspbian Busterのインストール</a>\nからあまり違わないけど、微妙に違いもあるので、もう一度メモしておく。</p>\n\n<h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspberry Pi OS with desktop」 の 「Download」でダウンロードしてSDカードに書き込む。<br />\n(「・・・ and recommended software」 の方ではない)<br />\n以下の手順は、RaspberryPi4 model B で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の <code class=\"language-plaintext highlighter-rouge\">[pi4]</code>の行の前に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\nシリアルコンソールの送信改行コードは<code class=\"language-plaintext highlighter-rouge\">CR</code>にしておくこと。<br />\nそうしないと、ビミョーに悲しいことが起こる場合がある。</p>\n</blockquote>\n\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>の <code class=\"language-plaintext highlighter-rouge\">[pi4]</code>の行の前に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group</code>と<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>については使用するモニタに合わせる。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group=2</code>はモニタ種別でDMT(一般的にモニタディスプレイ)、<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_mode=82</code>が 1920x1080 60Hz(1080p)を示している。<br />\n設定値の内容については、<a href=\"https://www.raspberrypi.org/documentation/configuration/config-txt/video.md\" target=\"_blank\">Video options in config.txt</a>\nを参照。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>はテキストモードで表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nhdmi_group=2\nhdmi_mode=82\nframebuffer_width=1920\nframebuffer_height=1080\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nHDMIディスプレイを常に接続しているなら設定しなくても問題ないが、<br />\nHDMIディスプレイをはずしてVNCでリモート接続だけする場合は設定しておかないと<br />\n解像度が1024x768までしか設定できなくなるので注意。</p>\n</blockquote>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S7 Splash Screen\n            Would you like to show the splash screen at boot? \n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nこの操作で<code class=\"language-plaintext highlighter-rouge\">/boot/cmdline.txt</code>が書き換えられるらしい。</p>\n</blockquote>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\" target=\"_blank\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n            B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    3 Interfacing Options        \n        P3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>    \n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n<p>Windows側のクライアントは、<br />\n<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a> \nから VNC Viewerをダウンロード。<br />\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。<br />\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。<br />\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。<br />\n日本語化の手順はこちらを参考に。 <a href=\"http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。<br />\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"--enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マウスフォーカスの変更\">マウスフォーカスの変更</h1>\n\n<p>ウィンドウをクリックしないとフォーカスが移動しないのはイライラするので x-mouse相当の設定をする。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/xdg/openbox/lxde-pi-rc.xml</code>の以下の部分をnoからyesに変更。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><followMouse>yes</followMouse>\n</code></pre></div></div>\n\n<h1 id=\"ipv6の無効化\">IPv6の無効化</h1>\n<p>IPv6を無効化したい場合は以下を設定。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/sysctl.conf</code>に以下を追加する\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Disable IPv6\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\n</code></pre></div>    </div>\n  </li>\n  <li>以下を実行する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sysctl <span class=\"nt\">-p</span>\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian SDカードイメージファイルの作成(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian SDカードイメージファイルの作成(改訂版)</h1>\n      <p>Raspbian SDカードイメージファイルの縮小</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/07/17/raspios_20210507.html\" target=\"_blank\">Raspberry Pi OS(May 7th 2021)のインストール</a> \nでセットアップしたSDカードをバックアップしておけば逐一セットアップ作業を行わなくても環境を復元できます。</p>\n\n<p>ただ、そのままSDカードをイメージファイル化しただけでは復元するSDカードのサイズが微妙に小さい場合などは、復元できなくなってしまいます。<br />\nそこで、バックアップしtイメージファイル内のパーティションサイズを縮小し、イメージファイルを小さくして保存します。</p>\n\n<p>以前、<a href=\"/memoBlog/2019/09/15/sd_image.html\" target=\"_blank\">Raspbian SDカードイメージファイルの縮小</a>、\n<a href=\"/memoBlog/2020/10/25/Jetson_nano_backup.html\" target=\"_blank\">Jetson nano のSDカードをバックアップする</a>\nでも書いていますが、今回はSDカード上でパーティションを縮小する方法にしてみました。<br />\nこれだと、不要な部分のバックアップを行わなくて済むので、ディスク領域/時間敵に有利かと思います。</p>\n\n<p>Windowsでは出来ない操作があるので、Ubuntu PCが必要です。<br />\nWSLではたぶん出来ません。<br />\nVirtualboxだと出来そうな気がしますが、試していません。</p>\n\n<h1 id=\"事前準備\">事前準備</h1>\n<h2 id=\"raspberrypiの準備\">RaspberryPiの準備</h2>\n<p>コピーしたSDカードで初回Boot時にパーティションを拡張するためのスクリプト<code class=\"language-plaintext highlighter-rouge\">expand_partition.sh</code>を\n<a href=\"/memoBlog/misc/stock/diskimage_shrink.sh\" target=\"_blank\">ここ</a> \nから適当なディレクトリにダウンロードしておきます。<br />\n(SDカードのコピーからブートしたあとに実行するので、コピーからブートした環境でダウンロードしても良いですが、\nマスタにダウンロードしておけばコピーの度にダウンロードしなくて済むので。)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/first_boot_settings\n<span class=\"nb\">cd</span>  ~/first_boot_settings\nwget https://ippei8jp.github.io/memoBlog/misc/stock/expand_partition.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPiの場合は<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>でパーティション拡張できるので、このスクリプトはなくても良い。</p>\n</blockquote>\n\n<p>RaspberryPiの電源をOFFし、SDカードを取り外してubuntu PCに挿入しておきます。</p>\n\n<h1 id=\"ubuntu-pcでの操作\">Ubuntu PCでの操作</h1>\n\n<p>以下、SDカードは<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0</code>に割り当てられているものとします。</p>\n\n<blockquote>\n  <p>[!NOTE]\nSDカードが自動マウントされている場合はアンマウントしておいてください。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount /dev/mmcblk0p1\n<span class=\"nb\">sudo </span>umount /dev/mmcblk0p2\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"gpartedのインストール\">gpartedのインストール</h2>\n<p>パーティション操作を行うため、gpartedがインストールされていなければインストールしておきます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gparted\n</code></pre></div></div>\n\n<h2 id=\"gpartedによりパーティションを縮小\">gpartedによりパーティションを縮小</h2>\n<ul>\n  <li>goartedを起動</li>\n  <li>対象デバイスとして<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0</code>を選択。</li>\n  <li>配置図またはパーティション一覧で<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0p2</code>を右クリックし、「リサイズ/移動」を選択</li>\n  <li>ダイアログで「新しいサイズ」に縮小したサイズを設定。 ダイアログ左上に表示されている「最小サイズ」よりも少し多めに。<br />\n(後方の空き領域は自動計算されます)</li>\n  <li>メニューの「編集」→「保留中の全ての操作を適用する」を選択し、パーティションを縮小する</li>\n  <li>gpartedを終了</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\ngpartedによるパーティションの縮小はマウントしたままではできません。<br />\nしたがって、RaspberryPiでは作業できず、Ubuntu PCで行う必要があります。</p>\n</blockquote>\n\n<h2 id=\"データサイズを確認\">データサイズを確認</h2>\n<p>以下のコマンドを実行し、コピーすべきデータサイズを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>parted /dev/mmcblk0 unit MiB print\n</code></pre></div></div>\n<p>以下が実行結果例。<br />\nここで、パーティション2の終了位置をメモ(ここでは<code class=\"language-plaintext highlighter-rouge\">3760</code>)しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>モデル: SD SA16G <span class=\"o\">(</span>sd/mmc<span class=\"o\">)</span>\nディスク /dev/mmcblk0: 14772MiB\nセクタサイズ <span class=\"o\">(</span>論理/物理<span class=\"o\">)</span>: 512B/512B\nパーティションテーブル: msdos\nディスクフラグ: \n\n番号  開始     終了     サイズ   タイプ   ファイルシステム  フラグ\n 1    4.00MiB  260MiB   256MiB   primary  fat32             lba\n 2    260MiB   3760MiB  3500MiB  primary  ext4\n</code></pre></div></div>\n\n<h2 id=\"イメージファイルの作成\">イメージファイルの作成</h2>\n<p>以下のコマンドでSDカードのデータをイメージファイルに保存します。<br />\nここで、<code class=\"language-plaintext highlighter-rouge\">of=</code>で指定しているのが作成するイメージファイル名、<br />\n<code class=\"language-plaintext highlighter-rouge\">count=</code>は上で調べたパーティションの終了位置をしていします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>/dev/mmcblk0 <span class=\"nv\">of</span><span class=\"o\">=</span>hoge1.img <span class=\"nv\">bs</span><span class=\"o\">=</span>1M <span class=\"nv\">count</span><span class=\"o\">=</span>3760 <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div></div>\n\n<p>必要ならzip圧縮しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>zip hoge1.zip hoge1.img \n</code></pre></div></div>\n\n<h1 id=\"新しい環境での起動\">新しい環境での起動</h1>\n\n<h2 id=\"新しいsdカードにバックアップを復元\">新しいSDカードにバックアップを復元</h2>\n\n<p>上で作成したイメージファイルをSDカードに書き込み(WindowsでもUbuntuでもお好きにどうぞ)、</p>\n\n<h2 id=\"最初のブート\">最初のブート</h2>\n<p>RaspberryPiに挿入しBootします(特別な手順は特にありません)。</p>\n\n<h2 id=\"新しいsdカードのパーティションを拡張\">新しいSDカードのパーティションを拡張</h2>\n\n<p>Boot完了したらlog inしてパーティションサイズを変更するために\n以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash first_boot_settings/expand_partition.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nまたは、RaspberryPiにgpartedをインストールして、<br />\nパーティションを縮小したときと同様に最大サイズまでパーティションサイズを拡大しても良いです。<br />\nパーティションの拡大はマウントしたままでも可能。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPiの場合は<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>でパーティション拡張できる</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config --expand-rootfs  \n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">Please reboot</code>と言われたらrebootする。</p>\n</blockquote>\n\n<h2 id=\"その他\">その他</h2>\n<p>必要であれば、ホスト名など必要な変更を行います。</p>\n\n<h2 id=\"リブート\">リブート</h2>\n<p>リブートします。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をセットアップする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をセットアップする(Jetpack4.6)</h1>\n      <p>Jetson nano をセットアップする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Nvidiaの<a href=\"https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/\">Jetson nano</a>をセットアップしたときのメモ<br />\nJetpack4.4のときのメモは<a href=\"/memoBlog/2020/10/23/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする</a> にあります。</p>\n\n<h1 id=\"参照先\">参照先</h1>\n<ul>\n  <li><a href=\"https://monoist.atmarkit.co.jp/mn/articles/1905/30/news029.html\">「Jetson Nano」の電源を入れて立ち上げる</a>\n    <ul>\n      <li>わりと詳しく書いてある</li>\n    </ul>\n  </li>\n  <li><a href=\"https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit\">Getting Started With Jetson Nano Developer Kit </a>\n    <ul>\n      <li>本家</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"シリアルコンソールの使用\">シリアルコンソールの使用</h1>\n<p>シリアルコンソールが必要なら接続できる。<br />\n特に設定等は必要ない。  <br />\n接続端子は以下を参照</p>\n<ul>\n  <li><a href=\"https://www.jetsonhacks.com/2019/04/19/jetson-nano-serial-console/\">Jetson Nano – Serial Console</a>\nの 「Wiring」の下の「Jetson Nano B01」を参照。</li>\n</ul>\n\n<p>シリアルポートの設定は115200bps/8bit/none/1bit/none</p>\n\n<p>その他、コネクタ類の配置が分かりにくい場合は、\n<a href=\"https://developer.download.nvidia.com/assets/embedded/secure/jetson/Nano/docs/NV_Jetson_Nano_Developer_Kit_User_Guide.pdf?yIbsUqvBKxI1G6r3WW7cOdheZGv2-eSfaFW_kMt3dSgi0NJ7h77OwFHr5b-rquc3IX7Tyrt8FV6IKD4DHqvP4_LzhWt55tb071gqXlNGwBPYCOC5pnEKAla8D-B82bPjhQMykANFyn-EhxZRHC8AIBYWuVwwwXVPWtCOjs34Tg50oBdN0vBNoyUlZMRFXLNJ2to\">JETSON NANO DEVELOPER KIT</a>\nのP22 に<strong>Developer kit module and carrier board: rev B01 top view</strong>として配置図が掲載されているので参照のこと。</p>\n\n<h1 id=\"sdカードの作成firstboot\">SDカードの作成~FirstBoot</h1>\n<p>基本的に参照先の通り。<br />\n<a href=\"https://developer.nvidia.com/embedded/downloads\">https://developer.nvidia.com/embedded/downloads</a>\nから「Jetson Nano Developer Kit SD Card Image」  の Version 「4.6」 をダウンロード<br />\n(他のバージョンが必要ならそのバージョンで)</p>\n\n<p>ファーストブートで設定が終わったら、何はともあれ最新版にアップデート。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ここで一旦リブートしておく。</p>\n\n<h1 id=\"sshでの接続\">SSHでの接続</h1>\n<p>特に設定などは必要ない。<br />\nTeraTermなどで接続すれば良い。\nUbuntuではmDNSが動いているので、«マシン名».localでアクセスできる。</p>\n\n<p>TeraTerm使用時のコマンドは以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\"C:\\Program Files (x86)\\teraterm\\ttermpro.exe\" /auth=password /user=«ユーザ名» /passwd=«パスワード» «JetsonのIPアドレス or マシン名.local»\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nSSHやmDNSは立ち上がるまで少し時間がかかるみたいなので、<br />\n起動後数十秒程度待ってから接続した方が良い。</p>\n</blockquote>\n\n<h2 id=\"ssh接続がタイムアウトする対策\">SSH接続がタイムアウトする対策</h2>\n<p>SSH接続したターミナルを触らずにしばらく置いておくと、タイムアウトしてクローズされてしまう。\nこれを防ぐにはクライアント側からkeep-aliveパケットを定期的に送信してやれば良いらしい。</p>\n\n<p>Teratermの場合、「設定」→「SSH」→「ハートビート(keep-alive)」を「8」とかに設定し、保存。\n次回接続時はこの保存した設定ファイルを読み込む</p>\n\n<h1 id=\"初期設定\">初期設定</h1>\n<h2 id=\"bashrcの修正\">.bashrcの修正</h2>\n<p>.bashrcの修正をお好みで。<br />\n以下は設定例</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> resize <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># numpy 1.19.5 のimportでcore dumpする対策</span>\n<span class=\"nb\">export </span><span class=\"nv\">OPENBLAS_CORETYPE</span><span class=\"o\">=</span>ARMV8\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"c\"># export PYTHON_CONFIGURE_OPTS=\"--enable-ipv6\\</span>\n    <span class=\"c\">#     --enable-unicode=ucs4\\</span>\n    <span class=\"c\">#     --enable-shared\\</span>\n    <span class=\"c\">#     --with-dbmliborder=bdb:gdbm\\</span>\n    <span class=\"c\">#     --with-system-expat\\</span>\n    <span class=\"c\">#     --with-system-ffi\\</span>\n    <span class=\"c\">#     --with-fpectl\"</span>\n    <span class=\"c\"># Ubuntu向け対策</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vim\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># venvの仮想環境名を表示するための設定</span>\n    show_virtual_env<span class=\"o\">()</span> <span class=\"o\">{</span>\n      <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"s2\">)\"</span>\n      <span class=\"k\">fi</span>\n    <span class=\"o\">}</span>\n    <span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s1\">'$(show_virtual_env)'</span><span class=\"nv\">$PS1</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># DISPLAYが未定義なら設定する</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-z</span> <span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n    <span class=\"k\">fi\nfi</span>\n</code></pre></div></div>\n\n<h2 id=\"不要なソフトのアンインストール\">不要なソフトのアンインストール</h2>\n<p>使わないのでアンインストールしておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\n</code></pre></div></div>\n\n<h2 id=\"guiの動作の設定変更をお好みで\">GUIの動作の設定変更をお好みで</h2>\n<!--\n「ウィンドウが勝手に最大化するのをやめる」はOK\n「ウィンドウにマウスを乗せるとフォーカスされるようにする」で \"focus-mode\" は 'mouse' ではなく 'sloppy'\n「デスクトップからゴミ箱とホームを消す」は項目としてないらしい\n「Dockのカスタマイズ」は設定できるけど有効でない?\n「マウスカーソルを大きくする」は設定できるけど有効でない?リブートすると元に戻る?\nwindowの閉じるボタンなどを右に移動するにはgnome-tweaskでWindowsのTitlebar Buttons を設定する → 反映されず\n「CAPSキーをCtrlキーに変更」はOK\n-->\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.mutter auto-maximize\ngsettings get org.gnome.mutter edge-tiling\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.desktop.wm.preferences auto-raise \ngsettings get org.gnome.desktop.wm.preferences focus-mode \ngsettings get org.gnome.desktop.wm.preferences raise-on-click\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode sloppy\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"capsキーをctrlキーに変更\">CAPSキーをCtrlキーに変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.input-sources xkb-options\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.input-sources xkb-options <span class=\"se\">\\[\\'</span>ctrl:nocaps<span class=\"se\">\\'\\]</span>\n\n<span class=\"c\"># 設定を有効にするにはGUIでのlogout&再loginが必要</span>\n\n</code></pre></div></div>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>IPv6を無効化したい場合は、\n/<code class=\"language-plaintext highlighter-rouge\">boot/extlinux/extlinux.conf</code>の<code class=\"language-plaintext highlighter-rouge\">APPEND</code>の行の最後に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加してリブートする<br />\n参考: <a href=\"https://www.rough-and-cheap.jp/ubuntu/ubuntu18_04_howto_diseable_ipv6/\" target=\"_blank\">Ubuntu 18.04 で ipv6 を無効にする</a></p>\n<blockquote>\n  <p>[!NOTE]\ngrubではなく、U-Bootなので設定するところが違う</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSysctl の設定ではうまくいかなかった。</p>\n</blockquote>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work\n</code></pre></div></div>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<h3 id=\"インストール\">インストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<h3 id=\"設定ファイル\">設定ファイル</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<h3 id=\"ユーザの追加と再起動\">ユーザの追加と再起動</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"vncサーバvinoの設定\">VNCサーバ(vino)の設定</h2>\n<p>参考: <a href=\"https://zenn.dev/tunefs/articles/9774eb8f229e1bf97a8c\">https://zenn.dev/tunefs/articles/9774eb8f229e1bf97a8c</a>\n以下、参考先をベースに説明</p>\n\n<h3 id=\"vinoのインストール\">Vinoのインストール</h3>\n<p>インストール済みなので不要</p>\n\n<h3 id=\"vinoの自動起動の設定\">Vinoの自動起動の設定</h3>\n<p>コピー先ディレクトリは作成済み</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> /usr/share/applications/vino-server.desktop ~/.config/autostart/\n</code></pre></div></div>\n\n<h3 id=\"vinoのコンフィグレーション\">Vinoのコンフィグレーション</h3>\n<p>実行は以下のみでOK</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.Vino prompt-enabled <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false</span>\n</code></pre></div></div>\n<p>以下は不要</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>set org.gnome.Vino authentication-methods は \"['vnc']\" でなく \"['none']\"   デフォルトと同じなので不要\ngsettings set org.gnome.Vino vnc-password $(echo -n 'thepassword'|base64) は不要\n</code></pre></div></div>\n\n<h3 id=\"自動loginの設定\">自動loginの設定</h3>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定する</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h3 id=\"解像度の設定\">解像度の設定</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n\n<h3 id=\"リブートする\">リブートする</h3>\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続する。</p>\n\n<h3 id=\"設定メニューを表示できるようにする\">設定メニューを表示できるようにする</h3>\n<p>上記だけで設定は完了するが、設定メニュー(Settings)から設定しようとするとエラーになるので、\nそれを修正しておく(やらなくても設定メニュー使わなければ問題ない)。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml</code>に以下のパッチを当てる</li>\n</ul>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  /tmp/a.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- org.gnome.Vino.gschema.xml.org      2020-10-19 06:21:32.034728957 +0900\n</span><span class=\"gi\">+++ org.gnome.Vino.gschema.xml  2020-10-19 06:22:30.887994965 +0900\n</span><span class=\"p\">@@ -154,5 +154,14 @@</span>\n       </description>\n       <default>true</default>\n     </key>\n<span class=\"gi\">+    <key name='enabled' type='b'>\n+      <summary>Enable remote access to the desktop</summary>\n+        <description>\n+          If true, allows remote access to the desktop via the RFB\n+          protocol. Users on remote machines may then connect to the\n+          desktop using a VNC viewer.\n+        </description>\n+      <default>false</default>\n+    </key>\n</span>   </schema>\n </schemalist>\n</code></pre></div></div>\n\n<ul>\n  <li>パッチを当てるコマンド\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>patch /usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml /tmp/a.patch\n</code></pre></div>    </div>\n  </li>\n  <li>さらにコンパイルが必要\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>glib-compile-schemas /usr/share/glib-2.0/schemas\n</code></pre></div>    </div>\n  </li>\n  <li>これで「settings」から「Desktop Sharing」が実行できるようになる</li>\n</ul>\n\n<h2 id=\"使用率等の確認ツールのインストールと起動\">使用率等の確認ツールのインストールと起動</h2>\n\n<p>pyenvインストール済みのときは念のため<code class=\"language-plaintext highlighter-rouge\">pyenv shell system</code>しておく。<br />\nvenv環境使用時はデアクティベートしておく。<br />\n(sudo付きで実行してるのでsystemのpython3が使用されるハズだけど)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip\n<span class=\"nb\">sudo </span>pip3 <span class=\"nb\">install </span>jetson-stats\n<span class=\"nb\">sudo </span>jtop \n</code></pre></div></div>\n<p>一度再起動したあとは、<code class=\"language-plaintext highlighter-rouge\">sudo</code>なしの<code class=\"language-plaintext highlighter-rouge\">jtop</code>のみで実行可能。</p>\n<blockquote>\n  <p>[!NOTE]\njtopは結構CPUパワーを喰うので、性能評価等の間は止めておくのが無難と思われる。</p>\n</blockquote>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"sdカードのイメージファイル化\">SDカードのイメージファイル化</h1>\n<p><a href=\"/memoBlog/2021/07/18/sd_image_2.html\" target=\"_blank\">Raspbian SDカードイメージファイルの作成(改訂版)</a>を参照。</p>\n\n<h1 id=\"イメージのコピーからの起動\">イメージのコピーからの起動</h1>\n<h2 id=\"縮小されたパーティションを拡張する\">縮小されたパーティションを拡張する</h2>\n<p>バックアップはパーティションが縮小されているので、拡張する。<br />\n上記参照先の拡張方法ではうまくいかない(JetsonはパーティションがGPTだから?)。<br />\nなので、GUIツールのgpartedを使用して拡張する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gparted\n<span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0       <span class=\"c\"># sshから実行するときはXserverが起動しているマシンをDISPLAY変数に設定</span>\n<span class=\"nb\">sudo </span>gparted /dev/mmcblk0\n</code></pre></div></div>\n\n<ul>\n  <li>Libparted Warning ダイアログで”Not all of the space available to ~”と出たらFixをクリック</li>\n  <li>Libparted Warning ダイアログで”The backup GPT table is corrupt, but the primary appears OK, so that will be used.”と出たらOKをクリック</li>\n  <li>以降も何度か出るが、以下の操作がすべて終わればbackup GPTが新たに作成されるので問題なし。\n    <ul>\n      <li>(これは、ディスクイメージを縮小したときにgdiskコマンドを実行しなかった場合に出ます)</li>\n    </ul>\n  </li>\n  <li>図の«SDカードのパーティション» を右クリック→「Resize/Move」をクリック\n    <ul>\n      <li>「New size」の欄に上にある「Maximum size」以下の値を入力(「Free space following」 に残したいサイズを入れても可)</li>\n      <li>他の入力欄をクリックして自動計算を反映</li>\n      <li>「Resize」をクリック\n-「Edit」→「Apply All Operations」をクリック</li>\n      <li>「Are you sure you want to apply the pending operations?」と聞かれるので、「Apply」をクリック</li>\n    </ul>\n  </li>\n  <li>処理が完了したら閉じるボタンでプログラム終了</li>\n</ul>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"venvによるpython-仮想環境の構築\">venvによるpython 仮想環境の構築</h1>\n<p>いつもはpyenv + virtualenv で環境構築しているが、この環境ではプリインストールされた opencv を使用できないらしい(core dumpする)。<br />\nなので、system上のpythonを使用してvenvで仮想環境を構築して使用するようにしてみた。<br />\n(これ、↓のnumpyの問題かも。でもtensorflowはpython3.6でないとダメだから、pyenv引っ張ってこなくてもいいか。)</p>\n\n<h2 id=\"venvのインストール\">venvのインストール</h2>\n<p>venv使用のためのプログラムをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-venv\n</code></pre></div></div>\n\n<h2 id=\"仮想環境の構築\">仮想環境の構築</h2>\n<p>仮想環境を構築する。<br />\nここで実行したpythonが仮想環境で実行されるpythonになる。<br />\n<code class=\"language-plaintext highlighter-rouge\">--system-site-packages</code> を付加しておくと元のパッケージも参照される。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> «venv_dir»\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">pip list/freeze</code> でも参照される。pipのバージョンが新しければ、<code class=\"language-plaintext highlighter-rouge\">pip -v list</code>と オプション<code class=\"language-plaintext highlighter-rouge\">-v</code>を付けることで インストール先を見分けることでどちらにインストールされているかが判別できる。</p>\n\n<p>例えばこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/TF2.5\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート\">仮想環境のアクティベート</h2>\n<p>pyenvではlocalで指定してあればディレクトリ移動で自動的に仮想環境を切り替えられたが、<br />\nvenvでは逐一仮想環境をアクティベートしなければならない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> «venv_dir»/bin/bin/activate\n</code></pre></div></div>\n\n<h2 id=\"お約束\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"仮想環境の終了\">仮想環境の終了</h2>\n<p>仮想環境を終了するときは以下のコマンドでデアクティベートする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>deactivate\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">deactivate</code>はアクティベート時に関数として登録されている<br />\n下記のようにdirenvで設定した場合は<code class=\"language-plaintext highlighter-rouge\">deactivate</code>は使えないが、ディレクトリから移動すれば元にもどるので問題ない</p>\n</blockquote>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"direnvのインストールと設定\">direnvのインストールと設定</h1>\n<p>仮想環境管理をvenvで行うようにしたが、venvだと逐一activateしないといけないので、pyenvに慣れたカラダでは なかなか 使いにくい。<br />\nそこで、direnvを使ってpyenvに近い使い勝手を実現してみる。</p>\n\n<p>参考:<a href=\"https://yoshitaku-jp.hatenablog.com/entry/2018/07/29/070000\">direnvを使って、source bin/activateを自動化する</a></p>\n\n<h2 id=\"インストール-1\">インストール</h2>\n<p>インストールは<code class=\"language-plaintext highlighter-rouge\">apt</code>でイッパツ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>direnv\n</code></pre></div></div>\n\n<h2 id=\"初期設定-1\">初期設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code> に以下の内容を追記。(上記<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>例では記載済み)<br />\nエディタはvimに設定してあるが、別のものを使いたければ設定変更のこと。<br />\n(direnv 未インストール時は設定はスキップされる)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vim\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># venvの仮想環境名を表示するための設定</span>\n    show_virtual_env<span class=\"o\">()</span> <span class=\"o\">{</span>\n      <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"s2\">)\"</span>\n      <span class=\"k\">fi</span>\n    <span class=\"o\">}</span>\n    <span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s1\">'$(show_virtual_env)'</span><span class=\"nv\">$PS1</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">source ~/.bashrc</code> するか、terminalを開きなおす。</p>\n\n<h2 id=\"対象ディレクトリに処理を登録する\">対象ディレクトリに処理を登録する</h2>\n<p>対象ディレクトリに移動して<code class=\"language-plaintext highlighter-rouge\">direnv edit .</code> を実行して中身を作成するか、 <code class=\"language-plaintext highlighter-rouge\">.envrc</code>を直接生成する。</p>\n\n<p>中身は以下の通り<br />\n他にも設定したい環境変数があれば設定しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> «venv_dir»/bin/activate\n</code></pre></div></div>\n<p>例えばこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/TF2.5/bin/activate\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">direnv: error .envrc is blocked. Run `direnv allow` to approve its content.</code>と言われたら、以下のように実行する。<br />\n(直接編集した時に言われるらしい)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>direnv allow\n</code></pre></div></div>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"tensorflow2-のインストール\">tensorflow2 のインストール</h1>\n<h2 id=\"仮想環境の構築-1\">仮想環境の構築</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/TF2.5\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート-1\">仮想環境のアクティベート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/TF2.5/bin/activate\n</code></pre></div></div>\n<p>またはdirenvで上記が実行されるように設定しておく</p>\n\n<h2 id=\"お約束-1\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<p>tensorflowをimportしたとき(具体的にはその中でnumpyをimportしたとき)に\n<code class=\"language-plaintext highlighter-rouge\">Illegal instruction (core dumped)</code>が発生する。<br />\nこれを回避するため、以下を<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に設定しておく(上記<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>例では記載済み) 。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">OPENBLAS_CORETYPE</span><span class=\"o\">=</span>ARMV8\n</code></pre></div></div>\n\n<p>tensoorflowはpypiではなく、nvidiaのサイトからダウンロードしてインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>https://developer.download.nvidia.com/compute/redist/jp/v46/tensorflow/tensorflow-2.5.0+nv21.7-cp36-cp36m-linux_aarch64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nn5pyインストールでエラーになった時は以下の手順で回避する。  <br />\nミソはh5pyのインストール時点でnumpy 1.19.5がインストールされているとエラーになるので、<br />\n一時的にnumpyのそれ以前のバージョンをインストールしてh5pyをインストールし、その後numpyを本来のバージョンに戻す。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libhdf5-serial-dev hdf5-tools libhdf5-dev\npip <span class=\"nb\">install </span>cython\n<span class=\"c\"># numpyのバージョン下げる  </span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">numpy</span><span class=\"o\">==</span>1.19.3\npip <span class=\"nb\">install </span><span class=\"nv\">h5py</span><span class=\"o\">==</span>2.10.0\n<span class=\"c\"># h5pyのインストールのためにインストールしたnumpyを本来のバージョンに更新  </span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">numpy</span><span class=\"o\">==</span>1.19.5\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"tensorflowなどのありか\">Tensorflowなどのありか</h2>\n<p>以下に色々まとめられている。<br />\n<a href=\"https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime\">https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime</a></p>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"onnx-runtimeのインストール\">onnx-runtimeのインストール</h1>\n<h2 id=\"仮想環境の構築-2\">仮想環境の構築</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/onnx\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート-2\">仮想環境のアクティベート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/onnx/bin/activate\n</code></pre></div></div>\n<p>またはdirenvで上記が実行されるように設定しておく</p>\n\n<h2 id=\"お約束-2\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"インストールファイルのダウンロード\">インストールファイルのダウンロード</h2>\n<p><a href=\"https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime\" target=\"_blank\">Jetson Zoo</a>\nから使用環境に対応するインストールファイルをダウンロードする。<br />\n表の下にあるコマンド例の<code class=\"language-plaintext highlighter-rouge\">wget</code>ではうまくダウンロードできないのでブラウザでダウンロードしてコピっておく。<br />\n以下、onnxruntime 1.8.0/Python 3.6 を選択したものとする。</p>\n\n<h2 id=\"インストール-2\">インストール</h2>\n\n<p>システムにインストールされたprotobufのバージョンが古くてエラーになるので、\nあらかじめ最新版にアップデートしておく。<br />\n(venv環境なので、システムのprotobufには影響ない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> protobuf\n</code></pre></div></div>\n\n<p>ダウンロードしたonnx-runtimeをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>onnxruntime_gpu-1.8.0-cp36-cp36m-linux_aarch64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</h1>\n      <p>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/09/13/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする(Jetpack4.6)</a>\nではVNCにvinoをインストールしましたが、vinoはキー入力/画面描画のレスポンスがかなり遅く、\n結構なストレスになります。<br />\nそこで、代わりに<a href=\"https://tigervnc.org/\">tigerVNC</a>をインストールしてみます。</p>\n\n<p>最初に結論を書いておきますが、レスポンスはvinoより良くなるのですが、クリップボードの共有\n(ホスト/ターゲット間でのコピペ)ができないので、普段使いにはあまり使い勝手が良くありません。<br />\ngithubのリポジトリもずいぶん前から更新されていないみたいなので、今後改善される可能性も低そうです。<br />\nなので、私は使っていません(^^ゞ</p>\n\n<h1 id=\"前準備\">前準備</h1>\n<p>vinoをセットアップしてある場合は停止しておいてください。<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.config/autostart/vino-server.desktop</code> を削除しておけば大丈夫でしょう。<br />\n以下、vinoのセットアップは行っていないものとして記載します。</p>\n\n<h1 id=\"tigervncの設定\">tigerVNCの設定</h1>\n\n<h2 id=\"tiger-vnc-のインストール\">tiger VNC のインストール</h2>\n<p>必要なプログラムをインストールします</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tigervnc-standalone-server tigervnc-scraping-server\n</code></pre></div></div>\n\n<h2 id=\"vncのパスワードの設定\">VNCのパスワードの設定</h2>\n<p>接続パスワードを設定します</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vncpasswd\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">Password:</code>と<code class=\"language-plaintext highlighter-rouge\">Verify:</code>で設定するパスワードを入力<br />\n<code class=\"language-plaintext highlighter-rouge\">Would you like to enter a view-only password (y/n)?</code>には <code class=\"language-plaintext highlighter-rouge\">n</code>を入力<br />\nVNCクライアントから接続する際にこのパスワードを入力します</p>\n\n<h2 id=\"自動loginの設定\">自動loginの設定</h2>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定します</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h2 id=\"解像度の設定\">解像度の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n<h2 id=\"ここで一旦リブートする\">ここで一旦リブートする</h2>\n<p>リブートしないと下の単体テストで「displayがopenできない」とエラーになる模様。</p>\n\n<h2 id=\"手動で動かしてみる画面のミラーリング\">手動で動かしてみる(画面のミラーリング)</h2>\n\n<p>動作確認として、サーバを手動で起動してみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>x0vncserver <span class=\"nt\">-display</span> :0 <span class=\"nt\">-passwordfile</span> ~/.vnc/passwd\n</code></pre></div></div>\n\n<p>サーバが起動したら、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続します。</p>\n\n<p>正常に設定できていればVNCクライアントにデスクトップが表示されます。</p>\n\n<h2 id=\"自動起動の設定\">自動起動の設定</h2>\n<p>逐一<code class=\"language-plaintext highlighter-rouge\">x0vncserver</code>を起動するのは面倒なので、自動で起動するように設定しておきます。</p>\n\n<p>参考: <a href=\"https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f\">https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/systemd/system/x0vncserver.service</code> を以下の内容で作成します。<br />\nただし、<code class=\"language-plaintext highlighter-rouge\">XXXXXXXX</code>の部分は 自分のユーザ名に置き換えてください。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Remote desktop service (VNC)\nAfter=syslog.target\nAfter=network.target remote-fs.target nss-lookup.target\nAfter=x11-common.service \n\n[Service]\nType=forking\nUser=XXXXXXXX\nGroup=XXXXXXXX\nWorkingDirectory=/home/XXXXXXXX\nExecStart=/bin/sh -c 'sleep 10 && /usr/bin/x0vncserver -display :0  -rfbport 5900 -passwordfile /home/XXXXXXXX/.vnc/passwd &'\n\n[Install]\nWantedBy=multi-user.target\n</code></pre></div></div>\n\n<h2 id=\"サービスの起動と確認\">サービスの起動と確認</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl start x0vncserver\n<span class=\"nb\">sudo </span>systemctl status x0vncserver\n</code></pre></div></div>\n\n<p>以下のように出力されることを確認します</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>● x0vncserver.service - Remote desktop service (VNC)\n   Loaded: loaded (/etc/systemd/system/x0vncserver.service; enabled; vendor pres\n   Active: active (running) since Fri 2021-09-03 11:08:07 JST; 8s ago\n  Process: 14646 ExecStart=/bin/sh -c sleep 10 && /usr/bin/x0vncserver -display ・・・・\n Main PID: 14659 (sh)\n    Tasks: 2 (limit: 4172)\n   CGroup: /system.slice/x0vncserver.service\n           ├─14659 /bin/sh -c sleep 10 && /usr/bin/x0vncserver -display :0  ・・・・\n           └─14666 sleep 10\n\n 9月 03 11:08:07 jetson systemd[1]: Starting Remote desktop service (VNC)...\n 9月 03 11:08:07 jetson systemd[1]: Started Remote desktop service (VNC).\n</code></pre></div></div>\n\n<h2 id=\"サービスの有効化\">サービスの有効化</h2>\n<p>起動時に自動実行されるように、サービスの有効化を行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl <span class=\"nb\">enable </span>x0vncserver\n</code></pre></div></div>\n\n<h2 id=\"リブート\">リブート</h2>\n\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続します。</p>\n\n<p>正常に起動できていればVNCクライアントにデスクトップが表示されます。</p>\n\n<h1 id=\"別のやり方参考\">別のやり方(参考)</h1>\n<p>ディスプレイとは別のデスクトップを表示する場合は以下の手順で。<br />\nここではwindow managerにlxdeを使用していますので、モニタ表示とは異なる見た目になりますし、\nウィンドウマネージャの設定も同じではありません。</p>\n\n<p>参考:<a href=\"https://forums.developer.nvidia.com/t/how-to-setup-tigervnc-on-jetson-nano/174244\">https://forums.developer.nvidia.com/t/how-to-setup-tigervnc-on-jetson-nano/174244</a></p>\n\n<p>一回試しただけ(ちゃんとメモってなかった)なので、抜けとかあるかも。</p>\n\n<h2 id=\"tiger-vnc-のインストール-1\">Tiger VNC のインストール</h2>\n<p>必要なプログラムをインストールします</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tigervnc-standalone-server\n</code></pre></div></div>\n\n<h2 id=\"vncのパスワードの設定-1\">VNCのパスワードの設定</h2>\n<p>接続パスワードを設定します</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vncpasswd\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">Password:</code>と<code class=\"language-plaintext highlighter-rouge\">Verify:</code>で設定するパスワードを入力<br />\n<code class=\"language-plaintext highlighter-rouge\">Would you like to enter a view-only password (y/n)?</code>には <code class=\"language-plaintext highlighter-rouge\">n</code>を入力<br />\nVNCクライアントから接続する際にこのパスワードを入力します</p>\n\n<h2 id=\"自動loginの設定-1\">自動loginの設定</h2>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定します</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h2 id=\"解像度の設定-1\">解像度の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n\n<h2 id=\"vncxstartup-の作成\">~/.vnc/xstartup の作成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.vnc/xstartup</code> を以下の内容で作成します<br />\nXXXXXXXX は 自分のユーザ名に置き換えてください</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">!</span>/bin/sh\n<span class=\"nb\">export </span><span class=\"nv\">XDG_RUNTIME_DIR</span><span class=\"o\">=</span>/run/user/1000\n<span class=\"nb\">export </span><span class=\"nv\">XKL_XMODMAP_DISABLE</span><span class=\"o\">=</span>1\n<span class=\"nb\">unset </span>SESSION_MANAGER\n<span class=\"nb\">unset </span>DBUS_SESSION_BUS_ADDRESS\nxrdb /home/XXXXXXXX/.Xresources\nxsetroot <span class=\"nt\">-solid</span> grey\ngnome-session &\nstartlxde &\n</code></pre></div></div>\n\n<p>実行属性を付けます</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod </span>755 ~/.vnc/xstartup\n</code></pre></div></div>\n\n<h2 id=\"xresources-ファイルの作成\">.Xresources ファイルの作成</h2>\n<p>.Xresources ファイルを作成します</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">touch</span> ~/.Xresources\n</code></pre></div></div>\n\n<h2 id=\"vncの自動起動の設定\">VNCの自動起動の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/systemd/system/vncserver@.service</code>を以下の内容で作成します<br />\nXXXXXXXX は 自分のユーザ名に置き換えてください</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Start TigerVNC Server at startup\nAfter=syslog.target network.target\n\n[Service]\nType=forking\nUser=XXXXXXXX\nGroup=XXXXXXXX\nWorkingDirectory=/home/XXXXXXXX\nPIDFile=/home/XXXXXXXX/.vnc/%H:%i.pid\nExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1\nExecStart=/usr/bin/vncserver :%i -depth 24 -geometry 1920x1080 -nolisten tcp\n\nExecStop=/usr/bin/vncserver -kill :%i\n\n[Install]\nWantedBy=multi-user.target\n</code></pre></div></div>\n\n<h2 id=\"リモートからのアクセス許可\">リモートからのアクセス許可</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/vnc.conf</code> に以下を追記してリモートアクセスを許可します</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$localhost = “no”;\n</code></pre></div></div>\n\n<h2 id=\"systemctl-enable-の代わりにシンボリックリンクの作成\">systemctl enable の代わりにシンボリックリンクの作成</h2>\n<p>参照元がこうなってたので。<br />\n<code class=\"language-plaintext highlighter-rouge\">sudo systemctl enable vncserver@</code>でも良い気がするけど。ここのファイル名でポート番号決めてる?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /etc/systemd/system/multi-user.target.wants/\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /etc/systemd/system/vncserver@.service vncserver@1.service\n</code></pre></div></div>\n\n<h2 id=\"リブートする\">リブートする</h2>\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5901に接続します。<br />\n(VNCクライアントの接続先に<code class=\"language-plaintext highlighter-rouge\">«JetsonのIPアドレス»:5901</code> を指定します)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</h1>\n      <p>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>SDカードのアクセスが遅いのと、USBドライブの方が大容量のメディアを入手しやすいので\nUSBドライブをブートデバイスに変更してみる。</p>\n\n<p>といっても、Jetpack4.5以降ではブートローダがUSBからのブートをサポートしたので、かなり簡単になった。</p>\n\n<p>Jetpack4.4のときのメモは<a href=\"/memoBlog/2020/10/30/Jetson_usb_boot.html\" target=\"_blank\">Jetson nano をUSBドライブからブートできるようにする</a> にあります。</p>\n\n<h1 id=\"ディスクイメージの書き込み\">ディスクイメージの書き込み</h1>\n<p>通常セットアップを行ったSDカードのディスクイメージをUSBドライブにコピーします。\nSDカード→USBドライブ直接でも構いませんし、バックアップとして作成したディスクイメージファイルからでも構いません。</p>\n\n<p>ubuntu PCでディスクイメージファイルからコピーする場合はこんな感じ。<br />\n<code class=\"language-plaintext highlighter-rouge\">/dev/sdc</code> の部分は環境により異なるので注意(間違って他のディスクに上書きしないように!!)。<br />\n<code class=\"language-plaintext highlighter-rouge\">jetpack46_XXXXXXXX.img</code>がディスクイメージファイルのファイル名です。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"nv\">of</span><span class=\"o\">=</span>/dev/sdc <span class=\"k\">if</span><span class=\"o\">=</span>jetpack46_XXXXXXXX.img <span class=\"nv\">bs</span><span class=\"o\">=</span>1M <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div></div>\n\n<h1 id=\"bootデバイス変更のための設定\">BOOTデバイス変更のための設定</h1>\n\n<p>ディスクイメージを書き込んたUSBドライブをSDカードブートした Jetson nano や ubuntu PCに接続し、\n設定ファイルを書き換えます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ディスクのマウント</span>\n<span class=\"nb\">sudo </span>mount /dev/sdc1 /mnt\n<span class=\"nb\">cd</span> /mnt/boot/extlinux/\n<span class=\"c\"># オリジナルファイルのバックアップ</span>\n<span class=\"nb\">sudo cp </span>extlinux.conf extlinux.conf.mmc\n<span class=\"c\"># 編集</span>\n<span class=\"nb\">sudo </span>vi extlinux.conf\n</code></pre></div></div>\n\n<p>以下のように変更します\n具体的には<code class=\"language-plaintext highlighter-rouge\">/mnt/boot/extlinux/extlinux.conf</code> 内の \n<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0p1</code>を<code class=\"language-plaintext highlighter-rouge\">/dev/sda1</code>に変更します。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- extlinux.conf.mmc\t2021-09-14 06:02:45.889520568 +0900\n</span><span class=\"gi\">+++ extlinux.conf\t2021-09-14 06:03:29.453873117 +0900\n</span><span class=\"p\">@@ -7,7 +7,7 @@</span>\n       MENU LABEL primary kernel\n       LINUX /boot/Image\n       INITRD /boot/initrd\n<span class=\"gd\">-      APPEND ${cbootargs} loglevel=6 root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 ipv6.disable=1\n</span><span class=\"gi\">+      APPEND ${cbootargs} loglevel=6 root=/dev/sda1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 ipv6.disable=1\n</span> \n # When testing a custom kernel, it is recommended that you create a backup of\n # the original kernel and add a new entry to this file so that the device can\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nrootパラメータはパーティションのUUIDを書いておくのが最近の作法らしいが\n大抵 マウント先は <code class=\"language-plaintext highlighter-rouge\">/dev/sda1</code> なので、お手軽にこっちで指定する。</p>\n</blockquote>\n\n<h1 id=\"ついでに設定\">ついでに設定</h1>\n<p>ついでにパーティションサイズも変更しておくと良いです。</p>\n\n<h1 id=\"boot\">BOOT</h1>\n<p>あとはJetson nano にUSBドライブを接続し、元々ブートに使用していた<strong>SDカードを取り外し</strong>て電源ON。</p>\n\n<p>起動後、USBドライブがrootにマウントされていることを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">mount</code>で確認しても良いけど、いっぱい出てきて鬱陶しいので<code class=\"language-plaintext highlighter-rouge\">df</code>で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">df</span> <span class=\"nt\">-h</span> /\n</code></pre></div></div>\n<p>こんな感じで行頭にマウント元が表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Filesystem      Size  Used Avail Use% Mounted on\n/dev/sda1       108G   13G   91G  13% /\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Dockerをインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Dockerをインストールする</h1>\n      <p>Windos/Ubuntu に Dockerをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows10-home-に-dockerをインストールする\">Windows10 Home に Dockerをインストールする</h1>\n<p>HomeだとWSL2必須なので、WSL2はあらかじめインストールして使用できるようにしておく。<br />\n<a href=\"/memoBlog/2021/03/03/WSL_memo.html\" target=\"_blank\">WSL2 メモ</a></p>\n\n<p><a href=\"https://docs.docker.jp/docker-for-windows/install-windows-home.html\" target=\"_blank\">https://docs.docker.jp/docker-for-windows/install-windows-home.html</a> を参考にインストールする。 <br />\nとはいっても、<a href=\"https://hub.docker.com/editions/community/docker-ce-desktop-windows/\" target=\"_blank\">https://hub.docker.com/editions/community/docker-ce-desktop-windows/</a>からダウンロードして実行するだけ。</p>\n\n<p>コンテナを一杯作るとデータ領域がどんどん肥大していくので、Cドライブから変更しておいた方が良いかも。<br />\n<a href=\"https://nosubject.io/windowsdocker-desktop-move-disk-image/\" target=\"_blank\">Docker Desktop の ディスク領域 を Cドライブから別のドライブへ移動する方法</a><br />\nを参考に作業すればOK。<br />\nVHDをエクスポート、元の仮想マシンのレジストリを削除、他の場所へ同名でインポート、とやってる。</p>\n\n<h1 id=\"ubuntu-に-dockerをインストールする\">Ubuntu に Dockerをインストールする</h1>\n<p><a href=\"https://docs.docker.jp/linux/step_one.html\" target=\"_blank\">https://docs.docker.jp/linux/step_one.html</a> を参考にインストールする。 <br />\n実際は以下を実行するだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>curl <span class=\"nt\">-fsSL</span> https://get.docker.com/ | sh\n</code></pre></div></div>\n\n<p>docker実行に逐一<code class=\"language-plaintext highlighter-rouge\">sudo</code>をつけるのは面倒なので、以下の設定をしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> docker\n</code></pre></div></div>\n<p>設定後は念のためリブートしておく(logoutだけで可らしいけど)。</p>\n\n<h1 id=\"インストール後のお試し実行\">インストール後のお試し実行</h1>\n<p>正常に動いていることを確認するためになんか動かしてみる。<br />\n以下はWindows版で書かれているが、基本的にUbuntuでも同じ。<br />\n<a href=\"https://qiita.com/nanaki11/items/97e5685ed84547526be2\" target=\"_blank\">https://qiita.com/nanaki11/items/97e5685ed84547526be2</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">docker pull</code>はしなくても<code class=\"language-plaintext highlighter-rouge\">docker run</code>したときにローカルにimegeがなければ自動でダウンロードしてくれるらしい。</p>\n\n<h1 id=\"コマンド例\">コマンド例</h1>\n<p>ちょろっと試したコマンド群</p>\n<h2 id=\"コンテナの生成\">コンテナの生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの起動\">コンテナの起動</h2>\n<p>終了したコンテナの再開も同じ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> py_test\n</code></pre></div></div>\n\n<h2 id=\"コンテナに新たなコンソール接続\">コンテナに新たなコンソール接続</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> py_test /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの生成と起動を同時に行う\">コンテナの生成と起動を同時に行う</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">create</code>を<code class=\"language-plaintext highlighter-rouge\">run</code>に変えるだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"nwork-を-work-にマウントする場合windows\">n:\\work を /work にマウントする場合(Windows)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /n/work:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"カレントディレクトリを-work-にマウントする場合ubuntu\">カレントディレクトリを /work にマウントする場合(ubuntu)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナ一覧起動中のもののみ\">コンテナ一覧(起動中のもののみ)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<h2 id=\"コンテナ一覧終了したものを含む\">コンテナ一覧(終了したものを含む)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n\n<h2 id=\"pull済みイメージ一覧\">pull済みイメージ一覧</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<h2 id=\"コンテナの情報を確認する\">コンテナの情報を確認する</h2>\n<p>下記コマンドでJSONデータが出力される。<br />\n直近で興味ありそうなのは<code class=\"language-plaintext highlighter-rouge\">HostConfig</code>、<code class=\"language-plaintext highlighter-rouge\">Mounts</code>、<code class=\"language-plaintext highlighter-rouge\">NetworkSettings</code>あたりかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker inspect py_test2\n</code></pre></div></div>\n\n<h1 id=\"どんなイメージがあるのか\">どんなイメージがあるのか?</h1>\n<p><a href=\"https://hub.docker.com/search?type=image\" target=\"_blank\">dockerhub</a>でサーチしてちょ。</p>\n\n<h1 id=\"dockerはwsl2でどんな感じで動いているのか\">DockerはWSL2でどんな感じで動いているのか?</h1>\n<p>あんまり意味ないけど。<br />\n<a href=\"https://www.docker.com/blog/new-docker-desktop-wsl2-backend/\" target=\"_blank\">https://www.docker.com/blog/new-docker-desktop-wsl2-backend/</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>VSCodeでDocker内のpythonプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>VSCodeでDocker内のpythonプログラムをデバッグする</h1>\n      <p>VSCodeでDocker内のpythonプログラムをデバッグする(Windos/Ubuntu)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからWindows上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nubuntu上のVSCodeからubuntu上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nどちらもほぼ同じ手順でデバッグできる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>VScodeに拡張機能Python、Docker、Remote Containers をインストールしておく</p>\n\n<h1 id=\"コンテナ起動\">コンテナ起動</h1>\n<p>ターミナルからコンテナ起動する<br />\nソースの編集をしやすいように、ホストのフォルダを<code class=\"language-plaintext highlighter-rouge\">/work</code>に割り当てている。<br />\nいや、VSCodeで編集すれば問題ないんだけどさ…<br />\nいつも編集は別のエディタ使ってたりするとコンテナ内のファイルいじるのが面倒なので…</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Windows\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> /m/work/zzz:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ubuntu\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> <span class=\"sb\">`</span><span class=\"nb\">realpath</span> .<span class=\"sb\">`</span>:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンテナを一度作成してあれば起動していなくても大丈夫らしい。</p>\n</blockquote>\n\n<h1 id=\"コンテナに接続\">コンテナに接続</h1>\n<p>VScodeのリモートエクスプローラにコンテナが見える</p>\n<blockquote>\n  <p>[!NOTE]\nRemote SSHやRemote WSLがインストールされている場合はリモートエクスプローラ上部のドロップダウンリストからContainersを選択</p>\n</blockquote>\n\n<p>対象のコンテナを右クリックして<code class=\"language-plaintext highlighter-rouge\">Attach to Container</code> または<code class=\"language-plaintext highlighter-rouge\">Attach in New Window</code>をクリック<br />\n<code class=\"language-plaintext highlighter-rouge\">Attaching to a container may execute arbitrary code</code><br />\nと言われるたら、変なコードが実行されないことが分かっていれば <code class=\"language-plaintext highlighter-rouge\">Got it</code> をクリック</p>\n<blockquote>\n  <p>[!NOTE]\n一度開いたフォルダはその下にショートカットが表示されているので、そこから開けば手っ取り早い。</p>\n</blockquote>\n\n<p>コンテナが開く</p>\n\n<p>コンテナ内には拡張機能が入ってないので、必要な拡張機能をインストールする</p>\n\n<h1 id=\"デバッグ\">デバッグ</h1>\n<p>エクスプローラでデバッグしたいフォルダを開いてソースを開く(VSCodeの設定によっては前回開いていたフォルダが開かれる)<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Python: Select Interpreter</code> で 使用するpythonを選択する。<br />\nこのとき、必ずしも使用するpythonのpathが表示されているとは限らないので、<br />\n(逆にコンテナ内にないホスト側のものが表示されたりする😢)<br />\n表示されていない場合は<code class=\"language-plaintext highlighter-rouge\">+ Enter Interpreter path...</code>から使用するpythonを選択する。<br />\n上記イメージの場合、<code class=\"language-plaintext highlighter-rouge\">/usr/local/bin/python3</code> なので、これを設定。</p>\n<blockquote>\n  <p>[!NOTE]\nあらかじめコンソールで which python3 して調べておく</p>\n</blockquote>\n\n<p>あとはローカルと同じようにデバッグできる。</p>\n\n<h1 id=\"コンテナとの接続終了\">コンテナとの接続終了</h1>\n\n<p>コンテナとの接続を終了するときは<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Remote: Close Remote Connection</code> で終了する。</p>\n\n<p>接続終了してもコンテナを停止しないので、別途停止処理を行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker stop py_test2\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>こういうのもある。<br />\n(参照しているのはmicrosoft純正のサンプルらしい)<br />\n普通にDocker使うのと異なるファイル<code class=\"language-plaintext highlighter-rouge\">devcontainer.json</code>を使うので、\n便利なんだか不便なんだか…<br />\nDocker拡張機能なくても動かせた気がする。<br />\n<a href=\"https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html\">https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerコンテナからGUIを起動する</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerコンテナからGUIを起動する</h1>\n      <p>Windos/Ubuntu の DockerコンテナからGUIを起動する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuでローカルのデスクトップに表示する場合\">Ubuntuでローカルのデスクトップに表示する場合</h1>\n<p>Docker(ubuntu)のみ。<br />\nコンテナ生成時に以下のように<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数の設定と<code class=\"language-plaintext highlighter-rouge\">/tmp/.X11-unix/</code>のマウントを行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test3 <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n<p>この場合、表示する前にホスト側で以下を実行しておく必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>xhost +local:\n</code></pre></div></div>\n<p>実行していない場合、GUI起動コマンド実行で以下のエラーが出る。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>No protocol specified\nError: Can't open display: XXX\n</code></pre></div></div>\n\n<p>Ubuntuを再起動したときに設定は忘れられてしまうので、起動の度に実行必要。</p>\n\n<blockquote>\n  <p>[!NOTE]\nxhostはセキュリティ上問題があるとのことだが、家の中だけだし、localだけなら許可してもいいかな…\nrc.localあたりに書いとこうかと思ったけど、使用するときだけ実行するのが無難かな。</p>\n</blockquote>\n\n<h1 id=\"windows上のvcxsrvに表示する場合\">Windows上のVcXsrvに表示する場合</h1>\n<p>Docker(windows)だとコレ一択。<br />\nDocker(ubuntu)でも大丈夫。<br />\nなので、Docker(ubuntu)にリモート接続で使用することがある場合はこっちを使っておくのが良いと思う。<br />\nWindowsマシンのIPアドレスが192.168.XXX.XXX(マシン名指定不可)だとして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test4 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XXX.XXX:0.0 <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ubuntuにSSHサーバをセットアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ubuntuにSSHサーバをセットアップする</h1>\n      <p>ubuntuにSSHサーバをセットアップするし、公開鍵認証を設定する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuにsshサーバをセットアップする\">UbuntuにSSHサーバをセットアップする</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n\n<p>この状態でWindowsなどから以下のコマンドで接続するとパスワード認証でlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«ユーザ名»@«IPアドレス»<span class=\"s1\">'s password: «パスワードを入力»  \n</span></code></pre></div></div>\n\n<p>リモート接続でshellを使うだけならこれでも良いが、\nVScodeでリモートデバッグをしたりするときなどはパスワード入力を何回も行う必要があったりして面倒。<br />\nそこで、公開鍵認証を設定してパスワード入力を不要にする。</p>\n\n<h1 id=\"秘密鍵と公開鍵の生成と公開鍵ファイルの設置\">秘密鍵と公開鍵の生成と公開鍵ファイルの設置</h1>\n<p>Windowsマシンで以下のコマンドを実行して秘密鍵ファイルと公開鍵ファイルを生成する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh-keygen.exe <span class=\"nt\">-t</span> rsa\n<span class=\"o\">(</span>リターン3回<span class=\"o\">)</span>\n※ 本当はpassphase入れないといけないけど、ローカルお試し環境なので省略\n</code></pre></div></div>\n<p>実行すると以下のファイルが出来る</p>\n<ul>\n  <li>%USERPROFILE%/.ssh/id_rsa</li>\n  <li>%USERPROFILE%/.ssh/id_rsa.pub</li>\n</ul>\n\n<p>このうち、<code class=\"language-plaintext highlighter-rouge\">id_rsa.pub</code>をUbuntuマシンの <code class=\"language-plaintext highlighter-rouge\">~/.ssh</code>へ<code class=\"language-plaintext highlighter-rouge\">authorized_keys</code>というファイル名でコピー(既に存在する場合は追記)する。</p>\n<blockquote>\n  <p>[!NOTE]\nやり方検索すると<code class=\"language-plaintext highlighter-rouge\">scp</code>コマンドでコピーする方法が紹介されているが、\n家の中だけなのでネットワークドライブ経由でのコピーや\nファイル自体はテキストファイルなので、SSH接続したshellからエディタを起動して\nコピペするのでも良い。</p>\n</blockquote>\n\n<p>コピーが完了したらファイルのパーミッションを変更する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod </span>600 ~/.ssh/authorized_keys\n</code></pre></div></div>\n\n<h1 id=\"接続テスト\">接続テスト</h1>\n<p>この状態でWindowsマシンから以下のコマンドで接続するとパスワード認証なしでlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«パスワード入力なしで接続»\n</code></pre></div></div>\n\n<p>Windows側のユーザディレクトリ/.ssh/config の設定もやっておくと便利<br />\n参考: <a href=\"https://qiita.com/passol78/items/2ad123e39efeb1a5286b\">https://qiita.com/passol78/items/2ad123e39efeb1a5286b</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</h1>\n      <p>ローカル(Windows)のVSCodeからリモートホスト(ubuntu)上のDockerコンテナ内のプログラムをデバッグする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからUbuntu上のDockerコンテナに接続してデバッグする方法。</p>\n\n<p>UbuntuへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>\nsudo なしで Docker動かせるようにしとく必要あり</p>\n\n<h1 id=\"リモートホストへの接続\">リモートホストへの接続</h1>\n<p>UbuntuへのSSH接続の準備については<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">こちら</a></p>\n\n<h2 id=\"手順\">手順</h2>\n<ul>\n  <li>WindowsマシンでVScode 起動する</li>\n  <li>拡張機能「Remote Development」をインストールしておく。</li>\n  <li>左下にある「><」ボタンをクリック</li>\n  <li>上にメニューが出るので、「Connect to host…」 または「Connect Current Window to Host…」を選択</li>\n  <li>続いて「Select configured SSH host~」で接続するホストを選択。\n    <ul>\n      <li>新規接続の場合は「Add New SSH Host…」を選択</li>\n      <li>「ssh «user»@«IPアドレス or マシン名»」</li>\n      <li>設定を保存するファイルを選択。特に理由がなければ c:\\Users\\«ユーザ».config でいいかな。</li>\n      <li>右下に「Host added!」ウィンドウが出るので「Connect」をクリック</li>\n      <li>初めて接続するホストの場合、上にSelect the platform of remote host “~” と聞かれるのでOS種別を選択</li>\n      <li>「あんた«OS»を選らんだでー。~に保存したから変えたかったら ここ変更しぃや~」みたいなことを言ってるウィンドウが出るので「Don’t Show Again」をクリック</li>\n    </ul>\n  </li>\n  <li>接続された。右下の「><」ボタンが「>< SSH:«マシン名»」に変わっている。</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n一度接続すればリモートエクスプローラ(SSH TARGETS)に表示されるのでそこから接続しても良い。</p>\n</blockquote>\n\n<p>リモートホスト上のプログラムをデバッグしたい場合はここでフォルダを開いてごちょごちょやればよい。</p>\n\n<h1 id=\"dockerコンテナへの接続\">Dockerコンテナへの接続</h1>\n<h2 id=\"準備\">準備</h2>\n<p>WindowsマシンにDocker desktop for windows が必要になるので、インストールしておく。<br />\nWindowsへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\">こちら</a><br />\nCLIだけでよさそうなんだけど、CLIだけってのがどこかにあるのか分からんかったのでとりあえず全部入れた。<br />\nDocker Desktopは動いてなくて良いので、Exitして可。<br />\n普段から使わないならDocker Dashboardの設定のGeneralから「Start Docker Desktop when you log in」のチェックを はずしておけばOK。</p>\n\n<h2 id=\"dockerexeで疎通確認\">docker.exeで疎通確認</h2>\n<p>コマンドプロンプト等で以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">set </span><span class=\"nv\">DOCKER_HOST</span><span class=\"o\">=</span>ssh://«ユーザ名»@«ホスト»\ndocker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<p>リモートホスト上のコンテナの状態が返ってくるか確認。</p>\n\n<h2 id=\"docker-hostの設定\">DOCKER HOSTの設定</h2>\n<p>VScodeの<code class=\"language-plaintext highlighter-rouge\">settings.json</code> に以下の一文を追加する。もちろん上で確認した内容で。</p>\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\">    </span><span class=\"nl\">\"docker.host\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"ssh://«ユーザ名»@«ホスト»\"</span><span class=\"err\">,</span><span class=\"w\">\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルにつなぎたいときはこの行をコメントアウト(<code class=\"language-plaintext highlighter-rouge\">//</code>をつける)すればOK。<br />\n<code class=\"language-plaintext highlighter-rouge\">setting.json</code>はJSONファイルだけど、 <code class=\"language-plaintext highlighter-rouge\">//</code>でコメントアウトできる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nVScode settings.json の開き方</p>\n  <ul>\n    <li>メニュー ファイル→ユーザ設定→ 設定</li>\n    <li>設定画面の右上のボタン「設定(JSON)を開く」をクリック</li>\n  </ul>\n\n  <p>または</p>\n  <ul>\n    <li>メニュー表示→コマンドパレット</li>\n    <li>Preference:  Open Settings(JSON) を選択</li>\n  </ul>\n</blockquote>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その1\">VScodeでリモート エクスプローラからリモートホストに接続(その1)</h2>\n<p>リモートホストに拡張機能 Docker と Docker Explorer をインストールしておき、\nDockerペインを開くとリモートホスト上のコンテナとかが見える</p>\n\n<p>ここでは既にリモートホスト上でコンテナ作成済みとする。<br />\n(イメージからコンテナ作ったりDockerfileからBuildしたりできると思うけど、今はおいとく)</p>\n\n<ul>\n  <li>接続するコンテナが起動していない場合はDockerペインで使用するコンテナを右クリック→Start でコンテナを起動</li>\n  <li>起動したら対象コンテナのアイコンが三角マークになる</li>\n  <li>同じくDockerペインで使用するコンテナを右クリック→Attach Visual Studio Code を選択</li>\n  <li>select the container to attach VS Code と聞かれるのでアタッチするコンテナを選択(コンテナ選択してAttachしたはずだけど、なぜかここで再度選択が必要)</li>\n  <li>初めて接続した場合は「Attaching to a container may execute arbitrary code」<br />\nと言われるので、変なコードが実行されないことが分かっていれば Got it をクリック</li>\n  <li>接続された。右下の「><」ボタンが「>< Conteiner «コンテナ名»」に変わっている。</li>\n</ul>\n\n<p>あとはリモート SSH や ローカルのDockerでのデバッグと同じ。</p>\n\n<h2 id=\"接続の終了\">接続の終了</h2>\n<p>接続を終了する場合は</p>\n<ul>\n  <li>メニュー表示→コマンドパレット</li>\n  <li>Remote:  Close Remote Connection を選択</li>\n</ul>\n\n<p>このとき、コンテナからだけでなく、リモートホストからも切断される。</p>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その2\">VScodeでリモート エクスプローラからリモートホストに接続(その2)</h2>\n<p>リモートエクスプローラ(Containers)で接続するコンテナを右クリックし、「Attach to Container」または「Attach in New Window」を選択<br />\n(コンテナが起動されていなければ起動して)コンテナに接続される。</p>\n\n<p>あんまりごちょごちょしなくて済むのでこっちの方がおススメかな。</p>\n\n<h1 id=\"ネットワークポート\">ネットワークポート</h1>\n<p>通常Cockerコンテナ内のネットワークポートをホストや外部コンピュータからアクセスするには、<br />\nコンテナ作成時に-p (–publish) オプションで接続を受け入れるポート番号を指定する必要があるが、<br />\nVScodeから接続している場合は、Docker内のネットワークポートにVScodeが実行されているマシンからlocalhost:«ポート番号»で接続できる。<br />\n(アクセス遅いけど、ちょっと別のポート開けて試したい なんて時には便利)</p>\n\n<p>ただし、これはDockerが動作しているホストコンピュータや他のコンピュータからはアクセスできない。<br />\nこれらからアクセスするには-pオプションを指定する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n<p><a href=\"https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0\">https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0</a><br />\n↑ここにある、「Remote-Containers: Open Folder in Container…」での手順はリモートホストに接続した状態では実行できないらしい。<br />\nどうしてもこのコンテナでデバッグしたい場合は、<br />\n一旦リモートホスト上でVSCodeを起動してコンテナを作成しておき、<br />\nその後ローカルPCからこのコンテナにアタッチするような手順をふめばデバッグできる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerでopenVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerでopenVINO</h1>\n      <p>DockerでopenVINOプログラムの開発</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>DockerコンテナでopenVINOのプログラム開発を行う手順。<br />\n↓ここを参考にUbuntu 20.04/openVINO 2021.3に変更してみる。ついでによく使う機能の準備もやっておく。<br />\n<a href=\"https://kuttsun.blogspot.com/2021/06/openvino-docker.html\">https://kuttsun.blogspot.com/2021/06/openvino-docker.html</a></p>\n\n<h1 id=\"dockerイメージの作成\">Dockerイメージの作成</h1>\n\n<p>上の参照先を参考に公式イメージに必要な処理を加えておく。<br />\nDockerfile は以下。<br />\n参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>ベースをopenVINO/ubuntu20に変更</li>\n  <li>sudoとvimとless入れとく。sudoはパスワードなしで動作するようにしとく。</li>\n  <li>開発マシンなのでbaskhの補完機能を有効にしておく</li>\n  <li>キーバインド変更 ( <code class=\"language-plaintext highlighter-rouge\">^p</code> / <code class=\"language-plaintext highlighter-rouge\">^n</code> )</li>\n  <li>日本語文字化け対策</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code> がキー入力待ちになってbuildエラーになるので<code class=\"language-plaintext highlighter-rouge\">-y</code>オプションを追加</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-docker highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースイメージ</span>\n<span class=\"k\">FROM</span><span class=\"s\"> openvino/ubuntu20_dev:2021.3</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">ENV</span><span class=\"s\"> DEBIAN_FRONTEND=noninteractive</span>\n\n<span class=\"c\"># sudo と vim と less のインストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install sudo </span>vim less <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo </span>openvino <span class=\"nv\">ALL</span><span class=\"o\">=</span><span class=\"se\">\\(</span>root<span class=\"se\">\\)</span> NOPASSWD:ALL <span class=\"o\">></span> /etc/sudoers.d/openvino <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">chmod </span>0440 /etc/sudoers.d/openvino\n\n<span class=\"c\"># bashの補完機能 & キーバインドの設定 & 日本語文字化け対策</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nb\">install </span>bash-completion <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"s2\">\". /usr/share/bash-completion/bash_completion\"</span> <span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-n</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-forward' </span><span class=\"se\">\\n\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-p</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-backward'</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">export LANG=C.UTF-8</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">export LANGUAGE=en_US:</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc\n\n<span class=\"c\"># 依存パッケージのインストール(-yオプションで Yes自動選択)</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies <span class=\"o\">&&</span> ./install_openvino_dependencies.sh <span class=\"nt\">-y</span>\n\n<span class=\"c\"># サンプル、デモアプリのビルド</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/samples/cpp <span class=\"o\">&&</span> ./build_samples.sh\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/demos <span class=\"o\">&&</span> ./build_demos.sh\n<span class=\"c\"># /opt/intel/openvino_2021/deployment_tools/demo にデモアプリがある</span>\n\n<span class=\"c\"># 他に必要なものを適宜インストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>wget git python3-pip\n<span class=\"k\">RUN </span>pip3 <span class=\"nb\">install </span>onnxruntime flask\n\n<span class=\"c\"># aptのクリア</span>\n<span class=\"k\">RUN </span>apt clean <span class=\"o\">&&</span> <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> /var/lib/apt/lists/<span class=\"k\">*</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> openvino</span>\n\n<span class=\"c\"># bash起動</span>\n<span class=\"k\">CMD</span><span class=\"s\"> [ \"/bin/bash\" ]</span>\n</code></pre></div></div>\n\n<h1 id=\"ビルド\">ビルド</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker build <span class=\"nt\">-t</span> myopenvino/ubuntu20_dev:2021.3 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h1 id=\"コンテナの生成\">コンテナの生成</h1>\n<p>参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>カレントディレクトリ下のworkを/workに割り当てるように追加</li>\n  <li>GPU関連の設定を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ./work\ndocker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"se\">\\</span>\n       <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"se\">\\</span>\n       myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nX-Windowの表示先(<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code> 変数) は ここで固定されるので、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を変更したい場合は<br />\nコンテナをスタートした後、コンテナ内で手打ちで設定するか、<br />\n変更後の<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を設定したターミナルから以下を実行。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> openvino_2021.3 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<p>Windows の場合は以下な感じ。<br />\nDISPLAY変数は環境に合わせて変更してちょ。<br />\nNCS周りの設定は削除してある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.204:0.0 <span class=\"nt\">-v</span> %CD%<span class=\"se\">\\w</span>ork:/work myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ndocker をWSL上のコマンドラインから起動しているときは<code class=\"language-plaintext highlighter-rouge\">%CD%</code>でなく<code class=\"language-plaintext highlighter-rouge\">$PWD</code><br />\nPowerShellでコマンドを複数行に分割する場合は、行末記号は<code class=\"language-plaintext highlighter-rouge\">\\</code> ではなく <code class=\"language-plaintext highlighter-rouge\">`</code><br />\nコマンドプロンプトでは<code class=\"language-plaintext highlighter-rouge\">^</code> NYAGOSは分からん😢<br />\nそれぞれ違ってびみょーにストレス…</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> openvino_2021.3\n</code></pre></div></div>\n\n<p>コンテナ内でデモを動かしてみる<br />\n(デモの実行で必要なライブラリ類がインストールされたりするので、実行しましょう)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ~/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/demo1.log\n\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/dem2.log\n</code></pre></div></div>\n\n<p>前に作ったプログラムを試してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\ngit clone https://github.com/ippei8jp/ov_trial.git\n<span class=\"c\"># 入力画像の準備</span>\n<span class=\"nb\">cd </span>ov_trial/images/\nbash download.sh\n<span class=\"c\"># モデルファイルの準備(mobilenet-ssdのダウンロードがエラーになるけど大勢に影響ない) </span>\n<span class=\"nb\">cd</span> ../convert_model_ssd/\nbash convert_model_ssd.sh \n\n<span class=\"c\"># 認識してみる</span>\n<span class=\"nb\">cd</span> ../ssd/\nbash test.sh list\nbash test.sh 6\n</code></pre></div></div>\n\n<h1 id=\"ncs2の使用ubuntuのみ\">NCS2の使用(ubuntuのみ)</h1>\n<p>ubuntuではホストに接続したNCS2を使用することもできる。<br />\nただし、DockerコンテナからNCS2を使用するにはDokerホスト側にドライバをインストールしておく必要がある。<br />\n(udevルールだけ?イマイチ自信ないのでフルパッケージでインストールしておいた)<br />\n以下の部分がNCS2を使用するために必要な設定。(上記コマンド例では設定済み)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi向け)のbuild</h1>\n      <p>Raspberry Pi向けopenVINOのbuild(特にCPU extension)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi用 openVINO は デフォルト状態ではCPUで実行できない(NCS2必須)。<br />\nそこで、オープンソース版openVINOを使用してCPU extensionを作成してみる。<br />\nとはいえ、CPU extension だけサクっと作成できなくて、openVINO全体を作成するハメに…</p>\n\n<p>Raspberry Pi 実機でbuildすると、ディスク容量がバカにならないし、<br />\nあまり実環境を弄りたくなかったので、<br />\nUbuntuマシン上のDockerコンテナで実行する方法を試してみる(Docker Desktop for Windowsでもできると思う)</p>\n\n<h1 id=\"arm版dockerコンテナを使用したセルフコンパイル\">ARM版Dockerコンテナを使用したセルフコンパイル</h1>\n\n<p>Dockerコンテナ全体をQEMU上でARMエミュレーションしてくれるので、特に難しいことを考えずに<br />\nネイティブ環境と変わりなくあつかえる。<br />\nでも、かなり遅い(実機よりちょっと速い?同じくらい?)。<br />\n試した環境では、x86_64な環境でクロスコンパイルした場合の15倍くらいかかった。  <br />\n(M1 Mac上でACVMを使うとかなり早いという噂も…M1 Mac持ってない😢  <a href=\"https://qiita.com/kose3/items/af9edc9c40c9ae8fc5c3\" target=\"_blank\">参考</a>  )</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h3 id=\"qemuのインストール\">qemuのインストール</h3>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_emu\n</code></pre></div></div>\n\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm32v7/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成\">patchファイルを作成</h3>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_emu_1 ov_pi_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n以下のオプションを追加すると少しは速くなるかと思ったが、あまり変わらない。</p>\n  <ul>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_OPENCV=OFF</code></li>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_SAMPLES=OFF</code></li>\n  </ul>\n</blockquote>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。</p>\n\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./inference_engine</code> がない\n    <ul>\n      <li>実体は <code class=\"language-plaintext highlighter-rouge\">deployment_tools/inference_engine</code> なので、シンボリックリンクを作れば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/opencv/</code>からコピーすれば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>opencvのpythonモジュールがない\n        <ul>\n          <li>どこから持ってくれば良いんだろう?</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h3 id=\"実機へのインストール\">実機へのインストール</h3>\n<p>CPU extensionだけなら<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l/</code><br />\nへコピーするだけで良い。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれはmake install してもこれはコピーされないらしい。</p>\n</blockquote>\n\n<p>openVINO全体のインストールなら<code class=\"language-plaintext highlighter-rouge\">work/opt/intel/openvino</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/</code>にコピーすれば良いのだけど、opencvのpythonインタフェースがないので注意。<br />\nということで、実際に試していない…</p>\n\n<blockquote>\n  <p>[!NOTE]\n※※※※ メモ ※※※※ <br />\nopenCVはここでbuildするのではなく、<br />\n<a href=\"https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/\" target=\"_blank\">https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/</a> \nからbuild済みモジュールをダウンロードして<br />\n<code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/</code><br />\nに展開している。</p>\n</blockquote>\n\n<h1 id=\"i386版32bit-x86dockerコンテナを使用したクロスコンパイル\">i386版(32bit x86)Dockerコンテナを使用したクロスコンパイル</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>セルフコンパイルは時間がかかりすぎるので、クロスコンパイルで試してみた。<br />\nかなり早くなったが、一部使えないモジュールが…<br />\n当初の目的のCPU extensionは使えるので、掲載しとく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n当初、64bit版debianをベースに作業しようとしたが、\npybind11のbuildで以下のように怒られる。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Make Error at build/_deps/pybind11-src/tools/FindPythonLibsNew.cmake:127 (message):\n  Python config failure: Python is 64-bit, chosen compiler is 32-bit\nCall Stack (most recent call first):\n  build/_deps/pybind11-src/tools/pybind11Tools.cmake:16 (find_package)\n  build/_deps/pybind11-src/CMakeLists.txt:33 (include)\n</code></pre></div>  </div>\n  <p>以下のような対策が考えられる。</p>\n  <ul>\n    <li>FindPythonLibsNew.cmakeにbit数チェックをしないようにパッチを当てる\n      <ul>\n        <li>やり方がよう分からん…</li>\n      </ul>\n    </li>\n    <li>amd64なdebianに32bitのpythonをインストールする\n      <ul>\n        <li>イマイチうまくインストールできなかった</li>\n      </ul>\n    </li>\n  </ul>\n\n  <p>しかたないので、32bit版debianで作ることにした</p>\n</blockquote>\n\n<h2 id=\"準備-1\">準備</h2>\n\n<h3 id=\"作業用ディレクトリの準備-1\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_buster_32 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_buster_32\n</code></pre></div></div>\n<h3 id=\"openvino-の-gitリポジトリを-clone-1\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> i386/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> armhf <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-armhf <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:armhf <span class=\"se\">\\\n</span>    libgtk-3-dev:armhf <span class=\"se\">\\\n</span>    libavcodec-dev:armhf <span class=\"se\">\\\n</span>    libavformat-dev:armhf <span class=\"se\">\\\n</span>    libswscale-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:armhf <span class=\"se\">\\\n</span>    libpython3-dev:armhf <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python-argparse <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"c\"># aptでインストールするので削除</span>\n<span class=\"c\"># RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.3/cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     tar xzvf cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     (cd cmake-3.21.3 && ./bootstrap --parallel=$(nproc --all) -- -DCMAKE_USE_OPENSSL=OFF && make --jobs=$(nproc --all) && make install) && \\</span>\n<span class=\"c\">#     rm -rf cmake-3.21.3 cmake-3.21.3.tar.gz</span>\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"patchファイルを作成-1\">patchファイルを作成</h3>\n\n<p>以下の2つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch1.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake\nindex 6cb15a0..66a1ef6 100644\n</span><span class=\"gd\">--- a/cmake/dependencies.cmake\n</span><span class=\"gi\">+++ b/cmake/dependencies.cmake\n</span><span class=\"p\">@@ -19,8 +19,9 @@</span> if(CMAKE_CROSSCOMPILING AND CMAKE_HOST_SYSTEM_NAME MATCHES Linux AND CMAKE_HOST_\n     find_program(\n         SYSTEM_PROTOC\n         NAMES protoc\n<span class=\"gd\">-        PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n-        NO_DEFAULT_PATH)\n</span><span class=\"gi\">+        # PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n+        # NO_DEFAULT_PATH)\n+        )\n</span>     if(NOT SYSTEM_PROTOC)\n         message(FATAL_ERROR \"[ONNX IMPORTER] Missing host protoc binary\")\n     endif()\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる-1\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../patch1.patch<span class=\"o\">)</span>\n<span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino apply ../../patch1.patch\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_buster_32 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32_1</code> を使用。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_buster_32_1 ov_pi_buster_32 /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/386) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_buster_32_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_buster_32_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make-1\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n\n<p>コンテナから出て、<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の \n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l</code>/<br />\nへコピーする</p>\n\n<blockquote>\n  <p>[!WARNING]\ncythonの出力がx86のコードを吐くので、pythonモジュールの一部に正常に動作しないものがある。<br />\npythonモジュールを使いたいときはセルフコンパイルするしかないかな?</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その1)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(DDQN編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"https://qiita.com/bathtimefish/items/a9b23681720527c0bd7e?fbclid=IwAR3sbaoBn09U7pFL4AKyEOXMi0wNXyAYi9jODUzO1muYr-N7q6hFG-hDfKs\" target=\"_blank\">DonkeyCar3シミュレーターで強化学習してみる</a>のマネをしてDonkeyCarシミュレータライブラリの中にあるサンプルのddqn.pyを実行してみる。<br />\n参考:<br />\nDQNについてはここが分かりやすかったかな。<br />\n<a href=\"https://www.tcom242242.net/entry/ai-2/%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/%E6%B7%B1%E5%B1%A4%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/%E3%80%90%E6%B7%B1%E5%B1%A4%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92%E3%80%91deep_q_network_%E3%82%92tensorflow%E3%81%A7%E5%AE%9F%E8%A3%85/\" target=\"_blank\">【深層強化学習,入門】Deep Q Network(DQN)の解説とPythonで実装 〜図を使って説明〜 </a><br />\n<a href=\"https://www.tcom242242.net/entry/ai-2/%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92/%e3%80%90%e6%b7%b1%e5%b1%a4%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92%e3%80%91double-q-network/\" target=\"_blank\">【深層強化学習】Double Deep Q Network(DDQN)</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim\n<span class=\"nb\">cd</span> /work2/donkey_sim\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 donkey_sim\npyenv <span class=\"nb\">local </span>donkey_sim \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n\n<span class=\"c\"># 現時点での最新リリース v21.7.24 をcheckoutしておく</span>\ngit clone https://github.com/tawnkramer/gym-donkeycar <span class=\"nt\">-b</span> v21.07.24\n\n<span class=\"c\"># gym-donkeycarライブラリのインストール</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-e</span> gym-donkeycar\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ngym-donkeycar は -e (–editable) オプション付きでインストールしているので、編集も可能。 \ngit cloneした先を参照しているので、インストール後もgym-donkeycarを削除しちゃダメ。</p>\n\n  <p>githubから直接インストールする場合は以下。<br />\nこの場合、パッケージは通常のディレクトリにインストールされる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n</code></pre></div>  </div>\n  <p>でも、以下でサンプルプログラム使うので、git cloneもしないとダメ。</p>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p>以下のページから実行するプラットフォームに合わせて<code class=\"language-plaintext highlighter-rouge\">DonkeySimXXXX.zip</code>(XXXXはプラットフォーム名)をダウンロードし、<br />\n適当なディレクトリに展開しておきます。<br />\n(Linux/Macの場合は実行属性付けるのを忘れずに)<br />\n<a href=\"https://github.com/tawnkramer/gym-donkeycar/releases\">https://github.com/tawnkramer/gym-donkeycar/releases</a></p>\n\n<p>マシンスペックがそれほど高くない場合は別マシンで実行してリモート接続するのがおススメ。<br />\nSSH接続で実行する場合はリモート必須。</p>\n\n<h2 id=\"patchをあてる\">patchをあてる</h2>\n\n<p>以下のパッチファイルを使用してサンプルプログラムにパッチをあてます。<br />\n内容は、</p>\n<ul>\n  <li>なぜか<code class=\"language-plaintext highlighter-rouge\">gym_donkeycar</code>がimportされてなかった</li>\n  <li>tensorflow 1.13以降2.0未満用の設定をバージョン情報からスキップできるようにした</li>\n  <li>シミュレータのリモート実行対応(hostオプション追加)</li>\n  <li>探索率(ε値)の初期値設定オプションの追加<br />\n探索率(ε値)については<a href=\"https://www.tcom242242.net/entry/ai-2/%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/epsilon-greedy/\" target=\"_blank\">ε-greedy行動選択 </a>を参照</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  rl_sample.patch\n</p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/examples/reinforcement_learning/ddqn.py b/examples/reinforcement_learning/ddqn.py\nindex 87c74f0..5c32f49 100755\n</span><span class=\"gd\">--- a/examples/reinforcement_learning/ddqn.py\n</span><span class=\"gi\">+++ b/examples/reinforcement_learning/ddqn.py\n</span><span class=\"p\">@@ -21,6 +21,8 @@</span> from tensorflow.keras.layers import Activation, Conv2D, Dense, Flatten\n from tensorflow.keras.models import Sequential\n from tensorflow.keras.optimizers import Adam\n \n<span class=\"gi\">+import gym_donkeycar\n+\n</span> EPISODES = 10000\n img_rows, img_cols = 80, 80\n # Convert image into Black and white\n<span class=\"p\">@@ -121,6 +123,9 @@</span> class DQNAgent:\n         if self.epsilon > self.epsilon_min:\n             self.epsilon -= (self.initial_epsilon - self.epsilon_min) / self.explore\n \n<span class=\"gi\">+    def set_epsilon(self, epsilon):\n+        self.epsilon = epsilon\n+\n</span>     def train_replay(self):\n         if len(self.memory) < self.train_start:\n             return\n<span class=\"p\">@@ -196,15 +201,17 @@</span> def run_ddqn(args):\n     run a DDQN training session, or test it's result, with the donkey simulator\n     \"\"\"\n \n<span class=\"gd\">-    # only needed if TF==1.13.1\n-    config = tf.ConfigProto()\n-    config.gpu_options.allow_growth = True\n-    sess = tf.Session(config=config)\n-    K.set_session(sess)\n</span><span class=\"gi\">+    tf_ver = tf.__version__.split('.')\n+    if (tf_ver[0] == 1 and tf_ver[1] >= 13) :\n+        # only needed if TF==1.13.1\n+        config = tf.ConfigProto()\n+        config.gpu_options.allow_growth = True\n+        sess = tf.Session(config=config)\n+        K.set_session(sess)\n</span> \n     conf = {\n         \"exe_path\": args.sim,\n<span class=\"gd\">-        \"host\": \"127.0.0.1\",\n</span><span class=\"gi\">+        \"host\": args.host,\n</span>         \"port\": args.port,\n         \"body_style\": \"donkey\",\n         \"body_rgb\": (128, 128, 128),\n<span class=\"p\">@@ -237,6 +244,9 @@</span> def run_ddqn(args):\n     try:\n         agent = DQNAgent(state_size, action_space, train=not args.test)\n \n<span class=\"gi\">+        if args.epsilon > 0 :\n+            agent.set_epsilon(args.epsilon)\n+\n</span>         throttle = args.throttle  # Set throttle as constant value\n \n         episodes = []\n<span class=\"p\">@@ -350,6 +360,7 @@</span> if __name__ == \"__main__\":\n         default=\"manual\",\n         help=\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\",\n     )\n<span class=\"gi\">+    parser.add_argument(\"--host\", type=str, default=\"127.0.0.1\", help=\"simulator address\")\n</span>     parser.add_argument(\"--model\", type=str, default=\"rl_driver.h5\", help=\"path to model\")\n     parser.add_argument(\"--test\", action=\"store_true\", help=\"agent uses learned model to navigate env\")\n     parser.add_argument(\"--port\", type=int, default=9091, help=\"port to use for websockets\")\n<span class=\"p\">@@ -357,6 +368,7 @@</span> if __name__ == \"__main__\":\n     parser.add_argument(\n         \"--env_name\", type=str, default=\"donkey-warehouse-v0\", help=\"name of donkey sim environment\", choices=env_list\n     )\n<span class=\"gi\">+    parser.add_argument(\"--epsilon\", type=float, default=0.0, help=\"initial epsilon value\")\n</span> \n     args = parser.parse_args()\n</code></pre></div></div>\n\n<p>以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>gym-donkeycar/\npatch <span class=\"nt\">-p1</span> < rl_sample.patch \n</code></pre></div></div>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習しないと話にならないので学習します。<br />\n強化学習は教師データが要らないので、準備がラクチン…  でも学習には時間がかかる…<br />\nDonkeyCar シミュレータをリモートマシンで実行する場合、<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションに<code class=\"language-plaintext highlighter-rouge\">remote</code>を、実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>examples/reinforcement_learning\npython ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルマシンでシミュレータを実行する場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションにDonkeyCar シミュレータ起動コマンドをフルパスで指定します。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションは不要です。<br />\nシミュレータをあらかじめ起動しておく必要はなく、自動的に起動されます。</p>\n</blockquote>\n\n<p>エピソード毎に学習結果が <code class=\"language-plaintext highlighter-rouge\">rl_driver.h5</code>に保存されるので、任意のタイミングでCTRL-Cで中断できます。<br />\n次回学習を再開する場合は、ログとして表示されている<code class=\"language-plaintext highlighter-rouge\">epsilon: 0.XXXXXXX</code>の部分の最後の値を覚えておいてください。<br />\nこのプログラムではε値は0.02を下回ると固定されるので、ある程度学習が進んだ状態では<code class=\"language-plaintext highlighter-rouge\">0.02</code>だと思っても問題ないでしょう。</p>\n\n<p>学習を再開する場合は以下のように上記コマンドに<code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプションを追加して実行します。<br />\n(<code class=\"language-plaintext highlighter-rouge\">0.XXXXXXX</code>の部分は上で覚えておいた値。ピッタリ同じでなくて大体で可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--epsilon</span><span class=\"o\">=</span>0.XXXXXXX\n</code></pre></div></div>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンドに<code class=\"language-plaintext highlighter-rouge\">--test</code>を指定するだけです。<br />\n<code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプションは指定しません。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--test</span>\n</code></pre></div></div>\n<p>うまく学習が進んでいれば、コースアウトすることなく周回してくれるハズ。<br />\n学習時と同様、コースアウトすると自動的にスタート位置に戻って再スタートします。<br />\n適当にCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>以下はソースを読んだ時のメモです。<br />\n書いてみたけど、自分で読んでも なにが何だか分からない…😢</p>\n\n<h2 id=\"冒頭部分\">冒頭部分</h2>\n<p>この辺はお約束なので。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"s\">\"\"\"\nfile: ddqn.py\nauthor: Felix Yu\ndate: 2018-09-12\noriginal: https://github.com/flyyufelix/donkey_rl/blob/master/donkey_rl/src/ddqn.py\n\"\"\"</span>\n<span class=\"kn\">import</span> <span class=\"nn\">argparse</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">signal</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">from</span> <span class=\"nn\">collections</span> <span class=\"kn\">import</span> <span class=\"n\">deque</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">gym</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">tensorflow</span> <span class=\"k\">as</span> <span class=\"n\">tf</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras</span> <span class=\"kn\">import</span> <span class=\"n\">backend</span> <span class=\"k\">as</span> <span class=\"n\">K</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.layers</span> <span class=\"kn\">import</span> <span class=\"n\">Activation</span><span class=\"p\">,</span> <span class=\"n\">Conv2D</span><span class=\"p\">,</span> <span class=\"n\">Dense</span><span class=\"p\">,</span> <span class=\"n\">Flatten</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.models</span> <span class=\"kn\">import</span> <span class=\"n\">Sequential</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.optimizers</span> <span class=\"kn\">import</span> <span class=\"n\">Adam</span>\n\n</code></pre></div></div>\n<h2 id=\"冒頭部分その2\">冒頭部分その2</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">gym_donkey</code>をimportしないとDonkeyCarシミュレータと接続できないので。<br />\nなぜかオリジナルでは入ってなかった。<br />\n<code class=\"language-plaintext highlighter-rouge\">if __name__ == \"__main__\":</code>付けといた方が良いかもしれんが、とりあえずそのままimportしておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">gym_donkeycar</span>\n\n</code></pre></div></div>\n\n<h2 id=\"パラメータの設定\">パラメータの設定</h2>\n<p>意味は以下の通り。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: center\">変数</th>\n      <th style=\"text-align: left\">意味</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: center\">EPISODES</td>\n      <td style=\"text-align: left\">学習回数</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_rows</td>\n      <td style=\"text-align: left\">入力に使用する画像サイズ(Y)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_cols</td>\n      <td style=\"text-align: left\">入力に使用する画像サイズ(X)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_channels</td>\n      <td style=\"text-align: left\">入力に過去何フレーム分のデータを使用するか</td>\n    </tr>\n  </tbody>\n</table>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">EPISODES</span> <span class=\"o\">=</span> <span class=\"mi\">10000</span>\n<span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span> <span class=\"o\">=</span> <span class=\"mi\">80</span><span class=\"p\">,</span> <span class=\"mi\">80</span>\n<span class=\"c1\"># Convert image into Black and white\n</span><span class=\"n\">img_channels</span> <span class=\"o\">=</span> <span class=\"mi\">4</span>  <span class=\"c1\"># We stack 4 frames\n</span></code></pre></div></div>\n\n<h2 id=\"強化学習エージェントクラス\">強化学習エージェントクラス</h2>\n\n<p>強化学習のエージェントを定義したクラスです。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">DQNAgent</span><span class=\"p\">:</span>\n</code></pre></div></div>\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>クラス変数</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: center\">変数</th>\n      <th style=\"text-align: left\">意味</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: center\">t</td>\n      <td style=\"text-align: left\">実行カウンタ(ステータス表示用のみ使用)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">max_Q</td>\n      <td style=\"text-align: left\">Q値の最大値(ステータス表示用のみ使用)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">train</td>\n      <td style=\"text-align: left\">学習モード/テストモード(<code class=\"language-plaintext highlighter-rouge\">--test</code>オプションで指定)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">state_size</td>\n      <td style=\"text-align: left\">モデルの入力層のサイズ。現状未使用</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">action_space</td>\n      <td style=\"text-align: left\">シミュレータの現在のステアリング/スロットル設定値取得用</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">action_size</td>\n      <td style=\"text-align: left\">未使用。たぶん、ステアリング角を何分割するかの定義(15)にすべきだと思う</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">discount_factor</td>\n      <td style=\"text-align: left\">割引率(γ値) (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">learning_rate</td>\n      <td style=\"text-align: left\">学習率 (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">epsilon</td>\n      <td style=\"text-align: left\">現在の探索率(ε値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">initial_epsilon</td>\n      <td style=\"text-align: left\">探索率の最大値  最小率と共に探索率の変更率を計算する(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">epsilon_min</td>\n      <td style=\"text-align: left\">探索率の最小値 学習時の探索率をこれより小さくしない(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">explore</td>\n      <td style=\"text-align: left\">探索率を最小値にするまでの回数(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">batch_size</td>\n      <td style=\"text-align: left\">バッチサイズ (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">train_start</td>\n      <td style=\"text-align: left\">学習開始タイミング(最初は学習を行わない)(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">memory</td>\n      <td style=\"text-align: left\">Experience Buffer</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">model</td>\n      <td style=\"text-align: left\">メインモデル</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">target_model</td>\n      <td style=\"text-align: left\">ターゲットモデル(double DQNなので)</td>\n    </tr>\n  </tbody>\n</table>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state_size</span><span class=\"p\">,</span> <span class=\"n\">action_space</span><span class=\"p\">,</span> <span class=\"n\">train</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">max_Q</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train</span> <span class=\"o\">=</span> <span class=\"n\">train</span>\n\n        <span class=\"c1\"># Get size of state and action\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">state_size</span> <span class=\"o\">=</span> <span class=\"n\">state_size</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_space</span> <span class=\"o\">=</span> <span class=\"n\">action_space</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_size</span> <span class=\"o\">=</span> <span class=\"n\">action_space</span>\n\n        <span class=\"c1\"># These are hyper parameters for the DQN\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">discount_factor</span> <span class=\"o\">=</span> <span class=\"mf\">0.99</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">learning_rate</span> <span class=\"o\">=</span> <span class=\"mf\">1e-4</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1e-6</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1e-6</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span> <span class=\"o\">=</span> <span class=\"mf\">0.02</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">64</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train_start</span> <span class=\"o\">=</span> <span class=\"mi\">100</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">explore</span> <span class=\"o\">=</span> <span class=\"mi\">10000</span>\n\n        <span class=\"c1\"># Create replay memory using deque\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span> <span class=\"o\">=</span> <span class=\"n\">deque</span><span class=\"p\">(</span><span class=\"n\">maxlen</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Create main model and target model\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">build_model</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">build_model</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># Copy the model to target model\n</span>        <span class=\"c1\"># --> initialize the target model so that the parameters of model & target model to be same\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_target_model</span><span class=\"p\">()</span>\n\n</code></pre></div></div>\n<h3 id=\"モデルの生成\">モデルの生成</h3>\n\n<p>そんなに複雑なモデルではないみたい。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">build_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Sequential</span><span class=\"p\">()</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span>\n            <span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">24</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">,</span> <span class=\"n\">input_shape</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">,</span> <span class=\"n\">img_channels</span><span class=\"p\">))</span>\n        <span class=\"p\">)</span>  <span class=\"c1\"># 80*80*4\n</span>        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">32</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Flatten</span><span class=\"p\">())</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Dense</span><span class=\"p\">(</span><span class=\"mi\">512</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n\n        <span class=\"c1\"># 15 categorical bins for Steering angles\n</span>        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Dense</span><span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">activation</span><span class=\"o\">=</span><span class=\"s\">\"linear\"</span><span class=\"p\">))</span>\n\n        <span class=\"n\">adam</span> <span class=\"o\">=</span> <span class=\"n\">Adam</span><span class=\"p\">(</span><span class=\"n\">lr</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">learning_rate</span><span class=\"p\">)</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"nb\">compile</span><span class=\"p\">(</span><span class=\"n\">loss</span><span class=\"o\">=</span><span class=\"s\">\"mse\"</span><span class=\"p\">,</span> <span class=\"n\">optimizer</span><span class=\"o\">=</span><span class=\"n\">adam</span><span class=\"p\">)</span>\n\n        <span class=\"k\">return</span> <span class=\"n\">model</span>\n\n</code></pre></div></div>\n<h3 id=\"rgbグレースケール変換処理\">RGB→グレースケール変換処理</h3>\n<p>シミュレータの出力はRGB画像、モデルの入力はグレースケール画像なので、その変換を行うための関数。<br />\n<code class=\"language-plaintext highlighter-rouge\">cv2.dst = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)</code> で良い気もするが…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">rgb2gray</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">rgb</span><span class=\"p\">):</span>\n        <span class=\"s\">\"\"\"\n        take a numpy rgb image return a new single channel image converted to greyscale\n        \"\"\"</span>\n        <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">dot</span><span class=\"p\">(</span><span class=\"n\">rgb</span><span class=\"p\">[...,</span> <span class=\"p\">:</span><span class=\"mi\">3</span><span class=\"p\">],</span> <span class=\"p\">[</span><span class=\"mf\">0.299</span><span class=\"p\">,</span> <span class=\"mf\">0.587</span><span class=\"p\">,</span> <span class=\"mf\">0.114</span><span class=\"p\">])</span>\n\n</code></pre></div></div>\n\n<h3 id=\"入力画像前処理\">入力画像前処理</h3>\n<p>シミュレータの出力画像をモデルの入力データに変換する処理。<br />\nRGBからグレースケールに変換し、リサイズを行う。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">process_image</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">obs</span><span class=\"p\">):</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rgb2gray</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">obs</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ターゲットモデルのパラメータ更新\">ターゲットモデルのパラメータ更新</h3>\n\n<p>メインモデルのパラメータをターゲットモデルにコピーする</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">update_target_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span><span class=\"p\">.</span><span class=\"n\">set_weights</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">get_weights</span><span class=\"p\">())</span>\n\n</code></pre></div></div>\n\n<h3 id=\"現在の環境での次の行動を取得する\">現在の環境での次の行動を取得する</h3>\n\n<p>乱数を発生し、ε値以下だったら環境が生成したランダム値(<code class=\"language-plaintext highlighter-rouge\">self.action_space.sample()[0]</code>)を返す。<br />\nそれ以外はメインモデルで予測した結果を返す。<br />\nその際、モデルの出力結果そのままではなく、どのステアリング位置に当たるかの量子化を行って返す。<br />\n(得られるのはステアリング情報だけで、スロットル情報は固定値)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Get action from model using epsilon-greedy policy\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_action</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">rand</span><span class=\"p\">()</span> <span class=\"o\"><=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_space</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"c1\"># print(\"Return Max Q Prediction\")\n</span>            <span class=\"n\">q_value</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">)</span>\n\n            <span class=\"c1\"># Convert q array to steering value\n</span>            <span class=\"k\">return</span> <span class=\"n\">linear_unbin</span><span class=\"p\">(</span><span class=\"n\">q_value</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<h3 id=\"状態等の保存\">状態等の保存</h3>\n<p>現在の状態(state)、行動(action)、報酬(reward)、行動後の状態(next_state)、\n終了フラグ(done)をExperience Bufferに保存する。<br />\n(Experience Buffer は Experience Replayに使用するためのデータを保存しておくところ)<br />\n<code class=\"language-plaintext highlighter-rouge\">memory</code> は <code class=\"language-plaintext highlighter-rouge\">collections.dque()</code>で作成しているので、指定サイズを超えたときは古いデータから順に削除される。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">replay_memory</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">next_state</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">((</span><span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">next_state</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">))</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ε値の更新\">ε値の更新</h3>\n\n<p>現在のε値が最小値より大きかったら一定比率で小さくしていく。<br />\n最小値以下になっていたらそのまま。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">update_epsilon</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">></span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">-=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">-</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">explore</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ε値の初期設定\">ε値の初期設定</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプション追加したので、指定値でε値を変更する処理を追加。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">set_epsilon</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">epsilon</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"n\">epsilon</span>\n</code></pre></div></div>\n\n<h3 id=\"学習\">学習</h3>\n\n<p>Experience Bufferから任意の経験を取り出し、Q Networkをミニバッチ学習(Experience Replay)</p>\n\n<p>記憶したデータ数が<code class=\"language-plaintext highlighter-rouge\">self.train_start</code>に達するまでは何もしない。<br />\nバッチ学習に使用するデータをExperience Bufferから取り出し、<br />\nそれぞれの配列にバラす(<code class=\"language-plaintext highlighter-rouge\">state_t</code>,<code class=\"language-plaintext highlighter-rouge\">action_t</code>, <code class=\"language-plaintext highlighter-rouge\">reward_t</code>, <code class=\"language-plaintext highlighter-rouge\">state_t1</code>, <code class=\"language-plaintext highlighter-rouge\">terminal</code>)。<br />\n<code class=\"language-plaintext highlighter-rouge\">state_t</code>と<code class=\"language-plaintext highlighter-rouge\">state_t1</code>は<code class=\"language-plaintext highlighter-rouge\">np.concatenate()</code>でndarrayにまとめておく。<br />\n11行目の<code class=\"language-plaintext highlighter-rouge\">self.model.predict(state_t)</code>は<code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>の取得にしか使用されておらず、</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>はステータス表示にしか使用されてなく、無駄な計算なので、削除するのが良いと思われる(無駄な計算なので)。<br />\nその場合、<code class=\"language-plaintext highlighter-rouge\">targets</code>の初期化は<code class=\"language-plaintext highlighter-rouge\">targets = np.zeros((batch_size, 15))</code>で行う。<br />\n(<code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>を参照しているところも削除。あるいは<code class=\"language-plaintext highlighter-rouge\">get_action()</code>で戻り値として返すのも手か。)</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">state_t1</code>を入力としてメインモデルをターゲットモデルを使用して得られた出力から出力期待値を取得し、<br />\n学習を行う<code class=\"language-plaintext highlighter-rouge\">self.model.train_on_batch(state_t, targets)</code>。<br />\nこの辺は\n<a href=\"https://www.tcom242242.net/entry/ai-2/%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92/%e3%80%90%e6%b7%b1%e5%b1%a4%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92%e3%80%91double-q-network/\" target=\"_blank\">【深層強化学習】Double Deep Q Network(DDQN)</a>\nのソースとかを見ると分かったような分からないような気になれるかも…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">train_replay</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train_start</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span>\n\n        <span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">batch_size</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">))</span>\n        <span class=\"n\">minibatch</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">,</span> <span class=\"n\">batch_size</span><span class=\"p\">)</span>\n\n        <span class=\"n\">state_t</span><span class=\"p\">,</span> <span class=\"n\">action_t</span><span class=\"p\">,</span> <span class=\"n\">reward_t</span><span class=\"p\">,</span> <span class=\"n\">state_t1</span><span class=\"p\">,</span> <span class=\"n\">terminal</span> <span class=\"o\">=</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">minibatch</span><span class=\"p\">)</span>\n        <span class=\"n\">state_t</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">concatenate</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">)</span>\n        <span class=\"n\">state_t1</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">concatenate</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"n\">targets</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">max_Q</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n        <span class=\"n\">target_val</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"n\">target_val_</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">batch_size</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">terminal</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]:</span>\n                <span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">action_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">reward_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">target_val</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">])</span>\n                <span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">action_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">reward_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">discount_factor</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">target_val_</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">a</span><span class=\"p\">])</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">train_on_batch</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">,</span> <span class=\"n\">targets</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"モデルのロード\">モデルのロード</h3>\n\n<p>モデルの読み込み先はメインモデル。<br />\nこのあと、ターゲットモデルへコピーするので、ここではターゲットモデルは触らない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">load_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">load_weights</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"モデルの保存\">モデルの保存</h3>\n\n<p>メインモデルをファイルに保存する。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Save the model which is under training\n</span>    <span class=\"k\">def</span> <span class=\"nf\">save_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save_weights</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"ステアリング角モデル出力形式変換\">ステアリング角→モデル出力形式変換</h2>\n\n<p>ステアリング角(-1~1)をモデル出力形式(要素数15の配列のどれか1つに1が入る)に変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">linear_bin</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    Convert a value to a categorical array.\n\n    Parameters\n    ----------\n    a : int or float\n        A value between -1 and 1\n\n    Returns\n    -------\n    list of int\n        A list of length 15 with one item set to 1, which represents the linear value, and all other items set to 0.\n    \"\"\"</span>\n    <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    <span class=\"n\">b</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">a</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"mi\">2</span> <span class=\"o\">/</span> <span class=\"mi\">14</span><span class=\"p\">))</span>\n    <span class=\"n\">arr</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">)</span>\n    <span class=\"n\">arr</span><span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">b</span><span class=\"p\">)]</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">return</span> <span class=\"n\">arr</span>\n</code></pre></div></div>\n\n<h2 id=\"モデル出力形式ステアリング角変換\">モデル出力形式→ステアリング角変換</h2>\n\n<p>モデル出力のうち、最大値を持つindexに相当するステアリング角を取得する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">linear_unbin</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    Convert a categorical array to value.\n\n    See Also\n    --------\n    linear_bin\n    \"\"\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">15</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"nb\">ValueError</span><span class=\"p\">(</span><span class=\"s\">\"Illegal array length, must be 15\"</span><span class=\"p\">)</span>\n    <span class=\"n\">b</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">)</span>\n    <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">b</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"mi\">2</span> <span class=\"o\">/</span> <span class=\"mi\">14</span><span class=\"p\">)</span> <span class=\"o\">-</span> <span class=\"mi\">1</span>\n    <span class=\"k\">return</span> <span class=\"n\">a</span>\n</code></pre></div></div>\n\n<h2 id=\"メインルーチン\">メインルーチン</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">run_ddqn</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    run a DDQN training session, or test it's result, with the donkey simulator\n    \"\"\"</span>\n</code></pre></div></div>\n\n<h3 id=\"tensorflow-1131でのおまじない\">Tensorflow 1.13.1でのおまじない</h3>\n\n<p>Tensorflow 2 を使用したかったので、処理不要。<br />\nコメントアウトすれば良いのだけれど、なんとなくバージョンで分けてみた。<br />\n1.14以降では要るのかな?要ると思って書いてみた。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tf_ver</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">__version__</span><span class=\"p\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">'.'</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">tf_ver</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">tf_ver</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"mi\">13</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># only needed if TF==1.13.1\n</span>        <span class=\"n\">config</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">ConfigProto</span><span class=\"p\">()</span>\n        <span class=\"n\">config</span><span class=\"p\">.</span><span class=\"n\">gpu_options</span><span class=\"p\">.</span><span class=\"n\">allow_growth</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"n\">sess</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">Session</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">=</span><span class=\"n\">config</span><span class=\"p\">)</span>\n        <span class=\"n\">K</span><span class=\"p\">.</span><span class=\"n\">set_session</span><span class=\"p\">(</span><span class=\"n\">sess</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"シミュレータ環境の構築\">シミュレータ環境の構築</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">body_style</code> には <code class=\"language-plaintext highlighter-rouge\">donkey</code>、 <code class=\"language-plaintext highlighter-rouge\">bare</code>、<code class=\"language-plaintext highlighter-rouge\">car01</code>、<code class=\"language-plaintext highlighter-rouge\">cybertruck</code>、<code class=\"language-plaintext highlighter-rouge\">f1</code>が使用できるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">body_rgb</code> で 色を指定できるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">car_name</code> でシミュレータに表示される名前を指定。複数の車を走らせるときに見分けられるみたい。<br />\n<code class=\"language-plaintext highlighter-rouge\">font_size</code>で名前のフォントサイズを指定。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s\">\"exe_path\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sim</span><span class=\"p\">,</span>\n        <span class=\"s\">\"host\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">host</span><span class=\"p\">,</span>\n        <span class=\"s\">\"port\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">port</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_style\"</span><span class=\"p\">:</span> <span class=\"s\">\"donkey\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_rgb\"</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span>\n        <span class=\"s\">\"car_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"me\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"font_size\"</span><span class=\"p\">:</span> <span class=\"mi\">100</span><span class=\"p\">,</span>\n        <span class=\"s\">\"racer_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"DDQN\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"country\"</span><span class=\"p\">:</span> <span class=\"s\">\"USA\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"bio\"</span><span class=\"p\">:</span> <span class=\"s\">\"Learning to drive w DDQN RL\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"guid\"</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"p\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()),</span>\n        <span class=\"s\">\"max_cte\"</span><span class=\"p\">:</span> <span class=\"mi\">10</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\"># Construct gym environment. Starts the simulator if path is given.\n</span>    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">make</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">env_name</span><span class=\"p\">,</span> <span class=\"n\">conf</span><span class=\"o\">=</span><span class=\"n\">conf</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"プログラム終了時のフックルーチンの定義と登録\">プログラム終了時のフックルーチンの定義と登録</h3>\n\n<p>プログラム終了時にシミュレータの終了処理を行うようにフックルーチンを登録する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># not working on windows...\n</span>    <span class=\"k\">def</span> <span class=\"nf\">signal_handler</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"catching ctrl+c\"</span><span class=\"p\">)</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">unwrapped</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGINT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGTERM</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGABRT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"パラメータ用変数の定義\">パラメータ用変数の定義</h3>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Get size of state and action from environment\n</span>    <span class=\"n\">state_size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">,</span> <span class=\"n\">img_channels</span><span class=\"p\">)</span>\n    <span class=\"n\">action_space</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">action_space</span>  <span class=\"c1\"># Steering and Throttle\n</span></code></pre></div></div>\n\n<h3 id=\"エージェントの生成\">エージェントの生成</h3>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">agent</span> <span class=\"o\">=</span> <span class=\"n\">DQNAgent</span><span class=\"p\">(</span><span class=\"n\">state_size</span><span class=\"p\">,</span> <span class=\"n\">action_space</span><span class=\"p\">,</span> <span class=\"n\">train</span><span class=\"o\">=</span><span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ε値の設定\">ε値の設定</h3>\n\n<p>オプションでε値が指定されていたら設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">></span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">set_epsilon</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スロットル値の設定\">スロットル値の設定</h3>\n\n<p>スロットルの設定は固定値(コマンドラインオプションで設定)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">throttle</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">throttle</span>  <span class=\"c1\"># Set throttle as constant value\n</span>\n        <span class=\"n\">episodes</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n</code></pre></div></div>\n\n<h3 id=\"モデルのロード-1\">モデルのロード</h3>\n\n<p>モデルファイルがあれば読み込む。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">):</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"load the saved model\"</span><span class=\"p\">)</span>\n            <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">load_model</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"学習ループ\">学習ループ</h3>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">for</span> <span class=\"n\">e</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">EPISODES</span><span class=\"p\">):</span>\n\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Episode: \"</span><span class=\"p\">,</span> <span class=\"n\">e</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h4 id=\"スタート位置へ移動\">スタート位置へ移動</h4>\n\n<p><code class=\"language-plaintext highlighter-rouge\">obs</code> ← スタート時のカメラ画像<br />\n<code class=\"language-plaintext highlighter-rouge\">x_t</code> ← <code class=\"language-plaintext highlighter-rouge\">obs</code> をモデルの入力形式に合わせて変換(グレースケール化&リサイズ) <br />\n<code class=\"language-plaintext highlighter-rouge\">s_t</code> ← <code class=\"language-plaintext highlighter-rouge\">x_t</code>を4枚分コピー(入力画像は過去4枚分を使用するので)(ちゃんと<code class=\"language-plaintext highlighter-rouge\">img_channels</code>参照して欲しいけど)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"n\">done</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">reset</span><span class=\"p\">()</span>\n\n            <span class=\"n\">episode_len</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n            <span class=\"n\">x_t</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">process_image</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n\n            <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">stack</span><span class=\"p\">((</span><span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">),</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"c1\"># In Keras, need to reshape\n</span>            <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>  <span class=\"c1\"># 1*80*80*4\n</span></code></pre></div></div>\n\n<h4 id=\"エピソードループ\">エピソードループ</h4>\n\n<p>終了フラグがセットされるまでループ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">done</span><span class=\"p\">:</span>\n</code></pre></div></div>\n\n<h5 id=\"現在の状態から行動を予測しシミュレータで実行\">現在の状態から行動を予測し、シミュレータで実行</h5>\n\n<p><code class=\"language-plaintext highlighter-rouge\">steering</code> ← 予測結果<br />\n<code class=\"language-plaintext highlighter-rouge\">env.step()</code>でシミュレータステップ実行<br />\n<code class=\"language-plaintext highlighter-rouge\">x_t1</code> ←ステップ実行後のカメラ画像<br />\n<code class=\"language-plaintext highlighter-rouge\">s_t1</code> ← 現在の入力データの一番古いものを削除し、今回の画像を追加</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"c1\"># Get action for the current state and go one step in environment\n</span>                <span class=\"n\">steering</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">get_action</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">)</span>\n                <span class=\"n\">action</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">steering</span><span class=\"p\">,</span> <span class=\"n\">throttle</span><span class=\"p\">]</span>\n                <span class=\"n\">next_obs</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">,</span> <span class=\"n\">info</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">(</span><span class=\"n\">action</span><span class=\"p\">)</span>\n\n                <span class=\"n\">x_t1</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">process_image</span><span class=\"p\">(</span><span class=\"n\">next_obs</span><span class=\"p\">)</span>\n\n                <span class=\"n\">x_t1</span> <span class=\"o\">=</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"mi\">1</span><span class=\"p\">)</span>  <span class=\"c1\"># 1x80x80x1\n</span>                <span class=\"n\">s_t1</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">x_t1</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">:,</span> <span class=\"p\">:</span><span class=\"mi\">3</span><span class=\"p\">],</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>  <span class=\"c1\"># 1x80x80x4\n</span></code></pre></div></div>\n\n<h5 id=\"experience-bufferに現在の状態を保存\">Experience Bufferに現在の状態を保存</h5>\n\n<p>ε値の更新も</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"c1\"># Save the sample <s, a, r, s'> to the replay memory\n</span>                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">replay_memory</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">linear_bin</span><span class=\"p\">(</span><span class=\"n\">steering</span><span class=\"p\">)),</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">s_t1</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">)</span>\n                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">update_epsilon</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h5 id=\"学習実行\">学習実行</h5>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n                    <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train_replay</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h5 id=\"ループ更新処理とステータス表示\">ループ更新処理とステータス表示</h5>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">s_t1</span>\n                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"n\">episode_len</span> <span class=\"o\">=</span> <span class=\"n\">episode_len</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">%</span> <span class=\"mi\">30</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span>\n                        <span class=\"s\">\"EPISODE\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">e</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"TIMESTEP\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ ACTION\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">action</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ REWARD\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">reward</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ EPISODE LENGTH\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">episode_len</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ Q_MAX \"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">max_Q</span><span class=\"p\">,</span>\n                    <span class=\"p\">)</span>\n</code></pre></div></div>\n<h5 id=\"ループ更新処理とステータス表示-1\">ループ更新処理とステータス表示</h5>\n\n<p><code class=\"language-plaintext highlighter-rouge\">agent.update_target_model()</code>でターゲットモデルの更新\n<code class=\"language-plaintext highlighter-rouge\">episodes.append(e)</code>はデバッグ用?</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"k\">if</span> <span class=\"n\">done</span><span class=\"p\">:</span>\n\n                    <span class=\"c1\"># Every episode update the target model to be same with model\n</span>                    <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">update_target_model</span><span class=\"p\">()</span>\n\n                    <span class=\"n\">episodes</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n\n                    <span class=\"c1\"># Save model for each episode\n</span>                    <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">save_model</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n\n                    <span class=\"k\">print</span><span class=\"p\">(</span>\n                        <span class=\"s\">\"episode:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">e</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"  memory length:\"</span><span class=\"p\">,</span>\n                        <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">),</span>\n                        <span class=\"s\">\"  epsilon:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">,</span>\n                        <span class=\"s\">\" episode length:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">episode_len</span><span class=\"p\">,</span>\n                    <span class=\"p\">)</span>\n</code></pre></div></div>\n<h4 id=\"エピソードループと学習ループの終わり\">エピソードループと学習ループの終わり</h4>\n<p>キーボード割り込み例外と終了処理</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">except</span> <span class=\"nb\">KeyboardInterrupt</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stopping run...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">finally</span><span class=\"p\">:</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">unwrapped</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"コマンドライン解析処理まわり\">コマンドライン解析処理まわり</h2>\n\n<p>コマンドライン解析処理とメインルーチンへのジャンプ</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n\n    <span class=\"c1\"># Initialize the donkey environment\n</span>    <span class=\"c1\"># where env_name one of:\n</span>    <span class=\"n\">env_list</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-roads-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-avc-sparkfun-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-roboracingleague-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-waveshare-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-minimonaco-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-warren-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-thunderhill-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-circuit-launch-track-v0\"</span><span class=\"p\">,</span>\n    <span class=\"p\">]</span>\n\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s\">\"ddqn\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--sim\"</span><span class=\"p\">,</span>\n        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span>\n        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"manual\"</span><span class=\"p\">,</span>\n        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\"</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--host\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"127.0.0.1\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"simulator address\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"rl_driver.h5\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"agent uses learned model to navigate env\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--port\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">9091</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for websockets\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--throttle\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.3</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"constant throttle for driving\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--env_name\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"name of donkey sim environment\"</span><span class=\"p\">,</span> <span class=\"n\">choices</span><span class=\"o\">=</span><span class=\"n\">env_list</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--epsilon\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"initial epsilon value\"</span><span class=\"p\">)</span>\n\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n    <span class=\"n\">run_ddqn</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"でもってこんな改造をするとちょびっと計算量が減る\">でもって、こんな改造をするとちょびっと計算量が減る</h2>\n<p>シミュレータに表示される車を変更してるのはご愛敬😅</p>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ddqn.py.old\t2021-12-02 06:25:02.149997073 +0900\n</span><span class=\"gi\">+++ ddqn.py\t2021-12-03 07:14:49.346378878 +0900\n</span><span class=\"p\">@@ -98,9 +98,10 @@</span>\n         return np.dot(rgb[..., :3], [0.299, 0.587, 0.114])\n \n     def process_image(self, obs):\n<span class=\"gd\">-        obs = self.rgb2gray(obs)\n-        obs = cv2.resize(obs, (img_rows, img_cols))\n-        return obs\n</span><span class=\"gi\">+        # obs1 = self.rgb2gray(obs)\n+        obs1 = cv2.dst = cv2.cvtColor(obs, cv2.COLOR_RGB2GRAY)\n+        obs2 = cv2.resize(obs1, (img_rows, img_cols))\n+        return obs2\n</span> \n     def update_target_model(self):\n         self.target_model.set_weights(self.model.get_weights())\n<span class=\"p\">@@ -108,13 +109,17 @@</span>\n     # Get action from model using epsilon-greedy policy\n     def get_action(self, s_t):\n         if np.random.rand() <= self.epsilon:\n<span class=\"gd\">-            return self.action_space.sample()[0]\n</span><span class=\"gi\">+            return self.action_space.sample()[0], 0\n</span>         else:\n             # print(\"Return Max Q Prediction\")\n             q_value = self.model.predict(s_t)\n \n<span class=\"gi\">+            max_q = np.amax(q_value[0])\n+            if self.max_Q < max_q :\n+                self.max_Q = max_q\n+\n</span>             # Convert q array to steering value\n<span class=\"gd\">-            return linear_unbin(q_value[0])\n</span><span class=\"gi\">+            return linear_unbin(q_value[0]), max_q\n</span> \n     def replay_memory(self, state, action, reward, next_state, done):\n         self.memory.append((state, action, reward, next_state, done))\n<span class=\"p\">@@ -136,16 +141,16 @@</span>\n         state_t, action_t, reward_t, state_t1, terminal = zip(*minibatch)\n         state_t = np.concatenate(state_t)\n         state_t1 = np.concatenate(state_t1)\n<span class=\"gd\">-        targets = self.model.predict(state_t)\n-        self.max_Q = np.max(targets[0])\n-        target_val = self.model.predict(state_t1)\n-        target_val_ = self.target_model.predict(state_t1)\n</span><span class=\"gi\">+\n+        targets = np.zeros((batch_size, 15))\n+        q_val = self.model.predict(state_t1)\n+        target_q_val = self.target_model.predict(state_t1)\n</span>         for i in range(batch_size):\n             if terminal[i]:\n                 targets[i][action_t[i]] = reward_t[i]\n             else:\n<span class=\"gd\">-                a = np.argmax(target_val[i])\n-                targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_val_[i][a])\n</span><span class=\"gi\">+                a = np.argmax(q_val[i])\n+                targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_q_val[i][a])\n</span> \n         self.model.train_on_batch(state_t, targets)\n \n<span class=\"p\">@@ -213,8 +218,8 @@</span>\n         \"exe_path\": args.sim,\n         \"host\": args.host,\n         \"port\": args.port,\n<span class=\"gd\">-        \"body_style\": \"donkey\",\n-        \"body_rgb\": (128, 128, 128),\n</span><span class=\"gi\">+        \"body_style\": \"f1\",\n+        \"body_rgb\": (255, 128, 128),\n</span>         \"car_name\": \"me\",\n         \"font_size\": 100,\n         \"racer_name\": \"DDQN\",\n<span class=\"p\">@@ -273,7 +278,7 @@</span>\n             while not done:\n \n                 # Get action for the current state and go one step in environment\n<span class=\"gd\">-                steering = agent.get_action(s_t)\n</span><span class=\"gi\">+                steering, max_Q = agent.get_action(s_t)\n</span>                 action = [steering, throttle]\n                 next_obs, reward, done, info = env.step(action)\n \n<span class=\"p\">@@ -305,7 +310,7 @@</span>\n                         \"/ EPISODE LENGTH\",\n                         episode_len,\n                         \"/ Q_MAX \",\n<span class=\"gd\">-                        agent.max_Q,\n</span><span class=\"gi\">+                        max_Q,\n</span>                     )\n \n                 if done:\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その2)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(PPO2編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_1.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a>\nではポリシーにDDQNを使用したサンプルを実行してみたが、今回はもう一つのサンプル(PPO2を使用)を試してみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim2\n<span class=\"nb\">cd</span> /work2/donkey_sim2\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv <span class=\"nb\">install </span>3.7.12 \npyenv virtualenv 3.7.12 donkey_sim2\npyenv <span class=\"nb\">local </span>donkey_sim2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>stable-baselines\npip <span class=\"nb\">install </span><span class=\"nv\">tensorflow</span><span class=\"o\">==</span>1.14.0\n\n<span class=\"c\"># 現時点での最新リリース v21.7.24 をcheckoutしておく</span>\ngit clone https://github.com/tawnkramer/gym-donkeycar <span class=\"nt\">-b</span> v21.07.24\n\n<span class=\"c\"># gym-donkeycarライブラリのインストール</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-e</span> gym-donkeycar\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nstable-baselines は tensorflow ~1.14.0 しかサポートしていないので、バージョン指定してインストールする。<br />\ntensorflow 1.14.0 は python ~3.7 しかサポートしていないので、3.7系の最新版を使用している。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ngym-donkeycar は -e (–editable) オプション付きでインストールしているので、編集も可能。 \ngit cloneした先を参照しているので、インストール後もgym-donkeycarを削除しちゃダメ。</p>\n\n  <p>githubから直接インストールする場合は以下。<br />\nこの場合、パッケージは通常のディレクトリにインストールされる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n</code></pre></div>  </div>\n  <p>でも、以下でサンプルプログラム使うので、git cloneもしないとダメ。</p>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a> と同じ</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<p>用意されているサンプルプログラムにパッチをあてようと思ったのだけど、<br />\n<code class=\"language-plaintext highlighter-rouge\">ppo_train.py</code> はやっつけ感満載のイマイチソースなので いっそ全書き換えで。</p>\n\n<p>主な対応内容は、</p>\n<ul>\n  <li>一定間隔でモデルの保存を行うようcallbackクラスの追加</li>\n  <li>シミュレータのリモート実行対応(<code class=\"language-plaintext highlighter-rouge\">--host</code>)</li>\n  <li>学習回数指定オプション(<code class=\"language-plaintext highlighter-rouge\">--step</code>)</li>\n  <li>テスト回数指定オプション(<code class=\"language-plaintext highlighter-rouge\">--test_step</code>)</li>\n  <li>保存したモデルファイルをロードしてからの学習に対応</li>\n  <li></li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ppo.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">signal</span>\n<span class=\"kn\">import</span> <span class=\"nn\">argparse</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">typing</span>\n<span class=\"kn\">from</span> <span class=\"nn\">typing</span> <span class=\"kn\">import</span> <span class=\"n\">Union</span><span class=\"p\">,</span> <span class=\"n\">List</span><span class=\"p\">,</span> <span class=\"n\">Dict</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">,</span> <span class=\"n\">Optional</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">gym</span>\n<span class=\"kn\">import</span> <span class=\"nn\">gym_donkeycar</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines</span> <span class=\"kn\">import</span> <span class=\"n\">PPO2</span>\n<span class=\"c1\"># from stable_baselines.common import set_global_seeds\n</span><span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.policies</span> <span class=\"kn\">import</span> <span class=\"n\">CnnPolicy</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.vec_env</span> <span class=\"kn\">import</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.callbacks</span> <span class=\"kn\">import</span> <span class=\"n\">EventCallback</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.base_class</span> <span class=\"kn\">import</span> <span class=\"n\">BaseRLModel</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MyCallback</span><span class=\"p\">(</span><span class=\"n\">EventCallback</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> \n                 <span class=\"n\">eval_env</span><span class=\"p\">:</span> <span class=\"n\">Union</span><span class=\"p\">[</span><span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">Env</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span><span class=\"p\">],</span>\n                 <span class=\"n\">save_freq</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">1000</span><span class=\"p\">,</span>\n                 <span class=\"n\">save_file</span><span class=\"p\">:</span> <span class=\"n\">Optional</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"bp\">None</span><span class=\"p\">,</span>\n                 <span class=\"n\">verbose</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">MyCallback</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"n\">verbose</span><span class=\"o\">=</span><span class=\"n\">verbose</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span> <span class=\"o\">=</span> <span class=\"n\">save_file</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">=</span> <span class=\"n\">save_freq</span>\n        \n        <span class=\"c1\"># Convert to VecEnv for consistency\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">eval_env</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span><span class=\"p\">):</span>\n            <span class=\"n\">eval_env</span> <span class=\"o\">=</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">([</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"n\">eval_env</span><span class=\"p\">])</span>\n            \n        <span class=\"k\">assert</span> <span class=\"n\">eval_env</span><span class=\"p\">.</span><span class=\"n\">num_envs</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"You must pass only one environment for evaluation\"</span>\n        \n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">eval_env</span> <span class=\"o\">=</span> <span class=\"n\">eval_env</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">init_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">model</span><span class=\"p\">:</span> <span class=\"s\">'BaseRLModel'</span><span class=\"p\">)</span> <span class=\"o\">-></span> <span class=\"bp\">None</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#### INIT ####\"</span><span class=\"p\">)</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">EventCallback</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">init_callback</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">_init_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#### _INIT ####\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">_on_step</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"o\">-></span> <span class=\"nb\">bool</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">></span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">n_calls</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">now</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">now</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">verbose</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">now</span><span class=\"si\">}</span><span class=\"s\"> saving...'</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span> <span class=\"p\">:</span>\n                <span class=\"n\">now_str</span>  <span class=\"o\">=</span> <span class=\"n\">now</span><span class=\"p\">.</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s\">'%y%m%d_%H%M%S'</span><span class=\"p\">)</span>\n                <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span>\n                <span class=\"c1\"># filename = os.path.join(os.path.dirname(self.save_file), f'{now_str}_{os.path.basename(self.save_file)}')\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">True</span>\n    \n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Initialize the donkey environment\n</span>    <span class=\"c1\"># where env_name one of:\n</span>    <span class=\"n\">env_list</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-roads-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-avc-sparkfun-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-roboracingleague-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-waveshare-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-minimonaco-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-warren-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-thunderhill-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-circuit-launch-track-v0\"</span><span class=\"p\">,</span>\n    <span class=\"p\">]</span>\n    \n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s\">\"ppo_train\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--sim\"</span><span class=\"p\">,</span>\n        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span>\n        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"sim_path\"</span><span class=\"p\">,</span>\n        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\"</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--model\"</span><span class=\"p\">,</span>     <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"ppo_donkey\"</span><span class=\"p\">,</span>  <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--host\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"127.0.0.1\"</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"simulator address\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--port\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">9091</span><span class=\"p\">,</span>          <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--step\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">,</span>         <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test_step\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">,</span>             <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test\"</span><span class=\"p\">,</span>      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">,</span>             <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"load the trained model and play\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--env_name\"</span><span class=\"p\">,</span>  <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"name of donkey sim environment\"</span><span class=\"p\">,</span> <span class=\"n\">choices</span><span class=\"o\">=</span><span class=\"n\">env_list</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">test_step</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test_step</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span> <span class=\"ow\">and</span> <span class=\"n\">test_step</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"n\">test_step</span> <span class=\"o\">=</span> <span class=\"mi\">1000</span>\n        \n    <span class=\"c1\"># Complement the file extension\n</span>    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s\">\".zip\"</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span> <span class=\"o\">+</span> <span class=\"s\">\".zip\"</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    \n    <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s\">\"exe_path\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sim</span><span class=\"p\">,</span>\n        <span class=\"s\">\"host\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">host</span><span class=\"p\">,</span>\n        <span class=\"s\">\"port\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">port</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_style\"</span><span class=\"p\">:</span> <span class=\"s\">\"car01\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_rgb\"</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span>\n        <span class=\"s\">\"car_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"me\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"font_size\"</span><span class=\"p\">:</span> <span class=\"mi\">100</span><span class=\"p\">,</span>\n        <span class=\"s\">\"racer_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"PPO\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"country\"</span><span class=\"p\">:</span> <span class=\"s\">\"USA\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"bio\"</span><span class=\"p\">:</span> <span class=\"s\">\"Learning to drive w PPO RL\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"guid\"</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"p\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()),</span>\n        <span class=\"s\">\"max_cte\"</span><span class=\"p\">:</span> <span class=\"mi\">10</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\"># Make an environment test our trained policy\n</span>    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">make</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">env_name</span><span class=\"p\">,</span> <span class=\"n\">conf</span><span class=\"o\">=</span><span class=\"n\">conf</span><span class=\"p\">)</span>\n    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">([</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"n\">env</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># hook terninate signal\n</span>    <span class=\"k\">def</span> <span class=\"nf\">signal_handler</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"catching ctrl+c\"</span><span class=\"p\">)</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGINT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGTERM</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGABRT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">try</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># check model path\n</span>        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">):</span>\n            <span class=\"c1\"># load model\n</span>            <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">PPO2</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">,</span> <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span> \n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">:</span>\n                <span class=\"c1\"># create model\n</span>                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"create new model\"</span><span class=\"p\">)</span>\n                <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">PPO2</span><span class=\"p\">(</span><span class=\"n\">CnnPolicy</span><span class=\"p\">,</span> <span class=\"n\">env</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">raise</span> <span class=\"nb\">ValueError</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Error: the file </span><span class=\"si\">{</span><span class=\"n\">model_path</span><span class=\"si\">}</span><span class=\"s\"> could not be found\"</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># change throttle lower limit\n</span>        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">action_space</span><span class=\"p\">.</span><span class=\"n\">low</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.1</span>\n        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">:</span>\n            <span class=\"c1\"># in training mode\n</span>            \n            <span class=\"n\">callback</span> <span class=\"o\">=</span> <span class=\"n\">MyCallback</span><span class=\"p\">(</span><span class=\"n\">env</span><span class=\"p\">,</span> <span class=\"n\">save_freq</span> <span class=\"o\">=</span> <span class=\"mi\">5000</span><span class=\"p\">,</span> <span class=\"n\">save_file</span> <span class=\"o\">=</span> <span class=\"n\">model_path</span><span class=\"p\">,</span> <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"c1\"># callback = MyCallback(env, save_freq = 10, verbose = 1)\n</span>            \n            <span class=\"c1\"># set up model in learning mode with goal number of timesteps to complete\n</span>            <span class=\"c1\"># model.learn(total_timesteps=10000)\n</span>            <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">learn</span><span class=\"p\">(</span><span class=\"n\">total_timesteps</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">,</span> <span class=\"n\">callback</span><span class=\"o\">=</span><span class=\"n\">callback</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># save model\n</span>            <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stert testing...\"</span><span class=\"p\">)</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">reset</span><span class=\"p\">()</span>\n        <span class=\"n\">prev_done_count</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">test_step</span><span class=\"p\">):</span>\n            <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">_states</span> <span class=\"o\">=</span> <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n            <span class=\"n\">obs</span><span class=\"p\">,</span> <span class=\"n\">rewards</span><span class=\"p\">,</span> <span class=\"n\">dones</span><span class=\"p\">,</span> <span class=\"n\">info</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">(</span><span class=\"n\">action</span><span class=\"p\">)</span>\n            <span class=\"c1\"># print(f\"cnt : {i}    rewards : {rewards[0]}    dones : {dones[0]}    pos : {info[0]['pos']}, CrossTrackError : {info[0]['cte']}, speed : {info[0]['speed']}\")\n</span>            <span class=\"c1\"># print(f\"+++ info: {info} +++\")\n</span>            <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">render</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">dones</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'dones flag detected : </span><span class=\"si\">{</span><span class=\"n\">i</span> <span class=\"o\">-</span> <span class=\"n\">prev_done_count</span><span class=\"si\">}</span><span class=\"s\">  (</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n                <span class=\"n\">prev_done_count</span> <span class=\"o\">=</span> <span class=\"n\">i</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done testing\"</span><span class=\"p\">)</span>\n        \n    <span class=\"k\">except</span> <span class=\"nb\">KeyboardInterrupt</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stopping run...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n</code></pre></div></div>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習。<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションに<code class=\"language-plaintext highlighter-rouge\">remote</code>を、実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>examples/reinforcement_learning\npython ppo.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n学習回数を指定するには<code class=\"language-plaintext highlighter-rouge\">--step</code>オプションで指定します。<br />\n指定する回数はエピソード数ではなく、アクション数。<br />\n例えば、<code class=\"language-plaintext highlighter-rouge\">--step=100000</code></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nローカルマシンでシミュレータを実行する場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションにDonkeyCar シミュレータ起動コマンドをフルパスで指定します。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションは不要です。<br />\nシミュレータをあらかじめ起動しておく必要はなく、自動的に起動されます。</p>\n</blockquote>\n\n<p>モデルの保存間隔は<code class=\"language-plaintext highlighter-rouge\">MyCallback</code>のインスタンス生成時に<code class=\"language-plaintext highlighter-rouge\">save_freq = 5000</code>で指定していますので、必要なら変更してください。</p>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンドに<code class=\"language-plaintext highlighter-rouge\">--test</code>を指定するだけです。<br />\nテストを実行するステップ数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--test_step</code>オプションで指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ppo.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--test</span> \n</code></pre></div></div>\n<p>途中で止めたい場合はCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>ほど複雑じゃないので省略。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その3)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(VAE+SAC編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_1.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a>、\n<a href=\"/memoBlog/2021/12/09/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その2)</a>\nではDonkeyCar simulatorに添付のサンプルプログラムを実行してみたが、結果がイマイチだったので別のプログラムを試してみる。<br />\n<del>パクった</del> 参考にしたのは、<a href=\"https://masato-ka.hatenablog.com/entry/2020/04/29/153505?fbclid=IwAR1sjfiN1dAGRn6vIKU9vOSnfoCCsmgvVXRV_MWaLdUr3FeIUvUAr1Ef_yo\" target=\"_blank\">Jetson Nanoで動く深層強化学習を使ったラジコン向け自動運転ソフトウェアの紹介</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim3\n<span class=\"nb\">cd</span> /work2/donkey_sim3/\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 donkey_sim3\npyenv <span class=\"nb\">local </span>donkey_sim3 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>torch\npip <span class=\"nb\">install </span>torchvision\npip <span class=\"nb\">install </span>pyyaml\npip <span class=\"nb\">install </span>stable_baselines3\npip <span class=\"nb\">install </span>gym\npip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n\n<span class=\"c\"># tensorboard も必要</span>\npip <span class=\"nb\">install </span>tensorboard\n<span class=\"c\"># たぶん要らないけど、念のため入れとく(tensorboard 実行時になんか言われるので)</span>\npip <span class=\"nb\">install </span>tensorflow\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n今回は stable-baselines3 を使用するので、 tensorflow ではなく、pytorch。<br />\nしかし、tensorboardは必要(学習ログ記録のため)。<br />\ntensorboardで可視化機能を使用する際はtensorflowが入ってないと実行時になんか言われるので\n念のためtensorflowも入れとく(たぶん入れなくても大丈夫)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n試したときのモジュール類のバージョンは以下の通り</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>opencv-python                4.5.4.60\ntorch                        1.10.0\ntorchvision                  0.11.1\nPyYAML                       6.0\nstable-baselines3            1.3.0\ngym                          0.19.0\ngym-donkeycar                1.1.1      ← Githubのtagはv21.07.24\ntensorboard                  2.7.0\ntensorflow                   2.7.0\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a> と同じ</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n<h3 id=\"プログラム拾ってくる\">プログラム拾ってくる。</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/masato-ka/airc-rl-agent.git\n<span class=\"nb\">cd </span>airc-rl-agent/\ngit checkout <span class=\"nt\">-b</span> release-v1.5.2 refs/tags/release-v1.5.2\n</code></pre></div></div>\n\n<h3 id=\"パッチをあてる\">パッチをあてる。</h3>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/config.yml b/config.yml\nindex bda2308..3bf2ad4 100644\n</span><span class=\"gd\">--- a/config.yml\n</span><span class=\"gi\">+++ b/config.yml\n</span><span class=\"p\">@@ -48,8 +48,8 @@</span> AGENT_SETTING:\n   N_COMMAND_HISTORY: 20\n   MIN_STEERING: -1.0\n   MAX_STEERING: 1.0\n<span class=\"gd\">-  MIN_THROTTLE: 0.7 # 0.4\n-  MAX_THROTTLE: 0.95 # 0.9\n</span><span class=\"gi\">+  MIN_THROTTLE: 0.3  # 0.7  # 0.4\n+  MAX_THROTTLE: 0.95 # 0.95 # 0.9\n</span>   MAX_STEERING_DIFF: 0.9 #0.35\n \n JETRACER_SETTING:\n<span class=\"gh\">diff --git a/learning_racer/commands/subcommand.py b/learning_racer/commands/subcommand.py\nindex 0cf6eac..e4474e7 100644\n</span><span class=\"gd\">--- a/learning_racer/commands/subcommand.py\n</span><span class=\"gi\">+++ b/learning_racer/commands/subcommand.py\n</span><span class=\"p\">@@ -56,6 +56,7 @@</span> def command_train(args, config):\n     model = CustomSAC(agent, args, config)\n     model.lean(callback=callback)\n     model.save(args.save)\n<span class=\"gi\">+    agent.close()\n</span> \n \n def command_demo(args, config):\n<span class=\"p\">@@ -65,4 +66,14 @@</span> def command_demo(args, config):\n     for step in range(args.time_steps):\n         if step % 100 == 0: print(\"step: \", step)\n         action, _states = model.predict(obs)\n<span class=\"gi\">+        steer = action[0]\n+        throttle = action[1]\n</span>         obs, rewards, dones, info = agent.step(action)\n<span class=\"gi\">+        steer2 = agent.action_history[-2]\n+        throttle2 = agent.action_history[-1]\n+        speed = info[\"speed\"]\n+        cte = info[\"cte\"]\n+        print(f'steer:{steer:9.5f}    steer2:{steer2:9.5f}    throttle:{throttle:9.5f}    throttle2:{throttle2:9.5f}    speed:{speed:9.5f}    cte:{cte:9.5f}')\n+        if dones :\n+            obs = agent.reset()\n+    agent.close()\n</span><span class=\"gh\">diff --git a/learning_racer/racer.py b/learning_racer/racer.py\nindex 3e67ca2..dee0905 100644\n</span><span class=\"gd\">--- a/learning_racer/racer.py\n</span><span class=\"gi\">+++ b/learning_racer/racer.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import sys\n+import os\n+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))\n+\n</span> import argparse\n from learning_racer.commands.subcommand import command_demo, command_train\n from learning_racer.config import ConfigReader\n<span class=\"p\">@@ -8,6 +12,20 @@</span> logger = getLogger(__name__)\n \n __version__ = '1.5.1'\n \n<span class=\"gi\">+track_list = [\n+    \"donkey-generated-roads-v0\",\n+    \"donkey-warehouse-v0\",\n+    \"donkey-avc-sparkfun-v0\",\n+    \"donkey-generated-track-v0\",\n+    \"donkey-mountain-track-v0\",\n+    \"donkey-roboracingleague-track-v0\",\n+    \"donkey-waveshare-v0\",\n+    \"donkey-minimonaco-track-v0\",\n+    \"donkey-warren-track-v0\",\n+    \"donkey-thunderhill-track-v0\",\n+    \"donkey-circuit-launch-track-v0\",\n+]\n+\n</span> parser = argparse.ArgumentParser(description='Learning Racer command.')\n parser.add_argument('--version', action='version', version='learning_racer version {} .'.format(__version__))\n subparser = parser.add_subparsers()\n<span class=\"p\">@@ -39,7 +57,7 @@</span> parser_train.add_argument('-host', '--sim-host', help='Define host IP of DonkeyS\n parser_train.add_argument('-port', '--sim-port', help='Define port number of DonkeySim host.',\n                           default='9091', type=int)\n parser_train.add_argument('-track', '--sim-track', help='Define track name for DonkeySim',\n<span class=\"gd\">-                          default='donkey-generated-track-v0', type=str)\n</span><span class=\"gi\">+                          default='donkey-generated-track-v0', type=str, choices=track_list)\n</span> parser_train.set_defaults(handler=command_train)\n \n # demo subcommand.\n<span class=\"p\">@@ -63,7 +81,7 @@</span> parser_demo.add_argument('-host', '--sim-host', help='Define host IP of DonkeySi\n parser_demo.add_argument('-port', '--sim-port', help='Define port number of DonkeySim host.',\n                          default='9091', type=int)\n parser_demo.add_argument('-track', '--sim-track', help='Define track name for DonkeySim',\n<span class=\"gd\">-                         default='donkey-generated-track-v0', type=str)\n</span><span class=\"gi\">+                         default='donkey-generated-track-v0', type=str, choices=track_list)\n</span> parser_demo.add_argument('-user', '--sim-user', help='Define user name for own car that showed DonkeySim',\n                          default='anonymous', type=str)\n parser_demo.add_argument('-car', '--sim-car', help='Define car model type for own car that showed DonkeySim',\n<span class=\"gh\">diff --git a/learning_racer/sac/custom_sac.py b/learning_racer/sac/custom_sac.py\nindex 734fd95..3642ca8 100644\n</span><span class=\"gd\">--- a/learning_racer/sac/custom_sac.py\n</span><span class=\"gi\">+++ b/learning_racer/sac/custom_sac.py\n</span><span class=\"p\">@@ -21,6 +21,7 @@</span> def _load_sac(agent, args, config, policy):\n                     sde_sample_freq=config.sac_sde_sample_freq()\n                     )\n     else:\n<span class=\"gi\">+        print(f\"**** load model{args.load_model} ****\")\n</span>         model = SAC.load(args.load_model, env=agent,\n                          policy_kwargs=policy,\n                          verbose=config.sac_verbose(),\n<span class=\"p\">@@ -31,7 +32,7 @@</span> def _load_sac(agent, args, config, policy):\n                          ent_coef=config.sac_ent_coef(), learning_rate=config.sac_learning_rate(),\n                          tensorboard_log=\"tblog\", gamma=config.sac_gamma(), tau=config.sac_tau(),\n                          use_sde_at_warmup=config.sac_use_sde_at_warmup(), use_sde=config.sac_use_sde(),\n<span class=\"gd\">-                         sde_sample_freq=config.sac_sample_freq(), n_episodes_rollout=1)\n</span><span class=\"gi\">+                         sde_sample_freq=config.sac_sde_sample_freq(), n_episodes_rollout=1)\n</span>     return model\n \n \n<span class=\"gh\">diff --git a/learning_racer/sac/hyperparam.py b/learning_racer/sac/hyperparam.py\nindex e58b3fa..5b4b3f0 100644\n</span><span class=\"gd\">--- a/learning_racer/sac/hyperparam.py\n</span><span class=\"gi\">+++ b/learning_racer/sac/hyperparam.py\n</span><span class=\"p\">@@ -2,7 +2,6 @@</span> import math\n \n from learning_racer.config.config import ConfigReader\n \n<span class=\"gd\">-hit_counter = 0\n</span> speed_counter = 0\n config = ConfigReader()\n \n<span class=\"p\">@@ -27,29 +26,32 @@</span> def reward_sim(self, done):\n \n \n # For gym_donkey\n<span class=\"gd\">-hit_counter = 0\n</span> speed_counter = 0\n initial = False\n \n \n def episode_over_sim(self):\n<span class=\"gd\">-    global hit_counter, speed_counter, initial\n</span><span class=\"gi\">+    global speed_counter, initial\n</span>     #    print(self.speed)\n \n     if not initial and self.speed > 3.0:\n         initial = True\n \n     if self.hit != \"none\":\n<span class=\"gd\">-        hit_counter += 1\n-        if hit_counter > 5:\n-            self.over = True\n-            hit_counter = 0\n</span><span class=\"gi\">+        self.over = True\n+        initial = False\n+    elif math.fabs(self.cte) > self.max_cte * 1.5:\n+        self.over = True\n+        initial = False\n</span>     elif self.speed < 0.03 and initial:\n         speed_counter += 1\n         if speed_counter > 10:\n             self.over = True\n             speed_counter = 0\n<span class=\"gi\">+            initial = False\n</span>     elif self.missed_checkpoint:\n         self.over = True\n<span class=\"gi\">+        initial = False\n</span>     elif self.dq:\n         self.over = True\n<span class=\"gi\">+        initial = False\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n主な変更内容は、</p>\n  <ul>\n    <li>config.yml\n      <ul>\n        <li>MIN_THROTTLE の値修正(ちょっと速すぎな感じだったので)</li>\n      </ul>\n    </li>\n    <li>learning_racer/commands/subcommand.py\n      <ul>\n        <li>simulatorのクローズ処理を追加</li>\n        <li>demo時の状態表示を追加</li>\n        <li>demo時のdonesステータスでsimulator初期化を追加</li>\n      </ul>\n    </li>\n    <li>learning_racer/racer.py\n      <ul>\n        <li>pip installせずに実行できるよう、sys.pathを修正する部分の追加</li>\n      </ul>\n    </li>\n    <li>learning_racer/sac/custom_sac.py\n      <ul>\n        <li>typo修正</li>\n      </ul>\n    </li>\n    <li>learning_racer/sac/hyperparam.py\n      <ul>\n        <li>エピソード終了判定<code class=\"language-plaintext highlighter-rouge\">episode_over_sim()</code>の変更</li>\n      </ul>\n    </li>\n  </ul>\n\n</blockquote>\n\n<h3 id=\"vaeの学習済みモデルを拾ってくる\">VAEの学習済みモデルを拾ってくる</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>learning_racer/\nwget <span class=\"s2\">\"https://drive.google.com/uc?export=download&id=19r1yuwiRGGV-BjzjoCzwX8zmA8ZKFNcC\"</span> <span class=\"nt\">-O</span> vae.torch\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこのVAEの学習済みモデルは<code class=\"language-plaintext highlighter-rouge\">donkey-generated-track-v0</code>用なので、\n以下の実行ではこのコースを使用する(<code class=\"language-plaintext highlighter-rouge\">-track</code>オプションのデフォルト)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">donkey-waveshare-v0</code>は簡単なコースなので流用できるっぽい。</p>\n</blockquote>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習。<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\nシミュレータ実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python racer.py train <span class=\"nt\">-robot</span><span class=\"o\">=</span>sim <span class=\"nt\">-vae</span><span class=\"o\">=</span>./vae.torch <span class=\"nt\">-config</span><span class=\"o\">=</span>../config.yml <span class=\"nt\">-device</span><span class=\"o\">=</span>cpu <span class=\"nt\">-host</span><span class=\"o\">=</span>192.168.78.200 \n</code></pre></div></div>\n\n<p>追加学習する場合は元のモデルファイルを<code class=\"language-plaintext highlighter-rouge\">-l</code>オプションで指定します。<br />\n学習に使用するステップ数を変更する場合は<code class=\"language-plaintext highlighter-rouge\">-steps</code>オプションで指定します(デフォルトは5000)。<br />\nその他詳細はソースを見てちょ。</p>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンド<code class=\"language-plaintext highlighter-rouge\">train</code>を<code class=\"language-plaintext highlighter-rouge\">demo</code>に変更するだけです。<br />\nテストを実行するステップ数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--steps</code>オプションで指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python racer.py demo <span class=\"nt\">-robot</span><span class=\"o\">=</span>sim <span class=\"nt\">-vae</span><span class=\"o\">=</span>./vae.torch <span class=\"nt\">-config</span><span class=\"o\">=</span>../config.yml <span class=\"nt\">-device</span><span class=\"o\">=</span>cpu <span class=\"nt\">-host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<p>途中で止めたい場合はCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>のはやめとく。</p>\n\n<p>おおざっぱに言うと、コースの画像を入力してその特徴を抽出するVAE(Variational Auto Encoder)と\nVAEの出力と過去の操作(steering/throttle)の履歴を入力に次の操作を決定するSAC(Soft-Actor-Critic)で構成されている。</p>\n\n<p>VAEはあらかじめ大量のコース画像を撮影したデータで学習しておく(<code class=\"language-plaintext highlighter-rouge\">airc-rl-agent/notebooks/colabo/VAE_CNN.ipyn</code>)。<br />\nこの学習はカメラ画像さえ用意できていれば実機(or シミュレータ)は不要なので、Google Colaboratoryなど高性能のマシンで一気に学習できる。<br />\n上記では参照元ページで用意されていた学習済みモデルを使用している。</p>\n\n<p>VAEは車載カメラ画像(RGBのカラー画像)で160x120pixelにリサイズしたものの下部160x80pixelを入力としている。<br />\n出力は32個のデータ。</p>\n\n<p>VAEは160x80x3(38400)の画素データを32の出力に圧縮するので、そのまま画素データを入力するより学習効率が上がるのかな??<br />\nちゃんと検証してないけど、「右カーブ」とか「左カーブ」とか「直進」みたいな情報に集約されるのかな?</p>\n\n<p>SACの入力はVAEの出力(32個)と過去の操作履歴(過去何回分かは<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.N_COMMAND_HISTOR</code>で指定。\n上記手順で使用した設定値は20なので、steeringとthrottleの2個 × 20 で40個)を使用。<br />\n出力はsteeringとthrottleの2個のデータ。</p>\n\n<p>SACの出力はそのまま車の操作に使用するのではなく、<br />\nthrottleは<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.MIN_THROTTLE</code>と<code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.MAX_THROTTLE</code>で指定した範囲に変換。<br />\nsteeringは前回の設定値との差が<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">MAX_STEERING_DIFF</code>で指定した値を超えないように制限処理、<br />\nを行って使用する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でJTAGデバッグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でJTAGデバッグ</h1>\n      <p>ESP32にFT232Hを接続してJTAGデバッグしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>ESP32のデフォルトの開発環境だと、シリアル通信でFlash書き込んで、<br />\nせいぜいprintfデバッグするしかないが、<br />\nJTAG接続でオンチップデバッグ機能を使えば、もっと使いやすくなるはず。</p>\n\n<p>ESP32のボードは<a href=\"https://www.espressif.com/en/products/devkits/esp32-devkitc\" target=\"_blank\">ESP32-DevKitC-VE</a>\n(<a href=\"https://www.espressif.com/sites/default/files/documentation/esp32-wrover-e_esp32-wrover-ie_datasheet_en.pdf\" target=\"_blank\">ESP32-WROVER-E</a>搭載)\nを使用。</p>\n\n<p>JTAGコントローラは<a href=\"https://ftdichip.com/products/ft232hl/\" target=\"_blank\">FTDIのFT232HL</a>を使用した\n<a href=\"https://akizukidenshi.com/catalog/g/gK-06503/\" target=\"_blank\">秋月電子のAE-FT232HL</a>を使用する(安価なので)。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://www.sunhayato.co.jp/material2/ett09/item_759\" target=\"_blank\">サンハヤトのMM-FT232H</a>\nが拡張コネクタが付いてて使いやすそうなんだけど、お値段かなりお高め…orz…</p>\n</blockquote>\n\n<p>IDEは以前はEclipse一択だったけど、最近はVisual Studio Code に拡張機能<a href=\"https://platformio.org/\" target=\"_blank\">PlatformIO</a>を使うのが\n流行ってるみたいなので、こっちを選択。<br />\nもう Visual Studio Code 最強だな…</p>\n\n<h1 id=\"まずはチュートリアルに沿って試してみる\">まずはチュートリアルに沿って試してみる</h1>\n\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html\" target=\"_blank\">PlatformIOの公式チュートリアル</a>に沿ってツールのインストール~JTAGを使用しないプログラムの書き込み、実行を試す。</p>\n\n<p>まずはツールとボードの動作確認ということで、まだJTAGモジュールは接続しない。</p>\n\n<h2 id=\"ツールのインストール\">ツールのインストール</h2>\n<p>これは上記ページには書いてないので、こっちを参照(Visual Studio Codeインストール済みなら参照するまでもないけど。)<br />\n<a href=\"https://kunsen.net/2018/07/28/post-618/\" target=\"_blank\">薫染庵 途上日誌 PlatformIO IDE for VSCode でESP32のプログラム開発</a><br />\n「3 ESP32プロジェクト作成」の手前まで(以降の説明はarduinoプロジェクトなので)。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPlatformIOのインストールには結構時間がかかる(数分くらい)。 \n右下に出るinstalling~のウィンドウが見難いので「ハングアップした~」と焦って強制終了しないように注意。</p>\n</blockquote>\n\n<h2 id=\"プロジェクトの作成\">プロジェクトの作成</h2>\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#setting-up-the-project\" target=\"_blank\">公式チュートリアルのSetting Up the Project</a>\nに従ってプロジェクトを作成。</p>\n<ul>\n  <li>Nameにプロジェクト名を設定</li>\n  <li>Boardで<code class=\"language-plaintext highlighter-rouge\">Espressif ESP32 Dev Module</code>を選択</li>\n  <li>Frameworkで<code class=\"language-plaintext highlighter-rouge\">Espressif IoT Development Framework</code>を選択(ESP-IDF)</li>\n  <li>Project Wizardの一番下、Locationのチェックをはずすとフォルダを選択できる<br />\nここで指定したフォルダの下にNameで設定した名前のフォルダが作られる<br />\nチェックしたままだと<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%\\Documents\\PlatformIO\\Projects\\</code>に作成されるらしい</li>\n  <li>「このフォルダーないのファイルの作成者を信頼しますか?」と聞かれたら、「はい」を選択</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n初回のみ、プロジェクトを作成すると、自動でESP-IDFがインストールされる。<br />\n環境にもよるけど、15分とかのオーダで覚悟してちょ。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nESP-IDFのインストールにはpythonが必要だが、platformioが自前で持っているのでインストールしなくても大丈夫っぽい。<br />\ngitはインストールしとかないとダメなのかな?なくても大丈夫な気もするけどわからん。</p>\n</blockquote>\n\n<h2 id=\"iniファイルの修正\">iniファイルの修正</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">platformio.ini</code>に<code class=\"language-plaintext highlighter-rouge\">monitor_speed = 115200</code>の1行を追加<br />\n最終的なの内容は以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = espidf\nmonitor_speed = 115200\n</code></pre></div></div>\n\n<h2 id=\"ソースコードの追加\">ソースコードの追加</h2>\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#adding-code-to-the-generated-project\" target=\"_blank\">公式チュートリアルのAdding Code to the Generated Project</a>\nにあるソースを<code class=\"language-plaintext highlighter-rouge\">src\\main.c</code>にコピペする</p>\n\n<blockquote>\n  <p>[!NOTE]\nCMakeLists.txtがどーたらこーたらとwarningが書いてあるけど、無視して良い。<br />\nバージョン変わってちょっと書き方変わったらしい。</p>\n</blockquote>\n\n<p>そのままでも無問題だけど、以下のパッチをあてておくと LEDがチカチカして かつ コンソールにカウント値が表示されるので、\nプログラムが動いてることが一目瞭然。<br />\n(もちろん、IO26端子にLEDを接続しておかないと見えないよ。端子変えるなら<code class=\"language-plaintext highlighter-rouge\">GPIO_NUM_26</code>の部分(2か所)を適当に変更してちょ。)</p>\n\n<p>あと、<code class=\"language-plaintext highlighter-rouge\">tcpip_adapter_init()</code>が非推奨だとワーニングがでるので、<code class=\"language-plaintext highlighter-rouge\">esp_netif_init()</code>に変更してある。<br />\n参考:<a href=\"https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/tcpip_adapter_migration.html\">https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/tcpip_adapter_migration.html</a></p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.c.org  2021-12-26 11:13:05.474815000 +0900\n</span><span class=\"gi\">+++ main.c      2021-12-26 11:12:42.842345600 +0900\n</span><span class=\"p\">@@ -18,6 +18,9 @@</span>\n #include \"lwip/err.h\"\n #include \"lwip/sys.h\"\n\n+#include       <stdio.h>\n<span class=\"gi\">+#include \"driver/gpio.h\"\n+\n</span> #define EXAMPLE_ESP_WIFI_SSID      \"mywifissid\"\n #define EXAMPLE_ESP_WIFI_PASS      \"mywifipass\"\n #define EXAMPLE_MAX_STA_CONN       (3)\n<span class=\"p\">@@ -40,7 +43,7 @@</span>\n\n void wifi_init_softap()\n {\n<span class=\"gd\">-    tcpip_adapter_init();\n</span><span class=\"gi\">+    esp_netif_init();\n</span>     ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();\n<span class=\"p\">@@ -81,4 +84,14 @@</span>\n\n     ESP_LOGI(TAG, \"ESP_WIFI_MODE_AP\");\n     wifi_init_softap();\n<span class=\"gi\">+\n+    gpio_set_direction(GPIO_NUM_26, GPIO_MODE_OUTPUT);\n+    int level = 0;\n+    int count = 0;\n+    while (true) {\n+        gpio_set_level(GPIO_NUM_26, level);\n+        level = !level;\n+        printf(\"count=%d\\n\", count++);\n+        vTaskDelay(300 / portTICK_PERIOD_MS);\n+    }\n</span> }\n</code></pre></div></div>\n\n<h2 id=\"ビルド\">ビルド</h2>\n<p>ビルド実行方法色々書いてあるけど、お好きな方法でどうぞ。<br />\n初回はライブラリもビルドするので時間がかかる。<br />\n(<code class=\"language-plaintext highlighter-rouge\">platform.ini</code>修正時も?)</p>\n\n<p>ターミナルに<code class=\"language-plaintext highlighter-rouge\">SUCCESS</code>と出てるのを確認して次へ。</p>\n\n<p>ターミナルの内容確認して不要になったら何かキーを押すと閉じられる。</p>\n\n<h2 id=\"ターゲットプログラムのダウンロード\">ターゲットプログラムのダウンロード</h2>\n<p>チュートリアルページにはuploadって書いてあるけど、普通はdownloadだと思うんだけど…<br />\nこれもお好きな方法でどうぞ。</p>\n\n<h2 id=\"実行状況の確認\">実行状況の確認</h2>\n<p>シリアルモニタでコンソール入出力を確認できる。<br />\nこれも起動方法はお好きな方法でどうぞ。</p>\n\n<p>うまく動いてたら、スマホやタブレットでWi-Fiスキャンすると「mywifissid」というSSIDが見つかるはず。<br />\n接続してもつながらないけど、なんか接続要求を受けたのがコンソールに表示されるみたい。</p>\n\n<h1 id=\"jtagデバッガを使用したデバッグ\">JTAGデバッガを使用したデバッグ</h1>\n<p>PlatformIOとESP32の動作が確認できたので、次はJTAGデバッガ。<br />\n念のため、cleanしてbuildファイルを一度消しておくのが良いかもしれない。</p>\n\n<p>でも、公式チュートリアルの<a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#debugging-the-firmware\" target=\"_blank\">Debugging the Firmware</a> \n以降は <a href=\"https://www.olimex.com/Products/ARM/JTAG/ARM-USB-OCD-H/\" target=\"_blank\">OLIMEXのARM-USB-OCD-H</a>\nを使用することが前提なので、今回は参照しない。</p>\n\n<p>代わりに<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h\" target=\"_blank\">Long-ship ESP32をPlatformIO上でJTAG(FT232H)デバッグする</a>を参照。<br />\n(でも、微妙に異なるのでちょっと補足書いとく)<br />\n<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc7\" target=\"_blank\">事前準備(自動書き込み)</a>までは上記で済んでいるのでスキップ。</p>\n\n<h2 id=\"ドライバの更新\">ドライバの更新</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc8\" target=\"_blank\">ドライバ更新</a>\nにあるように、ドライバの更新をする。</p>\n\n<p>ドライバ更新の詳しい手順は<a href=\"https://www.m-kobayashi.org/working_log/2018/06/10_01.html\" target=\"_blank\">ESP32で遊ぶ 開発環境を作る (4)</a>の「FT232HL のドライバをインストール」あたりを参照すると分かりやすい。</p>\n\n<p>最初に PCにFT232Hを接続しておくことを忘れないように。<br />\nツールは、<a href=\"https://zadig.akeo.ie/\" target=\"_blank\">Zadigのページ </a>のダウンロードからダウンロード。2021/12/23現在の最新は2.7。<br />\nメニューのoptions→ListAllDevices をやるのを忘れずに(忘れると表示されなくて「あれ?」となります(^^ゞ ) <br />\n対象のデバイスを見つけやすいように、不要なUSBデバイス(特に他のFTDIデバイス)は取り外しておいた方がいいかも。</p>\n\n<p>これは最初に1回やればOK</p>\n\n<h2 id=\"esp32とft232hの結線\">ESP32とFT232Hの結線</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc9\" target=\"_blank\">結線</a>の記載とは\nボードが異なるので、ボードのコネクタ名を含めて結線情報を掲載しておく。<br />\n以下の端子を結線する。</p>\n\n<table style=\"width:400px;\" border=\"3\">\n  <tbody>\n    <tr bgcolor=\"#ff7f7f\">\n      <th colspan=\"2\" width=\"50%\"><strong>FT232H</strong></th>\n      <th colspan=\"2\"><strong>ESP32</strong></th>\n    </tr>\n    <tr>\n      <td width=\"25%\">AD0(TxD)</td><td>J2-7</td>\n      <td width=\"25%\">IO13</td><td>J1-15</td>\n    </tr>\n    <tr>\n      <td>AD1(RxD)</td><td>J2-8</td>\n      <td>IO12</td><td>J1-13</td>\n    </tr>\n    <tr>\n      <td>AD2(RTS#)</td><td>J2-9</td>\n      <td>IO15</td><td>J2-17</td>\n    </tr>\n    <tr>\n      <td>AD3(CTS#)</td><td>J2-10</td>\n      <td>GPIO14</td><td>J3-12</td>\n    </tr>\n    <tr>\n      <td>AD5</td><td>J2-12</td>\n      <td>EN</td><td>J1-2</td>\n    </tr>\n    <tr>\n      <td>GND</td><td>J1-1</td>\n      <td>GND</td><td>J3-1</td>\n    </tr>\n  </tbody>\n</table>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc9\" target=\"_blank\">結線</a>には<br />\nAC1-EN結線と書いてあるけど、<br />\n設定値から判断してAD5-EN結線と思われる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://www.m-kobayashi.org/working_log/2018/06/10_01.html\" target=\"_blank\">ESP32で遊ぶ 開発環境を作る (4)</a>には<br />\nENの結線書いてないけど、結線なくても動くらしい。<br />\nRESET信号がJTAG側から入るのかな?</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nespressifのページによると、sRSTはオプションで繋いでも対応してるコンフィギュレーションが少ないと書いてある。<br />\nでも、CH_PDってどこやねん?<br />\n<a href=\"https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html#jtag-debugging-selecting-jtag-adapter\">https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html#jtag-debugging-selecting-jtag-adapter</a></p>\n</blockquote>\n\n<h2 id=\"iniファイルの修正-1\">iniファイルの修正</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">platformio.ini</code>に<code class=\"language-plaintext highlighter-rouge\">debug_tool = minimodule</code>の1行を追加<br />\n最終的なの内容は以下の通り。<br />\nこれはプロジェクト毎に必要。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = espidf\nmonitor_speed = 115200\ndebug_tool = minimodule\n</code></pre></div></div>\n<h2 id=\"minimoduleの設定変更\">minimoduleの設定変更</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc11\" target=\"_blank\">minimoduleの設定変更</a> のように以下のパッチでファイル修正<br />\n(コメントは変えなくても良いけど、あとで参照して分からなくなるので変更しておく)</p>\n\n<blockquote>\n  <p>[!WARNING]\nこの段階では<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%.platformio\\packages\\tool-openocd-esp32\\</code>ディレクトリがまだない(ダウウンロードされていない)ので、<br />\n一度、Visual Studio Codeのデバッグサイドバーを開き、デバッグターゲットに「PIO Debug」を選択し、実行ボタン(三角アイコン)をクリック<br />\nコンパイルが行われたあと、デバッガプログラムをダウンロードし、起動される。<br />\nデバッガの起動でエラー(<code class=\"language-plaintext highlighter-rouge\">no device found</code>)になるので、一旦キャンセルし、以下の修正を行う。</p>\n</blockquote>\n\n<p>修正するファイル:<br />\n<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%.platformio\\packages\\tool-openocd-esp32\\share\\openocd\\scripts\\interface\\ftdi\\minimodule.cfg</code></p>\n\n<p>変更内容は、ディスクリプタとPID(FT2232H→FT232H)。<br />\n変更後、Visual Studio Codeの再起動必要。<br />\nこれは最初に1回やればOK</p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- minimodule.cfg.org  2021-07-21 22:38:02.000000000 +0900\n</span><span class=\"gi\">+++ minimodule.cfg      2021-12-26 13:09:51.740579600 +0900\n</span><span class=\"p\">@@ -1,16 +1,16 @@</span>\n #\n<span class=\"gd\">-# FTDI MiniModule\n</span><span class=\"gi\">+# Akizuki AE-FT232HL(FTDI FT232HL)\n</span> #\n<span class=\"gd\">-# http://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT2232H_Mini_Module.pdf\n</span><span class=\"gi\">+# https://akizukidenshi.com/catalog/g/gK-06503/\n</span> #\n\n interface ftdi\n<span class=\"gd\">-ftdi_device_desc \"FT2232H MiniModule\"\n-ftdi_vid_pid 0x0403 0x6010\n</span><span class=\"gi\">+ftdi_device_desc \"Single RS232-HS\"\n+ftdi_vid_pid 0x0403 0x6014\n</span>\n # Every pin set as high impedance except TCK, TDI, TDO and TMS\n ftdi_layout_init 0x0008 0x000b\n\n-# nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip)\n<span class=\"gi\">+# nSRST defined on pin J2-12 of AE-FT232HL(pin ADBUS5 [AD5] on the FT232HL chip)\n</span> # This choice is arbitrary. Use other GPIO pin if desired.\n ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n好きなツール名を付けれれば良いんだけど、できないみたいなので一番近いものを修正して使用するということらしい。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">ftdi_layout_signal</code>の設定値を変えればESP32のEN端子に接続するFT232Hの端子を変更できるはずだけど試してない。<br />\nたぶん、値の意味はbit15から順に、 <code class=\"language-plaintext highlighter-rouge\">GPIOH7</code>、<code class=\"language-plaintext highlighter-rouge\">GPIOH6</code>、・・・、<code class=\"language-plaintext highlighter-rouge\">GPIOH0</code>、<code class=\"language-plaintext highlighter-rouge\">GPIOL3</code>、・・・、<code class=\"language-plaintext highlighter-rouge\">GPIOL0</code>、\n<code class=\"language-plaintext highlighter-rouge\">TMS/CS</code>、<code class=\"language-plaintext highlighter-rouge\">TDO/DI</code>、<code class=\"language-plaintext highlighter-rouge\">TDI/DO</code>、<code class=\"language-plaintext highlighter-rouge\">TCK/SK</code>に割り当てられていて、それらの端子は<code class=\"language-plaintext highlighter-rouge\">AC7</code>~<code class=\"language-plaintext highlighter-rouge\">AC0</code>、<code class=\"language-plaintext highlighter-rouge\">AD7</code>~<code class=\"language-plaintext highlighter-rouge\">AD0</code>にあたるものと思われる。<br />\n<a href=\"https://ftdichip.com/wp-content/uploads/2020/08/DS_FT232H.pdf\" target=\"_blank\">https://ftdichip.com/wp-content/uploads/2020/08/DS_FT232H.pdf</a> の「3.2 FT232H Pin Description」の表の\nMPSSEの桁を参照。<br />\nよって、<code class=\"language-plaintext highlighter-rouge\">ftdi_layout_signal</code>の設定値<code class=\"language-plaintext highlighter-rouge\">0x80</code>はAD5端子にあたると推測できる。<br />\nでも、つながなくても動いてるなぁ… 🤔</p>\n</blockquote>\n\n<h2 id=\"デバッグ\">デバッグ</h2>\n<p>Visual Studio Codeのデバッグサイドバーを開き、デバッグターゲットに「PIO Debug」を選択し、実行ボタン(三角アイコン)をクリックすると\nターゲットの依存関係にしたがってbuildを行い、ダウンロード、実行(<code class=\"language-plaintext highlighter-rouge\">app_main()</code>の先頭で一旦停止)を行う。<br />\nなお、デバッグターゲットに「PIO Debug (skip Pre-Debug)」だと、buildは行わず ダウンロード~のみ行う。\n「PIO Debug (without uploading)」ダウンロードも行わず、実行のみ。<br />\n通常は「PIO Debug」を選んでおけば問題ない。</p>\n\n<p>変数の確認やブレークポイントの設定、実行制御(go, step over, step in,…)などは他の環境と大差ない。 <br />\nレジスタダンプも動いてるっぽい。<br />\nコールスタックも動いてるっぽい。<br />\nメモリと逆アセンブルは動かし方分からんかった…</p>\n\n<blockquote>\n  <p>[!NOTE]\nコンソール入出力もVSCodeで上記のシリアルモニタ起動で送受信を行うことができるが、<br />\n外部ツール(TeraTermなど)でモニタすることが可能。<br />\nFlashの書き換えがJTAG経由なので、シリアルポートを他のツールがつかんだままでも大丈夫みたい。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\nプログラムを実行すると、コンソールに<code class=\"language-plaintext highlighter-rouge\">Brownout detector was triggered</code>と表示されてリセットを繰り返すことがある。<br />\nこれは、電圧低下を検出したことによるfail safeのリセット動作らしい。<br />\nWi-Fiを有効化したとき、モジュールに流れる電流が10mA程度→100~200mA程度(実測値)に上がる。<br />\nモジュールを接続しているUSB Hubにたくさんのデバイスを接続していると、電流を確保できなくなって 電圧が低下することがある模様。<br />\nこの場合、USB Hubに接続されている他のデバイスを取り外すか、セルフパワードHubに交換すると正常に動作するようになる。 <br />\nあと、使用するUSBケーブルのインピーダンスが大きいと電流増加で電圧が低下するので、大電流対応のUSBケーブルを使用しましょう。</p>\n\n</blockquote>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でBLEのデモを動かす</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でBLEのデモを動かす</h1>\n      <p>ESP32にBLEのデモを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>gistにupしたので、gistの埋め込みリンク貼っとく(コードをコピペするのめんどくさかったから)。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/3719faf64374d438fd879ce567becb4b\" target=\"_blank\">こちら</a> \nからどうぞ。</p>\n\n<script src=\"https://gist.github.com/ippei8jp/3719faf64374d438fd879ce567becb4b.js\"></script>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でBLEのデモを動かす 補足</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でBLEのデモを動かす 補足</h1>\n      <p>ESP32にBLEのデモの認証方法についての補足</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a>\nでは認証方法(IO capability なので入出能力と言うべきか? あまり直感的でないのでここでは認証方法と呼んでおこう)<br />\nを<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_NONE</code>(NoInputNoOutput; 入出力なし)に設定していたが、これを別の認証方法に変更する場合についてのメモ。</p>\n<blockquote>\n  <p>[!NOTE]\n自作の範囲だと<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_NONE</code>しか使わないと思うけど、使いたくなった時に備えて。</p>\n</blockquote>\n\n<h1 id=\"esp_io_cap_none-noinputnooutput\">ESP_IO_CAP_NONE (NoInputNoOutput)</h1>\n<p>入出力両方なし。<br />\npasskey(PINcode)入力などはなし。<br />\n接続すると自動的に鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (92315) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (92315) BLE_HEART_RATE:     connection start\nV (92975) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (92975) BLE_HEART_RATE:     event nor handled\nV (93245) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (93245) BLE_HEART_RATE:     event nor handled\nE (97855) BT_BTM: btm_ble_remove_resolving_list_entry_complete remove resolving list error 0x2\nV (98285) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (98285) BLE_HEART_RATE:     event nor handled\nW (98335) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (98375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98375) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (98375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98375) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (98385) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98385) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (98405) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98405) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (98405) nvs: nvs_open_from_partition bt_config.conf 1\nD (98415) nvs: nvs_set_blob bt_cfg_key0 475\nD (98425) nvs: nvs_close 4\nD (98425) nvs: nvs_open_from_partition bt_config.conf 1\nD (98425) nvs: nvs_set_blob bt_cfg_key0 475\nD (98485) nvs: nvs_close 5\nD (98485) nvs: nvs_open_from_partition bt_config.conf 1\nD (98485) nvs: nvs_set_blob bt_cfg_key0 475\nD (98495) nvs: nvs_close 6\nD (98495) nvs: nvs_open_from_partition bt_config.conf 1\nD (98495) nvs: nvs_set_blob bt_cfg_key0 475\nD (98515) nvs: nvs_close 7\nD (98515) nvs: nvs_open_from_partition bt_config.conf 1\nD (98515) nvs: nvs_set_blob bt_cfg_key0 475\nD (98515) nvs: nvs_close 8\nV (98515) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (98525) BLE_HEART_RATE:     remote BD_ADDR: 5d5308bb0efd\nI (98525) BLE_HEART_RATE:     address type = 1\nI (98535) BLE_HEART_RATE:     pair status = success\nI (98535) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_BOND\nI (98545) BLE_HEART_RATE:     Bonded devices number : 1\nI (98545) BLE_HEART_RATE:     Bonded devices list :\nI (98555) BLE_HEART_RATE:        0 :   5d:53:08:bb:0e:fd\nV (99025) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99025) BLE_HEART_RATE:     event nor handled\nV (99545) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99545) BLE_HEART_RATE:     event nor handled\nV (99755) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99755) BLE_HEART_RATE:     event nor handled```\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_out-displayonly\">ESP_IO_CAP_OUT (DisplayOnly)</h1>\n<p>表示機器のみ必要。<br />\n自分が指定するpasskeyをコンソール等に表示し、相手側(ホスト)にpasskey(PINcode)入力させる。</p>\n\n<p>passkeyは<code class=\"language-plaintext highlighter-rouge\">esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, ~);</code>で設定するので、<br />\n必ず表示しなくてはいけない、ということはない(BTヘッドフォンなどでマニュアルに「0000を入力」などと書かれているのと同じ)。</p>\n\n<p>相手側には入力手段が必須。</p>\n\n<p>GAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:               // passkey通知要求イベント\n        // 自身がDisplayOnly(ESP_IO_CAP_OUT)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_PASSKEY_NOTIF_EVT ====\");\n        // passkeyの表示\n        printf(\"**** The passkey Notify number:%06d\\n\", param->ble_security.key_notif.passkey);\n        break;\n</code></pre></div></div>\n\n<p>相手側で入力されたpasskeyが正しければ鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (17105) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (17105) BLE_HEART_RATE:     connection start\nV (17775) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17775) BLE_HEART_RATE:     event nor handled\nV (18025) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (18025) BLE_HEART_RATE:     event nor handled\nV (21935) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_PASSKEY_NOTIF_EVT(11)\nI (21935) BLE_HEART_RATE:     ==== ESP_GAP_BLE_PASSKEY_NOTIF_EVT ====\n**** The passkey Notify number:123456                     ← 相手側にこのpasskeyを入力\nV (22185) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (22185) BLE_HEART_RATE:     event nor handled\nW (33505) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (33535) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33535) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (33535) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33535) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (33545) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33545) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (33575) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33575) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (33575) nvs: nvs_open_from_partition bt_config.conf 1\nD (33575) nvs: nvs_set_blob bt_cfg_key0 250\nD (33595) nvs: nvs_close 4\nD (33595) nvs: nvs_open_from_partition bt_config.conf 1\nD (33595) nvs: nvs_set_blob bt_cfg_key0 264\nD (33605) nvs: nvs_close 5\nD (33605) nvs: nvs_open_from_partition bt_config.conf 1\nD (33605) nvs: nvs_set_blob bt_cfg_key0 347\nD (33625) nvs: nvs_close 6\nD (33625) nvs: nvs_open_from_partition bt_config.conf 1\nD (33625) nvs: nvs_set_blob bt_cfg_key0 407\nD (33625) nvs: nvs_close 7\nD (33625) nvs: nvs_open_from_partition bt_config.conf 1\nD (33635) nvs: nvs_set_blob bt_cfg_key0 462\nD (33635) nvs: nvs_close 8\nD (33645) nvs: nvs_open_from_partition bt_config.conf 1\nD (33645) nvs: nvs_set_blob bt_cfg_key0 476\nD (33655) nvs: nvs_close 9\nV (33655) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (33655) BLE_HEART_RATE:     remote BD_ADDR: 786562f732fc\nI (33655) BLE_HEART_RATE:     address type = 1\nI (33665) BLE_HEART_RATE:     pair status = success\nI (33665) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (33675) BLE_HEART_RATE:     Bonded devices number : 1\nI (33675) BLE_HEART_RATE:     Bonded devices list :\nI (33685) BLE_HEART_RATE:        0 :   78:65:62:f7:32:fc\nV (34185) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34185) BLE_HEART_RATE:     event nor handled\nV (34695) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34695) BLE_HEART_RATE:     event nor handled\nV (34885) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34885) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<p>passkeyを間違えると当然接続されない。<br />\n接続が成功したかどうかは、ログの以下の部分で判別できる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (27095) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (27095) BLE_HEART_RATE:     remote BD_ADDR: 67c015dc4505\nI (27105) BLE_HEART_RATE:     address type = 1\nI (27105) BLE_HEART_RATE:     pair status = fail            ← failしている\nI (27115) BLE_HEART_RATE:     reason = 0x51                 ← 失敗した原因だけど、ドキュメントがない...\nI (27115) BLE_HEART_RATE:     Bonded devices number : 0\nI (27125) BLE_HEART_RATE:     Bonded devices list :\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_in--keyboardonly\">ESP_IO_CAP_IN  (KeyboardOnly)</h1>\n<p>入力機器のみ必要。<br />\n相手側に表示されたpasskeyをコンソール等から入力する。</p>\n\n<p>passkeyは相手側から指定される値なので、どのような値かは相手の仕様による。<br />\n相手側には表示手段が必須。</p>\n\n<p>GAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_PASSKEY_REQ_EVT:                 // passkey 要求\n        // KeyboardOnly(ESP_IO_CAP_IN)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_PASSKEY_REQ_EVT ====\");\n        // 以下の関数で相手側に表示されたパスキーを返す\n        uint32_t    passkey;\n        char        passkey_buff[16];\n        int         passkey_len;\n        do {\n            printf(\"**** input paskey : \");\n            fflush(stdout);\n            passkey_len = uart_gets(passkey_buff, sizeof(passkey_buff));\n        } while (passkey_len == 0);\n        passkey = (uint32_t)strtol(passkey_buff, NULL, 10);\n        esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, passkey);\n        break;\n</code></pre></div></div>\n\n<p>passkeyに使用している<code class=\"language-plaintext highlighter-rouge\">uart_gets()</code>関数については後述。</p>\n\n<p>入力したpasskeyが正しければ鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (16805) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (16805) BLE_HEART_RATE:     connection start\nV (17425) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17425) BLE_HEART_RATE:     event nor handled\nV (17675) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17685) BLE_HEART_RATE:     event nor handled\nE (20765) BT_BTM: btm_ble_remove_resolving_list_entry_complete remove resolving list error 0x2\nV (20955) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_PASSKEY_REQ_EVT(12)\nI (20955) BLE_HEART_RATE:     ==== ESP_GAP_BLE_PASSKEY_REQ_EVT ====\n**** input paskey : 047528                                  ← 相手側で表示されているpasskeyを入力\nV (36455) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (36455) BLE_HEART_RATE:     event nor handled\nW (37335) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (37375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37375) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (37375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37375) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (37385) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37385) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (37405) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37405) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (37415) nvs: nvs_open_from_partition bt_config.conf 1\nD (37415) nvs: nvs_set_blob bt_cfg_key0 476\nD (37425) nvs: nvs_close 4\nD (37425) nvs: nvs_open_from_partition bt_config.conf 1\nD (37425) nvs: nvs_set_blob bt_cfg_key0 476\nD (37495) nvs: nvs_close 5\nD (37495) nvs: nvs_open_from_partition bt_config.conf 1\nD (37495) nvs: nvs_set_blob bt_cfg_key0 476\nD (37505) nvs: nvs_close 6\nD (37505) nvs: nvs_open_from_partition bt_config.conf 1\nD (37505) nvs: nvs_set_blob bt_cfg_key0 476\nD (37525) nvs: nvs_close 7\nD (37525) nvs: nvs_open_from_partition bt_config.conf 1\nD (37525) nvs: nvs_set_blob bt_cfg_key0 476\nD (37525) nvs: nvs_close 8\nV (37525) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (37535) BLE_HEART_RATE:     remote BD_ADDR: 786562f732fc\nI (37535) BLE_HEART_RATE:     address type = 1\nI (37545) BLE_HEART_RATE:     pair status = success\nI (37545) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (37555) BLE_HEART_RATE:     Bonded devices number : 1\nI (37555) BLE_HEART_RATE:     Bonded devices list :\nI (37565) BLE_HEART_RATE:        0 :   78:65:62:f7:32:fc\nV (38255) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (38255) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<p>passkeyを間違えたときの動作は <code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_OUT</code>(DisplayOnly)の場合と同様。</p>\n\n<h1 id=\"esp_io_cap_io-displayyesno\">ESP_IO_CAP_IO (DisplayYesNo)</h1>\n<p>入力機器/表示機器 両方必要。</p>\n\n<p>相手側に表示されたpasskeyとコンソールに表示されたpasskeyを目視確認して等しければyを入力し、相手側でも接続許可をタップする。\n確認せずにYesを選択しても良いけど、それならこのモードを指定する必要はないでしょう。</p>\n\n<p>相手側にも入力/表示手段が必須。<br />\nGAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_NC_REQ_EVT:                      // 数値比較リクエスト イベント\n        // DisplayYesNo(ESP_IO_CAP_IO)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_NC_REQ_EVT ====\");\n        printf(\"**** the passkey Notify number:%d\\n\", param->ble_security.key_notif.passkey);\n        printf(\"**** Accept? (y/n) : \");\n        fflush(stdout);\n        int kb_key = uart_getchar();\n        printf(\"%c\\n\", kb_key);\n        if (kb_key == 'y' || kb_key == 'Y') {\n            // 接続受け入れ\n            esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true);\n        }\n        else {\n            // 接続拒否\n            esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, false);\n        }\n        break;\n</code></pre></div></div>\n\n<p>両方でyesを選択すれば鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (14185) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (14185) BLE_HEART_RATE:     connection start\nV (14855) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (14855) BLE_HEART_RATE:     event nor handled\nV (15145) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (15145) BLE_HEART_RATE:     event nor handled\nE (18775) BT_SMP: Value for numeric comparison = 260195\nV (18775) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_NC_REQ_EVT(16)\nI (18775) BLE_HEART_RATE:     ==== ESP_GAP_BLE_NC_REQ_EVT ====\n**** the passkey Notify number:260195                                               ← 相手側で表示されている数値と目視比較\n**** Accept? (y/n) : y                                                              ← y 入力、相手側でもyesクリック\nV (26785) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (26785) BLE_HEART_RATE:     event nor handled\nW (28245) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (28275) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28275) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (28275) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28285) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (28285) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28295) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (28305) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28305) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (28315) nvs: nvs_open_from_partition bt_config.conf 1\nD (28315) nvs: nvs_set_blob bt_cfg_key0 250\nD (28325) nvs: nvs_close 4\nD (28325) nvs: nvs_open_from_partition bt_config.conf 1\nD (28325) nvs: nvs_set_blob bt_cfg_key0 264\nD (28335) nvs: nvs_close 5\nD (28335) nvs: nvs_open_from_partition bt_config.conf 1\nD (28335) nvs: nvs_set_blob bt_cfg_key0 347\nD (28355) nvs: nvs_close 6\nD (28355) nvs: nvs_open_from_partition bt_config.conf 1\nD (28355) nvs: nvs_set_blob bt_cfg_key0 407\nD (28365) nvs: nvs_close 7\nD (28365) nvs: nvs_open_from_partition bt_config.conf 1\nD (28365) nvs: nvs_set_blob bt_cfg_key0 462\nD (28385) nvs: nvs_close 8\nD (28385) nvs: nvs_open_from_partition bt_config.conf 1\nD (28385) nvs: nvs_set_blob bt_cfg_key0 476\nD (28395) nvs: nvs_close 9\nV (28395) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (28395) BLE_HEART_RATE:     remote BD_ADDR: 612610f26701\nI (28395) BLE_HEART_RATE:     address type = 1\nI (28405) BLE_HEART_RATE:     pair status = success\nI (28405) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (28415) BLE_HEART_RATE:     Bonded devices number : 1\nI (28415) BLE_HEART_RATE:     Bonded devices list :\nI (28425) BLE_HEART_RATE:        0 :   61:26:10:f2:67:01\nV (28905) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (28905) BLE_HEART_RATE:     event nor handled\nV (29435) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (29435) BLE_HEART_RATE:     event nor handled\nV (29655) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (29655) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_kbdisp-keyboard-display\">ESP_IO_CAP_KBDISP (Keyboard display)</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_OUT</code>(DisplayOnly) と <code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_IN</code>(KeyboardOnly) の合わせ技かと思いきや、<br />\n<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_IO</code>(DisplayYesNo)と同じ動作。<br />\nたしかにキーボードと表示両方必要だわな。。。</p>\n\n<h1 id=\"コンソール入力ルーチン\">コンソール入力ルーチン</h1>\n<p>passkeyの入力など、コンソールからの入力が必要な場合、<code class=\"language-plaintext highlighter-rouge\">gets()</code>などを使用するとキー入力待ちの間タスク切り替えが行われずに他のタスクが動作できない。<br />\n(esp-idfはFreeRTOSを使用したマルチタスク構成)。\nそこで、<code class=\"language-plaintext highlighter-rouge\">gets()</code>/<code class=\"language-plaintext highlighter-rouge\">getchar()</code>の代わりとなる関数を用意した。<br />\n動作としては、キー入力待ちの少しの間、<code class=\"language-plaintext highlighter-rouge\">vTaskDelay()</code>でCPUを解放して他のタスクの動作を阻害しないようにしている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">uart_checkkey()</code>は今回使ってないけど、〇秒以内に入力がなければデフォルトで動作、のような動作を実現するのに使用する関数。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">printf()</code>もあちこちのタスクから出力する場合はセマフォで排他処理した方が良いけど、今回は特に問題になりそうにないのでそのまま使用。</p>\n\n<p>Buildは これらのファイルをsrcディレクトリにぶち込むだけでOK。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  uart_console.h\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#include    <stdio.h>\n#include    <stdint.h>\n#include    <stdbool.h>\n\nextern bool uart_checkkey(int loop_num);\nextern int uart_getchar(void);\nextern int uart_gets(char* buf, int max);\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  uart_console.c\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#include    <stdio.h>\n#include    <stdint.h>\n#include    <stdbool.h>\n#include    <string.h>\n#include    <stdarg.h>\n\n#include    \"freertos/FreeRTOS.h\"\n#include    \"freertos/task.h\"\n#include    \"esp_system.h\"\n#include    \"rom/uart.h\"\n\n#include    \"uart_console.h\"\n\n// ========= UARTからの入力待ち ===============================================\n// param    loop_num: 待ち時間(単位100msec)\n// return   true: キー入力があった     false: キー入力はなかった\nbool uart_checkkey(int loop_num)\n{\n    bool    ret = false;\n    uint8_t ch;\n     for (int loop_cnt = 0; loop_cnt < loop_num; loop_cnt++) {\n        // UARTから1文字取得\n        if (uart_rx_one_char(&ch) == OK) {\n            // 入力あり\n            ret = true;\n            break;\n        }\n        if ((loop_cnt % 5)== 0) {\n            // たくさん出ると鬱陶しいので5回毎に\n            putchar('.');\n            fflush(stdout);\n        }\n        // 100ms待つ\n        vTaskDelay(100 / portTICK_RATE_MS);\n    }\n    putchar('\\n');\n\n    // バッファにたまっているデータを読み捨てる\n    while (uart_rx_one_char(&ch) == OK);\n    return ret;\n}\n\n\n// ========= UARTから1文字取得 ================================================\n// param    なし\n// return   文字コード\n// note     CRは無視するので注意\nint uart_getchar(void)\n{\n    uint8_t ch;\n    while (1) {\n        // UARTから1文字取得\n        if (uart_rx_one_char(&ch) == OK) {\n            // 入力あり\n            if (ch == '\\r') {\n                // CRなら次の値を取得\n                continue;\n            }\n            // 入力された値を返す\n            return ch;\n        }\n        // 100ms待つ(CPUを握りっぱなしにしないように)\n        vTaskDelay(100 / portTICK_RATE_MS);\n    }\n}\n\n// ========= UARTから1行取得 ===================================================\n// param    buf: 文字列格納領域へのポインタ\n//          max: 最大文字列長\n// return   入力された文字列長\nint uart_gets(char* buf, int max)\n{\n    int     i = 0;\n    while (i < (max - 1)) {     // null terminate の分を空けておくので max - 1\n        char ch = uart_getchar();\n        if (ch == '\\n') {\n            // LFで終了\n            putchar(ch);\n            fflush(stdout);\n            break;\n        }\n        if (ch == '\\b' || ch == 0x7f) {     // BackSpace or DEL\n            if (i > 0) {        // 先頭でない\n                i--;            // ポインタを一つ前に\n                putchar('\\b');  // 前の文字の表示を削除\n                putchar(' ');\n                putchar('\\b');\n                fflush(stdout);\n            }\n        }\n        else {\n            // それ以外の文字はバッファに格納\n            buf[i] = ch;\n            i++;\n            putchar(ch);        // 表示\n            fflush(stdout);\n        }\n    }\n    buf[i] = '\\0';          // null terminate\n    return i;\n}\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry PiでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry PiでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に Raspberry Pi からアクセスしてみる方法についてのメモ。</p>\n\n<p>Androidでアクセスすると、色々とブラックボックスで処理されてどうなってるのか分かり難いので理解を深める意味で試してみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"メモ\">メモ</h1>\n\n<p>ここにあるように、BLEでは「ボンディング(参照先ではペアリングと表記)なし」で実行するのが無難と思われる<br />\n<a href=\"https://www.musen-connect.co.jp/blog/course/trial-production/ble-beginner-8/\" target=\"_blank\">【サルでもわかるBLE入門】(8) ペアリング</a></p>\n\n<p>Wiresharkによるパケットキャプチャの解説(たぶん、そんなレイヤでデバッグすることはないと思うけど)<br />\n<a href=\"https://re-engines.com/2021/08/16/ble-secure/\" target=\"_blank\">BLEのペアリングをWiresharkでキャプチャしながら学ぶ</a></p>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<h1 id=\"ペリフェラル機器をスキャン\">ペリフェラル機器をスキャン</h1>\n\n<p>まずは接続可能デバイスをスキャンしないと始まらないので、スキャンする。<br />\nもちろん、ESP32側はAdvertising 開始状態である必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo timeout </span>5s hcitool lescan        ← 5秒間スキャンしてみる\nLE Scan ...\n48:BA:7E:24:D0:AA <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n50:17:FC:8C:D1:87 ESP_BLE_HR            ←見つかった\nE4:9A:9F:40:AD:09 <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\nC4:49:BB:8A:7F:6C EX-ZR1800-8A7F6B\nC4:49:BB:8A:7F:6C <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hcitool lescan</code>の実行には<code class=\"language-plaintext highlighter-rouge\">sudo</code>必須。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout 5s</code> を付けずにCTRL+Cで停止しても良い。</p>\n\n<h1 id=\"対象デバイスにアクセスしてみる\">対象デバイスにアクセスしてみる</h1>\n\n<blockquote>\n  <p>[!NOTE]\n<strong>UUIDについて</strong></p>\n\n  <p>16bit UUIDは以下のXXXXの部分(それ以外の部分が一致しないものは128bit UUID)<br />\n<code class=\"language-plaintext highlighter-rouge\">0000XXXX-0000-1000-8000-00805f9b34fb</code></p>\n\n  <p>16bit UUIDは 以下のページを参照<br />\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a></p>\n</blockquote>\n\n<h2 id=\"コマンド起動と接続\">コマンド起動と接続</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">gatttool</code>の実行に<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要。<br />\n<code class=\"language-plaintext highlighter-rouge\">«アドレス»</code> には上でみつけたアドレスを指定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>gatttool <span class=\"nt\">-t</span> random <span class=\"nt\">-I</span> <span class=\"nt\">-b</span> «アドレス»             ← ツールの実行   以下、インタラクティブモードに入る\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> connect                  ← 接続 \nAttempting to connect to 50:17:FC:8C:D1:87\nConnection successful                             ← 接続成功  \n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"サービス一覧を取得\">サービス一覧を取得</h2>\n\n<p>サービスの一覧を取得してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> primary\nattr handle: 0x0001, end grp handle: 0x0005 uuid: 00001801-0000-1000-8000-00805f9b34fb\nattr handle: 0x0014, end grp handle: 0x001c uuid: 00001800-0000-1000-8000-00805f9b34fb\nattr handle: 0x0028, end grp handle: 0xffff uuid: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<p>それぞれこんな意味</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>UUID</th>\n      <th>種別</th>\n      <th>ハンドル範囲</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>1801</td>\n      <td>Generic Attribute</td>\n      <td>0x0001 ~ 0x0005</td>\n    </tr>\n    <tr>\n      <td>1800</td>\n      <td>Generic Acces</td>\n      <td>0x0014 ~ 0x001c</td>\n    </tr>\n    <tr>\n      <td>180d</td>\n      <td>Heart Rate</td>\n      <td>0x0028 ~ 0xffff</td>\n    </tr>\n  </tbody>\n</table>\n\n<h2 id=\"generic-accesを調べてみる\">Generic Accesを調べてみる</h2>\n\n<p>上で調べたGeneric Acces のハンドル範囲を指定して実行。<br />\n表示されるUUIDを\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a>\nで探して右側にメモっておいた。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x14 0x1c\nhandle: 0x0014, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0015, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb        ← device name\nhandle: 0x0017, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb        ← Appearance\nhandle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb        ← Central Address Resolution\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"device-name-を読んでみる\">device name を読んでみる</h2>\n\n<p>とりあえず devece nameを読んでみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x016                       ← handle 0x16<span class=\"o\">(</span>device name<span class=\"o\">)</span> のリード\nCharacteristic value/descriptor: 45 53 50 5f 42 4c 45 5f 48 52     ← 結果\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<p>このままだとなんだかわからん…<br />\n別ウィンドゥで以下を実行。<br />\nただし、<code class=\"language-plaintext highlighter-rouge\">nkf</code>はデフォルトでインストールされていないので<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールする。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">echo</code>の中身には上でリードした結果をコピペする。<br />\nこれを<code class=\"language-plaintext highlighter-rouge\">xxd</code>コマンドでバイナリに変換、<br />\n<code class=\"language-plaintext highlighter-rouge\">nkf</code>で文字コード変換を行う(これだとUTF-8→UTF-8なのであんまり意味ない気が…)。<br />\n結果は改行されずに、プロンプトが続けて表示されるので注意。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">echo</span> <span class=\"s2\">\"45 53 50 5f 42 4c 45 5f 48 52\"</span>  | xxd <span class=\"nt\">-p</span> <span class=\"nt\">-r</span>  | nkf <span class=\"nt\">-WwmQ</span>\nESP_BLE_HR        ← おぉ、読めてる\n<span class=\"nv\">$ </span>\n</code></pre></div></div>\n\n<h2 id=\"heart-rateサービスを調べてみる\">Heart Rateサービスを調べてみる</h2>\n<p>同様にHeart Rateサービスについて調べてみる。<br />\nUUIDについてのメモも同様。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x0028 0xffff\nhandle: 0x0028, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0029, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002a, uuid: 00002a37-0000-1000-8000-00805f9b34fb        ← Heart Rate Measurement\nhandle: 0x002b, uuid: 00002902-0000-1000-8000-00805f9b34fb        ← Client Characteristic Configuration\nhandle: 0x002c, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002d, uuid: 00002a38-0000-1000-8000-00805f9b34fb        ← Body Sensor Location\nhandle: 0x002e, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002f, uuid: 00002a39-0000-1000-8000-00805f9b34fb        ← Heart Rate Control Point\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"heart-rate-control-point-を読み書きしてみる\">Heart Rate Control Point を読み書きしてみる</h2>\n\n<p>Characteristicの読み書きを試すため、Heart Rate Control Point(ハンドル0x2f;c<code class=\"language-plaintext highlighter-rouge\">har-desc</code>の結果から取得)にアクセスしてみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 読んでみる\nCharacteristic value/descriptor: 00                   ← 読めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 01       ← 書いてみる\nCharacteristic value was written successfully         ← 書けた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 確認してみる\nCharacteristic value/descriptor: 01                   ← 書けてる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 0x02     ← 書き込み値に0xを付けたらエラーになる\nError: Characteristic Write Request failed: Attribute value length is invalid\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<h2 id=\"notificationを有効にしてみる\">Notificationを有効にしてみる</h2>\n\n<p>NotificationをONにするにはCCCを操作する。<br />\nNotificationで受信したデータは自動で表示される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 00 00                ← Notification OFFになってる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0100     ← Notification ON にしてみる<span class=\"o\">(</span>0100を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\nNotification handle <span class=\"o\">=</span> 0x002a value: 50 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 51 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 52 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 01 00                ← Notification ONになってる\nNotification handle <span class=\"o\">=</span> 0x002a value: 53 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 54 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 55 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 56 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 57 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0000     ← Notification OFF にしてみる<span class=\"o\">(</span>0000を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>                              ← 以降、Notificationは停止\n</code></pre></div></div>\n\n<h2 id=\"書き込み禁止のcharacteristicに書き込んでみる\">書き込み禁止のCharacteristicに書き込んでみる</h2>\n\n<p>書き込み禁止のCharacteristicに書き込んでみるとどうなるか試してみる。<br />\n当然エラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>50:17:FC:8C:D1:87][LE]> char-write-req 0x2d 01         ← Body Sensor Locationに書き込んでみる\nError: Characteristic Write Request failed: Attribute can<span class=\"s1\">'t be written   ← エラーになった\n</span></code></pre></div></div>\n\n<h2 id=\"切断する\">切断する</h2>\n\n<p>操作が終わったら切断する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> disconnect                        ← 切断\n<span class=\"o\">(</span>gatttool:1840<span class=\"o\">)</span>: GLib-WARNING <span class=\"k\">**</span>: 12:55:27.500: Invalid file descriptor.   ← なんか言われるけど無視して良い\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> <span class=\"nb\">exit</span>                              ← インタラクティブモードの終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る\n</code></pre></div></div>\n\n<h1 id=\"bluetoothctlでアクセス参考\">bluetoothctlでアクセス(参考)</h1>\n\n<p>「ボンディングする」設定の場合、bluetoothctlでアクセスする必要がある。<br />\nボンディングしない設定で使う分には関係ないが、せっかく調べたのでメモっておく。</p>\n\n<p>ボンディング前後でアドレス違ったりしてイマイチ使いにくい。<br />\nどうしても「ボンディングする」にしなければならない場合は、自身のアドレスをパブリックアドレスにしておけばちょっとマシかも。</p>\n\n<h2 id=\"メモ-1\">メモ</h2>\n\n<p>bluetoothctlのコマンド <br />\n<a href=\"https://qiita.com/noraworld/items/55c0cb1eb52cf8dccc12\" target=\"_blank\">bluetoothctl のコマンド一覧と使い方をまとめてみた</a></p>\n\n<p>bluetoothctlだとGATTへのアクセスができないっぽいので、ボンディングの登録/解除以外は使えないっぽいな…</p>\n\n<h2 id=\"前提-1\">前提</h2>\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス           (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングする                           (ESP_LE_AUTH_REQ_SC_MITM_BOND)</li>\n  <li>IO capabilityはcapabilityはDisplayYesNo    (ESP_IO_CAP_IO)</li>\n</ul>\n\n<h2 id=\"起動\">起動</h2>\n\n<p>ツールの起動。<br />\n<code class=\"language-plaintext highlighter-rouge\">sudo</code>必要<br />\n以下インタラクティブモードで操作。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo </span>bluetoothctl                                        ← 起動\n</code></pre></div></div>\n\n<h2 id=\"スキャン\">スキャン</h2>\n\n<p>接続可能デバイスを見つけるためにスキャンする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# scan on                                       ← スキャン開始\nDiscovery started\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>NEW] Device 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\n<span class=\"o\">[</span>NEW] Device 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\n<span class=\"o\">[</span>NEW] Device 62:D1:88:DD:4F:7C リビングルーム\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E RSSI: <span class=\"nt\">-38</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower: 3\n・・・\n<span class=\"o\">[</span>bluetooth]# scan off                                      ← スキャン停止\nDiscovery stopped\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: no\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower is nil\n・・・\n<span class=\"o\">[</span>bluetooth]# devices                                       ← 接続可能デバイスの表示\nDevice 5A:E1:9A:05:96:E0 ESP_BLE_HR                        ← これがESP32<span class=\"o\">(</span>ランダムアドレスなので起動の度に変化する<span class=\"o\">)</span>\nDevice 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\nDevice 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\nDevice 62:D1:88:DD:4F:7C リビングルーム\n\n</code></pre></div></div>\n\n<h2 id=\"agentの登録\">agentの登録</h2>\n\n<p>ボンディングのために、agentを登録する(数字を入力したり、Yes/Noを選択したりするやつ)。<br />\nこちらの設定と相手側の設定の組み合わせで最終的にどの方法が使われるか決定される。<br />\nたとえば、こちら側を NoInputNoOutput に設定しておけば、相手側が DisplayYesNo であってもYes/Noの入力は求められない。<br />\n逆の設定でも同様。</p>\n\n<p>登録された状態で他のCapabilityで登録しようとしても「既に登録済み」と言われるので、念のため一旦登録解除してから登録しておく。<br />\nこのあたり、情報少なくてイマイチよく分からない…</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# agent off                                    ← 一旦agentの登録解除\nAgent unregistered                                         ← 解除された\n<span class=\"o\">[</span>ESP_BLE_HR]# agent DisplayYesNo                           ← DisplayYesNoで登録\nAgent registered                                           ← 登録された\n</code></pre></div></div>\n\n<h2 id=\"接続\">接続</h2>\n\n<p>接続する。<code class=\"language-plaintext highlighter-rouge\">connect</code>でなく、<code class=\"language-plaintext highlighter-rouge\">pair</code>で実行。<br />\n<code class=\"language-plaintext highlighter-rouge\">connect</code>による接続は後述。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# pair 5A:E1:9A:05:96:E0                       ← 接続\nAttempting to pair with 5A:E1:9A:05:96:E0\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 Connected: <span class=\"nb\">yes\n</span>Request confirmation\n<span class=\"o\">[</span>agent] Confirm passkey 680456 <span class=\"o\">(</span><span class=\"nb\">yes</span>/no<span class=\"o\">)</span>:                   ← agentがYes/Noを聞いてくる\n<span class=\"o\">[</span>NEW] Primary Service                                      ← これが自動的に表示されて上の質問を見失うので注意!!\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001\n        00001801-0000-1000-8000-00805f9b34fb\n        Generic Attribute Profile\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001/char0002\n        00002a05-0000-1000-8000-00805f9b34fb\n        Service Changed\n・・・\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0028/char002e\n        00002a39-0000-1000-8000-00805f9b34fb\n        Heart Rate Control Point\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001800-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001801-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 ServicesResolved: <span class=\"nb\">yes\nyes</span>                                                         ← yesを入力<span class=\"o\">(</span>同時に相手側でもyes入力<span class=\"o\">)</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Address: 94:B9:7E:65:AF:5E\nPairing successful                                         ← 接続された\n<span class=\"o\">[</span>ESP_BLE_HR]# paired-devices                               ← ボンディング結果を確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR                        ← advertisingがランダムアドレスでもパブリックアドレスで登録されるので注意!!\n<span class=\"o\">[</span>ESP_BLE_HR]#                                                以降、接続はこのアドレスを使用する!!\n</code></pre></div></div>\n\n<h2 id=\"切断\">切断</h2>\n\n<p>切断する。<br />\nCharacteristicアクセスできないので、実質ボンディングするのみ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断する\nAttempting to disconnect from 94:B9:7E:65:AF:5E            ← パブリックアドレスが表示されている\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<h2 id=\"再接続\">再接続</h2>\n\n<p>ボンディング済みのデバイスに再接続する場合の手順。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスの表示\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# connect 94:B9:7E:65:AF:5E                     ← 表示されたアドレスで接続\nAttempting to connect to 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: <span class=\"nb\">yes\n</span>Connection successful                                      ← 接続された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断\nAttempting to disconnect from 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<p>ボンディングしてない機器に対して<code class=\"language-plaintext highlighter-rouge\">connect</code>すると、<code class=\"language-plaintext highlighter-rouge\">agent off</code> で <code class=\"language-plaintext highlighter-rouge\">pair</code> したような動作になる模様。</p>\n\n<h2 id=\"ボンディング解除\">ボンディング解除</h2>\n\n<p>ボンディング済みデバイスを登録削除する。<br />\nESP32側も忘れず登録削除しておくこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスを確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# remove 94:B9:7E:65:AF:5E                      ← ボンディング解除\n<span class=\"o\">[</span>DEL] Descriptor                                           ← なんか ずらずらっと削除されたと出る\n        /org/bluez/hci0/dev_5F_76_EF_D2_45_E7/service0001/char0002/desc0004\n        00002902-0000-1000-8000-00805f9b34fb\n        Client Characteristic Configuration\n・・・\nDevice has been removed                                    ← 削除された\n<span class=\"o\">[</span>bluetooth]# paired-devices                                ← 確認\n<span class=\"o\">[</span>bluetooth]#                                               ← 削除されてる\n</code></pre></div></div>\n\n<h2 id=\"ツールの終了\">ツールの終了</h2>\n\n<p>ツールを終了してShellに戻る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# <span class=\"nb\">exit</span>                                          ← またはquitまたはCTRL+Dで終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る \n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>pythonでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に pythonスクリプトでアクセスしてみる方法についてのメモ。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<p>pythonスクリプトはRaspberryPiで動作している(実際に試したのはPi4だが、Pi3/Pi0wでも同様)。<br />\nubuntu-PCでも同様にできるはずだが、うちのマシンは内蔵Bluetoothのバージョンが古くてBLE非対応だったので試してない。<br />\nwindows-PCはよくわからん…</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/test1\n<span class=\"nb\">cd</span> /work/ble/test1\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.9.10 bluepy\npyenv <span class=\"nb\">local </span>bluepy\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>bluepy\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/9bbdfa53526411967975097cfbcc66e6.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>ESP32側はAdvertising 開始状態にしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>python ble_hr.py\n</code></pre></div></div>\n<p>デバイスのスキャンを行うので<code class=\"language-plaintext highlighter-rouge\">sudo</code>が必要。</p>\n<blockquote>\n  <p>[!NOTE]\nもし、scanせずにアドレスを指定して実行するだけの処理に書き換えれば<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要になる。</p>\n</blockquote>\n\n<h1 id=\"説明\">説明</h1>\n\n<h2 id=\"ble_hr_delegateクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR_Delegate</code>クラス</h2>\n<p>Notifyを受け取っての処理は<code class=\"language-plaintext highlighter-rouge\">bluepy.btle.DefaultDelegate</code>クラスを継承したクラスを作成して登録する必要がある。<br />\n処理自体は<code class=\"language-plaintext highlighter-rouge\">handleNotification</code>メソッドをオーバーライドして定義する。<br />\n受け取るデータ<code class=\"language-plaintext highlighter-rouge\">data</code>はbytes型なので、数値として使用する場合は<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換してやる必要があるが、<br />\nこの時のエンディアンは接続しているデバイスのFW仕様によるので、どちらを使うかはあらかじめ確認しておく必要がある。<br />\n(大抵はFWを動かしているCPUのエンディアンなのかな?)</p>\n\n<h2 id=\"ble_hrクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR</code>クラス</h2>\n<p>peripheralを操作するための処理をクラス化してある。<br />\nクラス化は必須ではないけど、処理をまとめておいた方が分かりやすいかな?と思ったので。</p>\n\n<p>コンストラクタ、接続、Characteristicのリード/ライト、Notifyの有効化/無効化/ポーリング、切断などの処理がある。</p>\n\n<h2 id=\"main関数\"><code class=\"language-plaintext highlighter-rouge\">main</code>関数</h2>\n<p>メイン処理。<br />\n処理の流れはこんな感じ。</p>\n<ul>\n  <li>デバイスのスキャン</li>\n  <li>スキャン結果から指定されたUUIDを持つデバイスを探す\n    <ul>\n      <li>UUIDやデバイス名が必ずしも同じところにあるとは限らないので色々読んでみる必要がある</li>\n    </ul>\n  </li>\n  <li>複数のデバイスを同時に操作することも可能だが、今回は最初の1個だけを決め打ちで使う</li>\n  <li>接続</li>\n  <li>Characteristicのリード\n    <ul>\n      <li>ここもリード結果はbytes型なので、<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換する</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト\n    <ul>\n      <li>ライトデータはbytes型に変換する必要があるが、この処理は、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.write()</code>で変換しているのでここではそのまま。</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト結果の確認\n    <ul>\n      <li>ライトできたか確認するために、再度リードしている</li>\n    </ul>\n  </li>\n  <li>Notifyの有効化</li>\n  <li>Notifyが通知されることを確認するために少し待つ\n    <ul>\n      <li>Notifyを待つ間、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.waitForNotifications()</code>(<code class=\"language-plaintext highlighter-rouge\">Peripheral.waitForNotifications()</code>のラッパ)をコールし続ける必要がある。<br />\nこれをコールしないとNotifyを受信できない(キューイングされるがコールバックは実行されない)。</li>\n    </ul>\n  </li>\n  <li>Notifyの無効化\n    <ul>\n      <li>Notifyが入らないことを確認するためにちょっと待つ</li>\n    </ul>\n  </li>\n  <li>切断</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>BLEでアプリケーションパラメータ設定</title>\n  </head>\n  <body>\n    <header>\n      <h1>BLEでアプリケーションパラメータ設定</h1>\n      <p>ESP32 BLEを使用してアプリケーションパラメータの設定を変更する処理の雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>アプリケーションを作成したとき、マシン名のように端末毎に変更を変更したり、\nサーバ名のように設置条件によって変更したいパラメータってありますよね。<br />\nいつもは起動時に設定モードに入ったり、動作中に簡易シェルを動かしてコンソール(UART)から設定していましたが、<br />\n実装面積などの関係でUARTが接続できなかったりした場合、それ以外の方法としてBLEで設定する方法を考えました。<br />\n(ESP32の場合、Flash書き換えでUART使うので繋がない訳にはいかないのですが…)</p>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nを参考にカスタムプロファイルでアプリケーションパラメータをread/writeできるようにしてみました。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは<a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a><br />\nにあるのでcloneしてください。</p>\n\n<p>このプログラムではアプリケーションはWi-Fiに接続するだけの処理です。<br />\nうまくパラメータが設定できて、nvsに保存しておけば、2回目以降はBLEによる設定なしにWi-Fiに接続することができます。<br />\n接続できれば、外部マシンからpingを打って応答があることが確認できます。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a> のREADME.mdを参照してください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nパラメータの設定はRaspberryPiのpythonから行っていますが、その気になればAndroidのBLE接続確認ツールなどからでも設定できます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n設定パラメータにループインターバルがありますが、プログラム中では参照していません。<br />\n数値を設定する例として入れてあります。</p>\n</blockquote>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>設定したいパラメータが増えてたら、Characteristicを増やしていけばいくらでも対応できるハズ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Bluetooth classic でシリアル通信(SPP)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Bluetooth classic でシリアル通信(SPP)</h1>\n      <p>ESP32 Bluetooth classic(SPP)を使用してシリアル通信するデモプログラム</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>シリアル通信でデータを送受信したいけど、有線接続はできない場合にBluetooth classicのSPP(Serial Port Profile )を使用して\nCOMポートとして接続する方法のデモ。<br />\nesp-idfのサンプルプログラムが私にとっては複雑怪奇だったので、ちょっとシンプルにしてみた。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは</p>\n<ul>\n  <li>VFS版: <a href=\"https://github.com/ippei8jp/BT_SPP_VFS\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_VFS</a></li>\n  <li>Callback版: <a href=\"https://github.com/ippei8jp/BT_SPP_CB\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_CB</a></li>\n</ul>\n\n<p>にあるのでcloneしてください。</p>\n\n<p>このプログラムではPC等のCOMポートへ/から接続して送信したデータをエコーバックするだけのデモプログラムです。<br />\nそれぞれのイベント発生時に発生イベントとパラメータを表示するようにしてあるので、動作の理解の一助になります…\nなったらいいな…でも期待はするな….</p>\n\n<p>上記2つのリポジトリはファイル構成を合わせてあるので、diffをとるとVFSとCallbackでどのような違いがあるのか分かりやすい<br />\n… かもね…</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<ul>\n  <li>VFS版: <a href=\"https://github.com/ippei8jp/BT_SPP_VFS#readme\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_VFS#readme</a></li>\n  <li>Callback版: <a href=\"https://github.com/ippei8jp/BT_SPP_CB#readme\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_CB#readme</a></li>\n</ul>\n\n<p>を参照してください。</p>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ <br />\n最近こればっかりや…</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>エコーバックタスクをコマンドシェルタスクなどに入れ替えるとすぐ使える…とも思えんけど…<br />\n踏み台くらいにはなるでしょう。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール</h1>\n      <p>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロード\">ダウンロード</h1>\n\n<p><a href=\"https://www.raspberrypi.com/software/operating-systems/\" target=\"_blank\">Raspberry Pi OS</a>ページの <br />\n「Manually install an operating system image」の「See all download options」をクリック、<br />\n「Raspberry Pi OS (64-bit)」の「Raspberry Pi OS with desktop」の「Download」をクリックしてダウンロード<br />\n試したのは Release date: January 28th 2022</p>\n\n<blockquote>\n  <p>[!NOTE]\n「Archive」リンクから過去のリリースも入手できる</p>\n</blockquote>\n\n<p>なんか見るたびにページ構成変わるよなぁ….😩💨</p>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nシリアルコンソールの送信改行コードはCRにしておくこと。<br />\nそうしないと、ビミョーに悲しいことが起こる場合がある。</p>\n\n</blockquote>\n\n<h2 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h2>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>の  最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group</code>と<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>については使用するモニタに合わせる。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group=2</code>はモニタ種別でDMT(一般的にモニタディスプレイ)、<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_mode=82</code>が 1920x1080 60Hz(1080p)を示している。<br />\n設定値の内容については、<a href=\"https://www.raspberrypi.com/documentation/computers/config_txt.html#hdmi-mode\" target=\"_blank\">HDMI Mode</a>を参照。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>はテキストモードで表示したいサイズに合わせる。1920と1080とか、1280と720とか。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># display resolution force setting</span>\n<span class=\"nv\">hdmi_group</span><span class=\"o\">=</span>2\n<span class=\"nv\">hdmi_mode</span><span class=\"o\">=</span>82\n<span class=\"nv\">framebuffer_width</span><span class=\"o\">=</span>1920\n<span class=\"nv\">framebuffer_height</span><span class=\"o\">=</span>1080\n<span class=\"nv\">hdmi_force_hotplug</span><span class=\"o\">=</span>1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nHDMIディスプレイを常に接続しているなら設定しなくても問題ないが、\nHDMIディスプレイをはずしてVNCでリモート接続だけする場合は設定しておかないと\n解像度が1024x768までしか設定できなくなるので注意。</p>\n</blockquote>\n\n<h3 id=\"vncが遅い問題対応\">VNCが遅い問題対応</h3>\n<p>このバージョンではHDMIディスプレイを繋いでいない状態でVNCで接続すると表示がとても遅くなる問題がある。<br />\n回避するには、<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code>に以下追記する。<br />\n<code class=\"language-plaintext highlighter-rouge\">1920x1080@60D</code>の部分は上記の<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>や<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>の設定値に合わせる。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>video=HDMI-A-1:1920x1080@60D\n</code></pre></div></div>\n\n<p>具体的にはこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>console=serial0,115200 console=tty1 root=PARTUUID=b635b4ec-02 rootfstype=ext4 fsck.repair=yes video=HDMI-A-1:1920x1080@60D rootwait\n</code></pre></div></div>\n\n<p>参考URL:<a href=\"https://forums.raspberrypi.com/viewtopic.php?p=1935714#p1935711\">Re: Bullseye vncserver is very slow without display</a></p>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。<br />\nSSID名は ダブルクォーテーションで囲む。<br />\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://qiita.com/mt08/items/2da1cce534dfdc84f5e3#%E7%92%B0%E5%A2%83\" target=\"_blank\">[メモ] (らずぱい)Windows上から固定IP設定 (Raspberry Pi Static IP)</a>\nにWindows版の<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase.exe</code>へのリンクがある。<br />\nワタシはUbuntuや別のRasberryPiで作ったから使ってないけど…</p>\n</blockquote>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase \"SSID名\" \"暗号化キー\"\n        ↓ 実行結果\nnetwork={\n        ssid=\"SSID名\"\n        #psk=\"暗号化キー\"\n        psk=ほにゃらら~~~ほにゃらら~~~\n}\n</code></pre></div></div>\n\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。<br />\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<blockquote>\n  <p>[!NOTE]\n起動後、公開鍵ファイルの設置を行うには、<br />\n<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">ubuntuにSSHサーバをセットアップする</a> <br />\nの「秘密鍵と公開鍵の生成と公開鍵ファイルの設置」の部分を参照。<br />\n(ページはUbuntuについて書いてあるけど、サーバがセットアップ済みなことを除けばRaspberry Pi OSでも同じ)</p>\n</blockquote>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># アップデート実行\nsudo apt update\nsudo apt upgrade\n# リブート\nsudo reboot\n</code></pre></div></div>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S7 Splash Screen\n            Would you like to show the splash screen at boot?\n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこの操作で/boot/cmdline.txtが書き換えられるらしい。</p>\n\n</blockquote>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# 新ユーザのパスワード変更する\npasswd\n《パスワードを設定》\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\" target=\"_blank\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n            B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/4f39afbcd8471426421944b597f3a5f2963984c6/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nresize.pyは以前python2ベースで作ってあったが、<br />\nこのバージョンからpython2がデフォルトでインストールされなくなったので、<br />\npython3ベースに修正したのでURLが変更されています。</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n\n<p>物理キーボード接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]<br />\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n\n</blockquote>\n\n<h1 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h1>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n\n<p>まずはワークディレクトリの作成</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo service smbd reload\nsudo service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo vi /etc/hostname\nsudo vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>s``udo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    3 Interfacing Options\n        I3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>\n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n\n<p>Windows側のクライアントは、<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a>\nから VNC Viewerをダウンロード。\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。\n日本語化の手順はこちらを参考に。 <a href=\"http://xn--u9j0md1592aqmt715c.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>SDカードイメージのバックアップを取るならこちら。<br />\n<a href=\"/memoBlog/2021/07/18/sd_image_2.html\" target=\"_blank\">Raspbian SDカードイメージファイルの作成(改訂版)</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>aspberry Pi OS(64bit)がリリースされたが、openVINOのBuild済みモジュールはまだこれに対応していない。<br />\nそのうち対応されると思うけど、とりあえず自前でBuildする方法を調べてみた。<br />\nついでにCPU Extensionも作成しておく。<br />\nなお、Raspberry Pi OS(32bit Buster)向けのBuild手順については、\n『<a href=\"/memoBlog/2021/10/28/openVINO_build.html\" target=\"_blank\">openVINO(Raspberry Pi向け)のbuild</a>』を参照。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<p>今回もARM版Dockerコンテナを使用してセルフコンパイルする方法で行う。<br />\n手順そのものは特殊なことはないので、Raspberry Pi上のNative環境でもBuildできそうだけど、\nディスク容量とかスワップ領域とか気にしないといけないかもしれないので試してない。<br />\n(今回はクロスコンパイル環境はなし。cythonの出力モジュールも使いたかったので)</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_emu\n</code></pre></div></div>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h2 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h2>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n32bit版との差分はこんな感じ。<br />\nあれ?32bit版の<code class=\"language-plaintext highlighter-rouge\">python-minimal</code>って間違ってる?<br />\n<code class=\"language-plaintext highlighter-rouge\">python3-numpy</code>で依存モジュールとしてインストールされて事なきを得たのか?<br />\n実質、ベースイメージを変更してるだけだな。</p>\n\n  <div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- Dockerfile.old\t2022-03-01 07:26:28.774187231 +0900\n</span><span class=\"gi\">+++ Dockerfile\t2022-03-01 07:19:45.668393598 +0900\n</span><span class=\"p\">@@ -1,4 +1,4 @@</span>\n<span class=\"gd\">-FROM arm32v7/debian:buster\n</span><span class=\"gi\">+FROM arm64v8/debian:bullseye\n</span> \n USER root\n \n<span class=\"p\">@@ -18,7 +18,7 @@</span>\n     libprotobuf-dev libprotoc-dev protobuf-compiler \\\n     cmake \\\n     python3-pip \\\n<span class=\"gd\">-    python-minimal \\\n</span><span class=\"gi\">+    python3-minimal \\\n</span>     python3-numpy cython3 scons\n \n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_emu_1 ov_pi64_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<p>数時間レベルでかかるので、のんびり待ちましょう。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"その他細々したところ\">その他細々したところ</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コメント\">コメント</h3>\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール\">実機へのインストール</h2>\n\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>を適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>ついでにopenCVのBuild方法についてもメモっておく。</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>openCVのリポジトリをcloneしておく。<br />\n指定するタグは適宜変更してください。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n<p>新しいDockerコンテナ作っても良いけど、別にその必要もないので上記のコンテナをそのまま使用する。</p>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n  <h2 id=\"本番-1\">本番</h2>\n</blockquote>\n\n<h3 id=\"準備-2\">準備</h3>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk2.0-dev  libjpeg-dev libpng-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev\n</code></pre></div></div>\n\n<h3 id=\"build\">Build</h3>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n\n<span class=\"c\"># インストール</span>\nmake <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf opencv.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コンテナから出る-1\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール-1\">実機へのインストール</h2>\n<p>openVINOをBuildしたコンテナで続けてBuildした場合は<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>にopenVINO、openCVがインストールされている。<br />\nこれを適当なディレクトリに展開して環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば良い。</p>\n\n<p>別のコンテナを使用したり、openVINOのBuild結果を削除していた場合は、<br />\n最終的に作成した<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>をopenVINOをインストールしたディレクトリに展開する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINOのクロスコンパイル</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINOのクロスコンパイル</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild(クロスコンパイル環境)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi OS(64bit)向けにopenVINOをクロスコンパイルする方法についてまとめた。<br />\nセルフコンパイル(Docker使用)については『<a href=\"/memoBlog/2022/03/07/openVINO_build_2.html\" target=\"_blank\">openVINO(Raspberry Pi OS(64bit)向け)のbuild</a>』を参照。<br />\nただ、クロスコンパイルだとセルフコンパイルの10倍くらい速い(環境によるけど)ので、クロスコンパイルがおススメ。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_cross <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_cross\n</code></pre></div></div>\n\n<h2 id=\"ソースの取得\">ソースの取得</h2>\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h3>\n<p>以下の1つのpatchファイルを作成する。<br />\nサンプル(テスト?)プログラムのBuildを抑制してコンパイル時間の短縮を計っている。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"opencv-の-gitリポジトリを-clone\">openCV の gitリポジトリを clone</h3>\n<p>opencv のリポジトリをcloneする(opencvのBuildを行わない場合は不要)。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libgtk-3-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_cross <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_cross_1 ov_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_cross_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_cross_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n<p>ここからコンテナ内</p>\n\n<h2 id=\"buildディレクトリの作成\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openvino/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/openvino/build\n</code></pre></div></div>\n\n<h2 id=\"cmake実行\">cmake実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm64.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_SAMPLES</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLANG_FORMAT</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_OPENCV</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n    .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>サンプルはBuildしないので、ENABLE_SAMPLES=OFF を設定</li>\n    <li>ソースをいじるわけではないので、ENABLE_CLANG_FORMAT=OFF を設定</li>\n    <li>openCVインストールされていないので、ENABLE_OPENCV=OFF を設定<br />\n(サンプルのBuildしないのでopenCVなくても大丈夫)</li>\n  </ul>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nログには いくつかWarningがあるが、とくに問題はなさそう</p>\n</blockquote>\n\n<h2 id=\"make\">make</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h2 id=\"その他細々したところ\">その他細々したところ</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"c\"># クロスコンパイルを反映したファイル名になっていないので修正</span>\n<span class=\"nb\">mv</span> /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-x86_64-linux-gnu.so /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-aarch64-linux-gnu.so\n\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>CPU Extentionは<code class=\"language-plaintext highlighter-rouge\">make install</code>でコピーされないので手動でインストールする。</li>\n    <li>バイナリリリースに<code class=\"language-plaintext highlighter-rouge\">inference_engine</code>のシンボリックリンクがあるので同様に作成しておく。</li>\n    <li>ngraphのライブラリファイルのファイル名がx86_64(ホスト環境の名前)になっているので、aarch64に修正。<br />\nバイナリ自体はaarch64になっているので、ファイル名のリネームだけでOK。<br />\n本来はファイル名決めてるところで対処するのが良いのだろうけど、とりあえず力技で。</li>\n  </ul>\n</blockquote>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<p>openCVのBuild方法についてもメモっておく。<br />\npythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。<br />\nその場合は、ここはスキップしても大丈夫。<br />\nopenVINOをBuildしたDockerコンテナで引き続き作業を行う</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk-3-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libjpeg-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libpng-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev:arm64\n</code></pre></div></div>\n<h2 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n</code></pre></div></div>\n<h2 id=\"cmakeの実行\">cmakeの実行</h2>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PKG_CONFIG_LIBDIR</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_ENABLE_PKG_CONFIG</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_FIND_ROOT_PATH</span><span class=\"o\">=</span>/ <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span>/work/opencv/platforms/linux/aarch64-gnu.toolchain.cmake <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_NUMPY_INCLUDE_DIRS</span><span class=\"o\">=</span>/usr/lib/python3/dist-packages/numpy/core/include <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n       .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあらかじめ環境変数<code class=\"language-plaintext highlighter-rouge\">PKG_CONFIG_LIBDIR</code>を設定して<code class=\"language-plaintext highlighter-rouge\">pkg-config</code>でaarch64のライブラリとNativeのツール類を参照するように設定しておく。<br />\nこれをやらないと、libjpegとかをインストールしてあることを検出できない</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeのオプションに <code class=\"language-plaintext highlighter-rouge\">-D CMAKE_FIND_DEBUG_MODE=1</code>を追加すると\ncmake中の<code class=\"language-plaintext highlighter-rouge\">find_xxx</code>の動作のログが出力されるので、パッケージのサーチなどの検索パスの確認などが容易になる。</p>\n</blockquote>\n\n<h2 id=\"make-1\">make</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install-1\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino/opencv</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/opencv</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-D CMAKE_INSTALL_PREFIX=/work/opt/intel/openvino/opencv</code>の部分を変更すれば良いけど、ここはopenVINOのインストール先と合わせておかないとうまく動かない。</p>\n\n<h1 id=\"実機へのインストール\">実機へのインストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">opt</code>ディレクトリ以下を丸ごとアーカイブする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<p>作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>をRaspberryPiの適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"コンテナから出る\">コンテナから出る</h1>\n<p>Dockerコンテナは作業終了したら終了しておく。<br />\nCTRL-D でshell終了</p>\n\n<h1 id=\"補足\">補足</h1>\n<p>コンテナにインストールされているパッケージは以下の通り。<br />\nバージョン違いで動かなくなることもあるかもしれんので、念のため。</p>\n\n<p>こんな感じで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span> | <span class=\"nb\">grep</span> <span class=\"nt\">-v</span> automatic\n</code></pre></div></div>\n\n<p>で、こんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>build-essential/stable,now 12.9 amd64 [installed]\ncmake/stable,now 3.18.4-2+deb11u1 amd64 [installed]\ncrossbuild-essential-arm64/stable,stable,now 12.9 all [installed]\ncython3/stable,now 0.29.21-3+b1 amd64 [installed]\ngit/stable,now 1:2.30.2-1 amd64 [installed]\nlibavcodec-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibavformat-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibgstreamer-plugins-base1.0-dev/stable,now 1.18.4-2 arm64 [installed]\nlibgstreamer1.0-dev/stable,now 1.18.4-2.1 arm64 [installed]\nlibgtk-3-dev/stable,now 3.24.24-4 arm64 [installed]\nlibjpeg-dev/stable,now 1:2.0.6-4 arm64 [installed]\nlibpng-dev/stable,now 1.6.37-3 arm64 [installed]\nlibprotobuf-dev/stable,now 3.12.4-1 arm64 [installed]\nlibprotoc-dev/stable,now 3.12.4-1 arm64 [installed]\nlibpython3-dev/stable,now 3.9.2-3 arm64 [installed]\nlibswscale-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibtiff-dev/stable,now 4.2.0-1 arm64 [installed]\nlibusb-1.0-0-dev/stable,now 2:1.0.24-3 arm64 [installed]\nlibwebp-dev/stable,now 0.6.1-2.1 arm64 [installed]\nprotobuf-compiler/stable,now 3.12.4-1 amd64 [installed]\npython3-minimal/stable,now 3.9.2-3 amd64 [installed]\npython3-numpy/stable,now 1:1.19.5-1 amd64 [installed]\npython3-pip/stable,stable,now 20.3.4-4 all [installed]\nscons/stable,stable,now 4.0.1+dfsg-2 all [installed]\nwget/stable,now 1.21-1+deb11u1 amd64 [installed]\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MediaPipeで手の認識</title>\n  </head>\n  <body>\n    <header>\n      <h1>MediaPipeで手の認識</h1>\n      <p>MediaPipe Handsで手の認識処理をやってみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>MediaPipe Handsを使って手の認識処理を行ってみる。<br />\nMediaPipeを使用するとかなり簡単に手の特徴点を取得できる。<br />\nまた、各特徴点の位置がわかるので、それらの位置関係からポーズを取得することもできる。</p>\n\n<p>参考: <a href=\"https://google.github.io/mediapipe/solutions/hands.html\" target=\"_blank\">https://google.github.io/mediapipe/solutions/hands.html</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/mediapipe\n<span class=\"nb\">cd</span> /work/ble/mediapipe\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 mediapipe\npyenv <span class=\"nb\">local </span>mediapipe\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>mediapipe\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<h2 id=\"共通ルーチン\">共通ルーチン</h2>\n\n<p>各指の関節と指先の位置関係から指が伸びているのか、曲がっているのかを判別し(親指だけは各関節の角度から判別)、<br />\nその組み合わせからどのようなポーズなのかを判別している。<br />\nアルゴリズムは <a href=\"https://github.com/geaxgx/openvino_hand_tracker\">https://github.com/geaxgx/openvino_hand_tracker</a> から拝借した。<br />\n元のプログラムは各関節の位置を検出された手の画像を回転して角度調整した画像のY座標から取得しているが、<br />\n今回は手の角度が分からないので、手首から各関節位置までの距離を比較するように変更した。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  hand_gesture.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">HandLandmark</span> <span class=\"o\">=</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">distance</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">):</span>\n    <span class=\"c1\"># a, b: 2 points in 3D (x,y,z)\n</span>    <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">a</span> <span class=\"o\">-</span> <span class=\"n\">b</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">angle</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">,</span> <span class=\"n\">c</span><span class=\"p\">):</span>\n    <span class=\"c1\"># a, b and c : points as np.array([x, y, z]) \n</span>    <span class=\"n\">ba</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">-</span> <span class=\"n\">b</span>\n    <span class=\"n\">bc</span> <span class=\"o\">=</span> <span class=\"n\">c</span> <span class=\"o\">-</span> <span class=\"n\">b</span>\n    <span class=\"n\">cosine_angle</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">dot</span><span class=\"p\">(</span><span class=\"n\">ba</span><span class=\"p\">,</span> <span class=\"n\">bc</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">ba</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">bc</span><span class=\"p\">))</span>\n    <span class=\"n\">angle</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arccos</span><span class=\"p\">(</span><span class=\"n\">cosine_angle</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">degrees</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ジェスチャの認識\n# 参考: https://github.com/geaxgx/openvino_hand_tracker\n</span><span class=\"k\">def</span> <span class=\"nf\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">debug</span> <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">):</span>\n    <span class=\"c1\"># 各landmarkの手首からの距離を求める\n</span>    <span class=\"n\">lm_pos</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([[</span><span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">z</span><span class=\"p\">]</span> <span class=\"k\">for</span> <span class=\"n\">lm</span> <span class=\"ow\">in</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">])</span>    <span class=\"c1\"># 計算のためndarray化\n</span>    <span class=\"c1\"># lm_pos = np.array([[lm.x, lm.y] for lm in landmarks.landmark])          # 計算のためndarray化(zは無視)\n</span>    <span class=\"n\">r_</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span> <span class=\"o\">-</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">WRIST</span><span class=\"p\">],</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>        <span class=\"c1\"># numpyなので一括計算\n</span>    \n    <span class=\"c1\"># 親指の角度で状態判別\n</span>    <span class=\"n\">distance0</span> <span class=\"o\">=</span> <span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">],</span>     <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指の第二関節と人差し指の付け根の距離\n</span>    <span class=\"n\">distance1</span> <span class=\"o\">=</span> <span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span>    <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">]</span>        <span class=\"p\">)</span>     <span class=\"c1\"># 親指の付け根と親指の第二関節の距離\n</span>    <span class=\"n\">angle0</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">WRIST</span><span class=\"p\">],</span>      <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_CMC</span><span class=\"p\">],</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指付け根の角度\n</span>    <span class=\"n\">angle1</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_CMC</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">]</span> <span class=\"p\">)</span>     <span class=\"c1\"># 親指第二関節の角度\n</span>    <span class=\"n\">angle2</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_TIP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指第一関節の角度\n</span>    <span class=\"n\">thumb_angle</span> <span class=\"o\">=</span> <span class=\"n\">angle0</span> <span class=\"o\">+</span> <span class=\"n\">angle1</span> <span class=\"o\">+</span> <span class=\"n\">angle2</span>\n    <span class=\"k\">if</span> <span class=\"n\">thumb_angle</span> <span class=\"o\">></span> <span class=\"mi\">460</span> <span class=\"ow\">and</span> <span class=\"n\">distance0</span> <span class=\"o\">/</span> <span class=\"n\">distance1</span> <span class=\"o\">></span> <span class=\"mf\">1.2</span><span class=\"p\">:</span> \n        <span class=\"n\">thumb_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">thumb_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># 人差し指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 中指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 薬指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 小指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># Gesture\n</span>    <span class=\"k\">if</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FIST\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"OK\"</span> \n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"PEACE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"ONE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"TWO\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"THREE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>      <span class=\"c1\"># 日本型の3\n</span>        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"THREE_J\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FOUR\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FIVE\"</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># for debug\n</span>    <span class=\"c1\"># print(f'{r_[HandLandmark.INDEX_FINGER_MCP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_PIP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_DIP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_TIP]:6.3f}    {index_state}')\n</span>\n    <span class=\"k\">if</span> <span class=\"n\">debug</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">21</span><span class=\"p\">):</span>\n            <span class=\"n\">lm_x</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"c1\"># * image_width\n</span>            <span class=\"n\">lm_y</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"c1\"># * image_height\n</span>            <span class=\"n\">lm_z</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">z</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">HandLandmark</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">))</span><span class=\"si\">:</span><span class=\"mi\">32</span><span class=\"n\">s</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">:</span><span class=\"mi\">2</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">):   </span><span class=\"si\">{</span><span class=\"n\">lm_x</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">lm_y</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">lm_z</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">:</span><span class=\"mf\">6.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">gesture</span>\n</code></pre></div></div>\n\n<h2 id=\"カメラ画像から認識\">カメラ画像から認識</h2>\n<p>カメラ画像から認識してみる。<br />\nこっちの方が用途は多いかな。<br />\nコマンドラインオプションについてはソース見てちょ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  test_camera.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span>  <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span>         <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-nh\"</span><span class=\"p\">,</span> <span class=\"s\">\"--num_hand\"</span><span class=\"p\">,</span>         <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span>   <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Max number of hands\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num_hand</span>            <span class=\"c1\"># 検出する手の個数\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">verbose2</span>                 <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>\n<span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">True</span>                    <span class=\"c1\"># 鏡像使用\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># カメラ\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span>   <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">,</span>            <span class=\"c1\"># 動画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>        <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 前のフレーム処理完了時刻を初期化\n</span>    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># キャプチャ\n</span>        <span class=\"n\">success</span><span class=\"p\">,</span> <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">success</span><span class=\"p\">:</span>\n            <span class=\"c1\"># エラーになったら再度キャプチャ\n</span>            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Ignoring empty camera frame.\"</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>        <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n            <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像サイズ\n</span>        <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n        \n        <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>        <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># 検出結果の処理\n</span>        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">handedness</span> <span class=\"ow\">in</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_handedness</span><span class=\"p\">):</span>\n                <span class=\"k\">if</span> <span class=\"n\">verbose</span> <span class=\"ow\">or</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'--------------------------------------------------------------------------'</span><span class=\"p\">)</span>\n                \n                <span class=\"c1\"># データは鏡像として判別されているので、鏡像でなければラベルを入れ替え\n</span>                <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span> <span class=\"o\">==</span> <span class=\"s\">\"Left\"</span> <span class=\"p\">:</span>\n                        <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Right\"</span>\n                    <span class=\"k\">else</span> <span class=\"p\">:</span>\n                        <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Left\"</span>\n                \n                <span class=\"c1\"># ジェスチャの認識\n</span>                <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n                \n                <span class=\"k\">if</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'==== sore ======================='</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">index</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'score   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">score</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'label   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>            <span class=\"c1\"># あんまりあてにならないな...\n</span>                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'gesture : </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'================================='</span><span class=\"p\">)</span>\n                \n                <span class=\"c1\"># landmarkの描画\n</span>                <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">draw_landmarks</span><span class=\"p\">(</span>\n                    <span class=\"n\">image</span><span class=\"p\">,</span>                              <span class=\"c1\"># 画像\n</span>                    <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span>                     <span class=\"c1\"># ランドマーク\n</span>                    <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span>          <span class=\"c1\"># ランドマーク接続リスト\n</span>                    <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_landmarks_style</span><span class=\"p\">(),</span>       <span class=\"c1\"># ランドマーク描画スタイル\n</span>                    <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_connections_style</span><span class=\"p\">()</span>      <span class=\"c1\"># 接続描画スタイル\n</span>                <span class=\"p\">)</span>\n                <span class=\"c1\"># ジェスチャ表示\n</span>                <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># 人差し指の付け根あたりに表示\n</span>                    <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n                    <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                        <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                        <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>     <span class=\"c1\"># 文字列\n</span>                        <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">),</span>                     <span class=\"c1\"># 座標\n</span>                        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                        <span class=\"mi\">1</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                        <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                        <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>                    <span class=\"p\">)</span>\n        \n        <span class=\"c1\"># フレーム処理時間\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 現在のフレーム処理完了時刻\n</span>        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>                   <span class=\"c1\"># このフレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        \n        <span class=\"c1\"># FPS表示\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                <span class=\"sa\">f</span><span class=\"s\">'FPS:</span><span class=\"si\">{</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>  <span class=\"c1\"># 文字列\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">50</span><span class=\"p\">),</span>                    <span class=\"c1\"># 座標\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>            <span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示終了待ち\n</span>        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'v'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'b'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose2</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose2</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"c1\"># ウィンドウをすべて閉じる\n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># カメラリリース\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"静止画像から認識\">静止画像から認識</h2>\n\n<p>デバッグ用途など、静止画から認識する場合はこちら。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  test_photo.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'input'</span><span class=\"p\">,</span> <span class=\"n\">metavar</span><span class=\"o\">=</span><span class=\"s\">\"INPUT_FILE\"</span><span class=\"p\">,</span>                          <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Path to the input picture \"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                 <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--world'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                         <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp world landmark map\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-nh\"</span><span class=\"p\">,</span> <span class=\"s\">\"--num_hand\"</span><span class=\"p\">,</span>         <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span>   <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Max number of hands\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># 入力ファイル名\n</span><span class=\"nb\">file</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num_hand</span>            <span class=\"c1\"># 検出する手の個数\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">False</span>                    <span class=\"c1\"># 鏡像使用しない\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span> <span class=\"o\">=</span> <span class=\"bp\">True</span><span class=\"p\">,</span>               <span class=\"c1\"># 静止画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>                    <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"c1\"># 画像読み込み\n</span>    <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'file name : </span><span class=\"si\">{</span><span class=\"nb\">file</span><span class=\"si\">}</span><span class=\"s\">   image size : </span><span class=\"si\">{</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>    <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n        <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    \n    <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>    <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># 検出結果の処理\n</span>    <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">handedness</span> <span class=\"ow\">in</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_handedness</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">verbose</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'--------------------------------------------------------------------------'</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># データは鏡像として判別されているので、鏡像でなければラベルを入れ替え\n</span>            <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n                <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span> <span class=\"o\">==</span> <span class=\"s\">\"Left\"</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Right\"</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Left\"</span>\n            \n            <span class=\"c1\"># ジェスチャの認識\n</span>            <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n            \n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'==== sore ======================='</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">index</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'score   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">score</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'label   : </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'gesture : </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'================================='</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># landmarkの描画\n</span>            <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">draw_landmarks</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                              <span class=\"c1\"># 画像\n</span>                <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span>                     <span class=\"c1\"># ランドマーク\n</span>                <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span>          <span class=\"c1\"># ランドマーク接続リスト\n</span>                <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_landmarks_style</span><span class=\"p\">(),</span>       <span class=\"c1\"># ランドマーク描画スタイル\n</span>                <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_connections_style</span><span class=\"p\">()</span>      <span class=\"c1\"># 接続描画スタイル\n</span>            <span class=\"p\">)</span>\n            <span class=\"c1\"># ジェスチャ表示\n</span>            <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># 人差し指の付け根あたりに表示\n</span>                <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n                <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                    <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                    <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>     <span class=\"c1\"># 文字列\n</span>                    <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">),</span>                     <span class=\"c1\"># 座標\n</span>                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                    <span class=\"mi\">1</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                    <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                    <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>                <span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"** NO HANDS **\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 表示終了待ち\n</span>    <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'p'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imwrite</span><span class=\"p\">(</span>\n                    <span class=\"s\">'output_'</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">),</span> \n                    <span class=\"n\">image</span>\n                <span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"ow\">not</span> <span class=\"n\">k</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n          <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># ウィンドウをすべて閉じる\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">world</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># hand world landmarks の 3D座標の表示\n</span>        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_world_landmarks</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">hand_world_landmarks</span> <span class=\"ow\">in</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_world_landmarks</span><span class=\"p\">:</span>\n                <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">plot_landmarks</span><span class=\"p\">(</span>\n                                <span class=\"n\">hand_world_landmarks</span><span class=\"p\">,</span> \n                                <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span> \n                                <span class=\"n\">azimuth</span><span class=\"o\">=</span><span class=\"mi\">5</span>\n                            <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<h2 id=\"カメラ画像から認識-1\">カメラ画像から認識</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: test_camera.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-nh</span> NUM_HAND]\n                      <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">-nh</span> NUM_HAND, <span class=\"nt\">--num_hand</span> NUM_HAND\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Max number of hands\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h2 id=\"静止画像から認識-1\">静止画像から認識</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: test_photo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--world</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-nh</span> NUM_HAND]\n                     <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n                     INPUT_FILE\n\npositional arguments:\n  INPUT_FILE            Path to the input picture\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">--world</span>               <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp world landmark map\n  <span class=\"nt\">-nh</span> NUM_HAND, <span class=\"nt\">--num_hand</span> NUM_HAND\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Max number of hands\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h1 id=\"説明\">説明</h1>\n\n<p>説明….するほどのことはないな。<br />\nほとんど出来あいの処理。</p>\n\n<p>各指の状態からポーズを取得する処理を変更すれば、ほかの認識(ジャンケン認識など)にも変更可能。<br />\nまた、人差し指の指先をトラッキングしていけば、バーチャルお絵描きなんてのもできるかも。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MediaPipeの手の認識でお絵かき</title>\n  </head>\n  <body>\n    <header>\n      <h1>MediaPipeの手の認識でお絵かき</h1>\n      <p>MediaPipe Handsでの手の認識結果と使ってお絵かきしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>MediaPipeで手の認識</p>\n\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』の手の認識子処理を使って空間にお絵かきしてみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』を参照。</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<h2 id=\"共通ルーチン\">共通ルーチン</h2>\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』を参照。</p>\n\n<h2 id=\"お絵かきプログラム\">お絵かきプログラム</h2>\n\n<p>お絵かきプログラム本体。<br />\n人差し指先端に点を打っていくことでお絵かきしている。<br />\n人差し指だけ立てた状態(ジェスチャ ONE)だと赤、人差し指と中指を立てた状態(ジェスチャ PEACE)だと緑で描画するようにしてあるが、この組み合わせにあまり意味はない。なんとなく色を切り替えてみたかったので。<br />\nコマンドラインオプションと表示中操作についてはソース見てちょ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  oekaki.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n<span class=\"n\">HandLandmark</span> <span class=\"o\">=</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span>  <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span>         <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n<span class=\"c1\">#     parser.add_argument(\"-nh\", \"--num_hand\",         default=2,   type=int,     help=\"(optional) Max number of hands\")\n</span>    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n# max_num_hands            = args.num_hand            # 検出する手の個数\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"mi\">1</span>                        <span class=\"c1\"># 検出する手の個数 今回は1固定\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">verbose2</span>                 <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>\n\n<span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">True</span>                    <span class=\"c1\"># 鏡像使用\n</span><span class=\"n\">fg_only</span>                  <span class=\"o\">=</span> <span class=\"bp\">False</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"n\">COLOR_WHITE</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_BLUE</span>  <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_GREEN</span> <span class=\"o\">=</span> <span class=\"p\">(</span>  <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_RED</span>   <span class=\"o\">=</span> <span class=\"p\">(</span>  <span class=\"mi\">0</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># カメラ\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像サイズ\n</span><span class=\"n\">image_width</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n<span class=\"n\">image_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n<span class=\"n\">fps</span>          <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'image size : </span><span class=\"si\">{</span><span class=\"n\">image_width</span><span class=\"si\">}</span><span class=\"s\"> x </span><span class=\"si\">{</span><span class=\"n\">image_height</span><span class=\"si\">}</span><span class=\"s\"> @ </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">Hz'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前景イメージを作成\n</span><span class=\"n\">image_fg</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">full</span><span class=\"p\">((</span><span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span>   <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">,</span>            <span class=\"c1\"># 動画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>        <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 前のフレーム処理完了時刻を初期化\n</span>    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># キャプチャ\n</span>        <span class=\"n\">success</span><span class=\"p\">,</span> <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">success</span><span class=\"p\">:</span>\n            <span class=\"c1\"># エラーになったら再度キャプチャ\n</span>            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Ignoring empty camera frame.\"</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>        <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n            <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        \n        <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>        <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>        <span class=\"c1\"># 検出できたか?\n</span>            <span class=\"c1\"># ポーズの認識\n</span>            <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 人差し指先の位置\n</span>            <span class=\"n\">finger_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n            <span class=\"n\">finger_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'(</span><span class=\"si\">{</span><span class=\"n\">finger_x</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">finger_y</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">)  </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ポーズによって色を変更\n</span>            <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"o\">==</span> <span class=\"s\">'ONE'</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"n\">COLOR_RED</span>           <span class=\"c1\"># 赤\n</span>            <span class=\"k\">elif</span> <span class=\"n\">gesture</span> <span class=\"o\">==</span> <span class=\"s\">'PEACE'</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"n\">COLOR_GREEN</span>         <span class=\"c1\"># 緑\n</span>            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n            <span class=\"k\">if</span> <span class=\"n\">color</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># 前景イメージに点を打つ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">circle</span><span class=\"p\">(</span><span class=\"n\">image_fg</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">finger_x</span><span class=\"p\">,</span> <span class=\"n\">finger_y</span><span class=\"p\">)</span> <span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span><span class=\"o\">=-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># フレーム処理時間\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 現在のフレーム処理完了時刻\n</span>        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>                   <span class=\"c1\"># このフレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        \n        <span class=\"c1\"># FPS表示\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                <span class=\"sa\">f</span><span class=\"s\">'FPS:</span><span class=\"si\">{</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>  <span class=\"c1\"># 文字列\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">50</span><span class=\"p\">),</span>                    <span class=\"c1\"># 座標\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                <span class=\"n\">COLOR_RED</span><span class=\"p\">,</span>                  <span class=\"c1\"># 色\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>            <span class=\"p\">)</span>\n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"n\">fg_only</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 前景イメージだけ表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image_fg</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 画像を重ね合わせ(COLOR_WHITEを透過色として指定)て表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">where</span><span class=\"p\">(</span><span class=\"n\">image_fg</span> <span class=\"o\">==</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">image_fg</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># 表示終了待ち\n</span>        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'c'</span><span class=\"p\">):</span>\n            <span class=\"c1\"># 前景イメージを初期化\n</span>            <span class=\"n\">image_fg</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">full</span><span class=\"p\">((</span><span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'d'</span><span class=\"p\">):</span>\n            <span class=\"n\">fg_only</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">fg_only</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'v'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'b'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose2</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose2</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'p'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imwrite</span><span class=\"p\">(</span>\n                    <span class=\"sa\">f</span><span class=\"s\">'z_oekaki_</span><span class=\"si\">{</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">now</span><span class=\"p\">().</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s\">\"%d_%H%M%S\"</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">.jpg'</span><span class=\"p\">,</span> \n                    <span class=\"n\">image_fg</span>\n                <span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"c1\"># ウィンドウをすべて閉じる\n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># カメラリリース\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: oekaki.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD]\n                 <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h1 id=\"感想\">感想</h1>\n\n<p>それなりにお絵かきできるけど…</p>\n<ul>\n  <li>認識処理が遅いと手をゆっくり動かさないと線にならない</li>\n  <li>ポーズの認識の精度がイマイチで描画結果が微妙な感じになる</li>\n</ul>\n\n<p>実際にユーザインタフェースとして使うには色々と工夫が必要かな。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi で python で PWM</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi で python で PWM</h1>\n      <p>Raspberry Pi 上で python で PWMの制御を行うブログラムの雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Piでロボットアームを制御するのに、PWMのテストを行ったときのプログラムソースを貼っておく。<br />\n使ったロボットアーム: <a href=\"https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1\" target=\"_blank\">https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1</a></p>\n\n<p>ソフトウェアPWMだと他の処理の負荷によってジッタが発生し、ガタガタいうのでこの使い方はあまり実用的ではない。<br />\nハードウェアPWMを使う(pigpio か wiringpi が必要)、PWM制御を担うMCUを用意してコマンド通信(TCP/IPやBluetoothなど経由)で制御するのが現実的かも。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>PRi.GPIOを使うので、インストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>RPi.GPIO\n</code></pre></div></div>\n\n<p>プログラムの設定にあわせてGPIOとサーボモータを接続しておく(または接続に合わせてプログラム修正)。<br />\nスイッチで調整できるようにしてあるけど、キーボードから調整できるのでスイッチの接続は必須ではない。</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/0e8eeedb37d59c85b6ae6085da2a2cb4.js\"></script>\n</dev>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">GPIO.add_event_detect()</code>には<code class=\"language-plaintext highlighter-rouge\">bouncetime=«チャタリング除去時間(msec)»</code>を追加しておくのが良いかも。<br />\n参考: <a href=\"https://tomosoft.jp/design/?p=8685\" target=\"_blank\">GPIOエッジ検出コールバック関数 | TomoSoft</a></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n公式マニュアルは存在しないらしい。<br />\n唯一以下のページがそれっぽい情報を掲載している。<br />\n<a href=\"https://sourceforge.net/p/raspberry-gpio-python/wiki/Examples/\" target=\"_blank\">raspberry-gpio-python / Wiki / Examples</a><br />\nあとはソース読むしかないんだけど、python - C インタフェースを理解してないと苦しい…<br />\nソース全体を<code class=\"language-plaintext highlighter-rouge\">python function</code>で検索すると出てくるけど全部じゃない…<br />\nソースはここ: <a href=\"https://pypi.org/project/RPi.GPIO/#files\" target=\"_blank\">RPi.GPIO · PyPI</a></p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>プログラム実行して、スイッチかキーボードで出力値変えてみる。<br />\n設定値の範囲は個体差があるので、適当に変更必要。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Pythonのasyncioでnon-blockingなコンソール入力</title>\n  </head>\n  <body>\n    <header>\n      <h1>Pythonのasyncioでnon-blockingなコンソール入力</h1>\n      <p>Pythonのasyncioでnon-blockingなコンソール入力を行うためのクラス</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでasyncioを使ったときにnon-blockingなコンソール入力(キーボード入力)ができなくて困ったので、実現するためのクラスを作ってみた。</p>\n\n<p>もともと Linux用に作ったら、Windowsだとうまく動かない。<br />\nちょっと汚い方法だけど、とりあえず動くようにしてお茶を濁しておく。<br />\n(あんまりテストしてないから動かなかったらごめん)</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/5033eec9b9b774ede4f87604a51fb162.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>お試しならこのソースをそのまま実行すると実行できます。<br />\n<code class=\"language-plaintext highlighter-rouge\">char_mode = False</code> の部分を変更すると、1行入力モードと1文字入力モードを切り替えられます。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout_mode = True</code> の部分を変更すると、タイムアウトなしとタイムアウトありを切り替えられます。</p>\n\n<p>実際に使用するには、このソースをimportして使ってください。</p>\n\n<h1 id=\"注意\">注意</h1>\n\n<p>Linuxで1文字入力モードを使っている場合は、終了時(例外で死んだ場合も含めて)<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行しないと悲しいことになります。<br />\n(ターミナルの入力モードが変更されてしまうので、うまく入力できなくなる)<br />\nそのために、<code class=\"language-plaintext highlighter-rouge\">atexit.retister()</code>で終了処理ルーチンを登録し、その中で<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行するようにしています。</p>\n\n<h1 id=\"ひとりごと\">ひとりごと</h1>\n\n<p>asyncioのサンプルって、タスク1個で動かしてることが多いからあんまり ありがたみが分からんのかな…<br />\nあと、タスクとコルーチンが同じように語られていて分かり難いのもあると思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</h1>\n      <p>Raspberry Pi OS(64bit)のRaspberry Pi Imagerを使用したインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>また手順が変わったみたいなので、メモも更新。<br />\n(2023/10/15 最新版での試行結果を反映)</p>\n\n<h1 id=\"sdカードへの書き込み\">SDカードへの書き込み</h1>\n\n<p>Raspberry Pi Imager なるツールを使うようになったらしい。<br />\n使い方はあちこちに書いてあるけど、例えばこちら。</p>\n<ul>\n  <li><a href=\"https://ascii.jp/elem/000/004/094/4094421/\" target=\"_blank\">Raspberry Pi Imagerの使い方 ― v1.7.2以降 対応版</a></li>\n  <li><a href=\"https://www.mikan-tech.net/entry/raspi-imager-headless-setup\" target=\"_blank\">Raspberry Pi Imagerが新しくなった!Lite版もらくらくHeadless Setup</a></li>\n</ul>\n\n<p>これを使うと、最初のユーザを自由に設定できるので、これまでのpiユーザを変更するなんてことはやらなくて済む。<br />\nWi-Fiの設定やSSHの設定も(なんかWindowsが適切に設定されてれば公開鍵が自動で設定されるみたい)ここでできる。</p>\n\n<p>パスワードが設定ファイルに書き出されるので(さすがに平文ではない、最初の起動が終わったら削除される)、<br />\nセキュリティ上気になる場合は仮パスワードを設定しておいて<br />\n最初にログインしたときに変更する、なんてことをやった方が良いと言ってる解説ページもあった。</p>\n\n<blockquote>\n  <p>[!WARNING]\n<del>なぜかSSHの認証方法が毎回「パスワード認証を使う」になってしまうので、公開鍵を使うときは再度設定が必要。</del> \n(1.7.5では改善された模様)</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\n<del>(少なくとも)2023/10以降のバージョンはopenSSHのバージョンがRSA非対応になっているので、 \n 鍵ファイル作成の際はRSA以外(ed25519など)で作成する必要がある。</del> <br />\n(2023/10/21 誤解してたので書き直し)<br />\n(少なくとも)2023/10以降のバージョンはopenSSHのバージョンが SSH-RSA 非対応になっているので、<br />\nTeraterm Ver4.106以前など RSA-SHA2未対応の環境ではRSA鍵では繋がらない。 \nその場合は RSA以外(ed25519など)で作成すれば良い。<br />\nssh-keygenのデフォルトはRSAなので、<code class=\"language-plaintext highlighter-rouge\">ssh-keygen -t ed25519</code> などとする。<br />\nもちろん、Teraterm Ver4.107以降に変更するという手もある。</p>\n</blockquote>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1\n</code></pre></div></div>\n<h2 id=\"ipv6の無効化\">IPv6の無効化</h2>\n<p>IPv6を無効化しておきたいときは、\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する。<br />\nこのファイルは1行で書かないといけないので、改行してはいけない。</p>\n\n<blockquote>\n  <p>[!WARNING]\n<del>以前はこれで無効化できていたはずだけど、2023/10現在 この手順では無効化できないらしい。<br />\n下でセットアップスクリプトで無効化処理を実行するように変更した。</del> <br />\n(2023/10/21 間違ってたので削除)</p>\n</blockquote>\n\n<h2 id=\"ブートログの表示\">ブートログの表示</h2>\n\n<p>ブートログが見えないと不安な人は、<br />\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> から <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code>\nを削除しておくとよい。</p>\n<blockquote>\n  <p>[!NOTE]\nLITE版では<code class=\"language-plaintext highlighter-rouge\">quiet</code>を削除(それ以外は指定されていないので)</p>\n</blockquote>\n\n<h1 id=\"最初の起動\">最初の起動</h1>\n<p>書き込んだSDカードをRaspberry Piに挿入して電源ON。<br />\nごちょごちょと設定したあと、起動する(途中2回ほどrebootしてるらしい)</p>\n\n<p>あとは起動後の設定。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># アップデート実行\nsudo apt update\nsudo apt upgrade\n\n# リブート\nsudo reboot\n</code></pre></div></div>\n\n<h1 id=\"カスタマイズ\">カスタマイズ</h1>\n\n<blockquote>\n  <p>[!NOTE]\n以降の処理をスクリプトにまとめました。<br />\n<a href=\"https://gist.github.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c\" target=\"_blank\">Raspberry Pi セットアップスクリプト </a><br />\n以下の手順で実行できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.githubusercontent.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c/raw/pi_setup1.sh\nbash pi_setup1.sh\n</code></pre></div>  </div>\n  <p>LITE版を使うときは変数<code class=\"language-plaintext highlighter-rouge\">LITE_OS</code>に<code class=\"language-plaintext highlighter-rouge\">1</code>を設定して実行します。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> <span class=\"nv\">LITE_OS</span><span class=\"o\">=</span>1 bash pi_setup1.sh\n</code></pre></div>  </div>\n\n  <p>途中でパスワード入力しないといけないので、完全自動じゃないけど、かなり手間は省けるはず。<br />\n実行後、<code class=\"language-plaintext highlighter-rouge\">pi_setup1.sh</code>は不要なので削除して可。<br />\n実行が終わったらリブートすること。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>reboot\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h2 id=\"resizeスクリプトの取得\">resizeスクリプトの取得</h2>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/4f39afbcd8471426421944b597f3a5f2963984c6/resize.py\n\n<span class=\"nb\">chmod</span> +x resize.py\n\n./resize.py\n</code></pre></div></div>\n\n<h2 id=\"ロケールの変更\">ロケールの変更</h2>\n<p>日本語表示のため、ロケールを変更する。<br />\n(imagerだとキーボードレイアウトの変更はやってくれるけど、ロケールの変更はやってくれないらしいので)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ロケールの変更</span>\n<span class=\"nb\">sudo </span>raspi-config nonint do_change_locale ja_JP.UTF-8\n\n<span class=\"c\"># リブートまでとりあえずLANGのみ変更で日本語表示</span>\n<span class=\"nb\">export </span><span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF-8\n</code></pre></div></div>\n\n<h2 id=\"bashrc-の変更\">.bashrc の変更</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n</code></pre></div></div>\n\n<h2 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h2>\n\n<p>物理キーボード接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]<br />\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n\n</blockquote>\n\n<h2 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h2>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h2 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h2>\n\n<p>まずはワークディレクトリの作成</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown $USER:$USER /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a $USER\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo service smbd reload\nsudo service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"vncサーバの有効化\">VNCサーバの有効化</h2>\n\n<p>リモートデスクトップを使うために、VNCサーバの有効化を行う。<br />\nLITE版では不要。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    # VNCサーバの有効化\n    3 Interfacing Options\n        I3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>\n            The VNC Server is enabled\n            と表示されるので <Ok>\n\n    # VNC解像度の設定\n    2 Display Options\n        D5 VNC Resolution\n        \n            解像度が色々表示されるので、\n            使いたい解像度を選択(例えば 1920x1080 )して<Select>\n            The resolution is set to «選択した解像度»\n            と表示されるので <Ok>\n    # 設定終了\n    <Finish>\n</code></pre></div></div>\n\n<h2 id=\"ipv6-の無効化\">IPv6 の無効化</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code>での設定では無効化できなくなったと思ったけど、勘違いだった。<br />\nなので、上記の<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する方法でOK。</p>\n\n<p>でも、その時に<code class=\"language-plaintext highlighter-rouge\">mncli</code>コマンドで無効化するスクリプトを作ったので、せっかくなので残しておく。</p>\n\n<p>接続名一覧を取得し、 それぞれに対して無効化するコマンドを実行する。<br />\n接続名に「有線接続 1」と空白が含まれている接続があるので、一時的に空白をセミコロンに置換して処理を行っている。<br />\n(これをやらないと「有線接続」と「1」に分けて処理されてしまう)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 接続一覧を取得</span>\n<span class=\"nv\">conn_data</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli <span class=\"nt\">-t</span> connection<span class=\"si\">)</span>\n\n<span class=\"c\"># 空白を\";\"に置換(配列代入時に誤動作するのを防止)</span>\n<span class=\"nv\">conn_data</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">conn_data</span><span class=\"p\">// /</span><span class=\"s2\">\";\"</span><span class=\"k\">}</span>\n\n<span class=\"c\"># ':'区切りで1列目をconnections配列に格納</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"s2\">\"</span><span class=\"nv\">$conn_data</span><span class=\"s2\">\"</span> | <span class=\"nb\">cut</span> <span class=\"nt\">-d</span><span class=\"s2\">\":\"</span> <span class=\"nt\">-f1</span><span class=\"si\">)</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 配列の要素を処理</span>\n<span class=\"k\">for </span>connection <span class=\"k\">in</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[@]</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 上で;に置換した空白を戻す</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"p\">//</span><span class=\"s2\">\";\"</span><span class=\"p\">/</span><span class=\"s2\">\" \"</span><span class=\"k\">}</span>\n\n    <span class=\"k\">if</span> <span class=\"o\">[[</span> <span class=\"s2\">\"</span><span class=\"nv\">$connection</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s1\">'lo'</span> <span class=\"o\">]]</span><span class=\"p\">;</span> <span class=\"k\">then</span>    <span class=\"c\"># loデバイスは無効にできないので除外</span>\n      <span class=\"nb\">echo</span> <span class=\"s2\">\"disable </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span> \n      <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> ipv6.method </span><span class=\"se\">\\\"</span><span class=\"s2\">disabled</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n      <span class=\"c\"># 有効にする場合はこちら</span>\n      <span class=\"c\"># cmd=\"sudo nmcli connection modify \\\"${connection}\\\" ipv6.method \\\"auto\\\"\"</span>\n      <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n      <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone</span>\n</code></pre></div></div>\n\n<h1 id=\"splash-screenの再有効化\">Splash screenの再有効化</h1>\n\n<p>セットアップ時にブートログが表示されるようにしたけど、<br />\nやっぱり表示したくなくなった(Splash screenを表示)、てなときは以下で。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S6 Splash Screen\n            Would you like to show the splash screen at boot?\n            と聞かれるので有効化するときは <Yes> を選択\n            Splash screen at boot is enabled)\n            と表示されるので <Ok>\n\n    Would you like to reboot now?\n    と聞かれるので、その場でリブートしてよければ<Yes>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n直接<code class=\"language-plaintext highlighter-rouge\">/boot/cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code> を追加しても良い。<br />\nLITE版では <code class=\"language-plaintext highlighter-rouge\">quiet</code>のみ追加。</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 22.04のVirtualBoxへのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 22.04のVirtualBoxへのインストール</h1>\n      <p>Ubuntu 22.04のVirtualBoxへのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 22.04のVirtualBoxへのインストール手順をまとめてみた。\n20.04と大差ないけど、微妙に違う点もあるので。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2204-インストール媒体の入手\">Ubuntu 22.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら:\n<a href=\"https://www.ubuntulinux.jp/products/JA-Localized/download\" target=\"_blank\">Ubuntu Desktop 日本語 Remixのダウンロード</a><br />\n日本語環境構築するなら本家よりRemix版を使った方がなにかと便利(な気がする)。<br />\n<a href=\"https://jp.ubuntu.com/download\" target=\"_blank\">本家はこちら</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを4096MB以上に設定しておくこと</strong></p>\n<blockquote>\n  <p>[!NOTE]\n推奨環境が4GB以上なので。<br />\nウィンドウマネージャだけ動いている状態で1GBちょい使用だったので、\n2048MBでも動くと思う。でも、何か動かしたらすぐ足りなくなりそう。 <br />\nそれにしても、どんどん必要メモリが大きくなるな。<br />\n仮想環境で4GBってことは、HostOS環境下には8GB以上は必要ってことだよな。<br />\nプロセッサも2個割り当てておいた方が良いのかな?<br />\nこれは様子見てからどうするか決めよう。</p>\n</blockquote>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<blockquote>\n  <p>[!TIP]\nウィンドウが画面からはみ出して「続ける」ボタンが押せないときは、Alt+F7キーを押したあと、マウスでドラッグすると\nウィンドウを移動できるので、ボタンが見えるようところまで移動してクリックしてちょ。</p>\n</blockquote>\n\n<p>以下の説明が図付きで分かりやすい:\n<a href=\"https://qiita.com/HirMtsd/items/d43fc5215a88cbf414c9\" target=\"_blank\">Windows11上のVirtualBoxにUbuntu22.04LTSをインストール</a><br />\nWindows11って書いてあるけど、Windows10でも同じ。<br />\nここの説明では「不完全な言語サポート」うんぬんの説明があるけど、日本語Remix版でインストールすると、この部分は不要みたい。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<p>まだGuestAdditionをインストールしてないからコピペできないけど、BashのTab補完が効くので、\nちょろっと入力してあとは補完に頼れば大丈夫。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面 を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源管理を選択<br />\n右側で画面のブランクのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>裏でソフトウェアの更新が動いていると、ロックファイルがロックされてしばらく適用できないので、<br />\nそうなっちゃったらお茶でも飲んでしばらくお待ちください。<br />\nソフトウェアの更新による自動更新を止める方法は後ほど。</p>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweaks \n</code></pre></div></div>\n\n<h3 id=\"一旦リブート\">一旦リブート</h3>\n<p>更新適用のため。</p>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>以前にマウントしたものが残ってたらアンマウントしておくこと(インストール後初めてなのでマウントされてることはないけれど)。<br />\nVirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<blockquote>\n  <p>[!TIPS]\nプログラムが自動で始まらない場合は、CDROMのマウント先(たぶん、<code class=\"language-plaintext highlighter-rouge\">/media/<USER>/VBox_GAs_x.x.xx/</code>)に移動して<code class=\"language-plaintext highlighter-rouge\">sudo VBoxLinuxAdditions.run</code>を実行すれば良い。</p>\n</blockquote>\n\n<h3 id=\"再度リブート\">再度リブート</h3>\n<p>GuestAdditionによる更新適用のため。</p>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから「デバイス」→「クリップボードの共有」→「双方向」<br />\nを選択。\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<h3 id=\"使わないのでアンインストール\">使わないのでアンインストール</h3>\n\n<p>使うツールがあったら残してちょ。</p>\n\n<h4 id=\"ツール類\">ツール類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h4 id=\"ゲーム類\">ゲーム類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h4 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"お好みで\">お好みで</h2>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>ディレクトリにコピるだけ。<br />\n下では全部コピってるけど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.0.0/UDEVGothic_v1.0.0.zip \nunzip UDEVGothic_v1.0.0.zip \n<span class=\"nb\">mkdir</span> ~/.fonts\n<span class=\"nb\">cp </span>UDEVGothic_v1.0.0/<span class=\"k\">*</span>.ttf ~/.fonts/\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。<br />\nさっきフォントのインストールに使った端末ウィンドウを使うと\nエラーで端末ウィンドウが落ちるかもしれないんで一旦終了して新しいウィンドウで。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<h3 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h3>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h3 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h3>\n\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h3 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h3>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>~/.bashrcに以下を追記。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"c\"># Ubuntu22.04だとwaylandになるらしい</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"wayland\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vi\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># # venvの仮想環境名を表示するための設定</span>\n    <span class=\"c\"># show_virtual_env() {</span>\n    <span class=\"c\">#   if [ -n \"$VIRTUAL_ENV\" ]; then</span>\n    <span class=\"c\">#     echo \"($(basename $VIRTUAL_ENV))\"</span>\n    <span class=\"c\">#   fi</span>\n    <span class=\"c\"># }</span>\n    <span class=\"c\"># PS1='$(show_virtual_env)'$PS1</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># openVINO の設定はdirenvで</span>\n<span class=\"c\"># for openVINO</span>\n<span class=\"c\"># source /opt/intel/openvino_2021/bin/setupvars.sh</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nUbuntu20.04とちょっとキーが変更されてる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-home <span class=\"nb\">false \n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"sambaのインストール\">sambaのインストール</h3>\n\n<p>ツール本体のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加<br />\n作らなかったワークディレクトリの部分は削除してね。<br />\n他にも共有したいディレクトリがあったら追加してちょ。<br />\nここではOpenVINOのサンプルとか見たかったのでoptを共有してます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n<span class=\"c\"># abcの下にリモートのファイルが見えたらOK</span>\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"ファイルnautilusのデフォルト動作変更\">ファイル(nautilus)のデフォルト動作変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アドレスバーをテキスト形式にする</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences always-use-location-entry <span class=\"nb\">true</span> \n\n<span class=\"c\"># 詳細表示をデフォルトに</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences default-folder-viewer <span class=\"s1\">'list-view'</span> \n\n<span class=\"c\"># 隠しファイルを表示する</span>\n<span class=\"c\"># 隠しファイルの表示はちょっと場所が違う</span>\ngsettings <span class=\"nb\">set </span>org.gtk.Settings.FileChooser show-hidden <span class=\"nb\">true</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアの更新(update-manager)を起動\n    <ul>\n      <li>更新のチェックが始まった場合はちょっと待つ</li>\n      <li>設定…をクリック\n        <ul>\n          <li>アップデートタブを選択</li>\n          <li>アップデートの自動確認を「なし」に変更</li>\n          <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n          <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n          <li>閉じるをクリック</li>\n        </ul>\n      </li>\n      <li>OKで終了</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a><br />\nリンク先は「Ubuntu 20.04/18.04 LTS」となっているが、Ubuntu22.04でも同じらしい。<br />\nNative環境にインストールしてないので未確認だけど…</p>\n\n<p>リブート必要だが、以下のIPv6無効化とまとめてリブートでも可。</p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<p>マスタイメージを残しておいて、色々な環境をお試しするには仮想マシンをクローンして使うのがおススメ。<br />\nVirtualBoxのメインウィンドウでマスタイメージの仮想マシンを右クリック→クローンを選択、名前とパスを設定し、あとはごにょごにょ…</p>\n\n<p>クローンした仮想マシンを起動し、必要な変更を加える。</p>\n\n<h2 id=\"ネットワーク設定の変更\">ネットワーク設定の変更</h2>\n\n<p>マシン名とか同じ名前だと色々不都合があるので、変更しておく。<br />\n他のクローン仮想環境と同時に使わないならそのままでも良いけど。<br />\nIPアドレスも固定で割り振っておくと名前が引けない時にさくっと分かってなにかと便利…なんだけど、最近はWindowsもUbuntuもRaspberryPiもmDNSがサポートされてるから自動割り当てのままでもそんなに不便はないかも。</p>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<p>このコマンドで<code class=\"language-plaintext highlighter-rouge\">/etc/hostname</code>が書き換えられる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<p>もちろん、vimとかで書き換えても可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<p>下のコマンドを実行するための接続名を確認しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<p>IPアドレスを手動割り当てに変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> \n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<p>IPアドレスを手動割り当てに変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> gw4 <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nIPアドレスの変更をGUIで行うには以下。<br />\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>まとめて実行するならこちら。<br />\nホスト名、接続名、IPアドレスなどは適宜変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># マシン番号の設定とホスト名の設定</span>\n<span class=\"nv\">number</span><span class=\"o\">=</span>30\n<span class=\"nv\">new_hostname</span><span class=\"o\">=</span>skull<span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span>\n\n<span class=\"c\"># HOSTNAMEの変更</span>\n<span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/ubuntu-22.*</span><span class=\"nv\">$/</span><span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span><span class=\"s2\">/\"</span> /etc/hosts\n\n<span class=\"c\"># HOST ONLY ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.56.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n\n<span class=\"c\"># BRIDGE ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.78.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> gw4 <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<h2 id=\"あとはお約束\">あとはお約束</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>VirtalBoxのバージョンが変更されているときは、GuestAdditionのバージョンアップも忘れずに。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</h1>\n      <p>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使うためのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1ではpypiからモジュールインストールするだけで使えるようになったのだけれど(python使用時)、<br />\nNCS2を使用しようとすると以下のようなエラーが発生します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>RuntimeError: Cannot load library 'libopenvino_intel_myriad_plugin.so: libopenvino_intel_myriad_plugin.so: cannot open shared object file: No such file or directory\n</code></pre></div></div>\n\n<p>どうやらNCS2(myriad)用のshared libraryがないらしい。<br />\nインストールミスか?と思ったけど、pypiのインストールファイル確認してみたけど、やっぱり入っていない。</p>\n<blockquote>\n  <p>[!NOTE]\nwhlファイルの拡張子をzipに変更するとファイルの中身を確認できる</p>\n</blockquote>\n\n<p>そこで、ソースからNCS2用のshared libraryをbuildしてみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p>参考: <a href=\"https://github.com/openvinotoolkit/openvino/wiki/BuildingForLinux\" target=\"_blank\">BuildingForLinux</a></p>\n\n<p>今回はWSL2の仮想マシンでbuildしてみることにする。<br />\nまた、NCS2用のshared libraryだけが目的なので、pythonモジュールとかはbuildしていない。<br />\nたぶん、ちゃんとCMAKEのオプション設定すればbuild時間が短くなるかもしれないけど、そこはお手軽最優先で。</p>\n\n<blockquote>\n  <p>[!NOTE]\n色々とbuildのために``apt install`するので、WSL2上のcloneした仮想マシンで実行した。<br />\nNCS2はWSL2上で使えないけど、buildするだけなら大丈夫みたい。<br />\n仮想マシンはUbuntu22.04を使用。 たぶん、20.04でも同様と思われる。<br />\nまぁ、Docker使えという説もある…</p>\n</blockquote>\n\n<h2 id=\"ソース取得\">ソース取得</h2>\n\n<p>openVINOのリポジトリからソース取得。<br />\n例によって<code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけてディスク容量&通信時間節約。<br />\n今回はcontribは使わない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> /work  clone  <span class=\"nt\">-b</span> 2022.1.0 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> /work/openvino submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n<span class=\"nb\">cd</span> /work/openvino\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこれ書いてる時点で2022.1.1がリリースされているけど、-bオプション変えればOKでしょう。\nたぶん。。。</p>\n</blockquote>\n\n<h2 id=\"必要なモジュールのインストール\">必要なモジュールのインストール</h2>\n\n<p>必要なモジュールはスクリプトファイルにまとめられているので、それを実行するだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash install_build_dependencies.sh \n</code></pre></div></div>\n\n<p>cmakeのバージョン3.17以上が必要なので、cmakeがそれ以下だとcmakeをソースからbuildしてくれる。<br />\nUbuntu22.04のデフォルト状態だとcmakeのバージョンは3.16なのでbuildが実行される。<br />\nちょっと時間がかかるけど、気長にお待ちください。</p>\n\n<h1 id=\"build\">build</h1>\n\n<p>準備ができたので、buildを実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>make.log\n</code></pre></div></div>\n\n<p>あとはひたすら待つ。<br />\n(うちの環境では1時間くらいだったかな)</p>\n\n<h1 id=\"ターゲットマシンにコピー\">ターゲットマシンにコピー</h1>\n\n<p>makeが終わると、以下のファイルが出来ているはず。<br />\nこの2つをNCS2を使用するターゲットマシンにコピーする。</p>\n\n<ul>\n  <li>openvino/bin/intel64/Release/lib/libopenvino_intel_myriad_plugin.so</li>\n  <li>openvino/bin/intel64/Release/lib/usb-ma2x8x.mvcmd</li>\n</ul>\n\n<p>ターゲットマシンのコピー先はopenVINOモジュールのインストール先の<code class=\"language-plaintext highlighter-rouge\">openvino/libs/</code>ディレクトリの下。<br />\n<code class=\"language-plaintext highlighter-rouge\">libopenvino.so</code>など、soファイルが並んでいるはず。</p>\n\n<p>なお、openVINOモジュールのインストール先は以下のようなコマンドで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"^openvino\"</span>\n</code></pre></div></div>\n\n<p>コピーの方法はエクスプローラでもrcpでも何でもよい。 \nエクスプローラなど、Windows経由でコピーすると実行属性が落ちてしまうけど、<br />\nそもそも実行属性必要ないので気にしなくて良いです。</p>\n\n<h1 id=\"テスト\">テスト</h1>\n<p>NCS2を使用してプログラム実行してみて、エラーにならずに実行できればOK。</p>\n\n<h1 id=\"つぶやき\">つぶやき</h1>\n<p>でも、なんでNCS2用のライブラリ入ってないんだろ?<br />\n単なる入れ忘れ? サポート終了目前?</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINO 2022.1のbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1はRaspberry Pi OS(64bit)向けのバイナリがリリースされていないので、自力でbuildしてみます。</p>\n\n<p>今回もUbuntu上のDockerコンテナを使用しましたが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思います。</p>\n\n<p>前回はPythonを諦めてクロスコンパイルする方法とbuild時間を諦めてセルフコンパイル(エミュレーション)する方法を使いましたが、<br />\n今回はPython以外をクロスコンパイル、Python関連部をセルフコンパイル(エミュレーション)して生成物をマージする方法をとってみます。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_2022.1_pi64 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_2022.1_pi64\n</code></pre></div></div>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>workディレクトリを作成し、openvino と openvino_contrib のリポジトリをcloneします。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 2022.1.1 <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib checkout 1a28b530ab40d2ad79ab29021dfddfbbc7d2db0b\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の2022.1だと一部のノードが未対応とエラーになるため、対応済みのcommitを使用します。<br />\ntagが振られていないので、commit IDを指定してcheckoutします。<br />\nこれ以降のcommitではopenvinoのバージョン2022.2が必要になります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ntagやbranchが設定されていない場合はcloneでcheckoutするバージョンを指定できないため、\n一旦cloneしてからcommit IDを指定してcheckoutします。<br />\nsubmoluleのcheckoutは対象のバージョンをcheckoutしてから行います。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の最新commit(試した時点ではcommit ID <code class=\"language-plaintext highlighter-rouge\">fd2ac364435757d23a9b3e91d67235b5e6555bf9</code>)を使用する場合は\nopenvinoのバージョン2022.2を使用する必要がありますが、試した時点で <code class=\"language-plaintext highlighter-rouge\">2022.2.0.dev20220829</code> がリリースされているので\nこれを使用します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0.dev20220829  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit -C ./work/openvino_contrib checkout fd2ac364435757d23a9b3e91d67235b5e6555bf9\ngit -C ./work/openvino_contrib submodule update --init --recursive --depth 1\n</code></pre></div>  </div>\n  <blockquote>\n    <p>2022.2.0正式リリース後はこんな感じになるのかな?</p>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  -b 2022.2    --recursive --depth 1 https://github.com/openvinotoolkit/openvino_contrib.git\n</code></pre></div>    </div>\n  </blockquote>\n\n  <p>この場合、NVIDIA GPUのpluginのbuildでエラーになるため、以下のcmakeのオプションに以下のオプションを追加します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      -D BUILD_nvidia_plugin=OFF\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h1 id=\"openvinoのbuildクロスコンパイル\">openVINOのBuild(クロスコンパイル)</h1>\n\n<p>クロスコンパイルでpython関連以外の部分をbuildします。</p>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir cross</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">cross/Dockerfile</code>を作成します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cross/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates:arm64 <span class=\"se\">\\\n</span>    libboost-regex-dev:arm64 <span class=\"se\">\\\n</span>    libgtk2.0-dev:arm64 <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev:arm64 <span class=\"se\">\\\n</span>    libcairo2-dev:arm64 <span class=\"se\">\\\n</span>    libpango1.0-dev:arm64 <span class=\"se\">\\\n</span>    libglib2.0-dev:arm64 <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev:arm64 <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗します</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeは新しめのをインストールしておきたいので、3.23.2をbuildして使用しています。<br />\nもしかすると、<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたものをそのまま使っても大丈夫かもしれませんが。</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_cross cross\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\ncacheを使わずimage buildしたい場合は<code class=\"language-plaintext highlighter-rouge\">--no-cache</code>オプションを追加します。<br />\n以前に作ったイメージのキャッシュを使って<code class=\"language-plaintext highlighter-rouge\">apt install</code>がエラーになったことがあったので。<br />\n(デフォルトのリポジトリに変更があったらしい)</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_cross_2 ov_2022.1_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_cross_2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_2022.1_pi64_cross_2 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/cmake/arm64.toolchain.cmake <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_BEH_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLDNN</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_FUNCTIONAL_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">THREADING</span><span class=\"o\">=</span>SEQ <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">CONTRIB_TOP</span><span class=\"k\">}</span>/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span> 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=${WORK_DIR}/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"クロスコンパイル終了\">クロスコンパイル終了</h3>\n<p>クロスコンパイルはここまでなので、コンテナから抜ける。</p>\n\n<h1 id=\"openvinoのbuildセルフコンパイル\">openVINOのBuild(セルフコンパイル)</h1>\n\n<p>セルフコンパイルでpython関連部分をbuildします。<br />\ncythonを使うときにクロスコンパイルする方法が分からないので、セルフコンパイルで。</p>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir emu</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">emu/Dockerfile</code>を作成します。</p>\n\n<p>python部だけなので、こんなにライブラリとか要らない気もしますが、全部セルフコンパイルするときのことも考えて\n全部入りのイメージを作っておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  emu/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates <span class=\"se\">\\\n</span>    libboost-regex-dev <span class=\"se\">\\\n</span>    libgtk2.0-dev <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev <span class=\"se\">\\\n</span>    libcairo2-dev <span class=\"se\">\\\n</span>    libpango1.0-dev <span class=\"se\">\\\n</span>    libglib2.0-dev <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_emu emu\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_emu_2 ov_2022.1_pi64_emu /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_emu_2\n</code></pre></div></div>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成-1\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build_python <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build_python\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">InferenceEngineDeveloperPackage_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/build <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/src/bindings/python 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">CMAKE_INSTALL_PREFIX</code>の設定はクロスコンパイルのときと同じ設定にしてください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npyenvでインストールしたpythonなど、デフォルトでないpythonを使用する場合に指定します。<br />\n(以下の設定値はubuntu 22.04の標準インストールの場合のパスなのであまり参考にならないかも)</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  -D PYTHON_EXECUTABLE=/usr/bin/python3.8 \\\n  -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.8.so \\\n  -D PYTHON_INCLUDE_DIR=/usr/include/python3.8 \\\n  -D PYTHON_MODULE_EXTENSION=\".so\" \\\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"make-1\">make</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。</p>\n\n<h3 id=\"セルフコンパイル終了\">セルフコンパイル終了</h3>\n<p>セルフコンパイルはここまでなので、コンテナから抜けます。</p>\n\n<h1 id=\"インストール媒体の作成\">インストール媒体の作成</h1>\n\n<p>ホスト側の<code class=\"language-plaintext highlighter-rouge\">work</code>ディレクトリ内を見ると、<code class=\"language-plaintext highlighter-rouge\">intel</code>ディレクトリが出来ているので、ここをtarなどで固めておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>work\n<span class=\"nb\">tar </span>czvf ov1.tar.gz intel/\n</code></pre></div></div>\n\n<p>この<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiにコピーして展開します。</p>\n\n<h1 id=\"raspberrypiへのインストール\">RaspberryPiへのインストール</h1>\n\n<h2 id=\"インストール\">インストール</h2>\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiの適当なディレクトリに展開します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/proj</code>ディレクトリに展開しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /proj/\n<span class=\"nb\">tar </span>xzvf ov1.tar.gz \n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<p>これで<code class=\"language-plaintext highlighter-rouge\">/proj/intel/openvino</code>ディレクトリにインストールされました。</p>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n<p>環境変数の設定のため、以下を実行します。<br />\nshell起動の度に実行が必要なので<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>などに書いておくと良いです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/intel/openvino/setupvars.sh \n</code></pre></div></div>\n\n<h2 id=\"udevルールの設定\">udevルールの設定</h2>\n<p>以下のスクリプトを実行すればNCS2を挿せば認識されるようになります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/proj/intel/openvino/install_dependencies/install_NCS_udev_rules.sh \n</code></pre></div></div>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n<p>openCVの必要になるので、インストールしておきます。<br />\n今回はお手軽にpipでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認用のプログラムは<a href=\"https://github.com/ippei8jp/ov_trial_2022.1\" target=\"_blank\">https://github.com/ippei8jp/ov_trial_2022.1</a> とかにあります。<br />\nでもモデルのダウンロード/コンバートはRaspberryPiではできないので、UbuntuやWondowsで実行したものをコピーして使用してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>test shellのひな型</title>\n  </head>\n  <body>\n    <header>\n      <h1>test shellのひな型</h1>\n      <p>linuxでのテストプログラム用コマンド入力処理のサンプル</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>linuxでプログラムを作ったとき、ユニットテストを各処理(コマンド)単位で行いたいときに、テストシェルを作ると便利。<br />\nでも、その都度作っていると効率悪いので、ひな型を作ってみた。<br />\nどうせなら、コマンドヒストリとか、入力補完とかあると便利だなぁ~、ということで、<br />\n<code class=\"language-plaintext highlighter-rouge\">readline</code>使ってそれらを実現しておく。</p>\n\n<p>たぶん、bash使ってるシステムなら<code class=\"language-plaintext highlighter-rouge\">libreadline</code>も入ってるだろうから、特にインストールとかも不要。</p>\n\n<h1 id=\"コンパイル方法\">コンパイル方法</h1>\n<p>以下のコマンドでコンパイルできる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gcc test_shell.c <span class=\"nt\">-lreadline</span> <span class=\"nt\">-o</span> test_shell\n</code></pre></div></div>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n『コマンド定義』の部分を所望のコマンドと処理に書き換えて使ってちょ。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/fbccd09aefa28dd097a13c68d0111d0d\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/fbccd09aefa28dd097a13c68d0111d0d.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>test shellのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>test shellのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用コマンド入力処理のサンプルのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/15/test_shell_1.html\" target=\"_blank\">test shellのひな型</a>\nでC言語版を作ったので、python版も作っておこうかと作ってみた。</p>\n\n<p>pythonには『行指向のコマンドインタープリタのサポート』というcmdモジュールが標準で用意されている。<br />\nこれを使用すれば、そんなに手間もかからず実装できる。<br />\n補完処理やヘルプ表示も簡単。<br />\nコマンドの大文字/小文字同一視はできなかったけど…</p>\n\n<p>コマンド補完だけでなく、パラメータ補完も可能。<br />\nもちろん、補完のための処理は書かないといけないけど。</p>\n\n<p>標準モジュールしか使ってないので、モジュールをインストールする必要なし。</p>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n大体コメントに書いたつもり。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>キーボードコマンダーのひな型(C言語版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>キーボードコマンダーのひな型(C言語版)</h1>\n      <p>linuxでのテストプログラム用キーボードコマンダー</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/15/test_shell_1.html\" target=\"_blank\">test shellのひな型</a>\nのようなテストシェルでコマンド処理するほどでもないが、いくつかのパターンを繰り返し実行してテストしてみたい\n場合に使えるキーボードコマンダー(という名前がふさわしいか分からないが)のひな型を作ってみた。</p>\n\n<p>キー入力1個(例えば<code class=\"language-plaintext highlighter-rouge\">a</code>キー)でリターンを押さずに何らかの処理が実行できると便利な時がある。<br />\nまた、ターゲットボードのスイッチ入力の代替処理としても便利かもしれない。</p>\n\n<p>Windowsの<code class=\"language-plaintext highlighter-rouge\">getch()</code>関数みたいなものと言えば分かるかな?<br />\nキー入力自体はブロッキング処理なので、<code class=\"language-plaintext highlighter-rouge\">kbhit()</code>みたいな使い方はできない。<br />\n(これを行うには<code class=\"language-plaintext highlighter-rouge\">select()</code>をタイムアウト付きで組み合わせて使う必要があるが、\n簡単なテスト用を想定しているので そこまでは対応しない)</p>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n大体コメントに書いたつもり。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6435ac7e3381ec2f8af0b1fdb166d469\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6435ac7e3381ec2f8af0b1fdb166d469.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>キーボードコマンダーのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>キーボードコマンダーのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用キーボードコマンダーのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/18/key_commander_1.html\" target=\"_blank\">キーボードコマンダーのひな型(C言語版)</a>\nのpython版も作/memoBlog定して使うだけなんだけど、<br />\nstdinの設定を元に戻すのを忘れないように、クラス化してデストラクタで設定を戻すようにしてみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれまでatexitモジュール使って終了処理ルーチン登録して<br />\nそこで元に戻してたけど、処理追加忘れて悲しいことになったことが数知れず…</p>\n</blockquote>\n\n<h1 id=\"ちょっと解説\">ちょっと解説</h1>\n<p>このクラスは、複数の箇所からインスタンスを作成してしまうとstdinの設定変更が複数箇所で行われてしまい、<br />\nデストラクタの実行順序によっては正常に元に戻せなくなる可能性がある。<br />\nそれを回避するため、Singletonパターンを適用し、インスタンスが一つだけ保持するようにした。</p>\n\n<p>しかし、これだけでは不十分で、コンストラクタ(<code class=\"language-plaintext highlighter-rouge\">__init__()</code>)が<code class=\"language-plaintext highlighter-rouge\">KeyReader()</code>実行の度に実行されてしまう。(下のNOTE参照) <br />\nそこで、インスタンス変数にコンストラクタ実行済みフラグ(<code class=\"language-plaintext highlighter-rouge\">_inited</code>)を用意し、\nこれが存在しないときのみコンストラクタ処理を実行するようにしている。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">__new__</code>、<code class=\"language-plaintext highlighter-rouge\">__init__</code>、<code class=\"language-plaintext highlighter-rouge\">__del__</code>の実行タイミングは以下のプログラムで確認できる。</p>\n\n  <pre><code class=\"language-pythn\">class Hoge:\n    def __new__(cls, *args, **kargs):\n        print(\"__new__\")\n        if not hasattr(cls, \"_instance\"):\n            print(\"create\")\n            cls._instance = super().__new__(cls)\n        return cls._instance\n    \n    # コンストラクタ\n    def __init__(self):\n        print(\"__init__\")\n        if not hasattr(self, \"_inited\"):\n            print(\"init\")\n            self._inited = True\n    \n    # デストラクタ\n    def __del__(self):\n        print(\"__del__\")\n    \n    def __call__(self):\n        print(\"__call__\")\n\ndef func2() :\n    h2 = Hoge()\n    print(\"h2 before\")\n    h2()\n    print(\"h2 after\")\n\ndef func1() :\n    h1 = Hoge()\n    print(\"h1 before\")\n    h1()\n    print(\"h1 after\")\n\nprint(\"func1 before\")\nfunc1()\nprint(\"func1 after\")\n\nprint(\"func2 before\")\nfunc2()\nprint(\"func2 after\")\n\nprint(\"end\")\n\n</code></pre>\n  <p>実行結果は以下。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>func1 before\n__new__\ncreate                  ← 1回だけ表示されている\n__init__\ninit                    ← 1回だけ表示されている\nh1 before\n__call__\nh1 after\nfunc1 after\nfunc2 before\n__new__\n__init__\nh2 before\n__call__\nh2 after\nfunc2 after\nend\n__del__\n</code></pre></div>  </div>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">Hoge()</code>が実行されると、<code class=\"language-plaintext highlighter-rouge\">__new__()</code>が実行されるが、\n2回目以降は新たにインスタンスを作成せずクラス変数<code class=\"language-plaintext highlighter-rouge\">_instance</code>に格納されたインスタンスを返す。<br />\n(2回目は「create」が表示されていない)</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__init__()</code>が<code class=\"language-plaintext highlighter-rouge\">Hoge()</code>実行の度に実行されているのが分かる。<br />\n(つまりインスタンス生成時に実行されるわけではない)<br />\n<code class=\"language-plaintext highlighter-rouge\">__init__()</code>内でインスタンス変数<code class=\"language-plaintext highlighter-rouge\">_inited</code>の存在をチェックしているので<br />\n「init」は1回しか表示されていないのが分かる。</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__del__()</code> はインスタンス破棄時に実行されるので、1回しか実行されない。</p>\n\n</blockquote>\n\n<p>その他のプログラムの動作についてはソース読んでちょ。<br />\nって、ほとんど何もしてないけど。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico Wでmicropython with Visual Studio Code</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico Wでmicropython with Visual Studio Code</h1>\n      <p>Raspberry Pi Pico W でmicropython の開発にVisual Studio Codeを使用する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico Wでmicropython を使用する際の開発環境(IDE)に 公式では Thonny が推奨されていますが、\nVisual Studio Codeを使用することもできます。<br />\nこのとき、拡張機能 「MicroPico」(旧称Pico-W-Go) を使用します。<br />\nここでは先人の成果を<del>パクり</del> 参照しつつ、なんとなく手順を書いてみることにします。</p>\n\n<h1 id=\"環境構築\">環境構築</h1>\n\n<h2 id=\"pc側の準備\">PC側の準備</h2>\n<p>セットアップ手順は以下が分かりやすい。<br />\n<a href=\"https://flatisle.com/raspberrypi/2289/\" target=\"_blank\">Pico W で遊ぼう(環境構築)</a><br />\nただし、モジュール名が「Pico-W-Go」から「MicroPico」に変更されているので、読み替え必要。</p>\n\n<p>PC側はVisual Studio Code がインストールされていれば 拡張機能で「MicroPico」を検索してインストールするだけ。</p>\n\n<h2 id=\"本体側の準備\">本体側の準備</h2>\n<p>本体側はファームウェアの書き換えを行う。<br />\nファームウェアの最新版は\n<a href=\"https://www.raspberrypi.com/documentation/microcontrollers/micropython.html\" target=\"_blank\">Raspberry Pi Documentation > MicroPython</a>\nからダウンロードできます。<br />\nまた、<a href=\"https://micropython.org/download/RPI_PICO_W/\" target=\"_blank\">MicroPython > DOWNLOAD > Pico W</a>\nには、Nightly buildsのバイナリもあったりします。</p>\n\n<h2 id=\"動作確認\">動作確認</h2>\n<p>Raspberry pi Pico をPCに接続しておいて、Visual Studio Code を起動。</p>\n\n<ul>\n  <li>メニューの「ターミナル」→「新しいターミナル」でターミナルウィンドウを開く(デフォルト状態だとPowershellが実行される)。</li>\n  <li>ターミナルウィンドウの右上の「+」ボタン(新しいターミナル)のドロップダウンリストを開いて\n「Pico(W) vREPL」を選択してvREPLに接続する。<br />\n(+をクリックするとPowershellが新しく開かれるので右のvっぽい記号をクリックする)</li>\n  <li>以下のような表示が出る。<br />\n(バージョン番号とかはファームウェアによって異なる)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>MicroPython v1.20.0-198-g0eacdeb1c on 2023-06-13; Raspberry Pi Pico W with RP2040\nType \"help()\" for more information or .cls/.clear to clear the terminal.\n\n>>> \n</code></pre></div></div>\n\n<p>ここで色々コマンドを入力すれば実行できる</p>\n\n<h1 id=\"いつでもwifiにつなげるように準備\">いつでもwifiにつなげるように準備</h1>\n\n<p>適当なところにフォルダを作成し(以下の例では「test」)、その下にlibフォルダを作り、\nその下にmy_wifi.py として以下のファイルを作成しておく。<br />\n1行目~2行目は自分の環境に合わせて変更しておくこと。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    test\n     +-- lib\n          +-- my_wifi.py\n          \n</code></pre></div></div>\n\n<!-- ファイル名を付けたいときはこれを指定-->\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  my_wifi.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SSID_NAME</span> <span class=\"o\">=</span> <span class=\"s\">\"SSID名\"</span>\n<span class=\"n\">SSID_PASS</span> <span class=\"o\">=</span> <span class=\"s\">\"SSIDパスワード\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">utime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">network</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n<span class=\"c1\"># ==== connecti to wifi access point ============================================\n</span><span class=\"k\">def</span> <span class=\"nf\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">,</span> <span class=\"n\">timeout</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">):</span>\n    <span class=\"n\">wifi</span><span class=\"o\">=</span> <span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">WLAN</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">STA_IF</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'already Connected.    connect skip'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">active</span><span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">)</span>\n        <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"ow\">and</span> <span class=\"n\">timeout</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'.'</span><span class=\"p\">,</span> <span class=\"n\">end</span><span class=\"o\">=</span><span class=\"s\">''</span><span class=\"p\">)</span>\n            <span class=\"n\">utime</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">timeout</span> <span class=\"o\">-=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">():</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">Connected'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Connection failed!'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">False</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">disconnect</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">disconnect</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"n\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">SSID_NAME</span><span class=\"p\">,</span> <span class=\"n\">SSID_PASS</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">ifconfig</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n<p>Visual Studio Code のエクスプローラウィンドウで「フォルダを開く」ボタンをクリック\n(またはメニューの「ファイル」→「フォルダを開く」を選択)し、\n上で作成したフォルダ(例ではtest)を開きます。</p>\n\n<p>コマンドパレットで「MicroPico: Upload project to Pico」を選択します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n現在書き込まれているファイルをすべて消去するには<br />\nコマンドパレットで「MicroPico: Delete all files from board」を選択します。</p>\n\n</blockquote>\n\n<p>実際に書き込まれたかはターミナルウィンドウで以下のように実行することで確認できます。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">>>></span> <span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'lib'</span><span class=\"p\">]</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/lib'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'my_wifi.py'</span><span class=\"p\">]</span>\n</code></pre></div></div>\n<p>または後述の仮想ファイルシステムを使用しても確認できます。</p>\n\n<p>でもって、使用するプログラムで<code class=\"language-plaintext highlighter-rouge\">import my_wifi</code> とやれば接続できます。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">my_wifi.isconnected()</code> で接続中かが分かります。\n<code class=\"language-plaintext highlighter-rouge\">my_wifi.disconnect()</code> でAPから切断できます。</p>\n\n<h1 id=\"仮想ファイルシステムを使用する\">仮想ファイルシステムを使用する</h1>\n<p>仮想ファイルシステムを使用すると、現在PaspberryPi Pico(W)のストレージに書き込まれているファイルを\n直接確認/操作することができます。</p>\n\n<ul>\n  <li>コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n  <li>エクスプローラウィンドウに「Pico (W) Remote Workspace」ができ、その下にディレクトリ/ファイルが表示される</li>\n</ul>\n\n<p>ここのファイルを開くとPaspberryPi Pico(W)のストレージにあるファイルを直接参照できます。<br />\nまた、内容を変更して保存すると PaspberryPi Pico(W)のストレージに直接格納されます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPC上のファイルとPaspberryPi Pico(W)のストレージ上のファイルをあちこち弄くると\nどちらをどう書き換えたか分からなくなるので、できるだけPC上のファイルを書き換えて「Upload project to Pico」で\nPaspberryPi Pico(W)のストレージを同期するのが良いと思います。</p>\n</blockquote>\n\n<p>mipコマンドでダウンロードしたモジュールや、プログラムでPaspberryPi Pico(W)のストレージ上に作成したファイルをPCのコピーするには、</p>\n<ul>\n  <li>エクスプローラウィンドウで仮想ファイルシステム上のコピーしたいフォルダまたはファイルを選択</li>\n  <li>CTRLキーを押しながらコピーしたいPC上のフォルダの位置にドラッグ&ドロップ\n    <ul>\n      <li>CTRLキーを押さないでドラッグ&ドロップした場合は移動になるので、「移動しますか?」と聞かれる。移動するなら「移動」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<p>仮想ファイルシステムを消すには、</p>\n<ul>\n  <li>再度コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n</ul>\n\n<p>で、エクスプローラウィンドウから「Pico (W) Remote Workspace」が消えます。<br />\n(エクスプローラウィンドウの表示が消えるだけで、PaspberryPi Pico(W)のストレージから消えるわけではありません)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W で SDK</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W で SDK</h1>\n      <p>Raspberry Pi Pico W で SDK を使用したプログラム開発</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico W で SDK を使用したプログラム開発方法のメモ</p>\n\n<p><a href=\"https://www.raspberrypi.com/documentation/microcontrollers/\" target=\"_blank\">公式ドキュメントサイト</a></p>\n\n<h1 id=\"セットアップ手順\">セットアップ手順</h1>\n<p>以下を参考すれば大体分かります。 <br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico-JP.pdf\" target=\"_blank\">公式スタートアップガイド(日本語版)</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a></p>\n\n<p>以下は作業メモ。<br />\n環境はWSL2上のubuntu20.04。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPi用のセットアップのスクリプトは<a href=\"https://github.com/raspberrypi/pico-setup\" target=\"_blank\">ここ</a> にある <code class=\"language-plaintext highlighter-rouge\">pico_setup.sh</code> <br />\nそれ以外のLinuxでもうごくっぽいですが、余計なものまで入ってしまいそうなので、ここでは手動でセットアップします。</p>\n</blockquote>\n\n<h2 id=\"必要なツールをインストールする\">必要なツールをインストールする</h2>\n\n<p>以下のコマンドでインストールできます。\ngitとかは既に入ってるものとして。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential\n</code></pre></div></div>\n\n<h2 id=\"sdkをダウンロードする\">SDKをダウンロードする</h2>\n\n<p>ますは作業ディレクトリを作成してSDKをダウンロードします。<br />\n以下では <code class=\"language-plaintext highlighter-rouge\">/work/Pico</code> を作業ディレクトリとしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Pico <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Pico\ngit clone https://github.com/raspberrypi/pico-sdk.git\n<span class=\"nb\">cd </span>pico-sdk/\ngit submodule update <span class=\"nt\">--init</span>\n<span class=\"nb\">cd</span> ..\n</code></pre></div></div>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n\n<p>以下のコマンドを実行し、環境変数を設定します。<br />\n上でSDKのダウンロード先を変更している場合はそれにあわせて変更してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PICO_SDK_PATH</span><span class=\"o\">=</span>/work/Pico/pico-sdk\n</code></pre></div></div>\n\n<p>次回起動時にそなえて、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code> に同様のコマンドを追加しておきます。</p>\n\n<h2 id=\"サンプルプログラムをダウンロードする\">サンプルプログラムをダウンロードする</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/raspberrypi/pico-examples.git\n</code></pre></div></div>\n\n<h2 id=\"lチカしてみる\">Lチカしてみる</h2>\n\n<p><a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a>の\n「Chapter 3. Blinking an LED in C」にあるのはPico用のサンプルなので、Pico Wでは使えません。<br />\n(正確にはGPIO端子にLEDを接続すれば使えるが、オンボードのLEDは点滅しない)<br />\nで、Pico W 用の手順をまとめてみました。</p>\n\n<h3 id=\"cmakeの実行\">cmakeの実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>pico-examples\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake .. <span class=\"nt\">-DPICO_BOARD</span><span class=\"o\">=</span>pico_w\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ncmake のオプションに <code class=\"language-plaintext highlighter-rouge\">-DPICO_BOARD=pico_w</code>を追加することでPico W用の設定が有効になります。</p>\n</blockquote>\n\n<h3 id=\"lチカプログラムのビルド\">Lチカプログラムのビルド</h3>\n\n<p>その場でmakeするとすべてのサンプルプログラムがビルドされますが、時間がかかるので\nLチカプログラムだけビルドします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>pico_w/wifi/blink/\nmake\n\n</code></pre></div></div>\n\n<p>これで <code class=\"language-plaintext highlighter-rouge\">pico-examples/build/pico_w/wifi/blink</code> の <code class=\"language-plaintext highlighter-rouge\">picow_blink.uf2</code>をpicoに書き込めばボード上のLEDが点滅するはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPico W のLチカのソースは <code class=\"language-plaintext highlighter-rouge\">pico-examples/pico_w/wifi/blink</code></p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">pico-examples\\pico</code> はpico用(Wなし)なので、実行してもオンボードのLEDが点灯しません。 \nこれを実行するには外付けLEDが必要です。</p>\n</blockquote>\n\n<h1 id=\"コンソール出力をusbに出力する\">コンソール出力をUSBに出力する</h1>\n\n<p>デフォルトでコンソール入出力はUART0に割り当てられています(端子はGP0(TX)/GP1(RX))。<br />\nUARTに接続するのが面倒なときはUSBから仮想COMポートに入出力できます。<br />\n手順は、ソースディレクトリの <code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>に以下を追加してmakeします。<br />\n例ではターゲット名に<code class=\"language-plaintext highlighter-rouge\">picow_blink</code>を使用していますが、使用するターゲットに合わせて変更してください。</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># enable usb output, disable uart output</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>picow_blink 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>picow_blink 0<span class=\"p\">)</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>を変更した場合でも <code class=\"language-plaintext highlighter-rouge\">make</code>を実行すればこの変更も反映されます。</p>\n</blockquote>\n\n<p>出来上がったuf2ファイルをPicoに書き込んだら自動的にリブートされるので、<br />\nPCに仮想COMポートドライバがインストールされたらTeratermで対象のCOMポートに接続します。</p>\n\n<h1 id=\"自作プロジェクトの作成\">自作プロジェクトの作成</h1>\n<p>サンプルプログラムを改造してうんぬんするのはダサいので、自作のプロジェクトを作ってみます。<br />\n一から作るのは面倒なので、プロジェクト生成ツールを使います。</p>\n\n<h2 id=\"プロジェクト生成ツールのダウンロード\">プロジェクト生成ツールのダウンロード</h2>\n\n<p>githubにプロジェクト生成ツールのリポジトリがあるのでダウンロードします。<br />\n以下では 前に作成した作業ディレクトリ <code class=\"language-plaintext highlighter-rouge\">/work/Pico</code> をダウンロードディレクトリとしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/Pico\ngit clone https://github.com/raspberrypi/pico-project-generator.git\n</code></pre></div></div>\n\n<p>ダウロードしたプログラムを直接起動しても良いですが、<br />\nオプション指定など忘れっぽいので起動スクリプトを用意しておきます。</p>\n\n<p>pathの通ったディレクトリ(<code class=\"language-plaintext highlighter-rouge\">~/bin</code>など)に以下の内容でファイルを作成し、実行属性を付与します。<br />\nファイル名は<code class=\"language-plaintext highlighter-rouge\">pico_project</code>とでもしておいてください。<br />\n実行ファイルのパスはダウンロード先に合わせて変更してね。<br />\n追加したいオプションがあったらご自由にどうぞ。<br />\nGUIを起動するので、最後に & をつけてバックグラウンド実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/Pico/pico-project-generator/pico_project.py <span class=\"nt\">--nouart</span> <span class=\"nt\">--usb</span>  <span class=\"nt\">--gui</span> &\n</code></pre></div></div>\n\n<h2 id=\"プロジェクトの作成\">プロジェクトの作成</h2>\n\n<p>上で作成したスクリプトを実行するとProject Generator のウィンドウが表示されます。<br />\nこのウィンドウで必要な設定を行います。</p>\n\n<ul>\n  <li>Project Name に プロジェクト名を設定</li>\n  <li>Board Type でpico_w を選択</li>\n  <li>Library Options   PiCO Wirless Options で必要なオプションをチェック</li>\n  <li>Console Options は必要なら変更してください。<br />\n(常にUART使うなら起動スクリプトのオプション変更した方が良いかも)</li>\n  <li>Code Options は 必要なら設定。 Advancedボタンをクリックすればさらに多くのパラメータが設定できます。</li>\n  <li>その下は必要なら設定してちょ。</li>\n</ul>\n\n<p>OKボタンをクリックしたらプロジェクトが作成され、cmakeが実行されます。<br />\n実行結果を表示するウィンドウが表示されますので、確認してOKボタンでクローズしてください。<br />\nLocationで指定したディレクトリ下のProjectNameで指定した名前のディレクトリに\nProjectNameで指定した名前.c が生成されているので必要な変更を行います。</p>\n\n<p>あとはコンソールでLocationで指定したディレクトリ下のProjectNameで指定したディレクトリ下の\nbuildディレクトリに移動し、<code class=\"language-plaintext highlighter-rouge\">make</code>を実行します。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</h1>\n      <p>Raspberry Pi Pico W の SDK を使用したプログラムをRaspberryPi3 + Visual Studio CodeでSWDデバッグする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico W の SDK を使用したプログラムをRaspberryPi3 + Visual Studio CodeでSWDデバッグするときのメモ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPi4 や Pi ZERO 2 W でも同様だと思うが、実際に試したのが Pi3 だったので。<br />\nたぶん Pi ZERO や Pi2 ではやめておいた方が無難。<br />\nPi ZERO 2 W やRAM512KByteだからビミョーかも…</p>\n</blockquote>\n\n<p><a href=\"https://www.raspberrypi.com/documentation/microcontrollers/\" target=\"_blank\">公式ドキュメントサイト</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico-JP.pdf\" target=\"_blank\">公式スタートアップガイド(日本語版)</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a></p>\n\n<p>試したときはRaspberryPi OS Lite(64bit) 使用(通常版でも大丈夫と思う)。</p>\n\n<h1 id=\"raspberrypi3のセットアップ\">RaspberryPi3のセットアップ</h1>\n\n<p>RaspberryPi3をセットアップします。<br />\nVisual Studio Code で リモートSSH接続するので、SSHが公開鍵認証で接続できるようにしておくこと。<br />\nセットアップの手順は\n<a href=\"https://ippei8jp.github.io/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</a>\nなど参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\nターゲットボードにPico W を使用する場合はボード種別を指定しておくこと</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"export PICO_BOARD=pico_w\"</span> <span class=\"o\">>></span> ~/.bashrc\n<span class=\"nb\">source</span> ~/.bashrc\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"セットアップスクリプトの実行\">セットアップスクリプトの実行</h2>\n<p>公式ドキュメントに記載されている通り、セットアップスクリプトを実行すればセットアップはほぼ自動です。<br />\nただし、今回はVisual Studio CodeをRaspberryPi上ではなく、WindowsPC上で動かし、\nリモートSSHでRaspberryPiに接続する方法をとるので、Visual Studio Codeのインストールは不要です。<br />\nまた、私はRaspberryPiのシリアルコンソールを残しておきたいので、UARTのセットアップも行いません。<br />\n(UARTは別途USB-Serialアダプタを使用して接続)</p>\n\n<p>以下のようにセットアップスクリプトを実行します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/work</code>ディレクトリにインストールすることにしています。<br />\n別のディレクトリにインストールする場合は読み替えてください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n\n<span class=\"c\"># スクリプトダウンロード</span>\nwget https://raw.githubusercontent.com/raspberrypi/pico-setup/master/pico_setup.sh \n\n<span class=\"c\"># VSCODEのインストールとUARTの設定をスキップしてセットアップ</span>\n<span class=\"nv\">SKIP_VSCODE</span><span class=\"o\">=</span>1 <span class=\"nv\">SKIP_UART</span><span class=\"o\">=</span>1 bash pico_setup.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nopenOCDのコンパイルとかで時間がかかるので(私が試したときは30分くらい)、<br />\nお茶でも飲んでのんびりお待ちくらはい。</p>\n</blockquote>\n\n<h2 id=\"セットアップスクリプト後の変更\">セットアップスクリプト後の変更</h2>\n\n<p>セットアップスクリプトでサンプルプログラムを一部ビルドしてくれますが、\nVisual Studio Code上の開発環境で作り直すので<code class=\"language-plaintext highlighter-rouge\">pico-examples/build</code>ディレクトリは削除しておいてください。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> /work/pico/pico-examples/build\n</code></pre></div></div>\n\n<p>また、Visual Studio Codeの設定ファイルを<code class=\"language-plaintext highlighter-rouge\">pico-examples/.vscode</code>ディレクトリに作成しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/pico/pico-examples\n<span class=\"nb\">mkdir</span> .vscode\n<span class=\"nb\">cp </span>ide/vscode/launch-raspberrypi-swd.json .vscode/launch.json\n<span class=\"nb\">cp </span>ide/vscode/settings.json .vscode/settings.json\n</code></pre></div></div>\n\n<p>このままだとビルドが全ビルドになってしまい、時間がかかってしまうのでビルドターゲットを指定できるように変更しておきます。<br />\n【2024.08.29修正】\nどこかのタイミングのバージョンアップで設定できる内容が大幅に変更されたようなので、setting.jsonを以下の内容で全書き換えしておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  settings.json\n</p>\n\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"p\">{</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.configureOnOpen\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"kc\">false</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.advanced\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n    </span><span class=\"nl\">\"build\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"buildTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"ctest\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"debug\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"launchTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n     </span><span class=\"nl\">\"launch\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"workflow\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"cpack\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">}</span><span class=\"w\">    \n  </span><span class=\"p\">},</span><span class=\"w\">\n</span><span class=\"p\">}</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h1 id=\"raspberry-pi3とraspberry-pi-pico-の接続\">Raspberry Pi3とRaspberry Pi Pico の接続</h1>\n<p>この辺で一旦Raspberry Pi3をシャットダウンし、Raspberry Pi Picoと接続します(最初に接続しておいても良いけど)。<br />\n接続方法は 公式スタートアップガイド の 「Chapter 5. Flash Programming with SWD」の下の「5.2. SWD Port Wiring」\nあたりを参照してください。<br />\n私はPicoのシリアルポートをRaspberryPiではなくUSB-Serialに接続するようにしたので、図の上3本の結線は行わず\nPi3のGPIO24とPicoのSWDIO、Pi3のGPIO25とPicoのSWDCLK、双方のGND同士 の3本を結線しました。<br />\n(PicoのPin1~3はUSB-Serialに接続し、WindowsPCかRaspberry Pi3に接続)</p>\n\n<h2 id=\"visual-studio-coce-起動フォルダのオープン\">Visual Studio COCE 起動&フォルダのオープン</h2>\n\n<p>ホストPCでVisual Studio COCE 起動。<br />\nリモートSSHでRaspberryPi3 に接続し、セットアップツールでインストールした\nサンプルプログラムのディレクトリを開きます(上の例では/work/pico/pico-example)</p>\n\n<h2 id=\"拡張機能のインストール\">拡張機能のインストール</h2>\n<p>これは最初の起動時のみ実行します。</p>\n\n<p>拡張機能で「Cmake Tools」「C/C++(C/C++ for Visual Studio Code)」「Cortex Debug」をRaspberry Pi3 にインストールします。<br />\n(ホストPCではないのでSSH接続した後でインストールすること)</p>\n\n<p>「Cmake Tools」のインストールが完了したら歯車アイコン(設定)をクリックして設定画面を開き、\n“CMake: Parallel Jobs” の設定値を0から1(または2)に変更\n(0だと設定できる上限値になるはずだけど、プロセッサ数4に対して6が設定されてしまい、システムがハングアップしてしまうことがあるので)</p>\n\n<p>右下に「プロジェクト”pico-examples”を構成しますか? ソース:CMake Tools(拡張機能)」と表示されるのでYesをクリック<br />\n続いて「プロジェクトを開いたときに常に構成しますか? ソース:CMake Tools(拡張機能)」 と表示されるので「はい」をクリック</p>\n\n<h2 id=\"ビルドデバッグ\">ビルド~デバッグ</h2>\n<p>ステータスバーの「キットが選択されていません」をクリックすると\nウィンドウ上部に「pico-examplesのキットを選択してください」と表示されるので\n「GCC 12.2.1  arm-none-eabi」を選択(バージョンは異なるかも)</p>\n\n<blockquote>\n  <p>[!NOTE]\n「この大規模なワークスペース フォルダーでのファイルの変更をウォッチできません。\nこの問題を解決するには、手順のリンクに従ってください。 」\nと表示された場合\n/etc/sysctl.conf に以下を追記</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>fs.inotify.max_user_watches = 524288\n</code></pre></div>  </div>\n  <p>設定を反映</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sysctl <span class=\"nt\">-p</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>ステータスバーで「プロジェクトを構成しています: pico-examples」が消えるのを待つ)</p>\n\n<p>ステータスバーで「既定のビルドターゲットの設定(ステータスバーの表示にマウスカーソルをあてると表示されるメッセージ)」と\n「起動するターゲットを選択します(ステータスバーの表示にマウスカーソルをあてると表示されるメッセージ)」を\nクリックしてデバッグしたいターゲットに設定します(例えば、picow_blink)。\nこれらば同じターゲットを指定する必要があります。(ビルドターゲットはallでも良いが、ビルドに時間がかかる)</p>\n<blockquote>\n  <p>[!NOTE]\nサンプルにあるide/vscode/settings.json そのままだと「既定のビルドターゲットの設定」がallのまま変更できないのでビルドに時間がかかるため\n上記の変更を行っています。</p>\n</blockquote>\n\n<p>構成が完了したら「実行とデバッグ」ウィンドウを開いて、右向き三角マーク(デバッグの開始)をクリック<br />\n(右向き三角マーク(デバッグの開始)が無ければ「実行とデバッグ」をクリック)<br />\nbuildが始まって、終わったらデバッガが起動します。<br />\nあとは他のデバッグ同様、RUNやSTEPなどでデバッグしてください。</p>\n\n<h1 id=\"自作プロジェクトの作成\">自作プロジェクトの作成</h1>\n\n<p>サンプルプログラムを改造してうんぬんするのはダサいだけでなく、関係ない処理が色々動いて\nビルドに時間がかかるので、自作プロジェクトの作成をした方が良いです。</p>\n\n<p><a href=\"https://ippei8jp.github.io/memoBlog/2023/10/11/RasPiPico_2.html\" target=\"_blank\">Raspberry Pi Pico W で SDK</a>\nの「自作プロジェクトの作成」にまとめておきましたが、デバッガの指定など追加手順もあるので\n再掲します。</p>\n\n<h2 id=\"プロジェクト生成ツールのインストール\">プロジェクト生成ツールのインストール</h2>\n<p>プロジェクト生成ツールをインストールして起動スクリプトを作成します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ダウンロード</span>\n<span class=\"nb\">cd</span> /work/pico/\ngit clone https://github.com/raspberrypi/pico-project-generator.git\n\n<span class=\"c\"># 起動用スクリプトの作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ~/bin\n<span class=\"nb\">cat</span> <span class=\"o\">></span> ~/bin/pico_project <span class=\"o\"><<</span> <span class=\"sh\">\"</span><span class=\"no\">_EOF_</span><span class=\"sh\">\"\n/work/Pico/pico-project-generator/pico_project.py --nouart --usb  --gui &\n</span><span class=\"no\">_EOF_\n\n</span><span class=\"nb\">chmod</span> +x ~/bin/pico_project\n\n<span class=\"c\"># tkinter のインストール(RaspberryPi OS lite の場合は要インストール)</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>python3-tk\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nそれまで<code class=\"language-plaintext highlighter-rouge\">~/bin</code>が存在していない場合は一旦ログアウトして再ログインで\n<code class=\"language-plaintext highlighter-rouge\">~/bin</code>にpathを通す(変数ゴチョゴチョやっても良いけど、再ログインが手っ取り早い)。</p>\n</blockquote>\n\n<h2 id=\"プロジェクト生成ツールの起動プロジェクト出力\">プロジェクト生成ツールの起動~プロジェクト出力</h2>\n\n<p>リモート接続で使用している場合はDISPLAY変数が設定されていること(ホストマシン)と、\nホストマシンでX-serverが動作していることを確認し、\nプロジェクト生成ツール起動スクリプトを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pico_project\n</code></pre></div></div>\n<p>ホストマシン上にプロジェクト生成ツールのウィンドウが表示されます。</p>\n\n<p>各パラメータを設定し、OKボタンをクリックしてプロジェクトを生成します。<br />\nこのウィンドウで必要な設定を行います。</p>\n\n<ul>\n  <li>Project Name に プロジェクト名を設定</li>\n  <li>Board Type でpico_w を選択</li>\n  <li>Library Options   PiCO Wirless Options で必要なオプションをチェック</li>\n  <li>Console Options は必要なら変更してください。<br />\n(常にUART使うなら起動スクリプトのオプション変更した方が良いかも)</li>\n  <li>Code Options は 必要なら設定。 Advancedボタンをクリックすればさらに多くのパラメータが設定できます。</li>\n  <li>その下は必要なら設定してちょ。</li>\n  <li>一番下の IDE Options は、「Create VSCode Project」をチェックし、「Debugger」に「SWD」を選択します。</li>\n</ul>\n\n<p>OKボタンをクリックしたらプロジェクトが作成され、cmakeが実行されます。<br />\n実行結果を表示するウィンドウが表示されますので、確認してOKボタンでクローズしてください。</p>\n\n<p>プロジェクト生成ツールはもう不要なのでクローズしてください。</p>\n\n<p>生成されたプロジェクトディレクトリの<code class=\"language-plaintext highlighter-rouge\">.vscode/settings.json</code> を以下の内容で全書き換えします。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  settings.json\n</p>\n\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"p\">{</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.configureOnOpen\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"kc\">false</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.advanced\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n    </span><span class=\"nl\">\"build\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"buildTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"ctest\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"debug\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"launchTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n     </span><span class=\"nl\">\"launch\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"workflow\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"cpack\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">}</span><span class=\"w\">    \n  </span><span class=\"p\">},</span><span class=\"w\">\n</span><span class=\"p\">}</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n毎回修正するのが面倒なら、<code class=\"language-plaintext highlighter-rouge\">pico_project.py</code>の\n関数<code class=\"language-plaintext highlighter-rouge\">generateProjectFiles</code>内の変数<code class=\"language-plaintext highlighter-rouge\">s1</code>の定義(1195行目あたり)\nを上記の内容で書き換えてしまえば生成時にこの内容にできる。<br />\n(そのうち公式さんが修正するだろうけど)</p>\n</blockquote>\n\n<h2 id=\"visual-studio-code-でプロジェクトを開くデバッグ\">Visual Studio Code でプロジェクトを開く~デバッグ</h2>\n\n<p>Visual Studio Code のリモートエクスプローラからRaspberry Pi に接続し、作成したディレクトリを開きます。</p>\n\n<p>ProjectNameで指定した名前.c が生成されているので必要な変更を行います。<br />\nファイルを追加する場合は <code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code> の修正も忘れずに。</p>\n\n<p>ステータスバーの「キットが選択されていません」をクリックすると 上に「XXXXのキットを選択してください」と表示されるので\n「GCC 12.2.1  arm-none-eabi」を選択(バージョンは異なるかも)<br />\n構成が完了したら「実行とデバッグ」ウィンドウを開いて、右向き三角マーク(デバッグの開始)をクリック<br />\n(右向き三角マーク(デバッグの開始)が無ければ「実行とデバッグ」をクリック)<br />\n上中央に「ターゲットの起動対象を選択します」と表示されるので、プロジェクト名で指定した名前を選択します。</p>\n\n<p>コンパイルが始まり、エラーがなければそのままデバッガが起動し、main関数の先頭でbreakします。</p>\n\n<p>あとは普通にデバッグしてくらはい。</p>\n\n<h2 id=\"ソースファイルの追加\">ソースファイルの追加</h2>\n\n<p>ソースファイルを追加する場合は<code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code> の <code class=\"language-plaintext highlighter-rouge\">add_executable</code>に追加するソースファイルを追加します。</p>\n\n<p>変更前</p>\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">add_executable</span><span class=\"p\">(</span>test1 test1.c<span class=\"p\">)</span>\n</code></pre></div></div>\n<p>変更後</p>\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">add_executable</span><span class=\"p\">(</span>test1 test1.c sub.c<span class=\"p\">)</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) でI2C Slave</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) でI2C Slave</h1>\n      <p>Raspberry Pi Pico W の SDK を使用してI2C Slaveプログラムを作成する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico のI2C マスタを使用してI2Cデバイスにアクセスするプログラムプログラムは\nネット上のあちこちに落ちているのですが、\nI2Cスレーブとしてホストデバイスからアクセスされるサンプルはあまりありません。<br />\nそこで、あちこち探してプログラム作ったのでメモを残しておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n【ホントのところ】<br />\n「I2Cデバイスをポチったけど、納期が長くてプログラム開発に取り掛かれない~」となって\nなんちゃってI2Cデバイスを作って先行デバッグしようとしました。</p>\n</blockquote>\n\n<p>通信プログラムなので通信相手が必要ですが、今回はRaspberry Pi3上でpython3で動く\n簡単な動作確認プログラムを載せておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n公式サンプルは<code class=\"language-plaintext highlighter-rouge\">pico-examples/i2c/slave_mem_i2c</code>にあります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nmicropython版の例は<a href=\"https://python-academia.com/raspberry-pi-pico-slave/\" target=\"_blank\">ここ</a>\nとかにあるけど、ちぃーっと無理くり感が…</p>\n</blockquote>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"i2cの結線\">I2Cの結線</h2>\n\n<p>以下のように結線します。<br />\nPico側はソース中の割り当て端子を変更すれば別の端子でもOKです。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>Pi3</th>\n      <th>Pico</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>SDA1(pin3)</td>\n      <td>I2C0_SDA/GP16(Pin21)</td>\n    </tr>\n    <tr>\n      <td>SCL1(pin5)</td>\n      <td>I2C0_SCL/GP17(Pin22)</td>\n    </tr>\n  </tbody>\n</table>\n\n<h2 id=\"pi3でのi2c有効化\">Pi3でのI2C有効化</h2>\n\n<p>Pi3で以下のコマンドを実行し、I2Cを有効化します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config nonint do_i2c 0\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nまたは以下のように手動で設定</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config\n</code></pre></div>  </div>\n\n  <p>以下のように設定</p>\n  <ul>\n    <li>3 Interface Options\n      <ul>\n        <li>I4 I2C\n          <ul>\n            <li>「Would you like the ARM I2C interface to be enabled?」<br />\n に対して「はい」を選択</li>\n            <li>「The ARM I2C interface is enabled」\nと表示されるので「了解」</li>\n          </ul>\n        </li>\n        <li>「Finish」で終了</li>\n      </ul>\n    </li>\n  </ul>\n\n</blockquote>\n\n<p>実行後、<code class=\"language-plaintext highlighter-rouge\">/dev/i2c-1</code>ファイルが存在することを確認してください。<br />\nリブートは不要です。</p>\n\n<h2 id=\"i2cツールのインストール\">I2Cツールのインストール</h2>\n\n<p>Pi3に<code class=\"language-plaintext highlighter-rouge\">i2cdetect</code>などのツールをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>i2c-tools\n</code></pre></div></div>\n\n<h1 id=\"picoのプログラム\">Picoのプログラム</h1>\n\n<p>作成したプログラムを以下に示します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n今回元にしたI2Cデバイスは先頭アドレスからのバーストリードのみサポートしていたので<br />\nちょっと一般的なアドレス/データ指定の方法と違うけど、なんとなく想像はつくでしょう…</p>\n</blockquote>\n\n<h2 id=\"メインルーチン\">メインルーチン</h2>\n\n<p>メインルーチンはI2Cを初期化したあと無限ループします。<br />\nループ内ではI2Cに関する処理はなく、生存確認用のLチカと\nデバッグ用に送信データが更新されたときにデータを表示しているだけです。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_test.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/stdlib.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/cyw43_arch.h\"</span><span class=\"cp\">\n</span>\n<span class=\"c1\">// プロトタイプ宣言</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n\n<span class=\"kt\">int</span> <span class=\"nf\">main</span><span class=\"p\">()</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">stdio_init_all</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// STDIOがUSBのとき、USB認識されないことがあるのでstdio初期化の後、ちょっと待つ</span>\n    <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">3000</span><span class=\"p\">);</span>\n\n    <span class=\"n\">puts</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">I2C slave test\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// LEDを使うためにwifi初期化</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">cyw43_arch_init</span><span class=\"p\">())</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"Wi-Fi init failed\"</span><span class=\"p\">);</span>\n        <span class=\"k\">return</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\">// I2Cスレーブ 初期化</span>\n    <span class=\"n\">setup_i2c_slave</span><span class=\"p\">();</span>\n    \n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">disp_next_data</span><span class=\"p\">();</span>\n        <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">1000</span><span class=\"p\">);</span>\n\n        <span class=\"c1\">// ==== 生存確認用にLチカ ====</span>\n        <span class=\"c1\">// 現在の出力値取得</span>\n        <span class=\"n\">bool</span> <span class=\"n\">led_out</span> <span class=\"o\">=</span> <span class=\"n\">cyw43_arch_gpio_get</span> <span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">);</span>\n        <span class=\"c1\">// 出力反転</span>\n        <span class=\"n\">cyw43_arch_gpio_put</span><span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">,</span> <span class=\"o\">!</span><span class=\"n\">led_out</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"i2c処理\">I2C処理</h2>\n\n<h3 id=\"初期化\">初期化</h3>\n<p>I2Cの初期化は<code class=\"language-plaintext highlighter-rouge\">setup_i2c_slave</code>です。<br />\n主に端子の初期化とI2Cの初期化、\nI2Cスレーブの初期化(I2C割り込みハンドラからのコールバックの登録)を行っています。</p>\n\n<h3 id=\"処理本体\">処理本体</h3>\n<p>I2C処理本体は<code class=\"language-plaintext highlighter-rouge\">i2c_slave_handler()</code>です。</p>\n\n<p>これはI2C割り込みハンドラからのコールバック処理です。<br />\nなので、できるだけ速やかにリターンする必要があります\n(printfなどの時間のかかる処理は行わないほうが良い)。</p>\n\n<p>なお、今回はマスタの通信プログラムをデバッグするためのダミーデバイスという位置づけで作ったので\n通信を行うたびに異なるデータを送信するようにしてあります。\nこのデータの更新処理をストップ/リスタートコンディション時に行うようにしてあります。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_test.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">16</span><span class=\"p\">;</span>  <span class=\"c1\">//GP16(Pin21)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">17</span><span class=\"p\">;</span>  <span class=\"c1\">//GP17(Pin22)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">16</span><span class=\"p\">];</span>            <span class=\"c1\">// 読み出しデータ</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>        <span class=\"c1\">// 読み出しインデックス</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_REQ</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// 表示要求あり</span>\n        <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"NEXT: %02x %02x %02x %02x : %02x %02x %02x %02x : %02x %02x %02x %02x : %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">14</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">i</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\">// 次に送信するデータの表示を要求</span>\n    <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n\n<span class=\"c1\">// 読み出しデータの更新</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">update_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"o\">++</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\">// 次に送信するデータの表示を要求</span>\n    <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではない</span>\n<span class=\"c1\">// 例えば、表示要求フラグを立ててメインルーチン側で表示してもらうようにするなど</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"p\">{</span>\n            <span class=\"c1\">// ライト動作はサポートしないのでとりあえず読み捨てておく</span>\n            <span class=\"k\">volatile</span> <span class=\"kt\">uint8_t</span> <span class=\"n\">dummy</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span><span class=\"n\">dummy</span><span class=\"p\">;</span>    <span class=\"c1\">// ワーニング対策</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// 1バイト送信する</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">]);</span>\n        <span class=\"c1\">// 次の転送に備えてインデックスを更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// オーバフローしたら0にもどしておく</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// リードポインタを初期化しておく</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        \n        <span class=\"c1\">// テスト用ダミーデータなので、次の読み出しに備えて値を更新しておく</span>\n        <span class=\"n\">update_data</span><span class=\"p\">();</span>\n        \n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave  done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"cmake設定ファイル\">cmake設定ファイル</h3>\n\n<p>プロジェクト生成ツールで作成したプロジェクト(一般的な設定に「I2C interface」のチェックを追加)に\n<code class=\"language-plaintext highlighter-rouge\">target_link_libraries</code> に <code class=\"language-plaintext highlighter-rouge\">pico_i2c_slave</code>を追加します。<br />\nまた、今回はメインルーチンとI2C処理を別ファイルに分けたので、\n<code class=\"language-plaintext highlighter-rouge\">add_executable</code> に <code class=\"language-plaintext highlighter-rouge\">i2c_slave0.c</code>(追加したファイル名)を追加します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  CMakeLists.txt\n</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># Generated Cmake Pico project file</span>\n\n<span class=\"nb\">cmake_minimum_required</span><span class=\"p\">(</span>VERSION 3.13<span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_C_STANDARD 11<span class=\"p\">)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_CXX_STANDARD 17<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise pico_sdk from installed location</span>\n<span class=\"c1\"># (note this can come from environment, CMake cache etc)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_SDK_PATH <span class=\"s2\">\"/work/pico/pico-sdk\"</span><span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_BOARD pico_w CACHE STRING <span class=\"s2\">\"Board type\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># Pull in Raspberry Pi Pico SDK (must be before project)</span>\n<span class=\"nb\">include</span><span class=\"p\">(</span>pico_sdk_import.cmake<span class=\"p\">)</span>\n\n<span class=\"nb\">if</span> <span class=\"p\">(</span>PICO_SDK_VERSION_STRING VERSION_LESS <span class=\"s2\">\"1.4.0\"</span><span class=\"p\">)</span>\n  <span class=\"nb\">message</span><span class=\"p\">(</span>FATAL_ERROR <span class=\"s2\">\"Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is </span><span class=\"si\">${</span><span class=\"nv\">PICO_SDK_VERSION_STRING</span><span class=\"si\">}</span><span class=\"s2\">\"</span><span class=\"p\">)</span>\n<span class=\"nb\">endif</span><span class=\"p\">()</span>\n\n<span class=\"nb\">project</span><span class=\"p\">(</span>i2c_slave_test C CXX ASM<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise the Raspberry Pi Pico SDK</span>\n<span class=\"nf\">pico_sdk_init</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># Add executable. Default name is the project name, version 0.1</span>\n\n<span class=\"nb\">add_executable</span><span class=\"p\">(</span>i2c_slave_test i2c_slave_test.c i2c_slave0.c<span class=\"p\">)</span>\n\n<span class=\"nf\">pico_set_program_name</span><span class=\"p\">(</span>i2c_slave_test <span class=\"s2\">\"i2c_slave_test\"</span><span class=\"p\">)</span>\n<span class=\"nf\">pico_set_program_version</span><span class=\"p\">(</span>i2c_slave_test <span class=\"s2\">\"0.1\"</span><span class=\"p\">)</span>\n\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>i2c_slave_test 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>i2c_slave_test 0<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard library to the build</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_test\n        pico_stdlib<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard include files to the build</span>\n<span class=\"nb\">target_include_directories</span><span class=\"p\">(</span>i2c_slave_test PRIVATE\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>/.. <span class=\"c1\"># for our common lwipopts or any other standard includes, if required</span>\n<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add any user requested libraries</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_test \n        pico_i2c_slave\n        hardware_i2c\n        pico_cyw43_arch_none\n        <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_add_extra_outputs</span><span class=\"p\">(</span>i2c_slave_test<span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>あとはビルドしてRaspberry Pi Picoに書き込みます。</p>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認です。<br />\nここからはRaspberry Pi3 での作業です。</p>\n\n<h2 id=\"i2cdetect\">i2cdetect</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdetect</code> で I2Cバス上でデバイスが検出されるか確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n\n<p>Picoのプログラムで設定したスレーブアドレス(<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>の設定値。上のプログラムだと0x17)\nが表示されていればOKです。<br />\n表示されていない場合はPicoのプログラムやボードの結線を見直してください。</p>\n\n<h2 id=\"レジスタリードプログラム\">レジスタリードプログラム</h2>\n<p>Raspberry Pi3で以下のプログラムを実行します。<br />\n<code class=\"language-plaintext highlighter-rouge\">i2c_address</code>の設定値は上のプログラムの<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>の設定値に合わせます。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">smbus2</span> <span class=\"kn\">import</span> <span class=\"n\">SMBus</span><span class=\"p\">,</span> <span class=\"n\">i2c_msg</span>\n\n<span class=\"n\">i2c_bus</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>                 <span class=\"c1\"># バス番号\n</span><span class=\"n\">i2c_address</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span>          <span class=\"c1\"># スレーブアドレス\n</span><span class=\"n\">data_size</span> <span class=\"o\">=</span> <span class=\"mi\">16</span>              <span class=\"c1\"># リードデータサイズ\n</span>\n<span class=\"c1\"># バスオープン\n</span><span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">SMBus</span><span class=\"p\">(</span><span class=\"n\">i2c_bus</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ読み出し\n</span><span class=\"n\">read</span> <span class=\"o\">=</span> <span class=\"n\">i2c_msg</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">(</span><span class=\"n\">i2c_address</span><span class=\"p\">,</span> <span class=\"n\">data_size</span><span class=\"p\">)</span>\n<span class=\"n\">bus</span><span class=\"p\">.</span><span class=\"n\">i2c_rdwr</span><span class=\"p\">(</span><span class=\"n\">read</span><span class=\"p\">)</span>\n<span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">read</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>正常に読み出せれば、以下のように結果が表示されます(10進数)。<br />\n(以下は何回か実行したあとの結果です)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n</code></pre></div></div>\n\n<p>同時にPicoのシリアルポートからは以下のように次に読み出せるデータが表示されます(16進数)。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>NEXT: 06 07 08 09 : 0a 0b 0c 0d : 0e 0f 10 11 : 12 13 14 15\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 22.04をNative環境にインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 22.04をNative環境にインストール</h1>\n      <p>Ubuntu 22.04をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuのダウンロード\">Ubuntuのダウンロード</h1>\n<p><a href=\"https://www.ubuntulinux.jp/download\" target=\"_blank\">Ubuntuの入手</a>からダウンロード<br />\nSecure Boot環境で日本語RemixのISOファイルを使うと<code class=\"language-plaintext highlighter-rouge\">Verification failed: (0x1A) Security Violation</code>\nと怒らたので、jp.ubuntu.comのダウンロードページからUbuntu Desktopをダウンロードした。<br />\nブータブルUSBを作るには、Rufus等を使う(ググってちょ)。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<p>以下の参考ページを参照して起動するとこまでやってちょ。</p>\n\n<ul>\n  <li><a href=\"https://ippei8jp.github.io/memoBlog/2021/07/15/install2004_native.html\" target=\"_blank\">UbuntuをNative環境にインストールする(20.04)</a></li>\n  <li><a href=\"https://ippei8jp.github.io/memoBlog/2022/07/24/install2204.html\" target=\"_blank\">Ubuntu 22.04のVirtualBoxへのインストール</a></li>\n  <li>Ubuntu 22.04 デュアルブートのインストール方法は以下を参考\n    <ul>\n      <li><a href=\"https://dailylife.pman-bros.com/ubuntu22_install/\" target=\"_blank\">Ubuntu 22.04 LTS をインストールする -【マルチブート編】</a></li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"お好みで\">お好みで</h1>\n<p>作業中に画面が消えると鬱陶しいのでパワマネ無効化。<br />\nTAB補完使えばコピペするほどでもないので、最初にやっとく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h1 id=\"最新版にupdate\">最新版にupdate</h1>\n\n<p>とりあえず最新版に</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ついでにsshもインストールしておく。<br />\nwebで調べたコマンドをコピペしたいので。<br />\n参考:<a href=\"https://ippei8jp.github.io/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">ubuntuにSSHサーバをセットアップする</a></p>\n\n<ul>\n  <li>パッケージをインストール\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\n</code></pre></div>    </div>\n    <ul>\n      <li>これだけでパスワード認証は繋がるはず。</li>\n    </ul>\n  </li>\n  <li>公開鍵認証を使用する場合は、公開鍵を<code class=\"language-plaintext highlighter-rouge\">~/.ssh/authorized_keys</code>に追記し、attribute変更。<br />\n(コピペで追記したいのでsshで接続したターミナルから作業するのがベター)</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/.ssh\nvi ~/.ssh/authorized_keys\n<span class=\"c\">### 公開鍵を追記 ###</span>\n<span class=\"nb\">chmod </span>600 ~/.ssh/authorized_keys\n</code></pre></div></div>\n\n<p>念のためここでリブート。</p>\n\n<h1 id=\"chromeとリモートデスクトップのインストール\">chromeとリモートデスクトップのインストール</h1>\n<p>参考: <a href=\"https://qiita.com/grgrjnjn/items/a5c4da336031b63f09a6\" target=\"_blank\">UbuntuにChromeをインストールする手順</a><br />\n参考: <a href=\"https://zenn.dev/karaage0703/articles/cfde5e6a4f43c3\" target=\"_blank\">Linux(Ubuntu)のリモートデスクトップ設定(Google Chrome リモートデスクトップ/xrdp)</a></p>\n\n<h2 id=\"おまじない\">おまじない</h2>\n<p>chrome リモートデスクトップをインストールすると、ローカル端末でのログインができなくなるので、\n以下の処理を行う。</p>\n\n<p>新しく使用する<code class=\"language-plaintext highlighter-rouge\">.desktop</code>ファイルを作成(ubuntuをベースに使用)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /usr/share/xsessions/\n<span class=\"nb\">sudo cp </span>ubuntu.desktop ubuntu-local.desktop\n</code></pre></div></div>\n\n<p>以下のパッチをあてる。</p>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">Name</code>の変更と<code class=\"language-plaintext highlighter-rouge\">Exec</code>に<code class=\"language-plaintext highlighter-rouge\">DISPLAY=\":0\"</code>を追加</p>\n</blockquote>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ubuntu.desktop      2022-04-08 04:07:53.000000000 +0900\n</span><span class=\"gi\">+++ ubuntu-local.desktop        2023-11-11 07:25:37.223280734 +0900\n</span><span class=\"p\">@@ -1,7 +1,7 @@</span>\n [Desktop Entry]\n<span class=\"gd\">-Name=Ubuntu\n</span><span class=\"gi\">+Name=Ubuntu on local\n</span> Comment=This session logs you into Ubuntu\n<span class=\"gd\">-Exec=env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu\n</span><span class=\"gi\">+Exec=env DISPLAY=\":0\" GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu\n</span> TryExec=/usr/bin/gnome-shell\n Type=Application\n DesktopNames=ubuntu:GNOME\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nローカル端末でログインするときはユーザ名選択後、画面右下の歯車アイコンをクリックし、\n「Ubuntu on local」を選択(一度選択すれば記憶されるので2度目以降は確認だけでOK)してログインする。\n (作成したセッションを選択可能にするには、リブートが必要)</p>\n</blockquote>\n\n<h2 id=\"chromeとリモートデスクトップのインストール-1\">chromeとリモートデスクトップのインストール</h2>\n\n<p>手間を省くためにコマンドラインで以下を実行(sshからで可)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール時にエラーにならないようおまじない</span>\n<span class=\"nb\">mkdir</span> ~/.config/chrome-remote-desktop\n\n<span class=\"c\"># リブート時に消せるようにダウンロード先に/tmpを使う</span>\n<span class=\"nb\">cd</span> /tmp\n\n<span class=\"c\"># chromeのダウンロード</span>\nwget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb\n<span class=\"c\"># chromeのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> ./google-chrome-stable_current_amd64.deb\n\n<span class=\"c\"># remote desktopのダウンロード</span>\nwget https://dl.google.com/linux/direct/chrome-remote-desktop_current_amd64.deb\n<span class=\"c\"># remote desktopのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> ./chrome-remote-desktop_current_amd64.deb\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nインストール時、以下のように提案/推奨されるが、入れなくても大丈夫。<br />\n提案パッケージ:<br />\n  python-psutil-doc x11-xfs-utils<br />\n推奨パッケージ:<br />\n  xserver-xorg-video-dummy pipewire</p>\n</blockquote>\n\n<h2 id=\"chrome起動して初期設定googleにログイン\">chrome起動して初期設定&Googleにログイン</h2>\n<p>ローカル端末でchrome起動</p>\n<ul>\n  <li>既定のブラウザにするか、障害レポートを送信するかを選んでOK</li>\n  <li>「Chromeを独自にカスタマイズ」で「開始する」をクリック\n    <ul>\n      <li>あとはお好みで設定</li>\n    </ul>\n  </li>\n  <li>「あなたのChromeをいつでもどこでも」で「続行」をクリック\n    <ul>\n      <li>chromeへのログインで使用するGoogleアカウントにログイン</li>\n    </ul>\n  </li>\n  <li>リモートデスクトップを検索し、「Chromeリモートデスクトップ」を開く\n    <ul>\n      <li><a href=\"https://remotedesktop.google.com/?hl=ja&pli=1\" target=\"_blank\">https://remotedesktop.google.com/?hl=ja&pli=1</a></li>\n    </ul>\n  </li>\n  <li>「パソコンにアクセス」をクリック</li>\n  <li>「リモートアクセスの設定」の「ONにする」ボタンをクリック</li>\n  <li>「名前の設定」で名前を設定して「次へ」</li>\n  <li>「PINの入力」で設定するPINを2回入力して「起動」</li>\n  <li>\n    <p>パスワード入力を求められるのでパスワード入力</p>\n  </li>\n  <li>ローカル端末でログアウト\n    <blockquote>\n      <p>[!WARNING]\nローカル端末でログインしたままだとリモートデスクトップがつながっても画面表示されない</p>\n    </blockquote>\n  </li>\n</ul>\n\n<h2 id=\"window-pc側から接続\">Window PC側から接続</h2>\n<p>Windows PCでリモートデスクトップアプリを起動し、Ubuntuマシンに接続する<br />\nセッションの選択ではUbunto on Xorg または Ubuntuを選択(たぶんどっちも同じ)</p>\n\n<h3 id=\"おまじない1\">おまじない1</h3>\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。<br />\nこのダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下の内容で作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n<p>参考: <a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></p>\n\n<h3 id=\"おまじない2\">おまじない2</h3>\n<p>接続時、毎回セッションの選択をするのは面倒なので、自動で選択できるようにしようとしたが、<br />\nこれをやるとローカル端末でログインできなくなるのでやめておく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n参考までに手順を記載しておく<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.chrome-remote-desktop-session</code>を以下の内容で作成する</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>exec /etc/X11/Xsession 'env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu'\n</code></pre></div>  </div>\n  <p>env以下は使用するセッションに合わせて変更すること。<br />\n(<code class=\"language-plaintext highlighter-rouge\">/usr/share/xsessions/≪セッション名≫.desktop</code>の<code class=\"language-plaintext highlighter-rouge\">Exec</code>行の内容)</p>\n</blockquote>\n\n<h1 id=\"使いそうなプログラムのインストールと使わないプログラムのアンインストール\">使いそうなプログラムのインストールと使わないプログラムのアンインストール</h1>\n\n<h2 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h2>\n\n<p>ま、使うでしょ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweaks \n</code></pre></div></div>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>使うツールがあったら残してちょ。</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h2 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"お好みで-1\">お好みで</h2>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>ディレクトリにコピるだけ。<br />\n下では全部コピってるけど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.0.0/UDEVGothic_v1.0.0.zip \nunzip UDEVGothic_v1.0.0.zip \n<span class=\"nb\">mkdir</span> ~/.fonts\n<span class=\"nb\">cp </span>UDEVGothic_v1.0.0/<span class=\"k\">*</span>.ttf ~/.fonts/\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。<br />\nさっきフォントのインストールに使った端末ウィンドウを使うと\nエラーで端末ウィンドウが落ちるかもしれないんで一旦終了して新しいウィンドウで。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<h1 id=\"その他設定\">その他設定</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>~/.bashrcに以下を追記。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"c\"># Ubuntu22.04だとwaylandになるらしい</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"wayland\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vi\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># # venvの仮想環境名を表示するための設定</span>\n    <span class=\"c\"># show_virtual_env() {</span>\n    <span class=\"c\">#   if [ -n \"$VIRTUAL_ENV\" ]; then</span>\n    <span class=\"c\">#     echo \"($(basename $VIRTUAL_ENV))\"</span>\n    <span class=\"c\">#   fi</span>\n    <span class=\"c\"># }</span>\n    <span class=\"c\"># PS1='$(show_virtual_env)'$PS1</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nUbuntu20.04とちょっとキーが変更されてる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-home <span class=\"nb\">false \n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"ファイルnautilusのデフォルト動作変更\">ファイル(nautilus)のデフォルト動作変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アドレスバーをテキスト形式にする</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences always-use-location-entry <span class=\"nb\">true</span> \n\n<span class=\"c\"># 詳細表示をデフォルトに</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences default-folder-viewer <span class=\"s1\">'list-view'</span> \n\n<span class=\"c\"># 隠しファイルを表示する</span>\n<span class=\"c\"># 隠しファイルの表示はちょっと場所が違う</span>\ngsettings <span class=\"nb\">set </span>org.gtk.Settings.FileChooser show-hidden <span class=\"nb\">true</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアの更新(update-manager)を起動\n    <ul>\n      <li>更新のチェックが始まった場合はちょっと待つ</li>\n      <li>設定…をクリック\n        <ul>\n          <li>アップデートタブを選択</li>\n          <li>アップデートの自動確認を「なし」に変更</li>\n          <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n          <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n          <li>閉じるをクリック</li>\n        </ul>\n      </li>\n      <li>OKで終了</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Chromeリモートデスクトップ環境ではWindowsで設定したのが有効になっているので必要ないが、\nローカル端末で使用する場合に備えて入れ替えを設定しておく。<br />\n方法は、<code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code> に <code class=\"language-plaintext highlighter-rouge\">XKBOPTIONS=\"ctrl:nocaps\"</code> を追加。<br />\n設定を有効にするにはリブート必要。</p>\n\n<p>参考:<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a><br />\nリンク先は「Ubuntu 20.04/18.04 LTS」となっているが、Ubuntu22.04でも同じらしい。</p>\n\n<h3 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h3>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h1 id=\"sambaのインストール\">sambaのインストール</h1>\n\n<p>ツール本体のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加<br />\n作らなかったワークディレクトリの部分は削除してね。<br />\n他にも共有したいディレクトリがあったら追加してちょ。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">force group</code>に設定するグループは存在するグループ(またはユーザ)名に変更してください。</p>\n\n<p>ここではちょっと見たいファイルがあったのでoptも共有してます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"nfsのインストール\">NFSのインストール</h1>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/exports</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n<span class=\"c\"># abcの下にリモートのファイルが見えたらOK</span>\n</code></pre></div></div>\n\n<h1 id=\"pyenvのインストール\">pyenvのインストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<h3 id=\"必要なモジュールをインストール\">必要なモジュールをインストール</h3>\n<p>インストールに必要なモジュールをインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div></div>\n\n<h3 id=\"bluetoothを使用する場合\">bluetoothを使用する場合</h3>\n<p>bluetoothを使用する場合は以下も必要</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>pyenvの設定のため、~/.bashrc に以下を追加。 <br />\n(上記手順で記載済み。念のため再掲しておく)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h2 id=\"sudoでpyenv環境を実行するように設定する\">sudoでpyenv環境を実行するように設定する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo</code>でpythonを実行すると、pyenvの設定に関係なくsystemのpythonが実行されてしまいます。<br />\nこれを防ぐためには、<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers</code>の<code class=\"language-plaintext highlighter-rouge\">Defaults secure_path</code>に以下のpathを追加します。</p>\n\n<ul>\n  <li>«pyenvインストール先»/plugins/pyenv-virtualenv/shims:</li>\n  <li>«pyenvインストール先»shims:</li>\n  <li>«pyenvインストール先»/bin:</li>\n</ul>\n\n<p>具体的には以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 変更前\nDefaults  secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n    ↓\n# 変更後\nDefaults  secure_path=\"/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n</code></pre></div></div>\n<ul>\n  <li></li>\n</ul>\n\n<h2 id=\"pythonのインストール-以降\">pythonのインストール 以降</h2>\n\n<p>参考: <a href=\"http://localhost:4000/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi で Text To Speech(音声合成)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi で Text To Speech(音声合成)</h1>\n      <p>Raspberry Pi でpythonを使用してText To Speech(音声合成)を試す</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi でText To Speech(音声合成)をofflineで実行することを試してみます。<br />\n(初回実行時は辞書データをダウンロードするのでインターネットにつながっている必要があります)</p>\n\n<blockquote>\n  <p>[!NOTE]\n環境変数 DISPLAY が設定されている場合、変数が示すマシンでXサーバが実行されている必要があります。<br />\n実行されていない場合は、オーディオ再生の際、コマンドがハングアップします、<br />\nその際は対象マシンでXサーバを実行するか、<code class=\"language-plaintext highlighter-rouge\">unset DISPLAY</code>で環境変数を削除してください。</p>\n</blockquote>\n\n<h1 id=\"スピーカの準備\">スピーカの準備</h1>\n<p>Raspberry Pi5ではオーディオジャックがなくなったので、\n将来のことを考えてUSBスピーカ(USBヘッドセット)を使用することにします。</p>\n\n<h2 id=\"スピーカの接続\">スピーカの接続</h2>\n\n<p>まず、USBスピーカをUSBポートに接続し、スピーカが認識されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>lsusb\nBus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub\nBus 001 Device 003: ID 0c76:161f JMTek, LLC. USB PnP Audio Device   ← これ\nBus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub\nBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub\n</code></pre></div></div>\n\n<h2 id=\"カード番号とデバイス番号の確認\">カード番号とデバイス番号の確認</h2>\n<p>使用するカード番号/デバイス番号を確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay <span class=\"nt\">-l</span>\n<span class=\"k\">****</span> ハードウェアデバイス PLAYBACK のリスト <span class=\"k\">****</span>\nカード 0: vc4hdmi0 <span class=\"o\">[</span>vc4-hdmi-0], デバイス 0: MAI PCM i2s-hifi-0 <span class=\"o\">[</span>MAI PCM i2s-hifi-0]\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\nカード 1: vc4hdmi1 <span class=\"o\">[</span>vc4-hdmi-1], デバイス 0: MAI PCM i2s-hifi-0 <span class=\"o\">[</span>MAI PCM i2s-hifi-0]\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\nカード 2: Headphones <span class=\"o\">[</span>bcm2835 Headphones], デバイス 0: bcm2835 Headphones <span class=\"o\">[</span>bcm2835 Headphones]\n  サブデバイス: 8/8\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\n  サブデバイス <span class=\"c\">#1: subdevice #1</span>\n  サブデバイス <span class=\"c\">#2: subdevice #2</span>\n  サブデバイス <span class=\"c\">#3: subdevice #3</span>\n  サブデバイス <span class=\"c\">#4: subdevice #4</span>\n  サブデバイス <span class=\"c\">#5: subdevice #5</span>\n  サブデバイス <span class=\"c\">#6: subdevice #6</span>\n  サブデバイス <span class=\"c\">#7: subdevice #7</span>\nカード 3: Device <span class=\"o\">[</span>USB PnP Audio Device], デバイス 0: USB Audio <span class=\"o\">[</span>USB Audio]         ← これ\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\n</code></pre></div></div>\n\n<p>カード番号が 3 または ‘Device’、デバイス番号が0であることが分かります</p>\n\n<h2 id=\"テスト再生\">テスト再生</h2>\n<p>テスト再生してみます。<br />\n-D オプションのパラメータは、<code class=\"language-plaintext highlighter-rouge\">plughw:</code>に続けて上で調べたカード番号、<code class=\"language-plaintext highlighter-rouge\">,</code>を挟んでデバイス番号を指定します。<br />\nwavファイルは何でもかまいません。下記はデフォルトでインストール済みのファイルなのでそれを使いました。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay <span class=\"nt\">-D</span> plughw:Device,0 /usr/share/sounds/alsa/Front_Center.wav\n再生中 WAVE <span class=\"s1\">'/usr/share/sounds/alsa/Front_Center.wav'</span> : Signed 16 bit Little Endian, レート 48000 Hz, モノラル\n</code></pre></div></div>\n\n<h2 id=\"デフォルトのオーディオデバイスの設定\">デフォルトのオーディオデバイスの設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">sudo raspi-config</code> を実行し、以下の順で選択します。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">1 System Options</code>\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">S2 Audio</code>\n        <ul>\n          <li>使用するオーディオデバイス( <code class=\"language-plaintext highlighter-rouge\">71 USB PnP Audio Device</code>など )</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">Finish</code>で終了</li>\n</ul>\n\n<p>デフォルト設定が変更されたことを確認するため、上記テスト再生のコマンドから-Dオプションを削除して再生されることを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay /usr/share/sounds/alsa/Front_Center.wav\n再生中 WAVE <span class=\"s1\">'/usr/share/sounds/alsa/Front_Center.wav'</span> : Signed 16 bit Little Endian, レート 48000 Hz, モノラル\n</code></pre></div></div>\n\n<h1 id=\"python仮想環境の作成とモジュールのインストール\">python仮想環境の作成とモジュールのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openjtalk\n<span class=\"nb\">cd</span> /work/openjtalk\n\npyenv virtualenv 3.11.9 openjtalk\npyenv <span class=\"nb\">local </span>openjtalk \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># pyopenjtalkのインストールに必要なのでcmakeをインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n\n<span class=\"c\"># pyopenjtalkのインストールbuildが実行されるので時間がかかる</span>\npip <span class=\"nb\">install </span>pyopenjtalk\n\n<span class=\"c\"># wavファイルの保存に使用するのでscipyもインストール</span>\npip <span class=\"nb\">install </span>scipy\n\n<span class=\"c\"># marineを使う場合は以下も実行</span>\npip <span class=\"nb\">install </span>pyopenjtalk[marine]\n</code></pre></div></div>\n\n<h1 id=\"pyopenjtalk-を実行してみる\">pyopenjtalk を実行してみる</h1>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  talk_test1.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">pyopenjtalk</span>\n<span class=\"kn\">from</span> <span class=\"nn\">scipy.io</span> <span class=\"kn\">import</span> <span class=\"n\">wavfile</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"c1\"># marineを使用する場合はrun_marineをTrueにする\n</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">sr</span> <span class=\"o\">=</span> <span class=\"n\">pyopenjtalk</span><span class=\"p\">.</span><span class=\"n\">tts</span><span class=\"p\">(</span><span class=\"s\">\"おめでとうございます\"</span><span class=\"p\">,</span> <span class=\"n\">run_marine</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n<span class=\"n\">wavfile</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">\"test1.wav\"</span><span class=\"p\">,</span> <span class=\"n\">sr</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">int16</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python talk_test1.py\n</code></pre></div></div>\n\n<p>再生します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>aplay test1.wav\n</code></pre></div></div>\n\n<p>スピーカーから「おめでとうございます」と聞こえたら成功です。おめでとうございます。</p>\n\n<h1 id=\"pythonからオーディオ再生する\">pythonからオーディオ再生する</h1>\n\n<p>オーディオ再生のためのモジュールは色々ありますが、\n下の直接再生に使用するにはnumpyデータを入力できることが必須となるので\nsimpleaudioを使用してみます。</p>\n\n<p>モジュールをインストールします。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># simpleaudioのインストールに必要なパッケージのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libasound2-dev\n\n<span class=\"c\"># インストール</span>\npip <span class=\"nb\">install </span>simpleaudio\n</code></pre></div></div>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  play_test1.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">simpleaudio</span>\n\n<span class=\"n\">wav_obj</span> <span class=\"o\">=</span> <span class=\"n\">simpleaudio</span><span class=\"p\">.</span><span class=\"n\">WaveObject</span><span class=\"p\">.</span><span class=\"n\">from_wave_file</span><span class=\"p\">(</span><span class=\"s\">\"test1.wav\"</span><span class=\"p\">)</span>\n<span class=\"n\">play_obj</span> <span class=\"o\">=</span> <span class=\"n\">wav_obj</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n<span class=\"n\">play_obj</span><span class=\"p\">.</span><span class=\"n\">wait_done</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python play_test1.py\n</code></pre></div></div>\n<h1 id=\"pyopenjtalkで作成した音声を直接再生する\">pyopenjtalkで作成した音声を直接再生する</h1>\n\n<p>逐一wavファイルを作成するのは面倒なので、合成したらすぐ再生するようにしてみます。</p>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  talk_test2.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">pyopenjtalk</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">simpleaudio</span>\n\n<span class=\"c1\"># marineを使用する場合はrun_marineをTrueにする\n</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">sr</span> <span class=\"o\">=</span> <span class=\"n\">pyopenjtalk</span><span class=\"p\">.</span><span class=\"n\">tts</span><span class=\"p\">(</span><span class=\"s\">\"直接再生します\"</span><span class=\"p\">,</span> <span class=\"n\">run_marine</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n<span class=\"c1\"># x : waveform\n# sr: sampling rate\n</span>\n<span class=\"n\">wav_obj</span> <span class=\"o\">=</span> <span class=\"n\">simpleaudio</span><span class=\"p\">.</span><span class=\"n\">WaveObject</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">int16</span><span class=\"p\">),</span> <span class=\"n\">num_channels</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">bytes_per_sample</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">sample_rate</span><span class=\"o\">=</span><span class=\"n\">sr</span><span class=\"p\">)</span>\n<span class=\"n\">play_obj</span> <span class=\"o\">=</span> <span class=\"n\">wav_obj</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n<span class=\"n\">play_obj</span><span class=\"p\">.</span><span class=\"n\">wait_done</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python talk_test2.py\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(Bookworm)のインストール(Raspberry Pi Imager)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(Bookworm)のインストール(Raspberry Pi Imager)</h1>\n      <p>Raspberry Pi OS(bookworm)のRaspberry Pi Imagerを使用したインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>RaspberrypiOSがBookwormになったので、インストール方法のメモ。<br />\n基本的にBullseyeのときと変わらないけど、ちょっと変わったところもあるので。<br />\n<a href=\"/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Bullseyeのときの手順メモ</a>も参照してください。</p>\n\n<h1 id=\"sdカードへの書き込み\">SDカードへの書き込み</h1>\n<p>Raspberry Pi Imager で書き込み。<br />\n使い方はあちこちに書いてあるけど、例えばこちら。</p>\n<ul>\n  <li><a href=\"https://qiita.com/mmake/items/576a2f60dffcd9291da3/\" target=\"_blank\">Raspberry Pi Imager のインストールと使い方</a></li>\n</ul>\n\n<p>バージョン変わると微妙に手順が変わったりするので、最新情報はぐぐってちょ。</p>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n<blockquote>\n  <p>[!NOTE]\n下記の変更をイッパツで行うスクリプトは以下。<br />\nWindowsのコマンドプロンプトで実行すると想定。  Windows版python必要。<br />\nそれぞれの<code class=\"language-plaintext highlighter-rouge\">F=</code>の部分を対象のドライブレターに変更する。</p>\n\n  <ul>\n    <li>UARTにUARTコネクタを使用する場合はこちら\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import re;F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">onfig.txt';a=open(F).read();a=re.sub(r'</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">(?!.*</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">)', '[pi5]</span><span class=\"se\">\\n</span><span class=\"s2\">dtparam=uart0</span><span class=\"se\">\\n\\n</span><span class=\"s2\">[all]</span><span class=\"se\">\\n</span><span class=\"s2\">enable_uart=1</span><span class=\"se\">\\n</span><span class=\"s2\">', a, flags=re.DOTALL);open(F, 'w').write(a)\"</span>\npython <span class=\"nt\">-c</span> <span class=\"s2\">\"F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">mdline.txt';a=open(F).read();a=a.replace(' quiet', '').replace(' splash', '').replace(' plymouth.ignore-serial-consoles', '')+' ipv6.disable=1';open(F, 'w').write(a)\"</span>\n</code></pre></div>      </div>\n    </li>\n    <li>UARTに40pinヘッダのpin8/10(GPIOs 14 & 15)を使用する場合はこちら\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import re;F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">onfig.txt';a=open(F).read();a=re.sub(r'</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">(?!.*</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">)', '[pi5]</span><span class=\"se\">\\n</span><span class=\"s2\">dtparam=uart0_console</span><span class=\"se\">\\n\\n</span><span class=\"s2\">[all]</span><span class=\"se\">\\n</span><span class=\"s2\">enable_uart=1</span><span class=\"se\">\\n</span><span class=\"s2\">', a, flags=re.DOTALL);open(F, 'w').write(a)\"</span>\npython <span class=\"nt\">-c</span> <span class=\"s2\">\"F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">mdline.txt';a=open(F).read();a=a.replace(' quiet', '').replace(' splash', '').replace(' plymouth.ignore-serial-consoles', '')+' ipv6.disable=1';open(F, 'w').write(a)\"</span>\n</code></pre></div>      </div>\n    </li>\n  </ul>\n</blockquote>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行を以下に変更</p>\n\n<ul>\n  <li>UARTにUARTコネクタを使用する場合はこちら</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[pi5]\ndtparam=uart0\n\n[all]\nenable_uart=1\n</code></pre></div></div>\n\n<ul>\n  <li>UARTに40pinヘッダのpin8/10(GPIOs 14 & 15)を使用する場合はこちら</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[pi5]\ndtparam=uart0_console\n\n[all]\nenable_uart=1\n</code></pre></div></div>\n\n<h2 id=\"ipv6の無効化\">IPv6の無効化</h2>\n<p>IPv6を無効化しておきたいときは、\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する。<br />\nこのファイルは1行で書かないといけないので、改行してはいけない。</p>\n\n<h2 id=\"ブートログの表示\">ブートログの表示</h2>\n\n<p>ブートログが見えないと不安な人は、<br />\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> から <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code>\nを削除しておくとよい。</p>\n<blockquote>\n  <p>[!NOTE]\nLITE版では<code class=\"language-plaintext highlighter-rouge\">quiet</code>を削除(それ以外は指定されていないので)</p>\n</blockquote>\n\n<h1 id=\"最初の起動\">最初の起動</h1>\n<p>書き込んだSDカードをRaspberry Piに挿入して電源ON。<br />\nごちょごちょと設定したあと、起動する(途中2回ほどrebootしてるらしい)</p>\n\n<h1 id=\"お約束\">お約束</h1>\n\n<p>ソフト類を最新版にする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n<span class=\"nb\">sudo </span>reboot \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <h4 id=\"ウィンドウマネージャをopenboxに変更したい場合\">ウィンドウマネージャをOpenboxに変更したい場合</h4>\n  <p>VNCに不具合がるなどの理由で以前のバージョンと同じX11ベースのOpenboxに変更したい場合は以下の手順で変更する。<br />\nちなみにOpenboxに変更したい場合は以下のコマンドで変更できる。<br />\nVNCを有効化した後にウィンドウマネージャを変更すると動作が不安定になることがあるので、VNCを有効化する前に変更するのがベター。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config nonint do_wayland W1\n<span class=\"nb\">sudo </span>reboot \n</code></pre></div>  </div>\n\n  <p>VNC有効化後、以下のコマンドでデフォルトのウィンドウマネージャ(wayfire)が無効になっていることを確認する。<br />\nなにも表示されなければOK</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pgrep wayfire\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"お好みで\">お好みで</h1>\n\n<p>その他お好み設定は\n<a href=\"/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</a>\nと同じ。<br />\nめんどくさいのでスクリプトを実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.githubusercontent.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c/raw/pi_setup1.sh\nbash pi_setup1.sh \n<span class=\"c\"># 途中sambaのパスワード設定がある  </span>\n<span class=\"nb\">sudo </span>reboot \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nIpV6無効の環境でwayfireでVNCを有効にする場合、VNCを有効化する前に\n以下のコマンドでwayfireでIPv4を使用するように設定する必要がある。<br />\nこの処理は上の<code class=\"language-plaintext highlighter-rouge\">pi_setup1.sh</code>の処理に含まれている。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /etc/wayvnc/config /etc/wayvnc/config.org\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s/</span><span class=\"se\">\\:\\:</span><span class=\"s2\">/0</span><span class=\"se\">\\.</span><span class=\"s2\">0</span><span class=\"se\">\\.</span><span class=\"s2\">0</span><span class=\"se\">\\.</span><span class=\"s2\">0/g\"</span> /etc/wayvnc/config\n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">/etc/wayvnc/config</code>の2行目の<code class=\"language-plaintext highlighter-rouge\">address=::</code>を<code class=\"language-plaintext highlighter-rouge\">address=0.0.0.0</code>に変更している。</p>\n</blockquote>\n\n<h1 id=\"pyenvのインストール\">pyenvのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<p>ここで一旦ログアウト&再ログイン</p>\n\n<h1 id=\"pythonのインストール\">pythonのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.11.9\npyenv shell 3.11.9 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\npyenv shell <span class=\"nt\">--unset</span> \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSBデバイスを使う(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSBデバイスを使う(その1)</h1>\n      <p>WSLでUSBデバイスを使う(その1:準備&USB-Serial編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLでUSBを使う方法。あちこちに情報があるけど、なんとなく自分なりにまとめておく。<br />\n<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb\" target=\"_blank\">本家の説明</a></p>\n\n<p>ますは、準備とLinuxカーネルのビルドが必要ないUSB-Serialデバイスから。</p>\n\n<h1 id=\"wsl側の準備\">WSL側の準備</h1>\n\n<h2 id=\"wslのバージョン\">WSLのバージョン</h2>\n<p>使用したWSLのバージョンは以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wsl <span class=\"nt\">--version</span>\n\nWSL バージョン: 2.2.4.0\nカーネル バージョン: 5.15.153.1-2\nWSLg バージョン: 1.0.61\nMSRDC バージョン: 1.2.5326\nDirect3D バージョン: 1.611.1-81528511\nDXCore バージョン: 10.0.26091.1-240325-1447.ge-release\nWindows バージョン: 10.0.19045.4529\n</code></pre></div></div>\n\n<p>使用したディストリビューションは「Ubuntu 22.04 LTS」</p>\n\n<h2 id=\"wslディストリビューションでsystemdの有効化\">WSLディストリビューションでsystemdの有効化</h2>\n\n<blockquote>\n  <p>[!NOTE]\nインストールしたタイミングによっては既に有効化されているかも。</p>\n</blockquote>\n\n<p>USBのホットプラグ処理は systemd + udev がよしなに行ってくれるみたいなので、systemdを有効化しておく。<br />\n使用するディストリビューションを起動し、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下の設定を行う。</p>\n\n<p>デフォルト(古いデフォルト?)のSystemVinitだとバカチョンで動かなかった…udevサービス再起動とかやったら動いたけど。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdを有効にするか否かはディストリビューション毎の設定</p>\n</blockquote>\n\n<p>設定後、WSLをシャットダウン(コマンドプロンプト等から<code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行)し、<br />\n再度ディストリビューションを起動する。</p>\n\n<p>参考:<a href=\"https://qiita.com/curacao/items/fb9adaf1c097b1acd6a8\" target=\"_blank\">WSL2でsystemctlを使う方法</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdが動作しているか確認するには、<code class=\"language-plaintext highlighter-rouge\">systemctl is-system-running</code> を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">running</code>(起動中) <code class=\"language-plaintext highlighter-rouge\">degraded</code>(起動中だが失敗したサービスなどが存在) と表示されれば動作している。<br />\n<code class=\"language-plaintext highlighter-rouge\">offline</code> と表示されれば起動していない。<br />\nその他使い方についてはぐぐってちょ。</p>\n</blockquote>\n\n<h2 id=\"必要なパッケージをインストール\">必要なパッケージをインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic hwdata\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nlinux-tools-generic : usbipコマンド等が入る<br />\nhwdata : USB ID等のデータベースが入る<br />\nlinux-tools-generic インストールしたら自動でhwdata入るけど….<br />\n参考にしたサイトにこう書いてあったので。<br />\nlinux-tools-virtualと書いてあるサイトもあるけど、ubuntu 22.04だとchangelogとcopyrightしか違わないみたい。<br />\n </p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /usr/lib/linux-tools\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> 5.15.0-113-generic <span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあちこちに<code class=\"language-plaintext highlighter-rouge\">sudo update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20</code>\nでコマンドのバージョン管理を行う例が書かれているけど、なんとなくシンボリックリンクを張る方がしっくりするのでこっちにした。</p>\n\n  <p>本来、usbipを実行すると <code class=\"language-plaintext highlighter-rouge\">/usr/bin/usbip</code> が <code class=\"language-plaintext highlighter-rouge\">/usr/lib/linux-tools/≪カーネルバージョン≫/usbip</code><br />\nを起動してくれるらしいのだけど、WSL環境では≪カーネルバージョン≫がカスタマイズバージョンでうまく働かないので<br />\n/usr/lib/linux-tools/≪カーネルバージョン≫をインストールされているバージョンに飛ばしてやればいい。<br />\nカーネルバージョンが変更されたら動かなくなるけど、そのときは、新しいカーネルバージョン名のシンボリックリンクを作ってやればよい。<br />\nもちろん、linux-tools-genericのアップデートが必要か判断して、必要ならアップデートする。</p>\n</blockquote>\n\n<h1 id=\"windows側の準備\">windows側の準備</h1>\n<h2 id=\"usbipd-win-のインストール\">usbipd-win のインストール</h2>\n<p>まずはUSBをTCP/IP経由で接続させるためのツール、usbipd-win をwindowsにインストールする。<br />\nインストールするには、<a href=\"https://github.com/dorssel/usbipd-win/releases\" target=\"_blank\">ダウンロードページ</a>  から\n最新版(以下の手順で使用したのは4.2.0)のmsiファイルをダウンロードして実行するだけ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストール時PATHが変更されるので、既に開いているコマンドプロンプトorPowerShellは一旦閉じて再実行する。</p>\n</blockquote>\n\n<h1 id=\"usbデバイスの操作\">USBデバイスの操作</h1>\n<p>WSLで使用したいUSBデバイスはあらかじめPCに接続しておく。</p>\n\n<p>以下の処理はコマンドプロンプトorPowerShellで行う。<br />\nただし、bind/unbindサブコマンドは管理者権限が必要なので、管理者として開いたコマンドプロンプトorPowerShellで実行する。</p>\n\n<h2 id=\"接続したいデバイスのbusidを調べる\">接続したいデバイスのBusIDを調べる</h2>\n\n<p>以下のコマンドを実行する。<br />\n結果は例。今回は3-4のUSB Serial Converter を使う。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">list</span><span class=\"w\">\n</span><span class=\"err\">≪結果≫</span><span class=\"w\">\n</span><span class=\"n\">Connected:</span><span class=\"w\">\n</span><span class=\"nx\">BUSID</span><span class=\"w\">  </span><span class=\"nx\">VID:PID</span><span class=\"w\">    </span><span class=\"nx\">DEVICE</span><span class=\"w\">                                                        </span><span class=\"nx\">STATE</span><span class=\"w\">\n</span><span class=\"mi\">2</span><span class=\"nt\">-1</span><span class=\"w\">    </span><span class=\"mi\">1</span><span class=\"n\">f75:0918</span><span class=\"w\">  </span><span class=\"nx\">USB</span><span class=\"w\"> </span><span class=\"err\">大容量記憶装置</span><span class=\"w\">                                            </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span><span class=\"mi\">2</span><span class=\"nt\">-2</span><span class=\"w\">    </span><span class=\"mi\">056</span><span class=\"n\">e:700a</span><span class=\"w\">  </span><span class=\"nx\">Venus</span><span class=\"w\"> </span><span class=\"nx\">USB2.0</span><span class=\"w\"> </span><span class=\"nx\">Camera</span><span class=\"w\">                                           </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span><span class=\"mi\">3</span><span class=\"nt\">-4</span><span class=\"w\">    </span><span class=\"mi\">0403</span><span class=\"p\">:</span><span class=\"mi\">6001</span><span class=\"w\">  </span><span class=\"n\">USB</span><span class=\"w\"> </span><span class=\"nx\">Serial</span><span class=\"w\"> </span><span class=\"nx\">Converter</span><span class=\"w\">                                          </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>ここで表示されたWSLで使用したいUSBデバイスのBUSID(例えば3-4)を覚えておく。</p>\n\n<h2 id=\"デバイスを共有設定する\">デバイスを共有設定する</h2>\n\n<p>管理者として開いたコマンドプロンプトorPowerShellで以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">bind</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">        </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">usbipd: warning: USB filter 'USBPcap' is known to be incompatible with this software; 'bind --force' will be required.</code><br />\nと出た時は、一旦unbindして、–forceオプションを追加して実行<br />\n(うちのPCはWiresharkインストールしてUSBPcap入ってるからだろうなぁ…)</p>\n</blockquote>\n\n<p>実行後、<code class=\"language-plaintext highlighter-rouge\">usbipd list</code>を実行すると、対象デバイスのステータスが Shared または Shared (forced) になっている</p>\n\n<h2 id=\"ディストリビューションの起動\">ディストリビューションの起動</h2>\n\n<p>接続するためのWSLのディストリビューションを起動しておく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n起動してないと<code class=\"language-plaintext highlighter-rouge\">usbipd: error: There is no WSL 2 distribution running; keep a command prompt to a WSL 2 distribution open to leave it running.</code>とエラーになる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nこのとき、複数のディストリビューションが起動していると変なことが起こりそうなので(未確認)\n対象のディストリビューションだけ起動しておくのが良いと思う。</p>\n</blockquote>\n\n<h2 id=\"デバイスを接続する\">デバイスを接続する</h2>\n\n<p>bindしただけではまだWSL側からはUSBデバイスは見えない。</p>\n\n<h3 id=\"windows側から接続する場合\">Windows側から接続する場合</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">attach</span><span class=\"w\"> </span><span class=\"nt\">--wsl</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">             </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"linux側から接続する場合\">linux側から接続する場合</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip attach <span class=\"nt\">-r</span> 172.20.160.1 <span class=\"nt\">-b</span> 3-4    <span class=\"c\"># 172.20.160.1 はWindows側のIPアドレス</span>\n                                            <span class=\"c\"># 3-4は接続するデバイスのBusID</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWindows側のIPアドレスはコマンドプロンプトorPowerShellから<code class=\"language-plaintext highlighter-rouge\">ipconfig</code>コマンドを実行し、<br />\n<code class=\"language-plaintext highlighter-rouge\">Ethernet adapter vEthernet (WSL):</code> に表示されているIPアドレスを使用する。<br />\nでもWSLがミラーネットワークモードになってたらどうなるんだろう???</p>\n</blockquote>\n\n<h2 id=\"デバイス接続を確認する\">デバイス接続を確認する</h2>\n<p>linux側で以下を実行し、接続されたデバイスが表示されていることを確認する。 \n以下のように接続したデバイスが表示されていればOK<br />\n(以下では2行目のFT232 Serial (UART) IC)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n≪結果≫\nBus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub\nBus 001 Device 003: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial <span class=\"o\">(</span>UART<span class=\"o\">)</span> IC\nBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub<span class=\"sb\">```</span>\n</code></pre></div></div>\n\n<h1 id=\"usb-serialデバイスを接続\">USB-Serialデバイスを接続</h1>\n<p>上記操作で接続したUSBデバイスがUSB-Serialデバイス(上記の例では FT232 Serial (UART) IC) であれば、\n<code class=\"language-plaintext highlighter-rouge\">/dev/ttyUSBx</code>(xは数字。通常0から順に割り当てられる)に割り当てられる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> <span class=\"nt\">-la</span> /dev/ttyUSB<span class=\"k\">*</span>\n≪結果≫\ncrw-rw---- 1 root dialout 188, 0  7月  3 11:02 /dev/ttyUSB0\n</code></pre></div></div>\n\n<p>一応、ログを確認してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dmesg\n≪結果≫\n・・・・・・\n<span class=\"o\">[</span>  189.418189] vhci_hcd vhci_hcd.0: pdev<span class=\"o\">(</span>0<span class=\"o\">)</span> rhport<span class=\"o\">(</span>0<span class=\"o\">)</span> sockfd<span class=\"o\">(</span>3<span class=\"o\">)</span>\n<span class=\"o\">[</span>  189.418196] vhci_hcd vhci_hcd.0: devid<span class=\"o\">(</span>196612<span class=\"o\">)</span> speed<span class=\"o\">(</span>2<span class=\"o\">)</span> speed_str<span class=\"o\">(</span>full-speed<span class=\"o\">)</span>\n<span class=\"o\">[</span>  189.418249] vhci_hcd vhci_hcd.0: Device attached\n<span class=\"o\">[</span>  189.690366] vhci_hcd: vhci_device speed not <span class=\"nb\">set</span>\n<span class=\"o\">[</span>  189.760405] usb 1-1: new full-speed USB device number 2 using vhci_hcd\n<span class=\"o\">[</span>  189.840475] vhci_hcd: vhci_device speed not <span class=\"nb\">set</span>\n<span class=\"o\">[</span>  189.910358] usb 1-1: SetAddress Request <span class=\"o\">(</span>2<span class=\"o\">)</span> to port 0\n<span class=\"o\">[</span>  190.135906] usb 1-1: New USB device found, <span class=\"nv\">idVendor</span><span class=\"o\">=</span>0403, <span class=\"nv\">idProduct</span><span class=\"o\">=</span>6001, <span class=\"nv\">bcdDevice</span><span class=\"o\">=</span> 6.00\n<span class=\"o\">[</span>  190.135918] usb 1-1: New USB device strings: <span class=\"nv\">Mfr</span><span class=\"o\">=</span>1, <span class=\"nv\">Product</span><span class=\"o\">=</span>2, <span class=\"nv\">SerialNumber</span><span class=\"o\">=</span>3\n<span class=\"o\">[</span>  190.135921] usb 1-1: Product: FT232R USB UART\n<span class=\"o\">[</span>  190.135923] usb 1-1: Manufacturer: FTDI\n<span class=\"o\">[</span>  190.135924] usb 1-1: SerialNumber: A50285BI\n<span class=\"o\">[</span>  190.511832] usbcore: registered new interface driver ftdi_sio\n<span class=\"o\">[</span>  190.511852] usbserial: USB Serial support registered <span class=\"k\">for </span>FTDI USB Serial Device\n<span class=\"o\">[</span>  190.511881] ftdi_sio 1-1:1.0: FTDI USB Serial Device converter detected\n<span class=\"o\">[</span>  190.511904] usb 1-1: Detected FT232RL\n<span class=\"o\">[</span>  190.521353] usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB0       ← /dev/ttyUSB0が割り当てられたことが分かる\n</code></pre></div></div>\n\n<p>デフォルトで使用できるUSB-Serialデバイスは、\nSilicon Labs社製 CP210x、FTDI社製シリアルコンバータ(FT232)、CH34x(安い中国製Arduinoで使われているらしい)らしい。</p>\n\n<p>/dev/ttyUSBxが割り当てられていない場合は、対応しているUSB-Serialデバイスか、systemdが有効になっているか、等を確認してください。</p>\n\n<blockquote>\n  <p>[!NOTE]\n参考:<a href=\"https://another.maple4ever.net/archives/3221/?fbclid=IwZXh0bgNhZW0CMTAAAR2mnOe2c5FmYg3ig1IQbB1r4Y3t43MLJyqvzAx6tyjuiWCjETjj_x9Rkd0_aem_EpK6sQQOwszToANXZLsfiQ\" target=\"_blank\">Windows WSL2 の Ubuntu 22.04 上から USB-UART 経由で M5Stack に書き込みする</a><br />\n上記サイトではudevルールをplatform.ioのサイトから拝借してきているが、上記の製品なら持ってこなくても可。<br />\n互換品とかでうまく認識しないときは試してみると動くかも(試してないので無責任発言)。</p>\n</blockquote>\n\n<h2 id=\"シリアルポートを使ってみる\">シリアルポートを使ってみる</h2>\n\n<p>シリアルポートを使うツールは色々あると思うけど、とりあえず動いているか確認するならこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>pyserial-miniterm <span class=\"nt\">--parity</span> N /dev/ttyUSB0 115200\n</code></pre></div></div>\n\n<p>終了するにはCTRL+]を入力する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nsudoなしで実行するには、自分のアカウントにdialoutグループを追加すればよい。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> dialout\n</code></pre></div>  </div>\n  <p>一旦ログアウトして再ログイン必要。</p>\n</blockquote>\n\n<h2 id=\"デバイスを接続解除する\">デバイスを接続解除する</h2>\n\n<p>WSLをシャットダウンしたら(ディストリビューションのシャットダウンではなくWSL全体)接続解除されるけど、\n手動で接続解除するには以下のコマンドを実行する。</p>\n\n<h3 id=\"windows側から接続解除する場合\">Windows側から接続解除する場合</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\">  </span><span class=\"nx\">detach</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">              </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"linux側から接続解除する場合\">linux側から接続解除する場合</h3>\n<p>linuxから解除するには、まずポート番号を確認する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip port\n≪結果≫\nImported USB devices\n<span class=\"o\">====================</span>\nPort 00: <Port <span class=\"k\">in </span>Use> at Full Speed<span class=\"o\">(</span>12Mbps<span class=\"o\">)</span>\n       Future Technology Devices International, Ltd : FT232 Serial <span class=\"o\">(</span>UART<span class=\"o\">)</span> IC <span class=\"o\">(</span>0403:6001<span class=\"o\">)</span>\n       1-1 -> usbip://172.20.160.1:3240/3-4       ← ホストアドレス\n           -> remote bus/dev 003/004              ← BusID\n           \n</code></pre></div></div>\n\n<p>上記の例ではポート番号は00なので、これをportオプションに指定して以下のように実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip detach <span class=\"nt\">--port</span> 00\n</code></pre></div></div>\n\n<h2 id=\"デバイスを共有解除する\">デバイスを共有解除する</h2>\n\n<p>USBデバイスを共有解除するには、管理者として開いたコマンドプロンプトorPowerShellで以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">unbind</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">           </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nデバイスの共有解除しなければ、PCを再起動しても共有設定されたままになる。<br />\nただし、使用しているUSBポートに別のUSBデバイスを挿入すると共有解除されるが、再度同じUSBデバイスを挿入すれば共有設定される。<br />\n何言ってるか分からんと思うけど、USBデバイス挿抜してみて確かめてみて。</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLのカーネルをビルドする</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLのカーネルをビルドする</h1>\n      <p>WSLのカーネルをビルドする手順(Docker使用)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLでUSBストレージ(USBメモリなど)を使う方法を書こうと手順をまとめている間に、カーネル v6.6.36.3 がリリースされてしまいました。<br />\nこのバージョンは自前でビルドしなくてもUSBストレージ関連のドライバが入っています(Builtinモジュールではなくロードモジュールとして)。<br />\nで、バイナリリリースされてしまえば何もしなくてもUSBストレージが使えるようになる(ハズ)ですが、\n今日の段階はまだバイナリリリースされてないので自前でビルドしてみることにしました。<br />\n以下はその時のメモ。<br />\nで、手順は以下のサイトのDockerを使用して開発環境を構築する方法を <del>パクった</del>  参考にしました。<br />\n(もともとカーネル差し替えずにドライバ組み込む手順を調べてて参考にしたサイト)</p>\n\n<p>参照:<a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">カーネルモジュールのビルドと使用</a></p>\n\n<h1 id=\"準備の準備\">準備の準備</h1>\n\n<h2 id=\"wslディストリビューションでsystemdの有効化\">WSLディストリビューションでsystemdの有効化</h2>\n\n<p>systemdの方がDockerのサービスの操作とかやりやすい(情報が多い?)のでsystemdを有効化しておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストールしたタイミングによっては既に有効化されているかも。</p>\n</blockquote>\n\n<p> \n使用するディストリビューションを起動し、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下の設定を行います。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdを有効にするか否かはディストリビューション毎の設定</p>\n</blockquote>\n\n<p>設定後、WSLをシャットダウン(コマンドプロンプト等から<code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行)し、<br />\n再度ディストリビューションを起動します。</p>\n\n<p>参考:<a href=\"https://qiita.com/curacao/items/fb9adaf1c097b1acd6a8\" target=\"_blank\">WSL2でsystemctlを使う方法</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdが動作しているか確認するには、<code class=\"language-plaintext highlighter-rouge\">systemctl is-system-running</code> を実行します。<br />\n<code class=\"language-plaintext highlighter-rouge\">running</code>(起動中) <code class=\"language-plaintext highlighter-rouge\">degraded</code>(起動中だが失敗したサービスなどが存在) と表示されれば動作しています。<br />\n<code class=\"language-plaintext highlighter-rouge\">offline</code> と表示されれば起動していません。<br />\nその他使い方についてはぐぐってちょ。</p>\n</blockquote>\n\n<h1 id=\"linuxカーネルのビルド環境の構築\">Linuxカーネルのビルド環境の構築</h1>\n\n<h2 id=\"dockerの準備\">Dockerの準備</h2>\n\n<p>コンパイル環境はDockerコンテナを使用するので、Dockerをインストールします。<br />\nWindows上で使用できるDocker Desktop for Windowsでも良いのですが、ディストリビューション上にDockerをインストールすることにします。</p>\n\n<blockquote>\n  <p>[!NOTE]\nDocker Desktop for Windows を使用する場合は「WSL統合」でDockerを統合したディストリビューションで作業することになるようです。<br />\n試してないから分からんけど….</p>\n</blockquote>\n\n<p>インストール方法は先人の知恵を拝借→<a href=\"https://zenn.dev/thyt_lab/articles/fee07c278fcaa8\" target=\"_blank\">WSL(Ubuntu)にDocker環境を構築する</a><br />\nこのページの通りに実行すればDockerがインストールできます。</p>\n\n<p>また、Dockerをsudoなしで実行できるように、dockerグループを追加しておきます。<br />\n追加しなくてもsudoで実行できますが、作成されたファイルのオーナーがrootになってしまって面倒なのでおススメしません。</p>\n\n<p>以下、私が実際に行ったコマンドです。上記サイトの手順ほとんどそのままです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># apt keyring ファイル格納ディレクトリを作成</span>\n<span class=\"nb\">sudo install</span> <span class=\"nt\">-m</span> 0755 <span class=\"nt\">-d</span> /etc/apt/keyrings\n\n<span class=\"c\"># 鍵ファイルの作成&リード属性付与</span>\ncurl <span class=\"nt\">-fsSL</span> https://download.docker.com/linux/ubuntu/gpg | <span class=\"nb\">sudo </span>gpg <span class=\"nt\">--dearmor</span> <span class=\"nt\">-o</span> /etc/apt/keyrings/docker.gpg\n<span class=\"nb\">sudo chmod </span>a+r /etc/apt/keyrings/docker.gpg\n\n<span class=\"c\"># aptリポジトリの追加</span>\n<span class=\"nb\">echo</span>   <span class=\"s2\">\"deb [arch=\"</span><span class=\"si\">$(</span>dpkg <span class=\"nt\">--print-architecture</span><span class=\"si\">)</span><span class=\"s2\">\" signed-by=/etc/apt/keyrings/docker.gpg] </span><span class=\"se\">\\</span><span class=\"s2\">\n        https://download.docker.com/linux/ubuntu </span><span class=\"se\">\\</span><span class=\"s2\">\n        \"</span><span class=\"si\">$(</span><span class=\"nb\">.</span> /etc/os-release <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"s2\">\"</span><span class=\"nv\">$VERSION_CODENAME</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"s2\">\" stable\"</span> <span class=\"se\">\\</span>\n        | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/docker.list\n\n<span class=\"c\"># 追加したリポジトリも含めてaptデータベースの更新</span>\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># Dockerのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n\n<span class=\"c\"># 自身にdockerグループを追加</span>\n<span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> docker\n</code></pre></div></div>\n\n<p>dockerグループの追加を有効にするため、<strong>ここで一旦ログアウトして再ログイン</strong></p>\n\n<p>dockerグループが追加されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">groups</span>\n</code></pre></div></div>\n\n<p>以下のようにdockerグループが追加されていればOK。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XXXX adm cdrom <span class=\"nb\">sudo </span>dip plugdev lxd docker\n</code></pre></div></div>\n\n<h3 id=\"dockerのテスト\">Dockerのテスト</h3>\n\n<p>Dockerが正常にインストールできたか確認するため、hello-worldを実行します。<br />\n実行後、コンテナを削除するように<code class=\"language-plaintext highlighter-rouge\">--rm</code>オプションを指定。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">--rm</span> hello-world\n</code></pre></div></div>\n\n<p>以下のように表示されればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・・\nHello from Docker!\nThis message shows that your installation appears to be working correctly.\n・・・・\n</code></pre></div></div>\n\n<p>使用したhello-worldイメージはもう使わないので削除しておきます。</p>\n\n<p>まずコンテナが残ってないか確認します。<br />\n<code class=\"language-plaintext highlighter-rouge\">-a</code>をつけるのを忘れずに!</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n\n<p>以下のようにヘッダ行だけ表示されればコンテナは残っていません(OKです)。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nもしコンテナが残っていたら(rmオプション付け忘れなど)以下のように表示されます。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES\nae8523f06af4   hello-world   \"/hello\"   13 seconds ago   Exited (0) 10 seconds ago             romantic_booth\n</code></pre></div>  </div>\n  <p>この場合は以下のコマンドで削除します(CONTAINER IDやNAMEは上で表示されたものを使用)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CONTAINER ID で指定</span>\ndocker <span class=\"nb\">rm </span>ae8523f06af4\n<span class=\"c\"># または NAME で指定</span>\ndocker <span class=\"nb\">rm </span>romantic_booth\n</code></pre></div>  </div>\n</blockquote>\n\n<p>イメージを確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<p>結果はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>REPOSITORY    TAG       IMAGE ID       CREATED         SIZE\nhello-world   latest    d2c94e258dcb   14 months ago   13.3kB\n</code></pre></div></div>\n\n<p>イメージを削除します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image <span class=\"nb\">rm </span>hello-world\n</code></pre></div></div>\n\n<p>結果はこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Untagged: hello-world:latest\nUntagged: hello-world@sha256:94323f3e5e09a8b9515d74337010375a456c909543e1ff1538f5116d38ab3989\nDeleted: sha256:d2c94e258dcb3c5ac2798d32e1249e42ef01cba4841c2234249495f87264ac5a\nDeleted: sha256:ac28800ec8bb38d5c35b49d45a6ac4777544941199075dff8c4eb63e093aa81e\n</code></pre></div></div>\n\n<p>削除されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<p>結果はこんな感じでヘッダ行だけ表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>REPOSITORY   TAG       IMAGE ID   CREATED   SIZE\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nカーネル入れ替えたり、なんやかんやしてるうちにDockerが起動しなくなることがありました。<br />\nそのときは <code class=\"language-plaintext highlighter-rouge\">systemctl status docker</code> を実行して <code class=\"language-plaintext highlighter-rouge\">Active</code>の表示を確認します。\n<code class=\"language-plaintext highlighter-rouge\">failed</code>になっていたら起動に失敗しています。<br />\n原因の調査方法はいろいろありますが、私が遭遇したパターンでは\n<code class=\"language-plaintext highlighter-rouge\">sudo dockerd --debug</code> を実行してエラーメッセージを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">networks have same bridge name</code> と出ている場合は\n<code class=\"language-plaintext highlighter-rouge\">/var/lib/docker/network</code>ディレクトリを消して(不安ならリネームして)、\n<code class=\"language-plaintext highlighter-rouge\">sudo systemctl start docker</code> を実行します。<br />\nこの後、 <code class=\"language-plaintext highlighter-rouge\">systemctl status docker</code> を実行して \n<code class=\"language-plaintext highlighter-rouge\">Active</code>の表示が<code class=\"language-plaintext highlighter-rouge\">active (running)</code>になっていればOKのはず。</p>\n\n</blockquote>\n\n<h1 id=\"カーネルのビルド\">カーネルのビルド</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<p>たとえば、以下。 どこでも良いけど、以下の手順はこのディレクトリで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /proj/wsl_kernel <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /proj/wsl_kernel\n</code></pre></div></div>\n\n<h2 id=\"カーネルソースの取得\">カーネルソースの取得</h2>\n<p>作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)にカーネルソースをダウンロードします。<br />\ngitリポジトリをcloneするか、リリースソースをダウンロードして展開します。</p>\n\n<h3 id=\"gitでcloneする場合\">gitでcloneする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/microsoft/WSL2-Linux-Kernel.git\n\n<span class=\"c\"># 目的のタグをチェックアウト</span>\ngit <span class=\"nt\">-C</span> WSL2-Linux-Kernel checkout <span class=\"nt\">-b</span> WSL-6.6.36.3 refs/tags/linux-msft-wsl-6.6.36.3\n\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> WSL2-Linux-Kernel linux\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nclone済みなら念のため<code class=\"language-plaintext highlighter-rouge\">git pull</code>して最新状態にしておく</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nブランチ作る必要ないけど、念のため。</p>\n</blockquote>\n\n<h3 id=\"リリースソースzipをダウンロードする場合\">リリースソース(zip)をダウンロードする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-6.6.36.3.zip\nunzip linux-msft-wsl-6.6.36.3.zip\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> linux-msft-wsl-6.6.36.3 linux\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nunzipはデフォルトではインストールされていないのでインストール必要。</p>\n</blockquote>\n\n<h2 id=\"スクリプトdockerfileの入手\">スクリプト&Dockerfileの入手</h2>\n<blockquote>\n  <p>[!NOTE]\nGistに必要なスクリプト&<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>を置いておいたので以下のページの<code class=\"language-plaintext highlighter-rouge\">DownloadZIP</code>ボタンからダウンロードして\n作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)に展開してください。<br />\n<a href=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021\" target=\"_blank\">Gist:WSLカーネルビルド環境</a></p>\n\n  <p>または以下のコマンドで取得できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021/archive/main.zip\nunzip <span class=\"nt\">-j</span> main.zip\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージを作成\">Dockerイメージを作成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>は上のサイトからダウンロードしてください。<br />\n<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>があるディレクトリで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker build <span class=\"nt\">-t</span> wslkernelbuilder:2.0 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<p>Dockerfileの内容は以下の通り。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=Dockerfile\"></script>\n</dev>\n\n<h2 id=\"dockerコンテナの起動確認\">Dockerコンテナの起動確認</h2>\n<p>上で作成したDockerイメージでコンテナを起動できることを確認します。<br />\nこのスクリプトは上のDockerイメージでDockerコンテナを起動し、シェルを実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_interactive.sh\n</code></pre></div></div>\n<p>プロンプトが以下のように変わればOKです(最後のディレクトリはlinuxのリンク先の実体のディレクトリ名になります)。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>builder [ /usr/src/WSL2-Linux-Kernel ]$\n</code></pre></div></div>\n<p>適当なコマンドを入力して遊んでみてください(カレントディレクトリのファイルは消さないように)。<br />\n最後は<code class=\"language-plaintext highlighter-rouge\">exit</code>で終了します。<br />\n起動時に<code class=\"language-plaintext highlighter-rouge\">--rm</code>しているので、終了時コンテナは削除されます。<br />\nなので、<code class=\"language-plaintext highlighter-rouge\">/usr/src</code>ディレクトリ以外にファイルを作っても終了後はなくなります。<br />\nもちろん<code class=\"language-plaintext highlighter-rouge\">tdnf install</code>(marinerなのでaptではない)でインストールしたアプリケーションもきれいさっぱりなくなります。<br />\n<code class=\"language-plaintext highlighter-rouge\">/usr/src</code>ディレクトリはスクリプトを起動したディレクトリをマウントしていますので、\nここに作成したファイルはコンテナ終了後も残ります(逆に削除するとホストからも削除されます)。</p>\n\n<h2 id=\"カーネルのビルド-1\">カーネルのビルド</h2>\n\n<p>カーネルソースの取得、Dockeイメージのビルドが終わったら、以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_kernel.sh\n</code></pre></div></div>\n\n<p>実行には1時間とか2時間とかのオーダーの時間がかかりますので、お茶でも飲んで気長に待ってください。</p>\n\n<p>実行完了後、<code class=\"language-plaintext highlighter-rouge\">out</code>ディレクトリに<code class=\"language-plaintext highlighter-rouge\">bzImage</code>と<code class=\"language-plaintext highlighter-rouge\">linux-module-6.6.36.3-microsoft-standard-wsl2_6.6.36.3-3_amd64.deb</code>ができます。<br />\nこれらを使用するPCのWindowsから見えるフォルダ(例えば、<code class=\"language-plaintext highlighter-rouge\">c:\\WSL_KERNEL\\</code>)にコピーします。</p>\n\n<h3 id=\"カーネルビルド用スクリプト\">カーネルビルド用スクリプト</h3>\n\n<p>用意したスクリプトの概要は以下の通りです。</p>\n\n<h4 id=\"build_functionssh\">build_functions.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_functions.sh</code>はビルドに関わる処理を関数化したものをまとめたファイルです。<br />\n以下のスクリプトからインクルードして使用します。</p>\n\n<p>Dockerコンテナを使用するので、あらかじめDockerイメージを作成しておく必要があります。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_functions.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_kernelsh\">build_wsl_kernel.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_kernel.sh</code>はカーネルのビルドを行います。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_kernel.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_interactivesh\">build_wsl_interactive.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_interactive.sh</code>はコンテナ内でインタラクティブにビルド操作をしたい場合に使用します。<br />\nたとえば、新しくモジュールを有効化したいとき、<code class=\"language-plaintext highlighter-rouge\">make menuconfig</code>して<code class=\"language-plaintext highlighter-rouge\">make</code>するような場合です。<br />\n実行するとコンテナ内のシェルが起動するので、実行したいコマンドを実行してください。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_interactive.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_usb-storagesh\">build_wsl_usb-storage.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_usb-storage.sh</code>はUSBストレージのカーネルモジュールのビルドを行います。<br />\nバージョン6.6.<em>ではすでに有効になっているので、使用しません。<br />\nバージョン5.15.</em>で標準カーネルのままカーネルモジュールをビルドして使用するときに使用します。<br />\n6.6.*でも他のモジュールを有効化するときに参考になるかもと残しています。</p>\n\n<p><a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">参照先</a>\nの処理を少し書き換えただけです。</p>\n\n<p>outディレクトリに作成された<code class=\"language-plaintext highlighter-rouge\">linux-module-usb-storage-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64</code>を使用するディストリビューションにコピーし、\n以下のように実行しますが、インストール先の<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/</code>が書き込み禁止のため\nあらかじめここにoverlayfsをマウントしておく必要があります。<br />\nマウント方法やその他使用方法は\n<a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">参照先</a>\nを参照してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> linux-module-usb-storage-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64\n</code></pre></div></div>\n<p>標準カーネルを使用することを前提にしているので、カーネルの差し替えは必要ありません。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_usb-storage.sh\"></script>\n</dev>\n\n<blockquote>\n  <p>[!NOTE]\nこのスクリプトは使用するWSLカーネルで実行されているディストリビューションで実行してください。<br />\nそうしないとBTFの確認(<code class=\"language-plaintext highlighter-rouge\">check_btf</code>関数)が失敗します。</p>\n</blockquote>\n\n<h1 id=\"差し替えたカーネルで実行\">差し替えたカーネルで実行</h1>\n\n<h2 id=\"wslの停止\">WSLの停止</h2>\n<p>WSL実行中の場合はすべてのウィンドウを閉じます。<br />\nさらにWSLを完全に終了するために以下のコマンドを実行します。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--shutdown</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>念のため、すべて停止していることを確認を確認)</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>結果はこんな感じで<code class=\"language-plaintext highlighter-rouge\">STATE</code>がすべて<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  NAME              STATE           VERSION\n* Ubuntu-20.04-1    Stopped         2\n  ubuntu-22.04-2    Stopped         2\n  test_6_6          Stopped         2\n</code></pre></div></div>\n\n<h2 id=\"差し替えカーネルの設定\">差し替えカーネルの設定</h2>\n\n<p>差し替えカーネルを設定するため、<code class=\"language-plaintext highlighter-rouge\">%USERPROFILE%\\.wslconfig</code> に以下を追記(なければ新規作成)します。<br />\nここで指定しているのは先にコピーしたbzImageファイルのパスです。<br />\nただし、フォルダ区切りの<code class=\"language-plaintext highlighter-rouge\">\\</code>は<code class=\"language-plaintext highlighter-rouge\">\\\\</code>に置き換える必要があります。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[wsl2]\nkernel=c:\\\\WSL_KERNEL\\\\bzImage\n</code></pre></div></div>\n\n<h2 id=\"差し替えカーネルでの起動\">差し替えカーネルでの起動</h2>\n<p>通常通り、ディストリビューションを起動します。<br />\n起動後、ディストリビューション内のシェルで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">uname</span> <span class=\"nt\">-r</span>\n</code></pre></div></div>\n<p>結果が<code class=\"language-plaintext highlighter-rouge\">6.6.36.3-microsoft-standard-WSL2</code>と差し替えたカーネルのバージョンになっていることを確認します。</p>\n\n<h2 id=\"カーネルモジュールのインストール\">カーネルモジュールのインストール</h2>\n\n<p>次に先ほどコピーしたカーネルモジュールをインストールします。</p>\n<blockquote>\n  <p>[!NOTE]\nカーネルモジュールのインストールはカーネル差し替え後に行ってください。<br />\n差し替え前が標準カーネルだった場合、インストール先がリードオンリーのため、インストールに失敗します。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> /mnt/c/WSL_KERNEL/linux-module-6.6.36.3-microsoft-standard-wsl2_6.6.36.3-3_amd64.deb\n</code></pre></div></div>\n\n<p>インストールされると、<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/6.6.36.3-microsoft-standard-WSL2/</code>以下に各種ファイルが作成されます。</p>\n\n<p>インストールしたモジュールを読み込むため、ディストリビューションを再起動します。<br />\nWSLを完全に終了するために以下のコマンドを実行します。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--shutdown</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>念のため、すべて停止していることを確認(<code class=\"language-plaintext highlighter-rouge\">STATE</code>が<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていることを確認)</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  NAME              STATE           VERSION\n* Ubuntu-20.04-1    Stopped         2\n  ubuntu-22.04-2    Stopped         2\n  test_6_6          Stopped         2\n</code></pre></div></div>\n\n<p>再度カーネルモジュールをインストールしたディストリビューションを起動し、\n起動したディストリビューションでモジュールが読み込まれていることを確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsmod\n</code></pre></div></div>\n<p>以下のように、いくつかのモジュールが読み込まれていることを確認します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Module                  Size  Used by\nintel_rapl_msr         16384  0\nintel_rapl_common      36864  1 intel_rapl_msr\ncrc32c_intel           16384  0\nconfigfs               61440  0\nip_tables              32768  0\nautofs4                53248  0\n</code></pre></div></div>\n\n<h1 id=\"おわり\">おわり</h1>\n<p>この状態でカーネルの差し替えは完了です。<br />\nusbipd-win を使用すれば、USBシリアルやUSBストレージ、USBカメラも使えるようになります。\nただし、モジュールvhci-hcd(USB 仮想ホストコントローラインターフェース)が読み込まれていないので、\n以下のコマンドで読み込んでおく必要があります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe vhci-hcd\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n起動時にモジュールを読み込むには、通常<code class=\"language-plaintext highlighter-rouge\">/etc/modules</code>に設定しておけば良いのですが、\n試してみましたがうまくいきませんでした。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下のように記述しておくとうまくいくかもしれません。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\ncommand=modprobe vhci-hcd\n</code></pre></div>  </div>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSBデバイスを使う(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSBデバイスを使う(その3)</h1>\n      <p>WSLでUSBデバイスを使う(その3:USBカメラ編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>で\nWSLカーネル v6.6.36.3 をビルドしたのでもうv5.15.153は使わなくて良くなったのですが、\nやっぱりカーネル入れ替えずにUSBカメラ使いたい衝動にかられ、手順をまとめてみました。<br />\n(その2でUSBストレージ編を書こうと思っていたので、その2は欠番、その3になりました)</p>\n\n<p>参考:<br />\n<a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a><br />\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a></p>\n\n<h1 id=\"開発環境の準備\">開発環境の準備</h1>\n<p>開発環境の準備については、\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>\nの「Linuxカーネルのビルド環境の構築」を参照してください。</p>\n\n<h1 id=\"カーネルモジュールのビルド\">カーネルモジュールのビルド</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<p>たとえば、以下。 どこでも良いけど、以下の手順はこのディレクトリで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /proj/wsl_kernel <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /proj/wsl_kernel\n</code></pre></div></div>\n\n<h2 id=\"カーネルソースの取得\">カーネルソースの取得</h2>\n<p>作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)にカーネルソースをダウンロードします。<br />\ngitリポジトリをcloneするか、リリースソースをダウンロードして展開します。</p>\n\n<h3 id=\"gitでcloneする場合\">gitでcloneする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/microsoft/WSL2-Linux-Kernel.git\n\n<span class=\"c\"># 目的のタグをチェックアウト</span>\ngit <span class=\"nt\">-C</span> WSL2-Linux-Kernel checkout <span class=\"nt\">-b</span> WSL-5.15.153.1 refs/tags/linux-msft-wsl-5.15.153.1\n\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> WSL2-Linux-Kernel linux\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nclone済みなら念のため<code class=\"language-plaintext highlighter-rouge\">git pull</code>して最新状態にしておく</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nブランチ作る必要ないけど、念のため。</p>\n</blockquote>\n\n<h3 id=\"リリースソースzipをダウンロードする場合\">リリースソース(zip)をダウンロードする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-5.15.153.1.zip\nunzip linux-msft-wsl-5.15.153.1.zip\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> linux-msft-wsl-5.15.153.1 linux\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nunzipはデフォルトではインストールされていないのでインストール必要。</p>\n</blockquote>\n\n<h2 id=\"スクリプトdockerfileの入手\">スクリプト&Dockerfileの入手</h2>\n<blockquote>\n  <p>[!NOTE]\nGistに必要なスクリプト&<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>を置いておいたので以下のページの<code class=\"language-plaintext highlighter-rouge\">DownloadZIP</code>ボタンからダウンロードして\n作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)に展開してください。<br />\n<a href=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021\" target=\"_blank\">Gist:WSLカーネルビルド環境</a></p>\n\n  <p>または以下のコマンドで取得できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021/archive/main.zip\nunzip <span class=\"nt\">-j</span> main.zip\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージを作成起動確認\">Dockerイメージを作成~起動確認</h2>\n<p>Dockerイメージを作成~起動確認は\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>\nのDockerイメージを作成~起動確認 を参照してください。<br />\n作成済みならスキップしてください。</p>\n\n<h2 id=\"カーネルモジュールのビルド-1\">カーネルモジュールのビルド</h2>\n\n<p>カーネルソースの取得、Dockeイメージのビルドが終わったら、以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_multimedia.sh\n</code></pre></div></div>\n\n<p>実行には数十分~1時間程度かかります(PCのスペックによる)。</p>\n\n<p>実行完了後、<code class=\"language-plaintext highlighter-rouge\">out</code>ディレクトリに<code class=\"language-plaintext highlighter-rouge\">linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb</code>ができます。<br />\nこれを使用するディストリビューションから見えるフォルダ(ディストリビューション内でなくWindowsのディレクトリでも可)にコピーします。</p>\n\n<h3 id=\"カーネルビルド用スクリプト\">カーネルビルド用スクリプト</h3>\n\n<p>用意したスクリプトの概要は以下の通りです。</p>\n\n<h4 id=\"build_functionssh\">build_functions.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_functions.sh</code>はビルドに関わる処理を関数化したものをまとめたファイルです。<br />\n以下のスクリプトからインクルードして使用します。</p>\n\n<p>Dockerコンテナを使用するので、あらかじめDockerイメージを作成しておく必要があります。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_functions.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_multimediash\">build_wsl_multimedia.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_multimedia.sh</code>はマルチメディア関連のカーネルモジュールのビルドを行います。<br />\n<code class=\"language-plaintext highlighter-rouge\">build_wsl_usb-storage.sh</code>の<code class=\"language-plaintext highlighter-rouge\">ADD_CONFIG</code>変数の設定値を変更しただけです。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_multimedia.sh\"></script>\n</dev>\n\n<p>その他は<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>を参照してください。</p>\n\n<h1 id=\"実行環境の準備\">実行環境の準備</h1>\n<p>実行環境の準備は <a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a>\nと同じです。<br />\n使用するUSBデバイスがUSBカメラに変わるだけです。</p>\n\n<h2 id=\"実行ディストリビューションの準備\">実行ディストリビューションの準備</h2>\n\n<p>デフォルト状態ではカーネルモジュールのインストール先(<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/</code>)が書き込みできないので、\noverlayfsで書き込みできるファイルシステムをマウントします。</p>\n\n<p>まず、マウントする(実際に書き込むための)ディレクトリを用意します。<br />\nupperとworkの2つが必要です。workにはなにも書き込まないでください。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> /modules_overlay/upper/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> /modules_overlay/work/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n</code></pre></div></div>\n\n<p>次にお試しマウントしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> overlay overlay <span class=\"nt\">-o</span> <span class=\"se\">\\</span>\n    <span class=\"nv\">lowerdir</span><span class=\"o\">=</span>/usr/lib/modules/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>,<span class=\"se\">\\</span>\n    <span class=\"nv\">upperdir</span><span class=\"o\">=</span>/modules_overlay/upper/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>,<span class=\"se\">\\</span>\n    <span class=\"nv\">workdir</span><span class=\"o\">=</span>/modules_overlay/work/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span> <span class=\"se\">\\</span>\n    /usr/lib/modules/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n</code></pre></div></div>\n\n<p>マウントできたか確認するため、ファイルを作成してみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo </span>hogehoge | <span class=\"nb\">sudo tee</span> /usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt</code>が出来ていること(内容が正しいこと)と、\n<code class=\"language-plaintext highlighter-rouge\">/modules_overlay/upper/5.15.153.1-microsoft-standard-WSL2/test.txt</code>に同じファイルがあることを確認します。</p>\n\n<p>終わったら削除しておきましょう。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo rm</span> /usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt\n</code></pre></div></div>\n\n<p>再起動したときに自動的にマウントされるように、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に先ほどのマウントコマンドを\n<code class=\"language-plaintext highlighter-rouge\">command=</code>に指定します。<br />\n以下は書き込んだ後の<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>の例。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\ncommand=mount -t overlay overlay -o \\\n    lowerdir=/usr/lib/modules/$(uname -r),\\\n    upperdir=/modules_overlay/upper/$(uname -r),\\\n    workdir=/modules_overlay/work/$(uname -r) \\\n    /usr/lib/modules/$(uname -r)\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>が正常に変更できたか確認するにはWSLの再起動が必要です(ウィンドウ閉じただけではダメ)。</p>\n\n<h2 id=\"カーネルモジュールのインストール\">カーネルモジュールのインストール</h2>\n\n<p>先ほど作成した<code class=\"language-plaintext highlighter-rouge\">linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb</code>を使用して\n以下のように実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb\n</code></pre></div></div>\n\n<h1 id=\"usbカメラを繋いでみる\">USBカメラを繋いでみる</h1>\n\n<p>実行手順は\n実行環境の準備は <a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a>\nの「USB-Serialデバイスを接続」を参照してください。</p>\n\n<p>USBカメラのを接続したときのログはこんな感じ</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[22183.171276] vhci_hcd vhci_hcd.0: pdev(0) rhport(0) sockfd(3)\n[22183.171281] vhci_hcd vhci_hcd.0: devid(196610) speed(3) speed_str(high-speed)\n[22183.171334] vhci_hcd vhci_hcd.0: Device attached\n[22183.550422] usb 1-1: new high-speed USB device number 3 using vhci_hcd\n[22183.700457] usb 1-1: SetAddress Request (3) to port 0\n[22183.786408] usb 1-1: New USB device found, idVendor=056e, idProduct=700a, bcdDevice= 1.00\n[22183.786412] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0\n[22183.786414] usb 1-1: Product: Venus USB2.0 Camera\n[22183.786416] usb 1-1: Manufacturer: Vimicro Corp.\n[22183.799190] usb 1-1: Found UVC 1.00 device Venus USB2.0 Camera (056e:700a)\n[22183.844401] input: Venus USB2.0 Camera: Venus USB2 as /devices/platform/vhci_hcd.0/usb1/1-1/1-1:1.0/input/input1\n</code></pre></div></div>\n\n<h2 id=\"画出し確認\">画出し確認</h2>\n\n<p>pythonのopwnCVでもguvcviewでもお好きな方でどうぞ。</p>\n\n<p>データ転送帯域が足りなくて画像が表示できない場合は、解像度を落としたり、\nフォーマットをYUYV等からMKPEGに変更したりしてデータ量を少なくして試してみてください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 24.04のVirtualBoxへのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 24.04のVirtualBoxへのインストール</h1>\n      <p>Ubuntu 24.04のVirtualBoxへのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 24.04のVirtualBoxへのインストール手順をまとめてみた。<br />\n今回は 極力コマンドコピペで実行できるように書いてみた。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2404-インストール媒体の入手\">Ubuntu 24.04 インストール媒体の入手</h2>\n<p>24.04は日本語Remixがリリースされないので(<a href=\"https://www.ubuntulinux.jp/News/ubuntu2404-ja-remix\" target=\"_blank\">ニュース</a>)、\n<a href=\"https://jp.ubuntu.com/download\" target=\"_blank\">本家</a>\nからダウンロードする必要がありますが、海外にあるサーバなのでとっても遅いです。<br />\n国内のミラーサーバの一覧が<a href=\"https://www.ubuntulinux.jp/ubuntu/mirrors#imagemirror\" target=\"_blank\">ここ</a>\nにあるので、お好きなところからダウンロードしてください。<br />\n(私がダウンロードしたときはKDDI研究所が速かった)</p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、CPU数2個以上、メインメモリーを4096MB以上に設定しておくこと</strong></p>\n<blockquote>\n  <p>[!NOTE]\n推奨環境が2 GHzデュアルコアプロセッサ以上、4GBシステムメモリなので。</p>\n</blockquote>\n\n<p>普通にインストール媒体からインストール。<br />\n以下の説明が図付きで分かりやすい:<br />\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a></p>\n\n<blockquote>\n  <p>[!TIP]\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a>では、「仮想マシンの作成」の「ハードウェア」で「EFIを有効化・・・チェックを入れます。」となっているが、\n入れなくて可(入れて試してないので入れて動くのか未確認。図でもチェック入ってないし)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nインストーラにアップデートがある場合は「今すぐアップデート」をクリックしてアップデートし、\n完了したら一旦インストーラを閉じる。<br />\nデスクトップにインストーラアイコンが出来ているので、そこから再度インストーラを起動し、\n最初から設定を行う(これまでの入力は覚えているっぽい)<br />\n参照:<a href=\"https://pc.watch.impress.co.jp/docs/column/ubuntu/1590461.html\" target=\"_blank\">Ubuntu24.04 LTSの新インストーラを徹底解説</a>\nの「インストーラにアップデートがあった場合」</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a>では、「アプリケーション」での「拡張選択」を選択とあるが、\n余計なアプリを入れたくないので「既定の選択」のままにしておく。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n</blockquote>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<blockquote>\n  <p>[!NOTE]\n設定アプリ等のGUIで設定を変更した内容をスクリプト化したいとき、どのパスを変更すれば良いか調べるには、ターミナルで</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf watch /\n</code></pre></div>  </div>\n  <p>と実行しておくと、変更される度にパスと設定値が表示される。<br />\nこれを <code class=\"language-plaintext highlighter-rouge\">dconf write</code> で書き込めばGUIで設定した内容をコマンドラインで再現できる。<br />\n参考:<a href=\"https://qiita.com/liqsuq/items/2c7aa741caa94508050b\" target=\"_blank\">デスクトップで変えた設定をCUIでやりたい!(gnome限定)</a><br />\nその関係で前回まで<code class=\"language-plaintext highlighter-rouge\">gsettings</code>コマンドでの設定手順を載せていたが、今回は<code class=\"language-plaintext highlighter-rouge\">dconf</code>コマンドに変更した。</p>\n\n</blockquote>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<p>まだGuestAdditionをインストールしてないからコピペできないけど、BashのTab補完が効くので、\nちょろっと入力してあとは補完に頼れば大丈夫。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">dconf</code>だと変更済みのパスしか補完対象にならないらしく入力が面倒なので、\nここは補完が効く<code class=\"language-plaintext highlighter-rouge\">gsettings</code>コマンドで。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">dconf</code>だとこんな感じ。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ndconf write /org/gnome/desktop/session/idle-delay 0\n\n<span class=\"c\"># 自動画面ロック OFF</span>\ndconf write /org/gnome/desktop/screensaver/lock-enabled <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\n設定 → Privacy & Security → Screen Lock → 自動画面ロックを off に</p>\n\n  <p>==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\n設定 → Privacy & Security → Screen Lock → Blank Screen Delay を「しない」に</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>裏でソフトウェアの更新が動いていると、ロックファイルがロックされてしばらく適用できないので、<br />\nそうなっちゃったらお茶でも飲んでしばらくお待ちください。<br />\nソフトウェアの更新による自動更新を止める方法は後ほど。</p>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">upgrade</code> や <code class=\"language-plaintext highlighter-rouge\">install</code> 時にオプション <code class=\"language-plaintext highlighter-rouge\">-U</code> (<code class=\"language-plaintext highlighter-rouge\">--update</code>)をつけると\n<code class=\"language-plaintext highlighter-rouge\">update</code>も一緒に実行してくれるので命令ひとつで済む。<br />\n(ubuntu 24.04に搭載された2.7.14以降)</p>\n</blockquote>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools dconf-editor gnome-tweaks \n</code></pre></div></div>\n\n<h3 id=\"一旦リブート\">一旦リブート</h3>\n<p>念のため一旦リブートしておく。</p>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>以前にマウントしたものが残ってたらアンマウントしておくこと(インストール後初めてなのでマウントされてることはないけれど)。<br />\nVirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<blockquote>\n  <p>[!TIPS]\nプログラムが自動で始まらない場合は、CDROMのマウント先(たぶん、<code class=\"language-plaintext highlighter-rouge\">/media/${USER}/VBox_GAs_x.x.xx/</code>)に移動して<code class=\"language-plaintext highlighter-rouge\">sudo ./VBoxLinuxAdditions.run</code>を実行すれば良い。</p>\n</blockquote>\n\n<h3 id=\"再度リブート\">再度リブート</h3>\n<p>GuestAdditionによる更新適用のため、もう一度リブート。<br />\n(再ログインだけでもよさそうな感じではあるが、念のため)</p>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから<br />\n「デバイス」→「クリップボードの共有」→「双方向」 を選択。<br />\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<p>また、デスクトップサイズの変更(仮想マシンのウィンドウのサイズ変更)にも対応できる。</p>\n\n<h3 id=\"使わないアプリのアンインストール\">使わないアプリのアンインストール</h3>\n<p>「アプリケーション」で「既定の選択」を選んでいれば要らないアプリは入っていないハズ。</p>\n\n<h2 id=\"お好みで\">お好みで</h2>\n\n<h3 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h3>\n\n<p>bashでクリップボードからペーストするとペーストした文字が反転表示になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n以前の動作が良い場合は<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>に設定を追加するため、以下を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/inputrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n# disable bracked-paste mode\nset enable-bracketed-paste off\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<blockquote>\n  <p>[!NOTE]\nteraterm使ってるときはteratermが確認ダイアログ出すので邪魔なんだけど、<br />\ngnome-terminalだと誤ペースト防止にそのままが良いかも。</p>\n</blockquote>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>以下のコマンドで~/.bashrcに設定を追加。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.bashrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n# プロンプトの設定\nPS1=\"</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\n\n# キーバインドの設定\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-n\": history-search-forward'\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-p\": history-search-backward'\n\n# ディレクトリスタックの表示改善\nfunction pushd() {\n    command pushd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction popd() {\n    command popd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction dirs() {\n    command dirs -v\n}\n\n# 表示色変更\nexport LS_COLORS='di=01;32:ln=01;36:ex=01;31:'\nexport GREP_COLORS='mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'\n\n# lessのオプション\nexport LESS=\"-iMR\"\n\n# grepのオプション指定(GREP_OPTIONS)は廃止されたのでaliasで設定\n# export GREP_OPTIONS=\"--exclude-dir .git\"\nalias grep='grep --exclude-dir .git'\n\n# for pyenv\nexport PYENV_ROOT=/proj/.pyenv    #環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    # 仮想環境名をプロンプトに表示しない場合は以下を有効化\n    # export VIRTUAL_ENV_DISABLE_PROMPT=1\n    eval \"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"sh\">\"          # pyenv 2.0以降で必要\n    eval \"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"sh\">\"\n    eval \"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"sh\">\"\n    export PYTHON_CONFIGURE_OPTS=\"</span><span class=\"se\">\\</span><span class=\"sh\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"sh\">\n    \"\nfi\n\n# for nodenv\nexport NODENV_ROOT=/proj/.nodenv    # 環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    eval \"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"sh\">\"\nfi\n\n# x11からのログイン以外ならDISPLAYを設定する\n# Ubuntu22.04/24.04だとwaylandになるらしい\nif [ \"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"sh\">\" != \"x11\" ] && [ \"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"sh\">\" != \"wayland\" ]; then\n    export DISPLAY=192.168.78.200:0.0\nfi\necho DISPLAY=\"</span><span class=\"nv\">$DISPLAY</span><span class=\"sh\">\"\n\n# direnv 設定\nif type direnv > /dev/null 2>&1; then\n    export EDITOR=vi\n    eval \"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"sh\">\"\n    \n    # # venvの仮想環境名を表示するための設定\n    # show_virtual_env() {\n    #   if [ -n \"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"sh\">\" ]; then\n    #     echo \"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"sh\">)\"\n    #   fi\n    # }\n    # PS1='</span><span class=\"si\">$(</span>show_virtual_env<span class=\"si\">)</span><span class=\"sh\">'</span><span class=\"nv\">$PS1</span><span class=\"sh\">\nfi\n\n# __pycache__ディレクトリの生成を抑制する\nexport PYTHONDONTWRITEBYTECODE=1\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nヒアドキュメント内での変数展開やコマンド置換を抑止するには、\nヒアドキュメント開始文字列(上記では__EOF__)をシングルクォートで囲む。<br />\n参考:<a href=\"https://qiita.com/take4s5i/items/e207cee4fb04385a9952#%E5%A4%89%E6%95%B0%E5%B1%95%E9%96%8B%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E7%BD%AE%E6%8F%9B\" target=\"_blank\">bashのヒアドキュメントを活用する/変数展開・コマンド置換</a></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npython でimportする度に<code class=\"language-plaintext highlighter-rouge\">__pycache__</code>ディレクトリ<code class=\"language-plaintext highlighter-rouge\">*.pyc</code>ファイルが作成されるのが\n鬱陶しかったので、<code class=\"language-plaintext highlighter-rouge\">PYTHONDONTWRITEBYTECODE</code>に1を設定している。<br />\n2回目以降、若干実行時間が延びるかもしれないが、気にするほどでもないので。<br />\n通常の動作がよければ削除してください。</p>\n</blockquote>\n\n<h3 id=\"ubuntu-japanese-teamのパッケージリポジトリを追加\">Ubuntu Japanese Teamのパッケージリポジトリを追加</h3>\n\n<p>日本語特有のパッケージをインストールするため、Ubuntu Japanese Teamのパッケージリポジトリを追加します。<br />\n参考:<a href=\"https://www.ubuntulinux.jp/News/ubuntu2404-ja-remix\" target=\"_blank\">Ubuntu 24.04 LTSの日本語Remixについて</a>\nの最後の部分</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>wget https://www.ubuntulinux.jp/sources.list.d/noble.sources <span class=\"nt\">-O</span> /etc/apt/sources.list.d/ubuntu-ja.sources <span class=\"o\">&&</span><span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade <span class=\"o\">&&</span><span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ubuntu-defaults-ja\n</code></pre></div></div>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">/usr/share/fonts</code>の下(自分専用なら<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>の下)にコピるだけ。<br />\n下では全部コピってる(移動だけど)けど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp/ <span class=\"o\">&&</span> <span class=\"se\">\\</span>\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.3.1/UDEVGothic_v1.3.1.zip <span class=\"o\">&&</span> <span class=\"se\">\\</span>\nunzip UDEVGothic_v1.3.1.zip <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo mv </span>UDEVGothic_v1.3.1 /usr/share/fonts/truetype/ <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<p>設定を反映するため、開いている端末をすべて閉じで、再度起動します。<br />\n開いたままだと設定が中途半端に反映されてしまいます。<br />\nまた、一つでも端末が残っていると新しく開いた端末にも正常な反映がされません。</p>\n\n<blockquote>\n  <p>[!NOTE]\nCLIで設定するならこちら….なんだけど、UUIDが同じとは限らないので参考まで。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/use-system-font    <span class=\"nb\">false\n</span>dconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/font               <span class=\"s2\">\"'UDEV Gothic JPDOC 12'\"</span>\ndconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/default-size-rows  40\n</code></pre></div>  </div>\n\n  <p>すべてのプロファイルに適用するならこんな感じでもできるかな。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">for </span>prof <span class=\"k\">in</span> <span class=\"si\">$(</span>dconf list /org/gnome/terminal/legacy/profiles:/<span class=\"si\">)</span> <span class=\"p\">;</span> <span class=\"k\">do\n    </span>dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>use-system-font    <span class=\"nb\">false</span>                       <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n    dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>font               <span class=\"s2\">\"'UDEV Gothic JPDOC 12'\"</span>    <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n    dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>default-size-rows  40\n<span class=\"k\">done</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h3>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /NFSROOT <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span> /proj /work /NFSROOT\n</code></pre></div></div>\n\n<h3 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h3>\n\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく<br />\n(CLIでも「どこにインストールする?」と聞かれて「どこだっけ?」となるのでその予防)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<p>設定が正常に行われたか確認するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<p>正常に設定されていれば、以下のような結果が出力される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>0 /dev/sda\n</code></pre></div></div>\n<h3 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h3>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gnome-extensions disable tiling-assistant@ubuntu.com <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/mutter/edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/desktop/wm/preferences/focus-mode        <span class=\"s2\">\"'sloppy'\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/desktop/wm/preferences/auto-raise        <span class=\"nb\">false</span>      <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/desktop/wm/preferences/raise-on-click    <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。<br />\nと書いてあったけど、同じ動き(フォーカスがはずれる)に見える….</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/ding/show-home  <span class=\"nb\">false</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/shell/extensions/ding/show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/desktop/interface/cursor-size 48\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nGUIで設定する場合は「設定」→「アクセシビリティ」→「Seeing」→「Cursor Size」で選択<br />\n(数値ではなく画像で選択)</p>\n</blockquote>\n\n<h3 id=\"ファイルnautilusの設定変更\">ファイル(nautilus)の設定変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<h4 id=\"ロケーションバーをデフォルトにする\">ロケーションバーをデフォルトにする</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/nautilus/preferences/always-use-location-entry <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h4 id=\"詳細表示をデフォルトに\">詳細表示をデフォルトに</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/nautilus/preferences/default-folder-viewer <span class=\"s2\">\"'list-view'\"</span> \n</code></pre></div></div>\n\n<h4 id=\"隠しファイルを表示する\">隠しファイルを表示する</h4>\n<p>隠しファイルの表示はちょっと場所が違う</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gtk/gtk4/settings/file-chooser/show-hidden <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n\n<h4 id=\"ゴミ箱削除\">ゴミ箱削除</h4>\n\n<p>私はゴミ箱使わないので消しときます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n<h4 id=\"dockバーを画面下に表示\">Dockバーを画面下に表示</h4>\n\n<p>Windows7っぽく下に移動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/dock-position <span class=\"s2\">\"'BOTTOM'\"</span>\n</code></pre></div></div>\n\n<h4 id=\"アプリケーションをdockバーの上または左に表示\">アプリケーションをDockバーの上(または左)に表示</h4>\n\n<p>Windows7のスタートボタンっぽく左に移動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/show-apps-at-top <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h4 id=\"アイコンサイズの変更\">アイコンサイズの変更</h4>\n\n<p>最後の数字が大きさなので、お好みの大きさにしてください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/dash-max-icon-size 20\n</code></pre></div></div>\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアとアップデート(software-properties-gtk)を起動\n    <ul>\n      <li>アップデートタブを選択</li>\n      <li>アップデートの自動確認を「なし」に変更</li>\n      <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n      <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n      <li>閉じるをクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a></p>\n\n<p>tewaksを使用する<br />\n<a href=\"https://yassan.hatenablog.jp/entry/2024/05/01/Ubuntu_Bdgie%E3%83%A1%E3%83%A2%EF%BC%9A_Tweeks%E3%81%A7Caps%E3%81%A8Ctrl%E3%81%AESwap\" target=\"_blank\">Ubuntu Bdgieメモ: TweeksでCapsとCtrlのSwap</a><br />\nというのもある。 お好きな方で。</p>\n\n<p>Native環境にインストールしてないので未確認だけど…</p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下のように「quiet splash」を削除。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h2 id=\"ネットワークアダプタの追加\">ネットワークアダプタの追加</h2>\n<p>ホストのWindowsや外部マシンからアクセスできるようにデフォルトのNAT以外にネットワークアダプタを追加します。<br />\n仮想マシンの設定を変更する必要があるので、一旦仮想マシンをシャットダウンしてください。</p>\n\n<h3 id=\"ネットワークアダプタ追加設定\">ネットワークアダプタ追加設定</h3>\n<ul>\n  <li>Virtualboxマネージャ で対象の仮想マシンを選択し、設定ボタンをクリック。</li>\n  <li>開いたウィンドウの左側で「ネットワーク」を選択</li>\n  <li>右側のウィンドウで「アダプタ2」をクリック\n    <ul>\n      <li>「ネットワークアダプタを有効化」にチェックを入れる</li>\n      <li>「割り当て」で「ホストオンリーアダプター」を選択</li>\n    </ul>\n  </li>\n  <li>右側のウィンドウで「アダプタ3」をクリック\n    <ul>\n      <li>「ネットワークアダプタを有効化」にチェックを入れる</li>\n      <li>「割り当て」で「ブリッジアダプター」を選択</li>\n      <li>「名前」で割り当てる物理的なネットワークアダプタを選択</li>\n    </ul>\n  </li>\n  <li>OKをクリック</li>\n</ul>\n\n<p>設定が終わったら仮想マシンを起動します。</p>\n\n<blockquote>\n  <p>[!NOTE]\nNATも削除してブリッジアダプターだけでも大丈夫な気もするが、ネットワーク不調になっても\nホストOS(Windows)からアクセスできるようにホストオンリーアダプターも追加しておく。<br />\nまた、ホストオンリーアダプターも不調になったときでも\nWebアクセスなど最低限のアクセスができるようNATも残しておく。<br />\n要らないと思ったら上記の設定の「ネットワークアダプタを有効化」のチェックをはずせば良い。</p>\n</blockquote>\n\n<h3 id=\"ネットワークのコネクション名の変更\">ネットワークのコネクション名の変更</h3>\n\n<p>ネットワークコントローラを追加したので、ネットワークマネージャのコネクション一覧を見てみます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection \n</code></pre></div></div>\n\n<p>結果はこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>NAME            UUID                                  TYPE      DEVICE \nnetplan-enp0s3  1eef7e45-3b9d-3043-bee3-fc5925c90273  ethernet  enp0s3 \n有線接続 1      eef7ccb4-2a33-336f-bb48-701058d5e6ce  ethernet  enp0s8 \n有線接続 2      eff49436-1aac-36eb-b1f6-2a32cc246b83  ethernet  enp0s9 \nlo              d30bde24-f5dd-458d-86b0-b5c8870f4485  loopback  lo     \n</code></pre></div></div>\n<p>「有線接続 1」と「有線接続 2」がさきほど追加したホストオンリーアダプターとブリッジアダプターなのですが、\nどっちがどっちか判別できません。<br />\nそこで判別できるような名前に変更しておきます。<br />\n(192.168.xx.xxのものだけ変更。NATとloはそのまま)<br />\n変更後のコネクション名はネットワークとの対応が分かりやすくなるよう、\n≪IPアドレスの3桁目≫_LINE としています。<br />\nお好みの名前に変更してください。<br />\n(現在、日本語だと文字化けするバグがあるようです。そのうち直ると思いますが)</p>\n\n<p>手動で設定するのは面倒なので、以下のスクリプトファイルを作成して実行してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># すべてのコネクション名を改行区切りで配列に取得</span>\n<span class=\"nv\">ORG_IFS</span><span class=\"o\">=</span><span class=\"nv\">$IFS</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"s1\">$'</span><span class=\"se\">\\n</span><span class=\"s1\">'</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span>nmcli  <span class=\"nt\">-t</span> <span class=\"nt\">-f</span> NAME connection<span class=\"si\">)</span><span class=\"o\">)</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"nv\">$ORG_IFS</span>        <span class=\"c\"># 元に戻す</span>\n\n<span class=\"k\">for </span>i <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"p\">!connections[@]</span><span class=\"k\">}</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各コネクションについて</span>\n    <span class=\"c\"># 直接取り出すとうまくいかないのでインデックス取り出して内容取得</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[</span><span class=\"nv\">$i</span><span class=\"p\">]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n\n    <span class=\"c\"># 現在設定されているIPv4アドレスを取得</span>\n    <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.ADDRESS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n    <span class=\"c\"># 結果⇒ 「IP4.ADDRESS[1]: 192.168.78.215/24」</span>\n    \n    <span class=\"c\"># IPアドスの各桁とサブネットマスクを空白区切りで取得し、配列に代入</span>\n    <span class=\"c\"># 1個目のsed ⇒ 192.168.78.215/24</span>\n    <span class=\"c\"># 2個目のsed ⇒ 192 168 78 215 24</span>\n    <span class=\"nv\">ipv4octet</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/[</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]/ /g\"</span><span class=\"si\">)</span><span class=\"o\">)</span>\n\n    <span class=\"c\"># echo ${str}</span>\n    <span class=\"c\"># echo ${ipv4octet[0]}  ${ipv4octet[1]}  ${ipv4octet[2]}  ${ipv4octet[3]}  ${ipv4octet[4]}</span>\n    \n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 192 <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 168 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n        <span class=\"c\"># 192.168.XX.XX のコネクション</span>\n        <span class=\"c\"># echo \"**** ${str} ****\"</span>\n\n        <span class=\"c\"># コネクション名を\"≪IPアドレスの3桁目≫_LINE\"変更する</span>\n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> connection.id </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[2]</span><span class=\"k\">}</span><span class=\"s2\">_LINE</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone\n\n</span><span class=\"nb\">echo</span> <span class=\"o\">==</span><span class=\"nv\">RESULT</span><span class=\"o\">==</span>\nnmcli  connection\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)→<br />\n左側のネットワークを選択し、対象のNICの設定ボタン(歯車アイコン)をクリック→<br />\n開いたウィンドウで「identity」タブをクリック→<br />\n「名前」に設定する名前を設定→<br />\n「適用」をクリック</p>\n</blockquote>\n\n<h3 id=\"sambaのインストール\">sambaのインストール</h3>\n\n<h4 id=\"ツール本体のインストール\">ツール本体のインストール</h4>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<h4 id=\"etcsambasmbconf-の設定を変更\">/etc/samba/smb.conf の設定を変更</h4>\n\n<p>以下のコマンドを実行します。<br />\n変更内容は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code>をバックアップ</li>\n  <li>[homes]セクションを有効化</li>\n  <li>[homes]セクションの「read only」を「no」に設定</li>\n  <li>[global]セクションに「map archive = no」を追加</li>\n  <li>ファイル末尾に[proj][work][NFSROOT]セクションを追加<br />\n他にも追加したいセクション(ディレクトリの設定)があったら追加してください。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /etc/samba/smb.conf /etc/samba/smb.conf.org     <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'/\\[homes\\]/s/;//g'</span> /etc/samba/smb.conf     <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'/\\[homes\\]/,/\\[/ {s/^;[^\\[]//g}'</span> /etc/samba/smb.conf   <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"/</span><span class=\"se\">\\[</span><span class=\"s2\">homes</span><span class=\"se\">\\]</span><span class=\"s2\">/,/^</span><span class=\"se\">\\[\\|</span><span class=\"s2\">^;</span><span class=\"se\">\\s</span><span class=\"s2\">*</span><span class=\"se\">\\[</span><span class=\"s2\">/ s/read only = .*/read only = no/1\"</span> /etc/samba/smb.conf <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'s/\\(^\\[global\\].*\\)/\\1\\n\\n    map archive = no/'</span> /etc/samba/smb.conf   <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/samba/smb.conf <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n</span><span class=\"no\">\n__EOF__\n</span></code></pre></div></div>\n\n<h4 id=\"ユーザの追加\">ユーザの追加</h4>\n\n<p>sambaのためのユーザを追加します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>pdbedit <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n</code></pre></div></div>\n\n<p>新しいパスワードを聞かれるので入力</p>\n\n<blockquote>\n  <p>[!NOTE]\n以前は<code class=\"language-plaintext highlighter-rouge\">sudo smbpasswd -a $USER</code> だったけど、最近は上のコマンドが正式らしい。<br />\n(まだ <code class=\"language-plaintext highlighter-rouge\">smbpasswd</code>も使えるけど)</p>\n</blockquote>\n\n<h4 id=\"sambaの再起動\">sambaの再起動</h4>\n\n<p>設定を反映するため、sambaを再起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl reload  smbd.service <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>systemctl restart smbd.service\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">Warning: The unit file, source configuration file or drop-ins of smbd.service changed on disk. Run 'systemctl daemon-reload' to reload units.</code>\nと言われたときは、<code class=\"language-plaintext highlighter-rouge\">sudo systemctl daemon-reload</code>を実行</p>\n</blockquote>\n\n<h3 id=\"nfsのインストール\">NFSのインストール</h3>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<h4 id=\"インストール-1\">インストール</h4>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<h4 id=\"設定ファイルの変更\">設定ファイルの変更</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">/NFSROOT</code>をエクスポートするため、<code class=\"language-plaintext highlighter-rouge\">/etc/exports</code>を修正。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/exports <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<h4 id=\"再起動\">再起動</h4>\n\n<p>変更した設定を反映するため、NFSを再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl restart nfs-server.service \n</code></pre></div></div>\n\n<h4 id=\"確認\">確認</h4>\n\n<h5 id=\"exportできているか確認\">exportできているか確認</h5>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>こんな感じで表示されればOK</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT      \t192.168.0.0/255.255.0.0\n</code></pre></div></div>\n\n<h5 id=\"別のマシンからマウントしてみる\">別のマシンからマウントしてみる</h5>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n\n<p>別のマシンから以下のコマンドを実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">abc</code>の下に今インストールしているPCの<code class=\"language-plaintext highlighter-rouge\">/NFSROOT</code>ディレクトリのファイルが見えたらOK</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<p>マスタイメージを残しておいて、色々な環境をお試しするには仮想マシンをクローンして使うのがおススメ。</p>\n<ul>\n  <li>VirtualBoxのメインウィンドウでマスタイメージの仮想マシンを右クリック→クローンを選択。</li>\n  <li>名前とパスを設定し、MACアドレスのポリシーは「すべてのネットワークアダプタでMACアドレスを生成」を選択。</li>\n  <li>「次へ」をクリック</li>\n  <li>すべてをクローンにチェックが入っていることを確認し、「完了」をクリック\nクローンが終了するまで待つ。</li>\n</ul>\n\n<p>クローンした仮想マシンを起動し、必要な変更を加える。</p>\n\n<h2 id=\"ネットワーク設定の変更\">ネットワーク設定の変更</h2>\n\n<p>マシン名とか同じ名前だと色々不都合があるので、変更しておく。<br />\n他のクローン仮想環境と同時に使わないならそのままでも良いけど。<br />\nIPアドレスも固定で割り振っておくと名前が引けない時にさくっと分かってなにかと便利…\nなんだけど、最近はWindowsもUbuntuもRaspberryPiもmDNSがサポートされてるから自動割り当てのままでもそんなに不便はないかも。</p>\n\n<p>ポリシー</p>\n<ul>\n  <li>IPアドレスの最終桁を決める(numberとする)。</li>\n  <li>ホスト名をskull≪number≫とする</li>\n  <li>ホストオンリーアダプタ/ブリッジアダプタの設定変更\n    <ul>\n      <li>IPv4アドレスを手動設定にする</li>\n      <li>IPv4アドレスの1桁目~3桁目、サブネットマスクを現在のIPアドレスと同じにする</li>\n      <li>IPv4アドレスの最終桁をnumberにする</li>\n      <li>GW、DNSが設定されていれば同じアドレスを設定する</li>\n    </ul>\n  </li>\n</ul>\n\n<p>以下の内容でスクリプトファイルを作成し、実行する。<br />\nホスト名などは適宜変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/usr/bin/env bash</span>\n\n<span class=\"c\"># 設定する数値の入力</span>\n<span class=\"nb\">read</span> <span class=\"nt\">-p</span> <span class=\"s2\">\"数値を入力してください: \"</span> number \n\n<span class=\"c\"># echo ${number}</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[[</span> <span class=\"o\">!</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">=</span>~ ^[0-9]+<span class=\"nv\">$ </span><span class=\"o\">]]</span><span class=\"p\">;</span> <span class=\"k\">then\n  </span><span class=\"nb\">echo</span> <span class=\"s1\">'数値ではありません'</span>\n  <span class=\"nb\">exit </span>1\n<span class=\"k\">fi\n\nif</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"nt\">-lt</span> 2 <span class=\"o\">]</span> <span class=\"o\">||</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"nt\">-gt</span> 254 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n  </span><span class=\"nb\">echo</span> <span class=\"s1\">'数値は2~254でなければなりません'</span>\n  <span class=\"nb\">exit </span>1\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># ホスト名の変更</span>\n<span class=\"nv\">old_name</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">hostname</span><span class=\"si\">)</span>\n<span class=\"nv\">new_name</span><span class=\"o\">=</span><span class=\"s2\">\"skull</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo nmcli general hostname </span><span class=\"k\">${</span><span class=\"nv\">new_name</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n<span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo sed -i -e \"</span>s/<span class=\"k\">${</span><span class=\"nv\">old_name</span><span class=\"k\">}</span>/<span class=\"k\">${</span><span class=\"nv\">new_name</span><span class=\"k\">}</span>/<span class=\"s2\">\" /etc/hosts\"</span>\n<span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n<span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n\n<span class=\"c\"># すべてのコネクション名を改行区切りで配列に取得</span>\n<span class=\"nv\">ORG_IFS</span><span class=\"o\">=</span><span class=\"nv\">$IFS</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"s1\">$'</span><span class=\"se\">\\n</span><span class=\"s1\">'</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span>nmcli  <span class=\"nt\">-t</span> <span class=\"nt\">-f</span> NAME connection<span class=\"si\">)</span><span class=\"o\">)</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"nv\">$ORG_IFS</span>        <span class=\"c\"># 元に戻す</span>\n\n<span class=\"k\">for </span>i <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"p\">!connections[@]</span><span class=\"k\">}</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各コネクションについて</span>\n    <span class=\"c\"># 直接取り出すとうまくいかないのでインデックス取り出して内容取得</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[</span><span class=\"nv\">$i</span><span class=\"p\">]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># 現在設定されているIPv4アドレスを取得</span>\n    <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.ADDRESS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n    <span class=\"c\"># 結果⇒ 「IP4.ADDRESS[1]: 192.168.78.215/24」</span>\n    \n    <span class=\"c\"># IPアドスの各桁とサブネットマスクを空白区切りで取得し、配列に代入</span>\n    <span class=\"c\"># 1個目のsed ⇒ 192.168.78.215/24</span>\n    <span class=\"c\"># 2個目のsed ⇒ 192 168 78 215 24</span>\n    <span class=\"nv\">ipv4octet</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/[</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]/ /g\"</span><span class=\"si\">)</span><span class=\"o\">)</span>\n    \n    <span class=\"c\"># echo ${str}</span>\n    <span class=\"c\"># echo ${ipv4octet[0]}  ${ipv4octet[1]}  ${ipv4octet[2]}  ${ipv4octet[3]}  ${ipv4octet[4]}</span>\n    \n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 192 <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 168 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n        <span class=\"c\"># 192.168.XX.XX のコネクション</span>\n        <span class=\"c\"># echo \"**** ${str} ****\"</span>\n        \n        <span class=\"c\"># 現在設定されているIPv4GWアドレスを取得</span>\n        <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.GATEWAY\"</span> <span class=\"si\">)</span>\n        <span class=\"c\"># 結果⇒ 「IP4.GATEWAY: 192.168.78.1」</span>\n        \n        <span class=\"c\"># IPv4GWアドレスを抽出(未定義では--なので-も抽出対象)</span>\n        <span class=\"nv\">gwaddr</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.</span><span class=\"s2\">-]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span><span class=\"si\">)</span>\n        <span class=\"c\"># \"--\" だったら空文字にする</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">=</span> <span class=\"s2\">\"--\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then </span><span class=\"nv\">gwaddr</span><span class=\"o\">=</span><span class=\"s2\">\"\"</span><span class=\"p\">;</span> <span class=\"k\">fi</span>\n        \n        <span class=\"c\"># 現在設定されているIPv4DNSアドレスを取得(未定義ならこのエントリがない)</span>\n        <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.DNS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n        <span class=\"c\"># 結果⇒ 「IP4.DNS[1]: 192.168.78.1」</span>\n        \n        <span class=\"c\"># IPv4DNSアドレスを抽出</span>\n        <span class=\"nv\">dnsaddr</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span><span class=\"si\">)</span>\n        \n        <span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"ipv4.method manual ipv4.addresses </span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[2]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[4]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n            </span><span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\"> ipv4.gateway </span><span class=\"k\">${</span><span class=\"nv\">gwaddr</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">fi\n        if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n            </span><span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\"> ipv4.dns </span><span class=\"k\">${</span><span class=\"nv\">dnsaddr</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">fi</span>\n        \n        <span class=\"c\"># echo ipv4.method manual ${set_str}</span>\n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n        \n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection down   </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n        \n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection up     </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone\n\n</span><span class=\"nb\">echo</span> <span class=\"o\">==</span><span class=\"nv\">DONE</span><span class=\"o\">==</span>\n</code></pre></div></div>\n\n<p>実行後、<br />\n<code class=\"language-plaintext highlighter-rouge\">ip address</code>や<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPアドレスが変更されていること、<br />\n<code class=\"language-plaintext highlighter-rouge\">hostname</code>でホスト名が変更されていること、<br />\n<code class=\"language-plaintext highlighter-rouge\">cat /etc/hosts</code>でhostsが変更されていること、\nをそれぞれ確認する。</p>\n\n<blockquote>\n  <p>[!TIP]\nIPアドレスの変更をGUIで行うには以下。<br />\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nこのスクリプトをマスタイメージのどこか(例えば<code class=\"language-plaintext highlighter-rouge\">~/bin</code>とか)に保存しておけば、\nクローンする度にスクリプトを実行すればIPアドレスとホスト名の変更をイッパツで完了できる。</p>\n</blockquote>\n\n<h2 id=\"あとはお約束\">あとはお約束</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade\n</code></pre></div></div>\n\n<p>VirtalBoxのバージョンが変更されているときは、GuestAdditionのバージョンアップも忘れずに。<br />\nまた、マスタイメージは定期的に<code class=\"language-plaintext highlighter-rouge\">sudo apt -U upgrade</code>しておくと\nクローン時のアップデート時間が短くて済む。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2 メモ(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2 メモ(改訂版)</h1>\n      <p>WSL2のディストリビューションインストール~初期設定に関するメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"インストール\">インストール</h1>\n<p>WSL自体はインストール済みとします。<br />\n(インストール方法はぐぐってちょ)</p>\n\n<p>ディストリビューションのインストールはコマンドプロンプト等で行います。</p>\n\n<h2 id=\"インストール可能なディストリビューション\">インストール可能なディストリビューション</h2>\n<p>オンラインでインストールできるディストリビューションの一覧は以下で表示できます。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--online</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"新しいディストリビューションのインストール\">新しいディストリビューションのインストール</h2>\n<p>表示されたディストリビューションからインストールしたいディストリビューションを選んでインストールします。<br />\n以下は Ubuntu-24.04 をインストールする例。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--install</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>インストールが終了したら自動的にディストリビューションが起動してユーザアカウントとパスワードの設定が行われますので、\n使用したいユーザ名とパスワードを設定してください。</p>\n\n<h1 id=\"セットアップ\">セットアップ</h1>\n\n<p>引き続きセットアップを行います。</p>\n\n<h2 id=\"アップデート\">アップデート</h2>\n<p>まずはアップデート</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nubuntu 24.04以降なら<code class=\"language-plaintext highlighter-rouge\">sudo apt -U upgrade</code> でもOK。</p>\n</blockquote>\n\n<h2 id=\"日本語化\">日本語化</h2>\n<p>日本語化のため、以下のインストール/設定を行います。</p>\n\n<ul>\n  <li>日本語ランゲージパックのインストール</li>\n  <li>ロケールの設定</li>\n  <li>日本語manページのインストール</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>language-pack-ja <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>update-locale <span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF8 <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>manpages-ja manpages-ja-dev \n</code></pre></div></div>\n\n<h2 id=\"クローンしたあとのデフォルトユーザを設定\">クローンしたあとのデフォルトユーザを設定</h2>\n\n<p>クローンした環境ではデフォルトでrootでログインしてしまうので、<br />\n現在のユーザをデフォルトユーザに設定しておきます。<br />\n(マスタで設定しておけば、クローンする毎に設定しなくて済むので)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span>  /etc/wsl.conf <span class=\"o\"><<</span> <span class=\"no\">__EOF__</span><span class=\"sh\">\n\n[user]\ndefault=</span><span class=\"nv\">$USER</span><span class=\"sh\">\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nPATHにWindowsのPATHを引き継がせない設定<br />\n仮想マシン起動語、PATHにWindows環境のPATHが引き継がれます。<br />\nWindows環境のPATHを引き継がせないようにすることもできます。</p>\n\n  <p>設定方法は <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に 以下の設定を追加します。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>interop]\nappendWindowsPath <span class=\"o\">=</span> <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n\n  <p>参考: <a href=\"https://zenn.dev/o2z/articles/zenn-20210524-01\" target=\"_blank\">WSL2でWindowsのPATH設定が引き継がれるのを解除する</a></p>\n\n  <p>なお、下の .bashrcの設定 ではWindowsのPATHを引き継いだうえで、\nWINDOWSディレクトリ下、VS Code格納ディレクトリ下以外のPATHを削除して不要なPATHを残さないようにしています。</p>\n</blockquote>\n\n<h2 id=\"ミニミニスクリプト\">ミニミニスクリプト</h2>\n<p>ちょっとした不便を解消するミニミニスクリプトを作成しておきます。</p>\n\n<p>以下はExplorerと秀丸をシンボリックリンクでも実体を追いかけて開いてくれるスクリプト</p>\n\n<blockquote>\n  <p>[!NOTE]\nたとえば、<code class=\"language-plaintext highlighter-rouge\">explorer.exe /lib</code>と実行するとエクスプローラでは<code class=\"language-plaintext highlighter-rouge\">/lib</code>を開けません。<br />\n以下のスクリプトを作成した後、<code class=\"language-plaintext highlighter-rouge\">explorer /lib</code>と実行すると\n<code class=\"language-plaintext highlighter-rouge\">/lib</code>の実体である<code class=\"language-plaintext highlighter-rouge\">/usr/lib</code>が開かれます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">~/bin</code>にpathを通すには、作成後再ログイン必要。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/bin\n\n<span class=\"nb\">tee</span> <span class=\"nt\">-a</span>  ~/bin/explorer <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n#!/usr/bin/env bash\n/mnt/c/WINDOWS/explorer.exe </span><span class=\"si\">$(</span>wslpath <span class=\"nt\">-w</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"sh\">\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">tee</span> <span class=\"nt\">-a</span>  ~/bin/hidemaru <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n#!/usr/bin/env bash\nEDITOR=\"/mnt/c/Program Files (x86)/Hidemaru/Hidemaru.exe\"\n\"</span><span class=\"k\">${</span><span class=\"nv\">EDITOR</span><span class=\"k\">}</span><span class=\"sh\">\" </span><span class=\"si\">$(</span>wslpath <span class=\"nt\">-w</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"sh\">&\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">chmod</span> +x ~/bin/<span class=\"k\">*</span>\n</code></pre></div></div>\n\n<h2 id=\"bashrcの設定\">.bashrcの設定</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に必要な変更/追加を行います。<br />\n以下は私の好みの設定なので、好みに合わせて変更してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.bashrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n\n# プロンプトの設定\n# PS1=\"</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\nPS1=\"</span><span class=\"se\">\\[\\e</span><span class=\"sh\">[36m</span><span class=\"se\">\\]</span><span class=\"nv\">$WSL_DISTRO_NAME</span><span class=\"se\">\\[\\e</span><span class=\"sh\">[0m</span><span class=\"se\">\\]</span><span class=\"sh\">:</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\n\n# キーバインドの設定\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-n\": history-search-forward'\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-p\": history-search-backward'\n\n# ディレクトリスタックの表示改善\nfunction pushd() {\n    command pushd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction popd() {\n    command popd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction dirs() {\n    command dirs -v\n}\n\n# 表示色変更\nexport LS_COLORS='di=01;32:ln=01;36:ex=01;31:'\nexport GREP_COLORS='mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'\n\n# lessのオプション\nexport LESS=\"-iMRq\"\n\n# grepのオプション指定(GREP_OPTIONS)は廃止されたのでaliasで設定\n# export GREP_OPTIONS=\"--exclude-dir .git\"\nalias grep='grep --exclude-dir .git'\n\n# WindowsのPATHのうち、\"WINDOWS\"を含むディレクトリ、\"VS Code\"を含むディレクトリ以外を削除\nexport PATH=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$PATH</span> | python3 <span class=\"nt\">-c</span> <span class=\"s1\">'import re,sys;PPP=sys.stdin.readline();print(\":\".join([a for a in PPP.split(\":\") if re.match(r\"^(?!\\/mnt)\", a) or re.match(r\"(^/mnt.*WINDOWS.*$|^/mnt.*VS Code.*$)\", a)]))'</span><span class=\"si\">)</span><span class=\"sh\">\n\n# for pyenv\nexport PYENV_ROOT=/proj/.pyenv    #環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    # 仮想環境名をプロンプトに表示しない場合は以下を有効化\n    # export VIRTUAL_ENV_DISABLE_PROMPT=1\n    eval \"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"sh\">\"          # pyenv 2.0以降で必要\n    eval \"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"sh\">\"\n    eval \"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"sh\">\"\n    export PYTHON_CONFIGURE_OPTS=\"</span><span class=\"se\">\\</span><span class=\"sh\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"sh\">\n    \"\nfi\n\n# for nodenv\nexport NODENV_ROOT=/proj/.nodenv    # 環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    eval \"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"sh\">\"\nfi\n\n# __pycache__ディレクトリの生成を抑制する\nexport PYTHONDONTWRITEBYTECODE=1\n\n<< '__COMMENT__'\n# この部分はミラーモードでは使えないし、WSLgサポートされたので特に必要ないのでコメントアウト\n# NATモードでは使えるが、hostコマンドインストール必要。(sudo apt install bind9-host)\n# HOSTのIPアドレス取得\n# export HOST_IP_ADDR=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span><span class=\"si\">)</span><span class=\"sh\">\n# HOSTのIPアドレス取得(アドレスが2つ以上返ってきたときは1個目だけ取り出す)\nexport HOST_IP_ADDR=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-n</span> 1p<span class=\"si\">)</span><span class=\"sh\">\n\n# DISPLAY変数が未定義(SSHログイン等)ならDISPLAYを設定する\nif [ -v </span><span class=\"nv\">$DISPLAY</span><span class=\"sh\"> ]; then\n    export DISPLAY=</span><span class=\"k\">${</span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"k\">}</span><span class=\"sh\">:0.0\nfi\necho DISPLAY=\"</span><span class=\"nv\">$DISPLAY</span><span class=\"sh\">\"\n__COMMENT__\n\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<p>変更した内容を有効にするには、再ログインするか、<code class=\"language-plaintext highlighter-rouge\">source ~/.bashrc</code>してください。</p>\n\n<h2 id=\"readlinebash等の設定\">readline(bash等)の設定</h2>\n\n<ul>\n  <li>beepを鳴らさない設定</li>\n  <li>ブラケットペーストモードを無効化する設定(コメントアウト)<br />\n無効化したければ<code class=\"language-plaintext highlighter-rouge\">enable-bracketed-paste</code> の行を有効にします</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalではブラケットペーストモードを無効にすると確認ダイアログでチェックできるようになりますが、\nブラケットペーストモードを有効にすると確認ダイアログは出ず入力欄で確認できるようになります。<br />\nTeraterm のように二重チェックにならないので有効にしてもストレスは少ないと思い無効にしていません。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span>  /etc/inputrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\nset bell-style visible\n# set enable-bracketed-paste off\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalの場合、beepを鳴らさない設定は <br />\n設定→各仮想環境の設定画面→詳細設定→ベル通知スタイル<br />\nからも変更できる。</p>\n</blockquote>\n\n<h2 id=\"vimの設定\">vimの設定</h2>\n\n<p>私はシンプルな1色表示が好きなのでsyntax highlightを無効にしておきます。<br />\nまた、<code class=\"language-plaintext highlighter-rouge\">sudo vi</code>実行時にも同じように動作するように、<code class=\"language-plaintext highlighter-rouge\">/root</code>にもコピーしておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">/etc/vim/vimrc</code>または<code class=\"language-plaintext highlighter-rouge\">/etc/vim/vimrc.local</code>に記述するとシステム全体で有効なはずですが、\nなぜかうまくいかないので自分とrootの設定を書き換えておきます。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.vimrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\nsyntax off\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">sudo cp</span> ~/.vimrc /root/\n\n</code></pre></div></div>\n\n<h2 id=\"一旦リブート\">一旦リブート</h2>\n\n<p>ここまでの設定を反映するため、念のためリブートしておきます。</p>\n\n<p>まず、ディストリビューションを停止します。<br />\n<code class=\"language-plaintext highlighter-rouge\">exit</code>コマンドやCTRL-Dでシェルを終了します。<br />\nこれだけではディストリビューションは終了していません。<br />\n(<code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>で「Running」になっている)<br />\nコマンドプロンプト等から以下のコマンドでディストリビューションを終了します。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>で「Stopped」になっていることを確認し、再度ディストリビューションを起動します。<br />\nこのとき、既に実行中のWindowsTerminalのドロップダウンメニューには新しいディストリビューションは表示されません。<br />\nあたらしくWindowsTerminalを開くとそのウィンドウのドロップダウンメニューには表示されますので、そこから実行します。</p>\n\n<p>引き続きセットアップを行います。</p>\n\n<h2 id=\"ワークディレクトリの作成\">ワークディレクトリの作成</h2>\n\n<p>ホームに色々置くのが嫌いなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span> /proj /work\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshをbashに変更\">デフォルトshをbashに変更</h2>\n\n<p>なんとなくいつも変更してるので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /usr/bin <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<h2 id=\"ツール類インストール\">ツール類インストール</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ifconfig</code>とか<code class=\"language-plaintext highlighter-rouge\">route</code>とかを使いたいので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n\n<h3 id=\"必要なツール類をインストール\">必要なツール類をインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev <span class=\"se\">\\</span>\n                    libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\n                    xz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div></div>\n\n<h3 id=\"pyenvのインストール-1\">pyenvのインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv  <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<p>pyenvを有効にするため、再ログイン(.bashrcに必要な処理は記載済み)。</p>\n\n<h3 id=\"pythonのインストール\">pythonのインストール</h3>\n\n<p>使いたいpythonのバージョンはそのシチュエーションで変わるので、<br />\nインストールするのはマスタからクローンした環境で行う方がいいかも。</p>\n\n<h4 id=\"インストール可能なバージョンを確認\">インストール可能なバージョンを確認</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span> | less\n</code></pre></div></div>\n\n<h4 id=\"インストール-1\">インストール</h4>\n\n<p>インストールが終わったらpip他をアップデートしておく。<br />\n(「pip 古いでぇ~」とうるさいので言われる前にやっとく)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.12.4\npyenv shell 3.12.4\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h1 id=\"仮想環境の複製\">仮想環境の複製</h1>\n\n<p>それまでの状態を保持した状態で新しい仮想環境を作成できます。<br />\n今までは一旦tarファイルにエクスポートしてからインポートしていましたが、\nvhdxファイルから直接インポートできるようになりました。</p>\n\n<h2 id=\"仮想hddファイルvhdxを探す\">仮想HDDファイル(.vhdx)を探す</h2>\n<p>インストールしたディストリビューションを含む各仮想環境の名前とパスの一覧は\n以下をコマンドプロンプト等で実行すると表示できる。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">reg</span><span class=\"w\"> </span><span class=\"nx\">query</span><span class=\"w\"> </span><span class=\"nx\">HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Lxss</span><span class=\"w\"> </span><span class=\"nx\">/s</span><span class=\"w\"> </span><span class=\"err\">^</span><span class=\"w\">\n</span><span class=\"o\">|</span><span class=\"w\"> </span><span class=\"n\">findstr</span><span class=\"w\"> </span><span class=\"s2\">\"BasePath DistributionName HKEY_CURRENT_USER\"</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n1行目末の<code class=\"language-plaintext highlighter-rouge\">^</code>は次行に続くことを示す。linuxの<code class=\"language-plaintext highlighter-rouge\">\\</code>と同じ</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">HKEY_CURRENT_USER</code>を検索しているのは区切り位置を見やすくするため</p>\n</blockquote>\n\n<h2 id=\"仮想環境をクローンする\">仮想環境をクローンする</h2>\n\n<p>クローンする仮想環境を停止する</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>確認(Stoppedになっていることを確認)</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\"> </span><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">-l</span><span class=\"w\"> </span><span class=\"nt\">-v</span><span class=\"w\">\n</span><span class=\"err\">・・・・・</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"仮想環境をクローンする-1\">仮想環境をクローンする</h2>\n<p>クローン先に移動しておく</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">cd</span><span class=\"w\"> </span><span class=\"nx\">F:\\WSL_VMs</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>クローンを作成するには以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"err\">≪クローンの名前≫</span><span class=\"w\"> </span><span class=\"err\">≪クローンの保存先≫</span><span class=\"w\"> </span><span class=\"err\">≪クローン元の</span><span class=\"nx\">vhdx</span><span class=\"err\">ファイル≫</span><span class=\"w\"> </span><span class=\"nt\">--vhd</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>例えば、</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04-temp1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">\\Ubuntu-24.04-temp1</span><span class=\"w\"> </span><span class=\"o\">%</span><span class=\"nx\">LOCALAPPDATA</span><span class=\"o\">%</span><span class=\"nx\">\\Packages\\CanonicalGroupLimited.Ubuntu24.04LTS_79rhkp1fndgsc\\LocalState\\\\ext4.vhdx</span><span class=\"w\"> </span><span class=\"nt\">--vhd</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>クローンが完了したらクローンした仮想環境を実行します。</p>\n\n<h3 id=\"削除\">削除</h3>\n<p>不要になった仮想環境は削除する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"err\">«削除する仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04-2</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h1 id=\"wsl2上のサーバプログラムへのアクセス\">WSL2上のサーバプログラムへのアクセス</h1>\n<p>参考:<a href=\"https://www.atmarkit.co.jp/ait/articles/1909/09/news020.html\" target=\"_blank\">Linuxがほぼそのまま動くようになった「WSL2」のネットワーク機能</a></p>\n\n<table>\n  <thead>\n    <tr>\n      <th>向き</th>\n      <th>可否</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>HOST → WSL2</td>\n      <td>localhost でアクセスできる</td>\n    </tr>\n    <tr>\n      <td>WSL2 → HOST</td>\n      <td>localhost でアクセスできない。<br /> IPアドレス指定ならアクセスできる。</td>\n    </tr>\n  </tbody>\n</table>\n\n<p>Windows11の場合は、ネットワークをミラーモードに設定するとどちらもlocalhostでアクセスできます。<br />\nそれどころか、外部PCからWSLの仮想環境内に直接アクセスできます。<br />\nただし、ポート番号はWindows、各仮想環境で共通で使用されるので、\n他で使用していないポート番号を使用しなければなりません。<br />\nミラーモードに設定するには、<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%\\.wslconfig</code> に以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[wsl2]\nnetworkingMode=mirrored\n</code></pre></div></div>\n<p>参考:<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/networking#mirrored-mode-networking\" target=\"_blank\">WSL を使用したネットワーク アプリケーションへのアクセス/ミラー モードのネットワーク</a></p>\n\n<h1 id=\"virtualboxとの共存\">Virtualboxとの共存</h1>\n\n<p>参考:<a href=\"https://zenn.dev/yuni_hutsuka/articles/46923a0b345619\" target=\"_blank\">【REPORT】Ubuntu Desktop on VirtualBox と wsl2 の共存</a></p>\n\n<p>要は「Windows ハイパーバイザープラットフォームを有効化する」だけど、設定箇所にたどり着くのがメンドクサイので\n上の参考サイトを見てね。</p>\n\n<h1 id=\"なんかのときに使うかも\">なんかのときに使うかも</h1>\n\n<h2 id=\"仮想ディスクが肥大化した場合の対処方法\">仮想ディスクが肥大化した場合の対処方法</h2>\n<p><del><a href=\"https://qiita.com/386jp/items/e469333c5a74789db46d\" target=\"_blank\">WSL2を使っているパソコンのディスク容量が枯渇したときにやってみるべきこと</a></del><br />\nこっちの方が分かりやすかった。<br />\n<a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1271vhdexpcmd/vhdexpcmd.html\" target=\"_blank\">仮想ディスクをコマンドラインから拡大/縮小する</a></p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>PS: XXXX> diskpart                                                 ← コマンド起動\n\nMicrosoft DiskPart バージョン 10.0.19041.964\n\nCopyright (C) Microsoft Corporation.\nコンピューター: XXXXXX\n\nDISKPART> select vdisk file=\"f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\" ← 圧縮したいvhdxファイル\n\nDiskPart により、仮想ディスク ファイルが選択されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   20 GB\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART> compact vdisk                                            ← 縮小の実行\n\n  100% 完了しました                       ← ちょっと時間がかかる\n\nDiskPart により、仮想ディスク ファイルは正常に圧縮されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   12 GB                      ← 小さくなった\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART>exit                                                      ← 終了\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>HTMLで疑似トースト表示</title>\n  </head>\n  <body>\n    <header>\n      <h1>HTMLで疑似トースト表示</h1>\n      <p>HTMLで疑似(なんちゃって)トースト表示するサンプル</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Javascriptでスクリプト書いていて、alert表示するとOKボタン押すまで戻ってこなくて使い勝手が悪いので、\n一定時間表示して勝手に消えるトースト表示みたいな表示ができないかと作ってみた。<br />\nあくまで簡易的なものなので、ウィンドウ作ったりとかはしてない。</p>\n\n<p>妙なこだわりで、消えるときはふわと消える(フェードアウト)にしてみた。<br />\n<code class=\"language-plaintext highlighter-rouge\">fadetime</code>を0にしたらぱっと消える。<br />\nま、ぱっと出てぱっと消えるなら<code class=\"language-plaintext highlighter-rouge\">style.visibility =\"visible\"</code>と<code class=\"language-plaintext highlighter-rouge\">style.visibility =\"hidden\"</code>でいいけど。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>以下のソースを適当に保存して、ブラウザで開いてちょ。<br />\nローカルファイル(file://)で開いてもOK。</p>\n\n<p>説明するほどのことはないので省略。</p>\n\n<p>ページの先頭に固定なので、スクロールしたら消えちゃうけど、\n表示領域の固定(position: fixed など)を使えばなんとかなりそう。</p>\n\n<p>表示が消える前に次の表示を始めたらうまくいかないかも…</p>\n\n<div class=\"language-html highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\"><!DOCTYPE HTML></span>\n<span class=\"nt\"><html</span> <span class=\"na\">lang=</span><span class=\"s\">\"ja\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><head></span>\n<span class=\"nt\"><meta</span> <span class=\"na\">charset=</span><span class=\"s\">\"UTF-8\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><title></span>疑似トースト表示<span class=\"nt\"></title></span>\n<span class=\"nt\"><script></span>\n<span class=\"c1\">// msgをdisptime(msec)表示後、fadetime(msec)でフェードアウトする</span>\n<span class=\"kd\">function</span> <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"nx\">msg</span><span class=\"p\">,</span> <span class=\"nx\">disptime</span><span class=\"o\">=</span><span class=\"mi\">2000</span><span class=\"p\">,</span> <span class=\"nx\">fadetime</span><span class=\"o\">=</span><span class=\"mi\">2000</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"kd\">let</span> <span class=\"nx\">elm</span> <span class=\"o\">=</span> <span class=\"nb\">document</span><span class=\"p\">.</span><span class=\"nx\">getElementById</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">toast</span><span class=\"dl\">\"</span><span class=\"p\">)</span>\n  <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">innerText</span> <span class=\"o\">=</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>            <span class=\"c1\">// 表示メッセージの変更</span>\n  <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">style</span><span class=\"p\">.</span><span class=\"nx\">animation</span> <span class=\"o\">=</span> <span class=\"dl\">\"</span><span class=\"s2\">none</span><span class=\"dl\">\"</span><span class=\"p\">;</span>   <span class=\"c1\">// アニメーションをキャンセルして表示する</span>\n  <span class=\"nx\">setTimeout</span><span class=\"p\">(()</span> <span class=\"o\">=></span> <span class=\"p\">{</span>              <span class=\"c1\">// disptime経過後、アニメーションを開始する。</span>\n    <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">style</span><span class=\"p\">.</span><span class=\"nx\">animation</span> <span class=\"o\">=</span> <span class=\"s2\">`fadeOut </span><span class=\"p\">${</span><span class=\"nx\">fadetime</span><span class=\"p\">}</span><span class=\"s2\">ms forwards`</span><span class=\"p\">;</span>\n  <span class=\"p\">},</span> <span class=\"nx\">disptime</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// ボタンクリック時にコールされる関数</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message1</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ1</span><span class=\"dl\">\"</span><span class=\"p\">,</span><span class=\"mi\">1000</span><span class=\"p\">,</span> <span class=\"mi\">4000</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message2</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ2</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"mi\">3000</span><span class=\"p\">,</span> <span class=\"mi\">1000</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message3</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ3</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message4</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ4</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"mi\">3000</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"nt\"></script></span>\n<span class=\"nt\"></head></span>\n\n<span class=\"nt\"><style></span>\n<span class=\"c\">/* フェードアウトのキーフレーム */</span>\n<span class=\"k\">@keyframes</span> <span class=\"n\">fadeOut</span> <span class=\"p\">{</span>\n  <span class=\"err\">0</span><span class=\"o\">%</span> <span class=\"p\">{</span>\n    <span class=\"nl\">opacity</span><span class=\"p\">:</span> <span class=\"m\">1</span><span class=\"p\">;</span>\n  <span class=\"p\">}</span>\n  <span class=\"err\">100</span><span class=\"o\">%</span> <span class=\"p\">{</span>\n    <span class=\"nl\">opacity</span><span class=\"p\">:</span> <span class=\"m\">0</span><span class=\"p\">;</span>\n  <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c\">/* トースト表示領域 */</span>\n<span class=\"nf\">#toast</span><span class=\"p\">{</span>\n  <span class=\"c\">/* 背景色 */</span>\n  <span class=\"nl\">background-color</span><span class=\"p\">:</span> <span class=\"nb\">rgb</span><span class=\"p\">(</span><span class=\"m\">128</span><span class=\"p\">,</span><span class=\"m\">256</span><span class=\"p\">,</span><span class=\"m\">128</span><span class=\"p\">);</span>\n  <span class=\"c\">/* 0secでアニメーションして表示を消しておく */</span>\n  <span class=\"nl\">animation</span><span class=\"p\">:</span> <span class=\"n\">fadeOut</span> <span class=\"m\">0s</span> <span class=\"n\">forwards</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n<span class=\"c\">/* ボタンを大きくしたいので */</span>\n<span class=\"nc\">.font-large</span><span class=\"p\">{</span>\n    <span class=\"nl\">font-size</span><span class=\"p\">:</span> <span class=\"m\">130%</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n<span class=\"nt\"></style></span>\n\n<span class=\"nt\"><body></span>\n<span class=\"nt\"><font</span> <span class=\"na\">size=</span><span class=\"s\">\"5\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><div></span>\n  <span class=\"nt\"><H3></span>疑似トースト表示<span class=\"nt\"></H3></span>\n  <span class=\"c\"><!-- トースト表示領域 --></span>\n  <span class=\"nt\"><div</span> <span class=\"na\">id=</span><span class=\"s\">\"toast\"</span><span class=\"nt\">></span>\n    メッセージ領域\n  <span class=\"nt\"></div></span>\n  \n  <span class=\"c\"><!-- テスト用ボタン --></span>\n  <span class=\"nt\"><div></span>\n    <span class=\"nt\"><p></span>\n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ1\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message1();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ2\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message2();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ3\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message3();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ4\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message4();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n    <span class=\"nt\"></p></span>\n  <span class=\"nt\"><div></span>\n<span class=\"nt\"></div></span>\n<span class=\"nt\"></font></span>\n<span class=\"nt\"></body></span>\n<span class=\"nt\"></html></span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Web Bluetooth APIを試す</title>\n  </head>\n  <body>\n    <header>\n      <h1>Web Bluetooth APIを試す</h1>\n      <p>Web bluetooth APIを試した時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>ブラウザからBluetoothにアクセスできる<a href=\"https://developer.mozilla.org/ja/docs/Web/API/Web_Bluetooth_API\" target=\"_blank\">Web Bluetooth API</a>\nを試してみた時に作ったプログラムを貼っておきます。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"ペリフェラル機器\">ペリフェラル機器</h2>\n\n<p>BLEは通信なので、通信相手が必要です。<br />\n市販機器を使うと仕様を調べるのが大変なので、エイヤッと自分で作っりました。<br />\nといっても Raspberry Pi Pico W にmicropythonのF/Wを書き込んでプログラム実行するだけ。<br />\n(使用したmicropython F/Wは「MicroPython v1.23.0 on 2024-06-02」です)</p>\n\n<p>以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。 と言ってもWi-Fiとか要らないからパクり先のリンク貼ってあるだけだけど。</p>\n\n<p>ということで、以下のソースを Raspberry Pi Pico で実行しておきます。<br />\n(特にH/W依存なことはしてないので、ESP32でも動くかも)</p>\n\n<p>BLEの処理については「micropython aioble」とかでググってください。<br />\nでも、公式のサンプル動かした例ばっかりであんまりないんだよなぁ…</p>\n\n<p>==懺悔==<br />\nUUIDはどっかのサンプルの値をちょこっといじったものです。<br />\n(調べたら温度計用のUUIDでした)<br />\n本来ならUUIDをちゃんと生成しないといけません。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=ble_peripheral.py\"></script>\n</dev>\n\n<h2 id=\"webサーバ\">Webサーバ</h2>\n<p>Web Bluetooth APIを使用するのは、HTMLファイルをHTTPSサーバからロードしなければならない仕様のようです。\n(httpやfileでは不可)<br />\nファイル1個だけなので、どこかのサーバの片隅に置くとかでも良いと思います。<br />\nローカルでサーバを立てるならApacheとかnginxとかで立ててください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsでApacheを使うなら<a href=\"https://nanbu.marune205.net/2022/01/windows10-apache-ssl.html?m=1\" target=\"_blank\">WindowsのApacheサーバーでSSL</a>\nあたりが参考になりました。<br />\nただし、仮の証明書を作るバッチファイルで、Apacheのインストール先がc:¥Apache24 以外の場合は\n以下の設定を追加しておく必要があります。</p>\n  <div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SET</span><span class=\"w\"> </span><span class=\"nx\">OPENSSL_CONF</span><span class=\"o\">=</span><span class=\"err\">≪</span><span class=\"n\">Apache</span><span class=\"err\">のインストール先≫</span><span class=\"nx\">\\conf\\openssl.cnf</span><span class=\"w\">\n</span></code></pre></div>  </div>\n  <p>インストール先を<code class=\"language-plaintext highlighter-rouge\">m:\\Apache24</code>にした場合の変更例はこんな感じ。</p>\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- aaa.txt     2024-07-29 06:58:34.154735900 +0900\n</span><span class=\"gi\">+++ make-snakeoil-cert.bat      2024-07-26 05:09:37.394502700 +0900\n</span><span class=\"p\">@@ -1,8 +1,11 @@</span>\n REM openssl.exe\n<span class=\"gd\">-SET OPENSSL=c:\\Apache24\\bin\\openssl.exe\n</span><span class=\"gi\">+SET OPENSSL=m:\\Apache24\\bin\\openssl.exe\n+\n+REM openssl.cnf\n+SET OPENSSL_CONF=m:\\Apache24\\conf\\openssl.cnf\n</span>\n REM 証明書用データの出力場所\n<span class=\"gd\">-SET ROOTDIR=c:\\Apache24\\certs\n</span><span class=\"gi\">+SET ROOTDIR=m:\\Apache24\\certs\n</span>\n REM サーバーのドメインまたはIPアドレス\n SET IPADDRESS=localhost\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h1 id=\"htmlファイル\">HTMLファイル</h1>\n\n<p>Web Bluetooth API のサンプルプログラムを以下に示します。<br />\nこれをHTTPSサーバに置いておきます</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=BLE_sample.html\"></script>\n</dev>\n\n<h1 id=\"実験\">実験</h1>\n\n<p>ペリフェラルプログラムを動作させておき、\nブラウザで上記HTMLファイルを開きます。</p>\n\n<p>アクセスするPCやスマホはBLE対応のBluetoothが搭載されている必要があります。<br />\nブラウザはChromeかEdge(は試してないけど)で。(firefox不可)</p>\n\n<p>WindowsPCとAndroidスマホのChromeは動作確認しました。<br />\nmacとiPhoneは持ってないので試してません。</p>\n\n<p>次に「接続」ボタンをクリック、「XXXXXがペア接続を要求しています」ダイアログが出るので\n「mpy-sensor」を選択し、「ペア設定」をクリックします。</p>\n\n<p>接続されると DATA1 に受信したデータを表示します。<br />\nDATA1はNotificationありのデータ読み取りです。<br />\nNotificationイベントを受けてデータを読み取ります。<br />\n上は1行を常に書き換えるタイプ。<br />\n下は過去分を含め10行程度表示(それ以前は削除)するタイプです。<br />\n受診自体は1回でページの書き換え処理を2通り行っています。</p>\n\n<p>DATA2はNotificationなしのデータ読み取りです。<br />\nREADボタンをクリックすると読み取った値を表示します。</p>\n\n<p>測定間隔のテキストボックスに数値を入力し、「WRITE」をクリックすると\nDATA1の取得間隔を変更できます。<br />\n値は100~5000が有効で、範囲外の値が設定されると範囲内の値に補正されます(補正はペリフェラル川で行っています)。</p>\n\n<p>接続を終了するには「切断」をクリックします。</p>\n\n<h1 id=\"操作例\">操作例</h1>\n\n<p><a href=\"/memoBlog/misc/WEB_BT_API_2024-07-29_075522.mp4\" target=\"_blank\">操作例の動画</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) でI2C Slave その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) でI2C Slave その2</h1>\n      <p>Raspberry Pi Pico W の SDK を使用してI2C Slaveプログラムを作成する(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/10/28/RasPiPico_i2c_slave.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) でI2C Slave</a>\nでI2Cスレーブのプログラムを載せましたが、ちょっと特殊な構成のデバイスをエミュレートしていたので\n一般的なレジスタアクセスをエミュレートするプログラムを作ってみました。</p>\n\n<blockquote>\n  <p>[!NOTE]\n公式サンプル<code class=\"language-plaintext highlighter-rouge\">pico-examples/i2c/slave_mem_i2c</code>をちょこっと修正しただけですが。</p>\n</blockquote>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"i2cの結線\">I2Cの結線</h2>\n\n<p>以下のように結線します。<br />\nPico側はソース中の割り当て端子を変更すれば別の端子でもOKです。<br />\n今回はI2C0とI2C1を使うので、両方結線します。<br />\npull-up抵抗はPi3についているのでここでは付けません。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>Pi3</th>\n      <th>Pico</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>SDA1(pin3)</td>\n      <td>I2C0_SDA/GP16(Pin21) I2C1_SDA/GP18(Pin24)</td>\n    </tr>\n    <tr>\n      <td>SCL1(pin5)</td>\n      <td>I2C0_SCL/GP17(Pin22) I2C1_SCL/GP19(Pin25)</td>\n    </tr>\n  </tbody>\n</table>\n\n<blockquote>\n  <p>[!NOTE]\n別に2ch使わなくても良いのですが、8bitアクセスと16bitアクセスを作りたかったので。<br />\nそれぞれ別のプログラムにすると動作確認が面倒だったのでまとめちゃいました。</p>\n</blockquote>\n\n<p>その他の準備は\n<a href=\"/memoBlog/2023/10/28/RasPiPico_i2c_slave.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) でI2C Slave</a>\nを参照してください。</p>\n\n<h1 id=\"picoのプログラム\">Picoのプログラム</h1>\n\n<h2 id=\"プロジェクト生成\">プロジェクト生成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">pico_project</code>でプロジェクトを生成します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">pico_project</code>については、\n<a href=\"/memoBlog/2023/10/23/RasPiPico_3.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</a>\nの「自作プロジェクトの作成」を参照してください)</p>\n</blockquote>\n\n<p>設定内容は以下の通りです</p>\n\n<ul>\n  <li>Project Name に プロジェクト名(例:i2c_slave_2ch)</li>\n  <li>Location に プロジェクトを作成するディレクトリ</li>\n  <li>Board Type で「pico_w」を選択</li>\n  <li>Library Options で「I2C interface」を選択</li>\n  <li>Pico wireless Options で「PicoW onboard LED」を選択</li>\n  <li>Console Options では必要な方式をチェック(両方でも可)</li>\n  <li>IDE Options で「Create VSCode Project」にチェック、「Debugger」は「SWD」を選択</li>\n</ul>\n\n<h2 id=\"プログラムの作成\">プログラムの作成</h2>\n<p>作成したプログラムを以下に示します。</p>\n\n<h3 id=\"メインルーチン\">メインルーチン</h3>\n\n<p>メインルーチンはI2Cを初期化したあと無限ループします。<br />\nループ内ではI2Cに関する処理はなく、生存確認用のLチカと\nキー入力監視して入力に応じて処理を行っています。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_2ch.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/stdlib.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"hardware/i2c.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/cyw43_arch.h\"</span><span class=\"cp\">\n</span>\n<span class=\"c1\">// プロトタイプ宣言</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n\n\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n\n\n<span class=\"kt\">int64_t</span> <span class=\"nf\">alarm_callback</span><span class=\"p\">(</span><span class=\"n\">alarm_id_t</span> <span class=\"n\">id</span><span class=\"p\">,</span> <span class=\"kt\">void</span> <span class=\"o\">*</span><span class=\"n\">user_data</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// Put your timeout handler code in here</span>\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"kt\">int</span> <span class=\"nf\">main</span><span class=\"p\">()</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">stdio_init_all</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// STDIOがUSBのとき、USB認識されないことがあるのでstdio初期化の後、ちょっと待つ</span>\n    <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">3000</span><span class=\"p\">);</span>\n\n    <span class=\"n\">puts</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">I2C slave 2ch\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// LEDを使うためにwifi初期化</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">cyw43_arch_init</span><span class=\"p\">())</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"Wi-Fi init failed\"</span><span class=\"p\">);</span>\n        <span class=\"k\">return</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\">// I2Cスレーブ 初期化</span>\n    <span class=\"n\">setup_i2c_slave0</span><span class=\"p\">();</span>\n    <span class=\"n\">setup_i2c_slave1</span><span class=\"p\">();</span>\n    \n\n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// ==== 生存確認用にLチカ ====</span>\n        <span class=\"c1\">// 現在の出力値取得</span>\n        <span class=\"n\">bool</span> <span class=\"n\">led_out</span> <span class=\"o\">=</span> <span class=\"n\">cyw43_arch_gpio_get</span> <span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">);</span>\n        <span class=\"c1\">// 出力反転</span>\n        <span class=\"n\">cyw43_arch_gpio_put</span><span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">,</span> <span class=\"o\">!</span><span class=\"n\">led_out</span><span class=\"p\">);</span>\n\n        <span class=\"c1\">// キー入力監視</span>\n        <span class=\"kt\">int</span> <span class=\"n\">key_in</span> <span class=\"o\">=</span>  <span class=\"n\">getchar_timeout_us</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'D'</span><span class=\"p\">)</span> <span class=\"o\">||</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'d'</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// 表示モード反転</span>\n            <span class=\"n\">DISP_flag</span> <span class=\"o\">=</span> <span class=\"o\">!</span><span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"**** DISP on ****</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"**** DISP off ****</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'0'</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// slave0データ表示</span>\n            <span class=\"n\">disp_data_slave0</span><span class=\"p\">();</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'1'</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// slave1データ表示</span>\n            <span class=\"n\">disp_data_slave1</span><span class=\"p\">();</span>\n        <span class=\"p\">}</span>\n\n\n        <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">1000</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"i2c0処理\">I2C0処理</h3>\n\n<h4 id=\"初期化\">初期化</h4>\n<p>I2C0の初期化は<code class=\"language-plaintext highlighter-rouge\">setup_i2c_slave0</code>です。<br />\n主に端子の初期化とI2C0の初期化、\nI2Cスレーブの初期化(I2C割り込みハンドラからのコールバックの登録)を行っています。</p>\n\n<p>読み書きするデータは1アドレスあたり8bitとしています。</p>\n\n<h4 id=\"処理本体\">処理本体</h4>\n<p>I2C0処理本体は<code class=\"language-plaintext highlighter-rouge\">i2c_slave0_handler()</code>です。</p>\n\n<p>これはI2C割り込みハンドラからのコールバック処理です。<br />\nなので、できるだけ速やかにリターンする必要があります。\nprintfなどの時間のかかる処理は行わないほうが良いのですが、\nデバッグ用途に送受信データを表示したいのでprintfで表示しています。<br />\nprintfをなくして高速に応答できるように、フラグを使用してprintfの有効/無効化を行っています。<br />\nフラグはメインルーチンでコンソールからのキー入力で切り替えています。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave0.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/rand.h></span><span class=\"c1\">      // 乱数</span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"k\">extern</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">16</span><span class=\"p\">;</span>  <span class=\"c1\">//GP16(Pin21)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">17</span><span class=\"p\">;</span>  <span class=\"c1\">//GP17(Pin22)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">256</span><span class=\"p\">];</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>\n    <span class=\"n\">bool</span> <span class=\"n\">mem_address_written</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"== ch0 ==  addr : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"mh\">0xff</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">+=</span><span class=\"mh\">0x10</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"%02x : %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">14</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">get_rand_32</span><span class=\"p\">();</span>        <span class=\"c1\">// 乱数で初期化</span>\n    <span class=\"p\">}</span>\n    <span class=\"c1\">// アドレス初期化</span>\n    <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではないけど使っちゃお...</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave0_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// STOP/RESTART後の最初の書き込みはアドレス更新</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 set memory address : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// メモリ内容書き換え</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 write memory : %02x : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// メモリから1バイト送信する</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">];</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 read memory : %02x : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// 次の書き込みはアドレス更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 STOP/RESTART condition</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch0</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave0_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch0 done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"i2c1処理\">I2C1処理</h3>\n\n<p>I2C1は読み書きするデータが1アドレスあたり16bitとしていることを除けばI2C0と同じです。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave1.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/rand.h></span><span class=\"c1\">      // 乱数</span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"k\">extern</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x32</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">18</span><span class=\"p\">;</span>  <span class=\"c1\">//GP18(Pin24)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">19</span><span class=\"p\">;</span>  <span class=\"c1\">//GP19(Pin25)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">512</span><span class=\"p\">];</span>\n    <span class=\"kt\">uint16_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>\n    <span class=\"n\">bool</span> <span class=\"n\">mem_address_written</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"== ch1 ==  addr : %02x  %s</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">);</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"mh\">0x200</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">+=</span><span class=\"mh\">0x10</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"%03x : %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">14</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">get_rand_32</span><span class=\"p\">();</span>        <span class=\"c1\">// 乱数で初期化</span>\n    <span class=\"p\">}</span>\n    <span class=\"c1\">// アドレス初期化</span>\n    <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではないけど使っちゃお...</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave1_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// STOP/RESTART後の最初の書き込みはアドレス更新</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint16_t</span><span class=\"p\">)</span><span class=\"n\">addr</span> <span class=\"o\">*</span> <span class=\"mi\">2</span><span class=\"p\">;</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 set memory address : %02x(%03x)</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// メモリ内容書き換え</span>\n            <span class=\"kt\">uint16_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n            <span class=\"p\">}</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 write memory : %02x %s : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span>  <span class=\"n\">addr</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// メモリから1バイト送信する</span>\n        <span class=\"kt\">uint16_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"p\">}</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">];</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 read memory : %02x %s : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span>  <span class=\"n\">addr</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// 次の書き込みはアドレス更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 STOP/RESTART condition</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch1</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c1</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c1</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE1_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave1_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch1 done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n</code></pre></div></div>\n\n<h3 id=\"cmake設定ファイル\">cmake設定ファイル</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>の\n<code class=\"language-plaintext highlighter-rouge\">add_executable</code> に <code class=\"language-plaintext highlighter-rouge\">i2c_slave0.c</code>と<code class=\"language-plaintext highlighter-rouge\">i2c_slave1.c</code>(追加したファイル名)を追加します。<br />\n<code class=\"language-plaintext highlighter-rouge\">target_link_libraries</code> に <code class=\"language-plaintext highlighter-rouge\">pico_i2c_slave</code>(I2Cスレーブを使用)と<code class=\"language-plaintext highlighter-rouge\">pico_rand</code>(乱数を使用)を追加します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  CMakeLists.txt\n</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># Generated Cmake Pico project file</span>\n\n<span class=\"nb\">cmake_minimum_required</span><span class=\"p\">(</span>VERSION 3.13<span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_C_STANDARD 11<span class=\"p\">)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_CXX_STANDARD 17<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise pico_sdk from installed location</span>\n<span class=\"c1\"># (note this can come from environment, CMake cache etc)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_SDK_PATH <span class=\"s2\">\"/work/pico/pico-sdk\"</span><span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_BOARD pico_w CACHE STRING <span class=\"s2\">\"Board type\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># Pull in Raspberry Pi Pico SDK (must be before project)</span>\n<span class=\"nb\">include</span><span class=\"p\">(</span>pico_sdk_import.cmake<span class=\"p\">)</span>\n\n<span class=\"nb\">if</span> <span class=\"p\">(</span>PICO_SDK_VERSION_STRING VERSION_LESS <span class=\"s2\">\"1.4.0\"</span><span class=\"p\">)</span>\n  <span class=\"nb\">message</span><span class=\"p\">(</span>FATAL_ERROR <span class=\"s2\">\"Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is </span><span class=\"si\">${</span><span class=\"nv\">PICO_SDK_VERSION_STRING</span><span class=\"si\">}</span><span class=\"s2\">\"</span><span class=\"p\">)</span>\n<span class=\"nb\">endif</span><span class=\"p\">()</span>\n\n<span class=\"nb\">project</span><span class=\"p\">(</span>i2c_slave_2ch C CXX ASM<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise the Raspberry Pi Pico SDK</span>\n<span class=\"nf\">pico_sdk_init</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># Add executable. Default name is the project name, version 0.1</span>\n\n<span class=\"nb\">add_executable</span><span class=\"p\">(</span>i2c_slave_2ch \n                i2c_slave_2ch.c\n                i2c_slave0.c\n                i2c_slave1.c\n                <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_set_program_name</span><span class=\"p\">(</span>i2c_slave_2ch <span class=\"s2\">\"i2c_slave_2ch\"</span><span class=\"p\">)</span>\n<span class=\"nf\">pico_set_program_version</span><span class=\"p\">(</span>i2c_slave_2ch <span class=\"s2\">\"0.1\"</span><span class=\"p\">)</span>\n\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>i2c_slave_2ch 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>i2c_slave_2ch 0<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard library to the build</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_2ch\n        pico_stdlib<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard include files to the build</span>\n<span class=\"nb\">target_include_directories</span><span class=\"p\">(</span>i2c_slave_2ch PRIVATE\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>/.. <span class=\"c1\"># for our common lwipopts or any other standard includes, if required</span>\n<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add any user requested libraries</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_2ch \n        hardware_i2c\n        pico_cyw43_arch_none\n        pico_i2c_slave\n        pico_rand\n        <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_add_extra_outputs</span><span class=\"p\">(</span>i2c_slave_2ch<span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>あとはビルドしてRaspberry Pi Picoに書き込みます。</p>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認です。<br />\nここからはRaspberry Pi3 での作業です。</p>\n\n<h2 id=\"i2cdetect\">i2cdetect</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdetect</code> で I2Cバス上でデバイスが検出されるか確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n\n<p>Picoのプログラムで設定したスレーブアドレス(<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>と<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE1_ADDRESS</code>の設定値。上のプログラムだと0x17と0x32)\nが表示されていればOKです。<br />\n表示されていない場合はPicoのプログラムやボードの結線を見直してください。</p>\n\n<h2 id=\"i2cdump\">i2cdump</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdump</code> で レジスタダンプしてみます。</p>\n\n<h3 id=\"i2c0\">I2C0</h3>\n<p>I2C0のレジスタをダンプしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdump <span class=\"nt\">-y</span> 1 0x17\n</code></pre></div></div>\n<p>RaspberryPiPICOのコンソールで<code class=\"language-plaintext highlighter-rouge\">0</code>を入力し、Slave0のレジスタをダンプした内容と比較して\n内容が同じであることを確認します。</p>\n\n<h3 id=\"i2c1\">I2C1</h3>\n<p>I2C1のレジスタをダンプしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdump <span class=\"nt\">-y</span> 1 0x32 w\n</code></pre></div></div>\n<p>RaspberryPiPICOのコンソールで<code class=\"language-plaintext highlighter-rouge\">1</code>を入力し、Slave1のレジスタをダンプした内容と比較して\n内容が同じであることを確認します。</p>\n\n<h2 id=\"その他\">その他</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cset</code>や<code class=\"language-plaintext highlighter-rouge\">i2cget</code>で色々読み書きしてみてください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tkinter で 低層のウィジェットでイベントを検出する</title>\n  </head>\n  <body>\n    <header>\n      <h1>tkinter で 低層のウィジェットでイベントを検出する</h1>\n      <p>tkinter で 低層のウィジェットでイベントを検出する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>tkinterでイベントを検出する際、対象のウィジェットの手前に別のウィジェットがあるとイベントを検出できません。<br />\nそれを回避し、手前にウィジェットが存在してもイベントが検出できるサンプルプログラムを書いてみました。</p>\n\n<h1 id=\"サンプルプログラム\">サンプルプログラム</h1>\n\n<p>さっそくサンプルプログラムを貼りつけておきます。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/59faf9f974e22d34a8e988954a32518b.js\"></script>\n</dev>\n\n<h2 id=\"解説のようなもの\">解説のようなもの</h2>\n\n<h3 id=\"canvasにバインドしたイベントハンドラ\">canvasにバインドしたイベントハンドラ</h3>\n\n<p>以下の部分が普通にcanvasにマウスクリックイベントをバインドしている部分です。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">test_canvas</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"s\">'<ButtonPress-1>'</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_on_click_canvas</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>canvas上(水色の部分)でクリックすると<code class=\"language-plaintext highlighter-rouge\">_on_click_canvas</code>が実行され、\n<code class=\"language-plaintext highlighter-rouge\">_on_click_canvas : click on canvas</code>と表示されます。<br />\nしかし、その上に配置されたラベル(labex_1x)上でクリックしたときは表示されません。</p>\n\n<p>labelもcanvasの一部なので、ここでもクリック処理が動いてほしいことはよくあると思います。</p>\n\n<h3 id=\"rootにバインドしたイベントハンドラ\">rootにバインドしたイベントハンドラ</h3>\n\n<p>そこで、以下の部分でrootにマウスクリックイベントをバインドします。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">winfo_toplevel</span><span class=\"p\">().</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"s\">'<ButtonPress-1>'</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_on_click</span><span class=\"p\">,</span> <span class=\"s\">\"+\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>これはrootにバインドされたイベントですから、当然canvas以外の部分でも処理が動きます。<br />\nそこで、イベントハンドラでマウス座標を取得し、canvasの範囲内かを確認し、\nそうであればクリック処理(ここでは<code class=\"language-plaintext highlighter-rouge\">_on_click : click on canvas</code>を表示)を実行します。<br />\nパラメータの最後の<code class=\"language-plaintext highlighter-rouge\">\"+\"</code>は、既にバインドされているハンドラがあった時、上書きせずに追加することを指定しています。<br />\n(つまり、以前にバインドしたハンドラと今回のハンドラ両方が実行されます)</p>\n\n<p>こちらの処理はcanvas上(水色の部分)でクリックしたときも\nその上に配置されたラベル(labex_1x)上でクリックしたときもクリック処理が実行されます。</p>\n\n<p>なお、イベントハンドラに渡されるパラメータ<code class=\"language-plaintext highlighter-rouge\">event</code>の<code class=\"language-plaintext highlighter-rouge\">event.x</code>、<code class=\"language-plaintext highlighter-rouge\">event.y</code>はウィジェット内の相対座標なので\n比較には<code class=\"language-plaintext highlighter-rouge\">event.x_root</code>、<code class=\"language-plaintext highlighter-rouge\">event.y_root</code>を使用して画面上の座標を使用します。<br />\n当然比較するcanvasの座標も<code class=\"language-plaintext highlighter-rouge\">widget.winfo_rootx()</code>、<code class=\"language-plaintext highlighter-rouge\">widget.winfo_rooty()</code>で画面上の座標を使用しなければなりません。</p>\n\n<h3 id=\"おまけ\">おまけ</h3>\n\n<p>おまけとして、ダブルクリックした位置に存在するウィジェットの一覧を表示する処理を入れておきました(<code class=\"language-plaintext highlighter-rouge\">_on_doubleclick</code>) 。<br />\nダブルクリックに意味はなく、クリックは既に使っていたのでダブルクリックにしただけです。</p>\n\n<blockquote>\n  <p>おーちゃくせずに別のプログラム書けよ > 自分</p>\n</blockquote>\n\n<h3 id=\"ふと思ったこと\">ふと思ったこと</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">event.widget</code> から 順に <code class=\"language-plaintext highlighter-rouge\">master</code> をたどって行き、対象のウィジェットが見つかるかで判断する方法もあるなぁ…<br />\nrootの <code class=\"language-plaintext highlighter-rouge\">master</code> は <code class=\"language-plaintext highlighter-rouge\">None</code> なのでそこでサーチ終了。<br />\nどっちが簡単かな…</p>\n\n<h3 id=\"ふと思ったこと-その2\">ふと思ったこと その2</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">bind</code>するときに、.winfo_children() を再帰的にサーチしてすべての子ウィジェットにbindしていく、という手もあるなぁ。<br />\nいっぱいウィジェット配置してるとえらいことになるかもしれんけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tkinter で スクロール可能なcanvasを作る</title>\n  </head>\n  <body>\n    <header>\n      <h1>tkinter で スクロール可能なcanvasを作る</h1>\n      <p>tkinter で スクロール可能なcanvasを作る</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>tkinterでスクロール可能なcanvasのクラス<code class=\"language-plaintext highlighter-rouge\">ScrollableCanvas</code>を作ってみました。<br />\nぶっちゃけ、あちこちにその手の記事はあるのですが、なんか自分のコーディングスタイルとあってないの気がしたので\n微妙に書き換えてみました。</p>\n\n<h1 id=\"サンプルプログラム\">サンプルプログラム</h1>\n\n<p>さっそくサンプルプログラムを貼りつけておきます。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/0ccd48b5cec72ad363d7eaa452972b1f.js\"></script>\n</dev>\n\n<h2 id=\"解説のようなもの\">解説のようなもの</h2>\n\n<h3 id=\"canvas-を継承した-scrollablecanvas-クラス\">canvas を継承した ScrollableCanvas クラス</h3>\n<p>ネット上にある例では、Frameクラスを継承してその下にcanvasを貼り付けているものが多いですが、\nなんとなく余分なウィジェットを作りたくない気分だったのでCanvasクラスを継承するようにしてみました。<br />\nまた、コンストラクタ中でpackしている例が多かったですが、配置の自由度を上げるため上位側に任せるようにしました。</p>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>今回は縦スクロールのみ対応なので、canvasの幅はあらかじめ指定しておくようにしてあります。<br />\nまた、表示するウィジェットを配置するためのフレーム(<code class=\"language-plaintext highlighter-rouge\">child_frame</code>)は幅を自由に設定できるようにすると\n親ウィジェットであるcanvasの幅まで大きくなりますが、これだとスクロールバーが見えなくなります。<br />\nそこで、<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の幅はcanvasの幅からスクロールバーの幅を差し引いたサイズを設定しています。</p>\n\n<blockquote>\n  <p>[!NOTE]\n縦横スクロール可能にした場合は このあたり見直さないといけないかもしれない。</p>\n</blockquote>\n\n<p>また、マウスドラッグによるスクロールをスムーズにするため、スクロール量(<code class=\"language-plaintext highlighter-rouge\">yscrollincrement</code>)のデフォルトを1に設定しています。\nこれはScrollableCanvasクラスのインスタンスを生成する際に変更することができます。</p>\n\n<h3 id=\"ウィンドウイベント\">ウィンドウイベント</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">\"<Configure>\"</code> イベントをbindすることで、ウィンドウが移動されたり、リサイズされたりしたときに実行する処理を割り当てています。<br />\n<code class=\"language-plaintext highlighter-rouge\">\"<Configure>\"</code> イベントはウィンドウのリサイズ等だけでなく、pack()等でFrameのサイズが変更されたときも通知されます。</p>\n\n<p>ここではスクロール範囲の再設定を行っています。</p>\n\n<h3 id=\"マウスイベント\">マウスイベント</h3>\n\n<p>マウスイベントのbindは\n<a href=\"/memoBlog/2024/09/14/tkinter_event_1.html\" target=\"_blank\">tkinter で 低層のウィジェットでイベントを検出する</a>\nの方法を使用しています。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>操作</th>\n      <th>処理</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>左クリック</td>\n      <td>ドラッグ開始位置の設定</td>\n    </tr>\n    <tr>\n      <td>左クリック→マウス移動</td>\n      <td>縦方向の移動量に応じたスクロール</td>\n    </tr>\n    <tr>\n      <td>左ダブルクリック</td>\n      <td>子ウィジェットの追加</td>\n    </tr>\n    <tr>\n      <td>ホイール</td>\n      <td>縦方向スクロール</td>\n    </tr>\n    <tr>\n      <td>右クリック</td>\n      <td>子ウィジェットの全削除</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"実は\">実は…</h3>\n\n<p>右クリックで子ウィジェットを全削除した際、<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の高さは削除前の高さのままになっています。<br />\nつまり、なにもないフレームをスクロールできる状態になっています。<br />\n次に左ダブルクリックでウィジェットを追加したときに1ジェット1個分の高さに変更されます。<br />\nこの仕様が気持ち悪くて色々試したのですが、うまくいきませんでした。<br />\nそこで、「cleard」と表示して<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の高さを変更して誤魔化しています。<br />\n子ウィジェットの差し替えしかしないのであれば特に気にしなくても良い部分だと思います。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Renodeお試し</title>\n  </head>\n  <body>\n    <header>\n      <h1>Renodeお試し</h1>\n      <p>シミュレータ Renode を試してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>おいそれと評価ボードを買えないボンビーの味方、シミュレータ(エミュレータ)。<br />\n<a href=\"https://www.qemu.org/\" target=\"_blank\">QEMU</a>が有名だけど、\n最近は<a href=\"https://renode.io/\" target=\"_blank\">Renode</a>というのもあるらしい。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://wokwi.com/\" target=\"_blank\">wokwi</a>というのもある。<br />\n見た目がきれいで惹かれるけど、VScodeで実行する環境のライセンスが\nよく分からんかった(30日は無料らしいけど、その後無料で更新できるのか、有料になるのか読み取れなかった)<br />\n至れり尽くせりなのはイヤだという天邪鬼気質もあるけど…</p>\n</blockquote>\n\n<p>ということで、Renodeをちらっと試してみた時のメモ。</p>\n\n<p>Renodeのドキュメントは<a href=\"https://renode.readthedocs.io/en/latest/\" target=\"_blank\">https://renode.readthedocs.io/en/latest/</a>にあります<br />\nソースやリリースバイナリは<a href=\"https://github.com/renode/renode\" target=\"_blank\">Github</a>にあります。</p>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"環境\">環境</h2>\n<p>今回はWindows11上のWSLのUbuntu 22.04で試してみます。</p>\n\n<h2 id=\"renodeのインストール\">Renodeのインストール</h2>\n<p>インストール用バイナリは<a href=\"https://github.com/renode/renode/releases\" target=\"_blank\">github</a>\nや<a href=\"https://builds.renode.io\" target=\"_blank\">https://builds.renode.io</a>にあります。</p>\n\n<p>プラットフォームはmono版と.NET版がありますが、ここではmono版を使います。<br />\ndebファイルがあるので、aptでもインストールできますが、ここではポータブル版を使います。</p>\n\n<p>以下のように実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /proj\nwget https://builds.renode.io/renode-latest.linux-portable.tar.gz\n<span class=\"nb\">mkdir </span>renode_portable\n<span class=\"nb\">tar </span>xvf  renode-latest.linux-portable.tar.gz <span class=\"nt\">-C</span> renode_portable <span class=\"nt\">--strip-components</span><span class=\"o\">=</span>1\n</code></pre></div></div>\n\n<p>これで <code class=\"language-plaintext highlighter-rouge\">/proj/renode_portable</code> に必要なファイルが展開されます。<br />\nここにPATHを通すため、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># renodeのインストール先をpathに追加</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span>/proj/renode_portable:<span class=\"nv\">$PATH</span>\n</code></pre></div></div>\n\n<h2 id=\"renodeの依存パッケージのインストール\">renodeの依存パッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mono-devel policykit-1 libgtk2.0-0 screen uml-utilities gtk-sharp2 libc6-dev libicu-dev gcc python3 python3-pip\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nmonoのリポジトリを追加してインストールする情報が散見されるが、ubuntu22.04のaptリポジトリにはmono-develも入っているらしい。<br />\nなので、普通に<code class=\"language-plaintext highlighter-rouge\">apt install</code>だけでインストールできる。<br />\nただし、最新版が欲しい場合は以下でインストールする。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ca-certificates gnupg\n<span class=\"nb\">sudo </span>gpg <span class=\"nt\">--homedir</span> /tmp <span class=\"nt\">--no-default-keyring</span> <span class=\"nt\">--keyring</span> /usr/share/keyrings/mono-official-archive-keyring.gpg <span class=\"nt\">--keyserver</span> hkp://keyserver.ubuntu.com:80 <span class=\"nt\">--recv-keys</span> 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF\n<span class=\"nb\">echo</span> <span class=\"s2\">\"deb [signed-by=/usr/share/keyrings/mono-official-archive-keyring.gpg] https://download.mono-project.com/repo/ubuntu stable-focal main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/mono-official-stable.list\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mono-devel\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"gccのインストール\">gccのインストール</h2>\n<p>Renodeの実行自体にコンパイラは不要ですが、実行するバイナリを作成するのに必要なので、gccをインストールします。</p>\n\n<p>ダウンロードサイト:<a href=\"https://developer.arm.com/downloads/-/gnu-rm\" target=\"_blank\">ARM Developer GNU Arm Embedded Toolchain Downloads</a></p>\n\n<p>以下の手順でインストールします(ファイル名/ディレクトリ名はダウンロードしたバージョンに合わせて変更)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /proj\nwget https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz\n<span class=\"nb\">tar </span>xvf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz \n\n<span class=\"c\"># 依存パッケージのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libncursesw5\n</code></pre></div></div>\n\n<p>PATHを通すため、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># arm-gccのインストール先をpathに追加</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span>/proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin:<span class=\"nv\">$PATH</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンパイラだけなら<code class=\"language-plaintext highlighter-rouge\">apt install gcc-arm-none-eabi</code>でインストールできますが、\ngdbが入ってないので上のサイトからダウンロードして使用します。</p>\n</blockquote>\n\n<h2 id=\"その他インストール\">その他インストール</h2>\n<p>ターゲットプログラムのbuild時にcmakeも使用するのでインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n</code></pre></div></div>\n\n<h1 id=\"デモの実行\">デモの実行</h1>\n<p>ドキュメントの<a href=\"https://renode.readthedocs.io/en/latest/introduction/demo.html\" target=\"_blank\">Running your first demo</a>\nにしたがって実行してみます。</p>\n\n<p>renodeを起動します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode\n</code></pre></div></div>\n\n<p>renodeウィンドウが開くのでそこで以下を入力</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>s @scripts/single-node/stm32f4_discovery.resc\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i @scripts/single-node/stm32f4_discovery.resc\ns\n</code></pre></div>  </div>\n  <p>と実行しても可。<br />\n<code class=\"language-plaintext highlighter-rouge\">i</code>は<code class=\"language-plaintext highlighter-rouge\">include</code>のalias<br />\n<code class=\"language-plaintext highlighter-rouge\">s</code>は<code class=\"language-plaintext highlighter-rouge\">start</code>のalias</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nrenode起動時に以下のようにパラメータとしてrescファイルを指定することもできます。<br />\nこれはincludeコマンドを実行するのと同義(というか起動時にincludeコマンドが実行されている)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode /proj/renode_portable/scripts/single-node/stm32f4_discovery.resc\n</code></pre></div>  </div>\n  <p>rescファイルのパスは絶対パス/カレントディレクトリからの相対パスで指定可能。<br />\n<code class=\"language-plaintext highlighter-rouge\">@</code>を使ったrenodeインストールディレクトリからの相対パスは指定不可。</p>\n</blockquote>\n\n<p>プログラムが実行されると uart4ウィンドウが開いてなにやら色々表示されます。</p>\n\n<p>renodeウィンドウで<code class=\"language-plaintext highlighter-rouge\">quit</code>と入力する(CTRL+Dでも可)と終了します。</p>\n\n<h2 id=\"おまけ\">おまけ</h2>\n<h3 id=\"その1\">その1</h3>\n<p>renodeウィンドウが見難かったら以下のように<code class=\"language-plaintext highlighter-rouge\">-P</code>オプションでポート番号を指定して実行し、</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode <span class=\"nt\">-P</span> 1234\n</code></pre></div></div>\n\n<p>他のターミナルから以下のように実行すると普段使っているターミナルから制御できます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>telnet localhost 1234\n</code></pre></div></div>\n\n<h3 id=\"その2\">その2</h3>\n<p>renode起動時に<code class=\"language-plaintext highlighter-rouge\">--console</code> オプションを指定すると、起動したターミナルがコンソールになります。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode <span class=\"nt\">--cnsole</span>\n</code></pre></div></div>\n<p>ログが同じターミナルに表示されるので見難くなったりするかもしれんけど</p>\n\n<h1 id=\"vscodeでデバッグ\">VScodeでデバッグ</h1>\n\n<p><a href=\"https://renode.readthedocs.io/en/latest/debugging/vscode.html\" target=\"_blank\">ドキュメント</a>\nの説明は分かり難いので、解説記事\n<a href=\"https://medium.com/@pc0is0me/getting-started-with-stm32f4-emulation-using-renode-f6cb158d27d1\" target=\"_blank\">Getting Started with STM32F4 Emulation using Renode</a>\nの手順を試してみます。</p>\n\n<h2 id=\"サンプルのリポジトリをclone\">サンプルのリポジトリをclone</h2>\n\n<p>まずはリポジトリをcloneします。<br />\n適当なディレクトリで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/PhanCuong91/data.git\n</code></pre></div></div>\n\n<h2 id=\"とりあえず動作確認\">とりあえず動作確認</h2>\n\n<p>VScodeでデバッグする前にターゲットプログラムのbuildが行えるか、\nbuildしたバイナリが実行できるか確認しておきます。<br />\nプログラムのbuildは以下のコマンドで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>data/renode\nbash build.bat\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nbatファイルなので、Windowsのバッチファイルですが、\n中身はLinuxでもそのまま実行できる内容なので、\nそのままシェルスクリプトとして実行します。</p>\n</blockquote>\n\n<p>こんな感じでbuildが実行されます。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Release build.\n-- The C compiler identification is GNU 13.3.1\n-- The CXX compiler identification is GNU 13.3.1\n-- The ASM compiler identification is GNU\n-- Found assembler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc\n-- Detecting C compiler ABI info\n-- Detecting C compiler ABI info - done\n-- Check for working C compiler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc - skipped\n-- Detecting C compile features\n-- Detecting C compile features - done\n-- Detecting CXX compiler ABI info\n-- Detecting CXX compiler ABI info - done\n-- Check for working CXX compiler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-g++ - skipped\n-- Detecting CXX compile features\n-- Detecting CXX compile features - done\n-- Configuring done\n-- Generating done\n-- Build files have been written to: /work/data/renode/build\n</code></pre></div></div>\n\n<p>正常にbuildできていれば<code class=\"language-plaintext highlighter-rouge\">build/src/STM32F4Template.elf</code>が出来ています。</p>\n\n<p>renodeを実行し、renodeターミナルで以下のように入力し、プログラムを実行します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mach create\nmachine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl\nsysbus LoadELF @/work/data/renode/build/src/STM32F4Template.elf \nshowAnalyzer sysbus.usart2\nstart\n</code></pre></div></div>\n\n<p>UART2ウィンドウに以下のように表示されればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Hello World!\n</code></pre></div></div>\n\n<p>確認したらrenodeを終了します。</p>\n\n<p>次の作業に備えて、buildディレクトリを削除(またはrename)しておきます。</p>\n\n<h2 id=\"vscodeでのデバッグ\">VScodeでのデバッグ</h2>\n\n<h3 id=\"rescファイルの修正\">rescファイルの修正</h3>\n<p>フルパスで記述されている部分を修正します。</p>\n\n<p>修正内容は以下。<br />\n<code class=\"language-plaintext highlighter-rouge\">$ORIGIN</code>を使用してrescファイルからの相対パス指定に変更。<br />\nこれにより、ダブルクォーテーションで囲む必要はなくなる。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/renode/renode-config.resc b/renode/renode-config.resc\nindex 2729cd1..fcb4f34 100644\n</span><span class=\"gd\">--- a/renode/renode-config.resc\n</span><span class=\"gi\">+++ b/renode/renode-config.resc\n</span><span class=\"p\">@@ -2,8 +2,8 @@</span>\n :description: This script runs the usart_printf example on stm32f4 discovery\n\n $name?=\"STM32F4_Discovery\"\n<span class=\"gd\">-$cmm_repl?=\"C:\\working\\data\\renode\\add-ccm.repl\"\n-$bin_path?=\"C:\\working\\data\\renode\\build\\src\\STM32F4Template.elf\"\n</span><span class=\"gi\">+$cmm_repl?=$ORIGIN/add-ccm.repl\n+$bin_path?=$ORIGIN/build/src/STM32F4Template.elf\n</span>\n # create Socket Terminal for UART\n emulation CreateServerSocketTerminal 3456 \"term\" false\n</code></pre></div></div>\n\n<h3 id=\"buildスクリプトに実行属性を付与\">buildスクリプトに実行属性を付与</h3>\n<p>元がwindows用なので、linuxで実行できるように実行属性を付与します。<br />\n中身はそのまま。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod</span> +x build-debug.bat\n</code></pre></div></div>\n\n<h3 id=\"vscodeを起動\">VScodeを起動</h3>\n<p>ホストOS側のVScodeを起動します。<br />\nWSLなので、ターミナルから以下のコマンドで起動してカレントディレクトリを開きます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>code <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"vscodeの拡張機能のインストール\">VScodeの拡張機能のインストール</h3>\n<p>VScodeの拡張機能で</p>\n<ul>\n  <li>C/C++ Extension Pack をインストールします</li>\n  <li>念のため、CMakeを無効化しておきます</li>\n</ul>\n\n<h3 id=\"実行\">実行</h3>\n\n<p>エクスプローラサイドパネルから<code class=\"language-plaintext highlighter-rouge\">src/main.c</code>を開き、<code class=\"language-plaintext highlighter-rouge\">main()</code> のどこかにブレークポイントを設定。<br />\nデバッグサイドパネルで 「Debug application in Renode」 を選んで実行。<br />\nRenoteターミナルとUART2ウィンドウが開き、設定したブレークポイントで停止するはず。<br />\n実行を再開すると、UART2ウィンドウに<code class=\"language-plaintext highlighter-rouge\">Hello World!</code>と表示され、無限ループに入る。</p>\n\n<h1 id=\"renode-interactive-visualization-example\">Renode interactive visualization example</h1>\n<p>組み込みプログラムなので、ターゲットボードの動作を目で見たくなるのが人情…<br />\nということで、Renode interactive visualization exampleを実行してみます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nWSLのネットワークモードは mirrored にしておきます\n(ほかのモードでも動くかもしれんけど、試してないので)</p>\n</blockquote>\n\n<p><a href=\"https://github.com/antmicro/renode-board-visualization\" target=\"_blank\">github</a>\nからソースを取得します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/antmicro/renode-board-visualization.git\n<span class=\"nb\">cd </span>renode-board-visualization/\n</code></pre></div></div>\n\n<p>Renodeを実行します。<br />\n(バイナリファイルがあるのでbuildは不要。というよりソースファイルはない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode scripts/blinky.resc\n</code></pre></div></div>\n\n<p>rescファイルに<code class=\"language-plaintext highlighter-rouge\">start</code>コマンドが書いてあるので、\n起動と同時にターゲットプログラムが実行されます。</p>\n\n<p>renodeを起動したターミナルにはGPIOアクセスのログが以下のように表示されます。<br />\n(ログが表示されるか否かはPeripheralのエミュレーションプログラムによるので、\nどのCPUても表示されるわけではありません)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>11:28:31.6894 [NOISY] gpio0: Setting pin 24 output to False\n11:28:32.6891 [NOISY] gpio0: Setting pin 24 output to True\n11:28:33.6891 [NOISY] gpio0: Setting pin 24 output to False\n11:28:34.6892 [NOISY] gpio0: Setting pin 24 output to True\n11:28:35.6892 [NOISY] gpio0: Setting pin 24 output to False\n</code></pre></div></div>\n\n<p>renodeコンソールで以下のコマンドを実行します。<br />\nこれによりWebサーバが起動します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>serveVisualization 8000\n</code></pre></div></div>\n\n<p>ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページが表示され、ボード左上のLED(赤色)が点滅しているのが確認できます。</p>\n\n<p>Webサーバを停止するため、renodeコンソールで以下のコマンドを実行します。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>stopVisualization\n</code></pre></div></div>\n\n<p>Renodeを終了します。</p>\n<blockquote>\n  <p>[!NOTE]\nWebサーバを停止せずにRenodeを終了しても構いません。<br />\n停止せずに終了すると終了時に python で たくさんEXCEPTIONが起こるので\n気持ち悪い人はWebサーバを停止してから終了しましょう。</p>\n</blockquote>\n\n<h1 id=\"自分の環境を作ってみた\">自分の環境を作ってみた</h1>\n\n<p>以上を踏まえて、一通り作ってみました。<br />\n(公式サンプルにはターゲットプログラムのソースがないので、\nソースからビルドする部分も含めて試してみたかった)</p>\n\n<p>作った環境はgithubに登録しておきました。<br />\n<a href=\"https://github.com/ippei8jp/renode_my_sample\" target=\"_blank\">https://github.com/ippei8jp/renode_my_sample</a></p>\n\n<h2 id=\"リポジトリのクローン\">リポジトリのクローン</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/ippei8jp/renode_my_sample.git\n<span class=\"nb\">cd </span>renode_my_sample\n</code></pre></div></div>\n<h3 id=\"ソース構成\">ソース構成</h3>\n<p>srcディレクトリ下がプログラムソースです。</p>\n\n<h4 id=\"mainc\">main.c</h4>\n<p>メインルーチンと割り込みハンドラなど。</p>\n\n<h4 id=\"syscallsc\">syscalls.c</h4>\n<p>printf/scanfなどを使用するためのsyscallルーチンを定義。<br />\nコンソール入出力のための最低限の処理だけを定義しています。</p>\n\n<h4 id=\"startup_stm32f40_41xxxs\">startup_stm32f40_41xxx.s</h4>\n<p>bootルーチン、ベクタテーブル、デフォルト割り込みハンドラなど。</p>\n\n<h4 id=\"system_stm32f4xxc\">system_stm32f4xx.c</h4>\n<p>初期化処理(C言語部)</p>\n\n<h4 id=\"cmakeliststxt\">CMakeLists.txt</h4>\n<p>cmake処理定義ファイル。<br />\nソースファイルを追加したときなどはここに追加していく。</p>\n\n<h3 id=\"ビルド実行\">ビルド&実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake ..\nmake\n<span class=\"nb\">cd</span> ..\nrenode script/renode-config.resc\n</code></pre></div></div>\n\n<h3 id=\"ブラウザで接続\">ブラウザで接続</h3>\n<p>GUI部品を表示するため、ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページにLEDとスイッチが表示されます。</p>\n\n<h3 id=\"ターゲットプログラム実行\">ターゲットプログラム実行</h3>\n<p>renodeターミナルで<code class=\"language-plaintext highlighter-rouge\">start</code>コマンドを実行するとターゲットプログラムが実行されます。</p>\n\n<h3 id=\"ブラウザの表示\">ブラウザの表示</h3>\n<p>ターゲットプログラムの動作に応じてLEDが順次点灯/消灯していきます。\nスイッチをクリックするとON/OFFがトグルします。<br />\nこのスイッチの情報はターゲットプログラムのメインループで表示されます。<br />\nまたON時は割り込みハンドラが起動され、UARTコンソールに割り込みメッセージが表示されます。</p>\n\n<h3 id=\"renode終了\">Renode終了</h3>\n<p>renodeターミナルで<code class=\"language-plaintext highlighter-rouge\">quit</code>コマンドを実行して Renodeを終了します。</p>\n\n<h2 id=\"vscodeでデバッグ-1\">VScodeでデバッグ</h2>\n\n<p>VScodeでデバッグする前にbuildディレクトリを削除しておいてください。</p>\n\n<h3 id=\"vscodeでcloneしたディレクトリを開く\">VScodeでcloneしたディレクトリを開く</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>code <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"ビルド\">ビルド</h3>\n<p>VSCodeで</p>\n<ul>\n  <li>cmakeサイドパネルを開く\n    <ul>\n      <li>「構成」右側のアイコンをクリックし、「GCC XX.X.X arm-noen-eabi」選択\n        <ul>\n          <li>cmakeが実行される</li>\n        </ul>\n      </li>\n      <li>「ビルド」右側のアイコンをクリックしbuid実行\n        <ul>\n          <li>makeが実行される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>実行とデバッグサイドパネルを開く\n    <ul>\n      <li>Debug application in Renode を選んで実行</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ブラウザで接続-1\">ブラウザで接続</h3>\n<p>GUI部品を表示するため、ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページにLEDとスイッチが表示されます。</p>\n\n<h3 id=\"ブラウザの表示-1\">ブラウザの表示</h3>\n<p>ターゲットプログラムの動作に応じてLEDが順次点灯/消灯していきます。\nスイッチをクリックするとON/OFFがトグルします。<br />\nこのスイッチの情報はターゲットプログラムのメインループで表示されます。<br />\nまたON時は割り込みハンドラが起動され、UARTコンソールに割り込みメッセージが表示されます。</p>\n\n<h3 id=\"デバッグ\">デバッグ</h3>\n<p>デバッグは他の環境と同じなので、ここでは何も書きません。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>TkEasyGUIを使ってみる</title>\n  </head>\n  <body>\n    <header>\n      <h1>TkEasyGUIを使ってみる</h1>\n      <p>pythonでGUIを簡単に作れる TkEasyGUI を使ってみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでGUIを作るにはtkinterを使うが、とっても分かり難い。<br />\nそこで、簡単にGUIが作れるとウワサの TkEasyGUI を使ってみた。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/TkEasyGUI/0.1.4/\" target=\"_blank\">PyPI</a></li>\n  <li><a href=\"https://github.com/kujirahand/tkeasygui-python\" target=\"_blank\">GitHub</a></li>\n  <li><a href=\"https://note.com/sirodon_256/n/na73d3fdac68d?fbclid=IwY2xjawHpgzhleHRuA2FlbQIxMQABHWBZ650bkpcT7-r0B3xAXpeUoIWsjSZJjZ4lqPUtBrxxQp3mlsCzFtM7tA_aem_lSSEVGhwq5SisJRckTFZcw\" target=\"_blank\">TkEasyGUIライブラリの基本とサンプルコード解説</a></li>\n</ul>\n\n<h1 id=\"使ってみる\">使ってみる</h1>\n<p>使ってみようと思ってはみたものの 何を作れば良いか思いつかなかったので、\n以前にtkinterで作ったプログラムを TkEasyGUI を使って書き直して見ることにした。</p>\n\n<p>元にしたのは、\n<a href=\"https://gist.github.com/ippei8jp/b8af596718e357dce185b5279b3533b8\" target=\"_blank\">ketsuatsu_GUI.py</a><br />\nこれの <code class=\"language-plaintext highlighter-rouge\">ketsuatsu_GUI.py</code>だけを書き換えてみる。<br />\n(<code class=\"language-plaintext highlighter-rouge\">ketsuatsu_csv2xls.py</code>はそのまま使用)</p>\n\n<h1 id=\"作ってみた\">作ってみた</h1>\n<p>ということで、書き直してみた。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>TkEasyGUI のインストールは以下を実行するだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>TkEasyGUI\n</code></pre></div></div>\n<p>TkEasyGUI と pyperclip がインストールされる。</p>\n\n<p>全体を実行するには、上の元ソースのREADMEを参照。</p>\n\n<h2 id=\"ソース\">ソース</h2>\n<p>ということで、作ってみたソースがこちら。<br />\n元のソースと比べても行数で半分以下になった。<br />\nまた、イベントによる実行がイベントハンドラで登録するのから\nイベントループでイベントを監視するように変更されたので、プログラムの見通しがよくなった。</p>\n\n<p>これを</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ketsuatsu_easyGUI.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">dont_write_bytecode</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>      <span class=\"c1\"># pycacheを作成しない\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">TkEasyGUI</span> <span class=\"k\">as</span> <span class=\"n\">eg</span>\n\n<span class=\"c1\"># CSV→エクセル変換処理\n</span><span class=\"kn\">from</span> <span class=\"nn\">ketsuatsu_csv2xls</span> <span class=\"kn\">import</span> <span class=\"n\">ketsuatsu_csv2xls</span>\n\n<span class=\"c1\"># フォント\n# FONT_NAME1 = \"MS ゴシック\"\n</span><span class=\"n\">FONT_NAME1</span> <span class=\"o\">=</span> <span class=\"s\">\"BIZ UDゴシック\"</span>\n<span class=\"n\">FONT_NAME2</span> <span class=\"o\">=</span> <span class=\"s\">\"Noto Sans CJK JP\"</span>\n\n<span class=\"n\">FONT_SIZE</span> <span class=\"o\">=</span> <span class=\"mi\">12</span>\n\n\n<span class=\"c1\"># レイアウト\n</span><span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Text</span><span class=\"p\">(</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"CSV file  \"</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Input</span><span class=\"p\">(</span>       <span class=\"s\">\"\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"s\">\"-csvfilepath-\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span> \n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">FileBrowse</span><span class=\"p\">(</span>  <span class=\"n\">button_text</span> <span class=\"o\">=</span> <span class=\"s\">\"Browse...\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"CSV file\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">file_types</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"s\">'CSV file'</span><span class=\"p\">,</span> <span class=\"s\">'*.csv'</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"s\">'all'</span><span class=\"p\">,</span> <span class=\"s\">'*.*'</span><span class=\"p\">)),</span>\n                     <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Text</span><span class=\"p\">(</span>        <span class=\"s\">\"Excel file\"</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Input</span><span class=\"p\">(</span>       <span class=\"s\">\"\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"s\">\"-excelfilepath-\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span> \n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">FileBrowse</span><span class=\"p\">(</span>  <span class=\"n\">button_text</span> <span class=\"o\">=</span> <span class=\"s\">\"Browse...\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">title</span> <span class=\"o\">=</span> <span class=\"s\">\"Excel file\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">file_types</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"s\">'Excel file'</span><span class=\"p\">,</span> <span class=\"s\">'*.xlsx'</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"s\">'all'</span><span class=\"p\">,</span> <span class=\"s\">'*.*'</span><span class=\"p\">)),</span>\n                        <span class=\"n\">save_as</span> <span class=\"o\">=</span> <span class=\"bp\">True</span><span class=\"p\">,</span>\n                     <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Column</span><span class=\"p\">(</span>\n            <span class=\"n\">layout</span><span class=\"o\">=</span><span class=\"p\">[</span>\n                      <span class=\"p\">[</span>\n                        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Button</span><span class=\"p\">(</span>  <span class=\"s\">\"Convert\"</span><span class=\"p\">,</span>\n                                    <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">),</span>\n                                 <span class=\"p\">),</span> \n                        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Button</span><span class=\"p\">(</span>  <span class=\"s\">\"Exit\"</span><span class=\"p\">,</span>\n                                    <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">),</span>\n                                 <span class=\"p\">),</span>\n                      <span class=\"p\">]</span>\n                    <span class=\"p\">],</span>\n            <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n            <span class=\"n\">expand_y</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n            <span class=\"n\">text_align</span><span class=\"o\">=</span><span class=\"s\">\"right\"</span><span class=\"p\">,</span>\n            <span class=\"n\">vertical_alignment</span><span class=\"o\">=</span><span class=\"s\">\"bottom\"</span><span class=\"p\">,</span>\n        <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n<span class=\"p\">]</span>\n\n\n<span class=\"c1\"># CSVファイルからexcelファイルへの変換処理をコールする\n</span><span class=\"k\">def</span> <span class=\"nf\">convert_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">):</span>\n    <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n\n    <span class=\"c1\"># パラメータエラーチェック\n</span>    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ファイルが指定されていない\n</span>        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"入力ファイルを指定してください\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># filedialog.askopenfilename()は存在するファイルしか選択できないが\n</span>    <span class=\"c1\"># エディットボックスを直接編集した場合のためにチェック\n</span>    <span class=\"k\">elif</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"入力ファイルを指定してください\"</span><span class=\"p\">,</span>  <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">output_filename</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ファイルが指定されていない\n</span>        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"出力ファイルを指定してください\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># この判定はfiledialog.asksaveasfilename()内で行うが\n</span>    <span class=\"c1\"># エディットボックスを直接編集した場合のためにチェック\n</span>    <span class=\"k\">elif</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">output_filename</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">ret</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup_ok_cancel</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"出力ファイルが存在します</span><span class=\"se\">\\n</span><span class=\"s\">上書きしますか?\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"確認\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span> <span class=\"k\">if</span> <span class=\"n\">ret</span> <span class=\"o\">==</span> <span class=\"s\">'OK'</span> <span class=\"k\">else</span> <span class=\"bp\">False</span>\n    <span class=\"k\">if</span> <span class=\"n\">execute_flag</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 変換処理\n</span>        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"c1\"># CSVファイルからエクセルファイルを作成\n</span>            <span class=\"n\">ketsuatsu_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">)</span>\n            <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"変換終了\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"終了\"</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"nb\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">e</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n\n    <span class=\"c1\"># 使用するフォントの設定\n</span>    <span class=\"n\">fonts</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">get_font_list</span><span class=\"p\">()</span>\n    <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n    <span class=\"n\">target_font_size</span> <span class=\"o\">=</span> <span class=\"n\">FONT_SIZE</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">FONT_NAME1</span> <span class=\"ow\">in</span> <span class=\"n\">fonts</span> <span class=\"p\">:</span>\n        <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"n\">FONT_NAME1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">FONT_NAME2</span> <span class=\"ow\">in</span> <span class=\"n\">fonts</span> <span class=\"p\">:</span>\n        <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"n\">FONT_NAME2</span>\n\n\n    <span class=\"c1\"># window create\n</span>    <span class=\"n\">window</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Window</span><span class=\"p\">(</span><span class=\"s\">'血圧 CSV->excel'</span><span class=\"p\">,</span> \n                        <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">600</span><span class=\"p\">,</span> <span class=\"mi\">150</span><span class=\"p\">),</span>\n                        <span class=\"n\">font</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">target_font_name</span><span class=\"p\">,</span> <span class=\"n\">target_font_size</span><span class=\"p\">),</span>\n                        <span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"n\">layout</span>\n                    <span class=\"p\">)</span>\n\n    <span class=\"c1\"># event loop\n</span>    <span class=\"k\">while</span> <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">is_alive</span><span class=\"p\">():</span>\n        <span class=\"n\">event</span><span class=\"p\">,</span> <span class=\"n\">values</span> <span class=\"o\">=</span> <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#\"</span><span class=\"p\">,</span> <span class=\"n\">event</span><span class=\"p\">,</span> <span class=\"n\">values</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">event</span> <span class=\"o\">==</span> <span class=\"s\">\"Exit\"</span> <span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">event</span> <span class=\"o\">==</span> <span class=\"s\">\"Convert\"</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># print(values)\n</span>            <span class=\"n\">input_filename</span>  <span class=\"o\">=</span> <span class=\"n\">values</span><span class=\"p\">[</span><span class=\"s\">'-csvfilepath-'</span><span class=\"p\">]</span>\n            <span class=\"n\">output_filename</span> <span class=\"o\">=</span> <span class=\"n\">values</span><span class=\"p\">[</span><span class=\"s\">'-excelfilepath-'</span><span class=\"p\">]</span>\n            <span class=\"n\">convert_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 終了\n</span>    <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n\n\n<span class=\"c1\"># ======================================================\n</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">main</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"未対応項目\">未対応項目</h1>\n<h2 id=\"ドラッグアンドドロップ\">ドラッグアンドドロップ</h2>\n<p>TkEasyGUI は ドラッグアンドドロップに対応していないので、作成したプログラムも未対応。<br />\nissueはあがっていて、作者さんも「It seems we could easily support」と言っているので、近いうちにサポートされるかも。</p>\n<ul>\n  <li><a href=\"https://github.com/kujirahand/tkeasygui-python/issues/7\" target=\"_blank\">Drag & Drop files #7</a></li>\n</ul>\n\n<h2 id=\"テーマの使用\">テーマの使用</h2>\n<p>TkEasyGUI は ttkの使用に対応しているが、使い方によってはうまく動かない。<br />\n(今回は <code class=\"language-plaintext highlighter-rouge\">eg.Column</code> の中の <code class=\"language-plaintext highlighter-rouge\">eg.Button</code> で  <code class=\"language-plaintext highlighter-rouge\">use_ttk_buttons=True</code>を指定したらエラーになった。<br />\nなにか条件があるのかもしれんが。)<br />\nとりあえず「お手軽にGUI」が目的なので、テーマで見た目に凝らなくてもいいか、と対応はあきらめた。</p>\n\n<h1 id=\"まとめ\">まとめ</h1>\n<p>さらっと触っただけだけど、tkinterをそのまま使うよりかなり分かりやすい。<br />\nが、ちょっと凝ったことをやろうとすると、できなかったりすることも。<br />\nその辺は必須かどうか見極めて、あきらめるか、tkinterで泥沼にハマってでも実現するかを決めるしかないか。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openpyxlのバグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>openpyxlのバグ</h1>\n      <p>openpyxl(3.1.5)のバグ(ではないけど、あえてそう書いておく)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"内容\">内容</h1>\n<p>openpyxl(3.1.2)でExcelのグラフを作成するスクリプトを使っていたが、\nopenpyxlを現時点での最新版(3.1.5)にアップデートしたところ、表示されるグラフの見た目が変わってしまった。</p>\n\n<h1 id=\"原因\">原因</h1>\n<p>検索してみたところ、teratailに\n『<a href=\"https://teratail.com/questions/5q9cujzlc2307x\" target=\"_blank\">python openpyxl グラフ作成 グラフ書式が変わったのを治せない</a>』\nというエントリを見つけた。</p>\n\n<p>どうやら、Excelの仕様に厳密に従ったらExcelのバグに引っかかった ということらしい。<br />\n(バグが他のバグ回避になってた、みたいな感じ)</p>\n\n<h1 id=\"対策\">対策</h1>\n<p>Excelのバグの修正を待っててもしかたないので、なんとか出来る方法を探してみた。<br />\nこの部分は openpyxl の 3.1.4 で仕様変更されたようなので、3.1.3以前を使うというのも手なのだけど、<br />\n最新版を使いたい場合はExcelのバグに引っかかってる部分だけ元にもどしてやれば良い。</p>\n\n<p>ということで、上のページにあった変更点を出力している部分を探して修正してみた。</p>\n\n<p>結論から言うと、以下のパッチをインストールしたライブラリにあててやれば良い。</p>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -urpN openpyxl.org/packaging/extended.py openpyxl/packaging/extended.py\n</span><span class=\"gd\">--- openpyxl.org/packaging/extended.py  2025-01-07 07:23:30.159676700 +0900\n</span><span class=\"gi\">+++ openpyxl/packaging/extended.py      2025-01-07 07:41:28.823592900 +0900\n</span><span class=\"p\">@@ -126,7 +126,8 @@</span> class ExtendedProperties(Serialisable):\n         self.HLinks = None\n         self.HyperlinksChanged = HyperlinksChanged\n         self.DigSig = None\n<span class=\"gd\">-        self.Application = f\"Microsoft Excel Compatible / Openpyxl {__version__}\"\n</span><span class=\"gi\">+        # self.Application = f\"Microsoft Excel Compatible / Openpyxl {__version__}\"\n+        self.Application = f\"Microsoft Excel\"\n</span>         self.AppVersion = \".\".join(__version__.split(\".\")[:-1])\n         self.DocSecurity = DocSecurity\n</code></pre></div></div>\n\n<p>で、試してみたところ うまくグラフが表示されるようになった。<br />\nメデタシメデタシ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MSYS2とgccのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>MSYS2とgccのインストール</h1>\n      <p>WindowsにMSYS2とgccをインストールした時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows環境でLinuxライクな環境を使用できる<a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2</a><br />\ngcc は単体で配布されている <a href=\"https://github.com/niXman/mingw-builds-binaries/releases\" target=\"_blank\">MinGW-W64-binaries</a>を使っていたが、\nMSYS2で管理されているものに切り替えてみた。</p>\n\n<h1 id=\"msys2のインストール\">MSYS2のインストール</h1>\n<p>大体以下の感じでインストールできる。</p>\n<ul>\n  <li><a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2のページ</a> を開く</li>\n  <li>Installation セクションの Download the installer: に書かれているリンクからダウンロード(バージョンアップで更新されるのでここにはリンクを貼らないでおく)</li>\n  <li>ダウンロードしたファイルを実行</li>\n  <li>デフォルトのままNextをクリックして行き、Installをクリック</li>\n  <li>終わったらFinishをクリック</li>\n</ul>\n\n<h1 id=\"msys2の設定\">MSYS2の設定</h1>\n<p>後でWindowsTerminalから使えるようにするからやらなくても良いけど、ま、気持ちの問題なので。</p>\n<ul>\n  <li>msys2を起動(スタート→すべて→MSYS2→MSYS2 UCRT64)し、タイトルバーを右クリックし 「Options…」 を選択\n    <ul>\n      <li>Text の Font の Select.. をクリックしてフォントとサイズを変更</li>\n      <li>Text の Local で ja_JP と UTF8 を選択</li>\n      <li>Window の Default size で ウィンドウサイズが変更できる</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"最新版にアップデート\">最新版にアップデート</h1>\n<p>MSYS2を起動して以下を実行(ubuntuの<code class=\"language-plaintext highlighter-rouge\">apt update && apt upgrade</code>に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -Syuu\n</code></pre></div></div>\n\n<p>何か聞かれたらYを入力<br />\nウィンドウが閉じられたら再度MSYS2を起動<br />\n再度MSYS2を起動したらもう一回 <code class=\"language-plaintext highlighter-rouge\">pacman -Syuu</code> を実行</p>\n\n<h1 id=\"開発ツールのインストール\">開発ツールのインストール</h1>\n<p>MSYS2を起動して以下を実行<br />\n(make、gcc、gdbなどのインストール)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -S base-devel\npacman -S mingw-w64-ucrt-x86_64-gcc\npacman -S mingw-w64-ucrt-x86_64-gdb\n</code></pre></div></div>\n\n<h1 id=\"pathの変更\">PATHの変更</h1>\n<p>MSYS2のbashで実行する際はpathは設定済みだが、\nコマンドプロンプト等で実行するためにWindows側のPATHを変更する。</p>\n\n<ul>\n  <li>設定 → システム → バージョン情報</li>\n  <li>関連リンクの「システムの詳細設定」をクリック</li>\n  <li>開いたウィンドウの下のほうにある「環境変数(N)…」をクリック</li>\n  <li>上側のユーザ環境変数で「Path」を選択して「編集」をクリック</li>\n  <li>「新規」をクリックして以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>c:\\msys64\\ucrt64\\bin\nC:\\msys64\\usr\\bin\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\nc:\\msys64\\ucrt64\\bin にはpythonが入っているので、Windowsでインストールしたpythonを使用したい場合は\nそのPATHより後(下)に設定すること</p>\n    </blockquote>\n  </li>\n</ul>\n\n<p>念のためここでPCを再起動する。<br />\n(PATHの変更が有効にならない場合がある)</p>\n\n<h1 id=\"windowsterminal-にmsys2を登録\">WindowsTerminal にMSYS2を登録</h1>\n<p>MSY2のデフォルトのターミナルはminttyだが、いつも使っているWindowsTerminalで使えるようにする。</p>\n<ul>\n  <li>WindowsTerminalを起動</li>\n  <li>「新しいプロファイルを追加」を選択</li>\n  <li>「新しい空のプロファイル」をクリック\n    <ul>\n      <li>コマンドラインに以下を設定(ucrt64の場合。それ以外は最後のオプションを変更する)\n        <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>C:/msys64/msys2_shell.cmd -defterm -here -no-start -ucrt64\"  \n</code></pre></div>        </div>\n      </li>\n      <li>開始ディレクトリに MSYS2のhomeディレクトリ(<code class=\"language-plaintext highlighter-rouge\">cygpath.exe -w ~</code> で取得可能) を指定</li>\n      <li>アイコンは何でもいいけど、<code class=\"language-plaintext highlighter-rouge\">C:\\\\msys64\\\\ucrt64.ico</code>とかが良いかな</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"vs-codeのターミナルでmsys2のbashを使用する方法\">VS CodeのターミナルでMSYS2のBashを使用する方法</h1>\n<p>VS CodeのターミナルでもMSYS2を使えるようにしておく。<br />\n(別ウィンドウでWindowsTerminalから実行すればいいんだけど)</p>\n\n<ul>\n  <li>VSCodeを起動</li>\n  <li>設定(ファイル→ユーザ設定→設定)を開く</li>\n  <li>機能→ターミナルを選ぶ\n-「integrated > profiles:windows」 を探す(検索すれば良いんだけど)\n    <ul>\n      <li>「setting,jsonで編集」 をクリック\n        <ul>\n          <li>ひな型作って開いてくれる。</li>\n          <li>そこに 以下を追加\n            <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>          \"MSYS2 Bash\": {\n              \"path\": [\n                  \"C:\\\\msys64\\\\msys2_shell.cmd\"\n              ],\n              \"args\": [\n                  \"-defterm\",\n                  \"-here\",\n                  \"-no-start\",\n                  \"-ucrt64\"\n              ]\n          }\n</code></pre></div>            </div>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nファイルは ユーザだと、<code class=\"language-plaintext highlighter-rouge\">%APPDATA%\\code\\User\\settings.json</code><br />\nワークスペースだとワークスペース下の<code class=\"language-plaintext highlighter-rouge\">.vscode\\settings.json</code></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nデフォルトのプロファイルをBashにすると悲しい結果が待ち受けているのでやらない方が良さそう</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Buildozerをお試し</title>\n  </head>\n  <body>\n    <header>\n      <h1>Buildozerをお試し</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerをお試ししたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonプログラムをAndroid アプリ化できる Buildozer を試してみた時のメモ<br />\n(iOSもできるみたいだけど試してないのでわからん)<br />\n参考:<br />\n<a href=\"https://buildozer.readthedocs.io/en/latest/installation.html\" target=\"_blank\">公式サイト</a><br />\n<a href=\"https://qiita.com/kouzimiso/items/1332ab62791ca5d81c5f\" target=\"_blank\">BuildozerでAndroidアプリを作る 2024 WSL2</a><br />\n<a href=\"https://paloma69.hatenablog.com/entry/2022/07/05/195915\" target=\"_blank\">pythonでAndroidの野良アプリを作りたい2 buildozerでコンパイル編</a></p>\n\n<h1 id=\"準備\">準備</h1>\n<p>環境はWSL で Ubuntu 24.04を使用した。<br />\n(公式では20.04 or 22.04 となってるけど、24.04でも動いた)<br />\n以下ディストリビューション情報</p>\n\n<p>Andoridはちょっと古いけど ZenFone Max Pro (M2) Android9<br />\n新しいAndroidでも動くかどうかわからん。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>~<span class=\"nv\">$ </span>lsb_release <span class=\"nt\">-a</span>\nNo LSB modules are available.\nDistributor ID: Ubuntu\nDescription:    Ubuntu 24.04.2 LTS\nRelease:        24.04\nCodename:       noble\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n\n<p><a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a>参照</p>\n\n<h2 id=\"pyenvでpythonインストール\">pyenvでpythonインストール</h2>\n<p>公式では python は 3.8 以降となっているので、3.12を使うこととした。</p>\n\n<blockquote>\n  <p>[!NOTE]\n3.12では<code class=\"language-plaintext highlighter-rouge\">distutils</code>が廃止されているので、<code class=\"language-plaintext highlighter-rouge\">setuptools</code>のインストールが必須。<br />\n参考:<a href=\"https://openillumi.com/python-3-12-distutils-error-fix-guide/\" target=\"_blank\">Python 3.12での「ModuleNotFoundError: distutilsが見つかりません」を解決する方法</a></p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.12.9 \npyenv shell 3.12.9 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\npyenv shell <span class=\"nt\">--unset</span> \n</code></pre></div></div>\n\n<h2 id=\"pyenvで仮想環境構築\">pyenvで仮想環境構築</h2>\n<p>お約束で仮想環境を作っておく。<br />\n(そのまま3.12.xにインストールしてもいいけど)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Buildozer <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Buildozer\npyenv virtualenv 3.12.9 Buildozer\npyenv <span class=\"nb\">local </span>Buildozer \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"必要なツール類のインストール\">必要なツール類のインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>zip unzip openjdk-17-jdk autoconf libtool pkg-config zlib1g-dev cmake libffi-dev libssl-dev\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n公式サイトで指定されているライブラリのうち以下は24.04では存在しない。<br />\n<code class=\"language-plaintext highlighter-rouge\">libncurses5-dev libncursesw5-dev libtinfo5</code><br />\nWSL2のUbuntu24.04ではデフォルトで後継のlibncurses-dev、libtinfo6が入ってるので気にしなくても大丈夫</p>\n</blockquote>\n\n<h2 id=\"buildozer関連のモジュールのインストール\">Buildozer関連のモジュールのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> buildozer\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">Cython</span><span class=\"o\">==</span>0.29.33 virtualenv\n</code></pre></div></div>\n\n<h2 id=\"使用するフォントのインストール\">使用するフォントのインストール</h2>\n<p>どっかからダウンロードしてきてもいいけど、お手軽にaptでインストール<br />\n(あとで作業ディレクトリにコピーする)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n\n<h2 id=\"ubuntu上でアプリ実行するとき必要なライブラリのインストール\">Ubuntu上でアプリ実行するとき必要なライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libmtdev-dev\n</code></pre></div></div>\n\n<h2 id=\"アプリで使うモジュールのインストール\">アプリで使うモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>kivy\n</code></pre></div></div>\n\n<h1 id=\"アプリの作成\">アプリの作成</h1>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n\n<p>どこでも良いけど、先に作ったpyenvの仮想環境<code class=\"language-plaintext highlighter-rouge\">Buildozer</code>が使えるh場所で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /work/Buildozer/app <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Buildozer/app\n</code></pre></div></div>\n\n<h2 id=\"フォントのコピー\">フォントのコピー</h2>\n<p>先ほどインストールしたフォントを作業ディレクトリにコピー</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir assets\ncp /usr/share/fonts/truetype/fonts-japanese-gothic.ttf assets/\n</code></pre></div></div>\n\n<h2 id=\"mainpyを作成\">main.pyを作成</h2>\n\n<p><a href=\"https://qiita.com/kouzimiso/items/1332ab62791ca5d81c5f\" target=\"_blank\">参考にしたサイト</a>\nにあったプログラムを使わせてもらった(ちょっち変更あり)。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  main.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.app</span> <span class=\"kn\">import</span> <span class=\"n\">App</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.button</span> <span class=\"kn\">import</span> <span class=\"n\">Button</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.label</span> <span class=\"kn\">import</span> <span class=\"n\">Label</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.boxlayout</span> <span class=\"kn\">import</span> <span class=\"n\">BoxLayout</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.utils</span> <span class=\"kn\">import</span> <span class=\"n\">platform</span>\n\n<span class=\"c1\"># フォントのパスを指定してフォントを設定する\n</span><span class=\"k\">if</span> <span class=\"n\">platform</span> <span class=\"o\">==</span> <span class=\"s\">'win'</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Windowsの場合はシステムフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">\"C:/Windows/Fonts/YuGothR.ttc\"</span><span class=\"p\">)</span>\n<span class=\"k\">elif</span> <span class=\"n\">platform</span> <span class=\"o\">==</span> <span class=\"s\">'android'</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Androidの場合はassetsフォルダ内のフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'assets/fonts-japanese-gothic.ttf'</span><span class=\"p\">)</span>\n<span class=\"k\">else</span><span class=\"p\">:</span>\n    <span class=\"c1\"># その他のプラットフォームではデフォルトフォントを使用\n</span>    <span class=\"c1\"># LabelBase.register(DEFAULT_FONT, fn_regular='DejaVuSans.ttf')\n</span>    <span class=\"c1\"># その他の場合もassetsフォルダ内のフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'assets/fonts-japanese-gothic.ttf'</span><span class=\"p\">)</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MyApp</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># レイアウトの生成\n</span>        <span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"n\">BoxLayout</span><span class=\"p\">(</span><span class=\"n\">orientation</span><span class=\"o\">=</span><span class=\"s\">'vertical'</span><span class=\"p\">,</span> <span class=\"n\">spacing</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ボタンの生成\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span> <span class=\"o\">=</span> <span class=\"n\">Button</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"o\">=</span><span class=\"s\">'クリックしてください'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ボタンにコールバックを設定\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"n\">on_press</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">on_button_press</span><span class=\"p\">,</span> <span class=\"n\">on_release</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">on_button_release</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ラベルの生成\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">Label</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"o\">=</span><span class=\"s\">'ボタンがクリックされるとここに表示されます'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># layoutにボタンとラベルを配置\n</span>        <span class=\"n\">layout</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span><span class=\"p\">)</span>\n        <span class=\"n\">layout</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">layout</span>\n\n    <span class=\"c1\"># ボタンが押されたたときのコールバック処理\n</span>    <span class=\"k\">def</span> <span class=\"nf\">on_button_press</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">instance</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">'ボタンが押されました!'</span>\n    \n    <span class=\"c1\"># ボタンが離されたたときのコールバック処理\n</span>    <span class=\"k\">def</span> <span class=\"nf\">on_button_release</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">instance</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">'ボタンが離されました!'</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">MyApp</span><span class=\"p\">().</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"とりあえずununtu上で試してみる\">とりあえずUnuntu上で試してみる</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python main.py\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n上半分がボタン、下半分がラベル<br />\nボタンを押す/離すとラベルの表示が変わる<br />\nXボタンで終了</p>\n</blockquote>\n\n<h2 id=\"buildozer初期化\">Buildozer初期化</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n<p>buildozer.spec が生成される</p>\n\n<h2 id=\"buildozerspecファイルの修正\">buildozer.specファイルの修正</h2>\n<p>以下の修正を行う</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- buildozer.spec.org  2025-03-28 11:44:32.382972664 +0900\n</span><span class=\"gi\">+++ buildozer.spec      2025-03-28 11:52:18.977717226 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,ttf\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*.ttf\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n</code></pre></div></div>\n\n<h2 id=\"clean--build\">clean & build</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer android clean     <span class=\"c\"># 初回はやらなくてOK(FileNotFoundErrorになる)</span>\nbuildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee</span> <span class=\"nt\">-a</span> buildozer.log\n</code></pre></div></div>\n\n<p>正常にbuildが終了したら以下のように表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n初回は途中ライセンスに同意を求められるので同意するならyを入力(同意しないと終わっちゃうけど)<br />\n終了まで15分ほどかかった(環境依存なのであまりあてにしないで)<br />\n初回はダウンロードが入るのでもうちょっとかかる</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n<h2 id=\"android側の準備\">Android側の準備</h2>\n<p>adbが接続できるようになんか準備が必要(デバッグモードを有効にするとか?)だった気がするけど\n忘れちゃったので良きに計らってちょ\n(<a href=\"https://developer.android.com/studio/debug/dev-options?hl=ja\" target=\"_blank\">このへん?</a>)</p>\n\n<p>で、PCとUSBで接続しておく。</p>\n\n<h2 id=\"windows用-adbのダウンロード\">Windows用 adbのダウンロード</h2>\n<p><a href=\"https://developer.android.com/tools/releases/platform-tools?hl=ja\" target=\"_blank\">SDK Platform-Tools リリースノート</a><br />\n「ダウンロード」セクションの「SDK Platform-Tools for Windowsをダウンロード」からダウンロードし、適当なディレクトリに展開\n(例:C:\\Android_tools )</p>\n\n<blockquote>\n  <p>[!NOTE]\nPATHを通してもいいけど、AndroidStudio使うときに不安なので通さないでcdしてから実行するようにした</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nAndroidStudioが入っているのであれば、そっちを使っても可。<br />\n その場合、adb.exeは<code class=\"language-plaintext highlighter-rouge\">%LOCALAPPDATA%\\Android\\Sdk\\platform-tools</code>にある。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n公式の情報ではWindowsのadbとUbuntuのadbのバージョンが同じでないとダメと書いてあるが、多少違っても大丈夫っぽい。<br />\n(てか、古いバージョンダウンロードできるんだろか?と思ったら、\n<a href=\"https://qiita.com/azumagoro/items/3a44fad53d88b3b2817b\" target=\"_blank\">Android SDK platform-tools 旧バージョン インストール</a>\nに手順書いてあった。メンドクサイけど…)</p>\n</blockquote>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動するためだと思う)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪上で展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!IMPORTANT]\n最初のadbの実行はWindows側。コマンドプロンプトやpowershellで実行する。</p>\n</blockquote>\n\n<p>以下のように表示されるはず</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>* daemon not running; starting now at tcp:XXXX\n* daemon started successfully\nList of devices attached\n== 接続されているデバイスが表示される ==\n</code></pre></div></div>\n\n<p>ちなみにサーバを停止するには以下</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>adb kill-server\n</code></pre></div></div>\n\n<h2 id=\"ダウンロードと実行\">ダウンロードと実行</h2>\n\n<p>WSL側のターミナルに戻って以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run \n</code></pre></div></div>\n\n<p>これでプログラムがAndroidにダウンロードされて実行される。</p>\n\n<p>logcatを表示したいときは以下</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n上記のコマンドを実行すると内部でadbが実行されるようだ。</p>\n</blockquote>\n\n<h2 id=\"usb接続せずに実行したい場合\">USB接続せずに実行したい場合</h2>\n<p>USB接続せずに実行したい場合は以下のように実行してWebサーバを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer serve\n</code></pre></div></div>\n<p>WEBサーバが立ち上がったら、Androidのchrome等からアクセスし、apkファイルをダウンロードしてインストール<br />\n…できるんだけど、通常firewallが動いていてアクセスが弾かれるのでfirewallの設定変更しないといけない。<br />\n変更方法は<a href=\"https://www.fmworld.net/cs/azbyclub/qanavi/jsp/qacontents.jsp?PID=0111-2966\" target=\"_blank\">このへん</a><br />\n(試してないけど)</p>\n\n<h2 id=\"その他の方法\">その他の方法</h2>\n<p>quickshreを使うとか、USBのファイル転送モードを使えばapkファイルを転送できるので、\nあとはFiles等で表示してapkファイルとタップすればインストールできる。<br />\n(なんか野良アプリのインストール許可とか色々許可しないといけなかった気がする)</p>\n\n<h1 id=\"まとめ\">まとめ</h1>\n<p>とりあえずなんか実行できるものができたけど、実用に堪えるかはビミョー。<br />\nファイルアクセスとかネットワークアクセスとか出来るのかな?<br />\nBluetoothはどうなんだろ?<br />\nアクセス権限とかいろいろメンドクサイ処理が必要だったけど、そこまで対応してるんだろか?<br />\n気が向いたらもうちょっと調べてみるかも…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Buildozerでブロック崩しを作る</title>\n  </head>\n  <body>\n    <header>\n      <h1>Buildozerでブロック崩しを作る</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerでブロック崩しを作ってみたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>では訳も分からずとりあえずbuildして実行してみたが、\n少し何がどうなっているか調べてみたところ、\n実行の実体は<a href=\"https://github.com/kivy/python-for-android\" target=\"_blank\">python for android</a>\nというもので、Buildozerはこのプロジェクトをbuildするためのヘルパーらしい。</p>\n\n<p>で、githubのリポジトリを眺めていると<code class=\"language-plaintext highlighter-rouge\">pythonforandroid/recipes</code>にモジュールをbuildするためのレシピが置いてあるようだ。<br />\nそこに、<code class=\"language-plaintext highlighter-rouge\">pygame</code>というディレクトリがあったので、たぶんゲームを作るためのモジュールなんだろうとあたりをつけて\nぐぐってみた。</p>\n\n<p>で、<a href=\"https://python.joho.info/pygame/pygame-blockout/\" target=\"_blank\">【Pygame】ブロック崩しの作り方とサンプルコード(効果音付き)</a>\nにブロック崩しのプログラムの例があったので拝借してAndroidアプリ化してみることにした。</p>\n\n<p>今回は趣向を変えて、失敗事例も含めて書いてみる。</p>\n\n<p>以下、<a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>での環境構築が終わっているものとして進める。</p>\n\n<h1 id=\"使用したソース\">使用したソース</h1>\n<p><a href=\"https://python.joho.info/pygame/pygame-blockout/\" target=\"_blank\">【Pygame】ブロック崩しの作り方とサンプルコード(効果音付き)</a>\nのソースそのままでは動かなかったので、色々試行錯誤した結果のソースが以下。</p>\n\n<p>画像ファイルとオーディオファイルをプロジェクトフォルダに移動して\nアクセスするためのベースディレクトリを環境変数<code class=\"language-plaintext highlighter-rouge\">ANDROID_APP_PATH</code>から取得するようにした。<br />\n(相対パスだとうまく動かない。実行時のディレクトリがmain.pyがあるディレクトリと異なるため)</p>\n\n<p>あと、全画面表示にするため<code class=\"language-plaintext highlighter-rouge\">pygame.display.set_mode</code>に第2パラメータ<code class=\"language-plaintext highlighter-rouge\">(SCALED | FULLSCREEN)</code>を追加している。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pygame</span>\n<span class=\"kn\">from</span> <span class=\"nn\">pygame.locals</span> <span class=\"kn\">import</span> <span class=\"o\">*</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pygame.mixer</span>\n\n<span class=\"c1\"># ベースディレクトリの設定\n# Androidだとchdirされて相対パスでアクセスできなくなるので\n</span>\n<span class=\"n\">BASE_DIR</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getenv</span><span class=\"p\">(</span><span class=\"s\">'ANDROID_APP_PATH'</span><span class=\"p\">)</span>    <span class=\"c1\"># アプリケーションの格納されているパスを環境変数から取得\n</span><span class=\"k\">if</span> <span class=\"n\">BASE_DIR</span> <span class=\"ow\">is</span> <span class=\"bp\">None</span><span class=\"p\">:</span>\n    <span class=\"n\">BASE_DIR</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getcwd</span><span class=\"p\">()</span>                  <span class=\"c1\"># 設定されていない(Androidでない)→ カレントディレクトリを設定\n</span>\n<span class=\"c1\"># 画面サイズ\n</span><span class=\"n\">WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">400</span>\n<span class=\"n\">HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">400</span>\n<span class=\"n\">SCREEN</span> <span class=\"o\">=</span> <span class=\"n\">Rect</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">WIDTH</span><span class=\"p\">,</span> <span class=\"n\">HEIGHT</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像ファイルのパス\n</span><span class=\"n\">PADDLE_IMG_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'paddle.png'</span><span class=\"p\">)</span>\n<span class=\"n\">BLOCK_IMG_PATH</span>  <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'block.png'</span><span class=\"p\">)</span>\n<span class=\"n\">BALL_IMG_PATH</span>   <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'ball.png'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># オーディオファイルのパス\n</span><span class=\"n\">PADDLE_SOUND_PATH</span>   <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'paddle_sound.mp3'</span><span class=\"p\">)</span>\n<span class=\"n\">BLOCK_SOUND_PATH</span>    <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'block_sound.mp3'</span><span class=\"p\">)</span>\n<span class=\"n\">GAMEOVER_SOUND_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'gameover_sound.mp3'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># バドルのスプライトクラス\n</span><span class=\"k\">class</span> <span class=\"nc\">Paddle</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"c1\"># コンストラクタ\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">-</span> <span class=\"mi\">20</span>          <span class=\"c1\"># パドルのy座標\n</span>\n    <span class=\"k\">def</span> <span class=\"nf\">update</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mouse</span><span class=\"p\">.</span><span class=\"n\">get_pos</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span>  <span class=\"c1\"># マウスのx座標をパドルのx座標に\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">clamp_ip</span><span class=\"p\">(</span><span class=\"n\">SCREEN</span><span class=\"p\">)</span>                     <span class=\"c1\"># ゲーム画面内のみで移動\n</span>\n<span class=\"c1\"># ボールのスプライトクラス\n</span><span class=\"k\">class</span> <span class=\"nc\">Ball</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"c1\"># コンストラクタ\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">paddle</span><span class=\"p\">,</span> <span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">,</span> <span class=\"n\">speed</span><span class=\"p\">,</span> <span class=\"n\">angle_left</span><span class=\"p\">,</span> <span class=\"n\">angle_right</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>  <span class=\"c1\"># ボールの速度\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span> <span class=\"o\">=</span> <span class=\"n\">paddle</span>  <span class=\"c1\"># パドルへの参照\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">blocks</span> <span class=\"o\">=</span> <span class=\"n\">blocks</span>  <span class=\"c1\"># ブロックグループへの参照\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">start</span> <span class=\"c1\"># ゲーム開始状態に更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">score</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 連続でブロックを壊した回数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">=</span> <span class=\"n\">speed</span> <span class=\"c1\"># ボールの初期速度\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_left</span> <span class=\"o\">=</span> <span class=\"n\">angle_left</span> <span class=\"c1\"># パドルの反射方向(左端:135度)\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_right</span> <span class=\"o\">=</span> <span class=\"n\">angle_right</span> <span class=\"c1\"># パドルの反射方向(右端:45度)\n</span>\n    <span class=\"c1\"># ゲーム開始状態(マウスを左クリック時するとボール射出)\n</span>    <span class=\"k\">def</span> <span class=\"nf\">start</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># ボールの初期位置(パドルの上)\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span>\n\n        <span class=\"c1\"># 左クリックでボール射出\n</span>        <span class=\"k\">if</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mouse</span><span class=\"p\">.</span><span class=\"n\">get_pressed</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">move</span>\n\n    <span class=\"c1\"># ボールの挙動\n</span>    <span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">+=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centery</span> <span class=\"o\">+=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n        <span class=\"c1\"># 壁との反射\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span><span class=\"p\">:</span>    <span class=\"c1\"># 左側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>              <span class=\"c1\"># 速度を反転\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">></span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>  <span class=\"c1\"># 右側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">right</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span><span class=\"p\">:</span>      <span class=\"c1\"># 上側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n        <span class=\"c1\"># パドルとの反射(左端:135度方向, 右端:45度方向, それ以外:線形補間)\n</span>        <span class=\"c1\"># 2つのspriteが接触しているかどうかの判定\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">colliderect</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                                <span class=\"c1\"># 連続ヒットを0に戻す\n</span>            <span class=\"p\">(</span><span class=\"n\">x1</span><span class=\"p\">,</span> <span class=\"n\">y1</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">-</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">width</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_left</span><span class=\"p\">)</span>\n            <span class=\"p\">(</span><span class=\"n\">x2</span><span class=\"p\">,</span> <span class=\"n\">y2</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_right</span><span class=\"p\">)</span>\n            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span>                          <span class=\"c1\"># ボールが当たった位置\n</span>            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">y2</span><span class=\"o\">-</span><span class=\"n\">y1</span><span class=\"p\">)</span><span class=\"o\">/</span><span class=\"p\">(</span><span class=\"n\">x2</span><span class=\"o\">-</span><span class=\"n\">x1</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">x1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">y1</span>  <span class=\"c1\"># 線形補間\n</span>            <span class=\"n\">angle</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">radians</span><span class=\"p\">(</span><span class=\"n\">y</span><span class=\"p\">)</span>                     <span class=\"c1\"># 反射角度\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">*</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">cos</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">*</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">sin</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>                    <span class=\"c1\"># 反射音\n</span>\n        <span class=\"c1\"># ボールを落とした場合\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">></span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">start</span>                    <span class=\"c1\"># ボールを初期状態に\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">gameover_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">set_score</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>                               <span class=\"c1\"># スコアを0点にする\n</span>            <span class=\"c1\">#self.score.add_score(-100)                  # スコア減点-100点\n</span>\n        <span class=\"c1\"># ボールと衝突したブロックリストを取得(Groupが格納しているSprite中から、指定したSpriteと接触しているものを探索)\n</span>        <span class=\"n\">blocks_collided</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">spritecollide</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">blocks_collided</span><span class=\"p\">:</span>  <span class=\"c1\"># 衝突ブロックがある場合\n</span>            <span class=\"n\">oldrect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span>\n            <span class=\"k\">for</span> <span class=\"n\">block</span> <span class=\"ow\">in</span> <span class=\"n\">blocks_collided</span><span class=\"p\">:</span>\n                <span class=\"c1\"># ボールが左からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"ow\">and</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n                    \n                <span class=\"c1\"># ボールが右からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"ow\">and</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n\n                <span class=\"c1\"># ボールが上からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"ow\">and</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n                <span class=\"c1\"># ボールが下からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"ow\">and</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">block_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>     <span class=\"c1\"># 効果音を鳴らす\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>               <span class=\"c1\"># 衝突回数をカウント\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">add_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">*</span> <span class=\"mi\">10</span><span class=\"p\">)</span>   <span class=\"c1\"># 衝突回数に応じてスコア加点\n</span>\n<span class=\"c1\"># ブロック\n</span><span class=\"k\">class</span> <span class=\"nc\">Block</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"c1\"># ブロックの左上座標\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">+</span> <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">width</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">+</span> <span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">height</span>\n\n<span class=\"c1\"># スコア\n</span><span class=\"k\">class</span> <span class=\"nc\">Score</span><span class=\"p\">():</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">sysfont</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">font</span><span class=\"p\">.</span><span class=\"n\">SysFont</span><span class=\"p\">(</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"mi\">20</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">draw</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">screen</span><span class=\"p\">):</span>\n        <span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">sysfont</span><span class=\"p\">.</span><span class=\"n\">render</span><span class=\"p\">(</span><span class=\"s\">\"SCORE:\"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">),</span> <span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span><span class=\"mi\">255</span><span class=\"p\">,</span><span class=\"mi\">250</span><span class=\"p\">))</span>\n        <span class=\"n\">screen</span><span class=\"p\">.</span><span class=\"n\">blit</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">))</span>\n    <span class=\"k\">def</span> <span class=\"nf\">add_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">+=</span> <span class=\"n\">x</span>\n    <span class=\"k\">def</span> <span class=\"nf\">set_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">score</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"c1\"># 初期化\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># スクリーンの設定\n</span>    <span class=\"c1\"># screen = pygame.display.set_mode(SCREEN.size)\n</span>    <span class=\"n\">screen</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">display</span><span class=\"p\">.</span><span class=\"n\">set_mode</span><span class=\"p\">(</span><span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">SCALED</span> <span class=\"o\">|</span> <span class=\"n\">FULLSCREEN</span><span class=\"p\">))</span>    <span class=\"c1\"># (SCALED | FULLSCREEN) で前画面に拡大表示できる\n</span>\n    <span class=\"c1\"># オーディオ初期化\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># 各種効果音の設定\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">paddle_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">PADDLE_SOUND_PATH</span><span class=\"p\">)</span>               <span class=\"c1\"># パドルにボールが衝突した時の効果音取得\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">block_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">BLOCK_SOUND_PATH</span><span class=\"p\">)</span>                 <span class=\"c1\"># ブロックにボールが衝突した時の効果音取得\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">gameover_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">GAMEOVER_SOUND_PATH</span><span class=\"p\">)</span>           <span class=\"c1\"># ゲームオーバー時の効果音取得\n</span>    \n    <span class=\"c1\"># 描画用のスプライトグループ\n</span>    <span class=\"n\">group</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">RenderUpdates</span><span class=\"p\">()</span>  \n\n    <span class=\"c1\"># 衝突判定用のスプライトグループ\n</span>    <span class=\"n\">blocks</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Group</span><span class=\"p\">()</span>   \n\n    <span class=\"c1\"># スプライトグループに追加    \n</span>    <span class=\"n\">Paddle</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span>\n    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span>\n    <span class=\"n\">Block</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span><span class=\"p\">,</span> <span class=\"n\">blocks</span>\n\n    <span class=\"c1\"># パドルの作成\n</span>    <span class=\"n\">paddle</span> <span class=\"o\">=</span> <span class=\"n\">Paddle</span><span class=\"p\">(</span><span class=\"n\">PADDLE_IMG_PATH</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ブロックの作成(14*10)\n</span>    <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">15</span><span class=\"p\">):</span>\n        <span class=\"k\">for</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">11</span><span class=\"p\">):</span>\n            <span class=\"n\">Block</span><span class=\"p\">(</span><span class=\"n\">BLOCK_IMG_PATH</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># スコアを画面(10, 10)に表示\n</span>    <span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">Score</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>    \n\n    <span class=\"c1\"># ボールを作成\n</span>    <span class=\"n\">Ball</span><span class=\"p\">(</span><span class=\"n\">BALL_IMG_PATH</span><span class=\"p\">,</span> <span class=\"n\">paddle</span><span class=\"p\">,</span> <span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">135</span><span class=\"p\">,</span> <span class=\"mi\">45</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">clock</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">Clock</span><span class=\"p\">()</span>\n\n    <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>  <span class=\"c1\"># ループ処理の実行を継続するフラグ\n</span>\n    <span class=\"k\">while</span> <span class=\"n\">running</span><span class=\"p\">:</span>\n        <span class=\"n\">clock</span><span class=\"p\">.</span><span class=\"n\">tick</span><span class=\"p\">(</span><span class=\"mi\">60</span><span class=\"p\">)</span>      <span class=\"c1\"># フレームレート(60fps)\n</span>        <span class=\"n\">screen</span><span class=\"p\">.</span><span class=\"n\">fill</span><span class=\"p\">((</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">20</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 全てのスプライトグループを更新\n</span>        <span class=\"n\">group</span><span class=\"p\">.</span><span class=\"n\">update</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 全てのスプライトグループを描画       \n</span>        <span class=\"n\">group</span><span class=\"p\">.</span><span class=\"n\">draw</span><span class=\"p\">(</span><span class=\"n\">screen</span><span class=\"p\">)</span>\n        <span class=\"c1\"># スコアを描画  \n</span>        <span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">draw</span><span class=\"p\">(</span><span class=\"n\">screen</span><span class=\"p\">)</span> \n        <span class=\"c1\"># 画面更新 \n</span>        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">display</span><span class=\"p\">.</span><span class=\"n\">update</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># イベント処理\n</span>        <span class=\"k\">for</span> <span class=\"n\">event</span> <span class=\"ow\">in</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">event</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">():</span>\n            <span class=\"c1\"># 閉じるボタンが押されたら終了\n</span>            <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"nb\">type</span> <span class=\"o\">==</span> <span class=\"n\">QUIT</span><span class=\"p\">:</span> \n                <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"c1\"># キーイベント\n</span>            <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"nb\">type</span> <span class=\"o\">==</span> <span class=\"n\">KEYDOWN</span><span class=\"p\">:</span>\n                <span class=\"c1\"># Escキーが押されたら終了\n</span>                <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"n\">K_ESCAPE</span><span class=\"p\">:</span>   \n                    <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># 終了処理\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">quit</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">main</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>画像ファイルとオーディオファイルは参照元のページにあるリンクからダウンロードして以下のように配置する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── main.py\n├── images\n│   ├── ball.png\n│   ├── block.png\n│   └── paddle.png\n└── sound\n    ├── block_sound.mp3\n    ├── gameover_sound.mp3\n    └── paddle_sound.mp3\n</code></pre></div></div>\n\n<p>とりあえずホスト上で動作するか確認してみる。<br />\n(Android上のpython/pygameとバージョンが違うので厳密な動作確認にはならないけど、大体OKを確認したいだけなのでこれでいく)</p>\n\n<p>pygameのインストールは以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>pygame\n</code></pre></div></div>\n\n<p>WSLではデフォルトでオーディオ再生するためのライブラリ類がインストールされていないので、以下でインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>pulseaudio\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWSLってオーディオ再生できるんだ。<br />\n初めて知った…</p>\n</blockquote>\n\n<p>で実行してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python main.py\n</code></pre></div></div>\n\n<p>全画面表示になるので、終了はESCキー押下で。</p>\n\n<h1 id=\"まずは何も考えずにbuildしてみる失敗\">まずは何も考えずにbuildしてみる(失敗)</h1>\n\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>とりあえず最低限必要な修正だけで試してみる。<br />\nbuildozer.spec を以下の内容で修正。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- block0/buildozer.spec       2025-04-04 07:08:53.520218478 +0900\n</span><span class=\"gi\">+++ block1/buildozer.spec       2025-04-04 06:25:27.858934801 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n</code></pre></div></div>\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<p>しばらくするとエラーで止まる。<br />\nmk.logを確認してみると、以下のようなエラーメッセージがあった。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/Buildozer/biock1/.buildozer/android/platform/build-arm64-v8a_armeabi-v7a/build/other_builds/pygame/arm64-v8a__ndk_target_21/pygame/setup.py:70: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives\n・・・\nsrc_c/_sdl2/sdl2.c:211:12: fatal error: 'longintrepr.h' file not found\n</code></pre></div></div>\n\n<p>どうやらpygameのbuuild中に<code class=\"language-plaintext highlighter-rouge\">longintrepr.h</code>が見つからなくてエラーになっているらしい。<br />\n「longintrepr.h」でぐぐってみると、python 3.10 → 3.11 の変更で削除されたファイルらしい。</p>\n\n<h1 id=\"それならばpygameのバージョンを新しくしてbuildしてみる失敗\">それならばpygameのバージョンを新しくしてbuildしてみる(失敗)</h1>\n\n<p>pygameをpython 3.11に対応しているバージョンに変更して試してみる。<br />\n調べてみると、2.1.3からpython 3.11 に対応しているようである。</p>\n\n<p>作成済みのファイルを削除<br />\n<code class=\"language-plaintext highlighter-rouge\">buildozer android clean</code>でも良さそうだけど、念のため全部消して最初からやってみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> .buildozer bin buildozer.spec mk.log\n</code></pre></div></div>\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>buildozer.spec を以下の内容で修正。<br />\npygameのバージョンを2.1.3指定している。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- block0/buildozer.spec       2025-04-04 07:08:53.520218478 +0900\n</span><span class=\"gi\">+++ block2/buildozer.spec       2025-04-04 09:32:40.050228726 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame==2.1.3\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n</code></pre></div></div>\n\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n<p>しばらく待つと、以下のように表示されたので、buildは成功したようである。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Android packaging done!\n# APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<p>なので、実行してみる。<br />\nWindows側でadbサーバを起動しておき、以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>起動はするが、すぐに落ちてしまう。<br />\nなにやらエラーが発生している模様。ログで何が起こっているか確認する。<br />\n無関係なログも多く含まれているので、python関連のログだけ抜き出してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"nt\">-i</span> python run.log <span class=\"o\">></span> run_python.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code> に以下を追加するとlogcatのフィルタが有効になるので、設定しておくと良いかもしれない。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>android.logcat_filters = *:S python:V pythonutil:V PythonActivity:V\n</code></pre></div>  </div>\n  <p>コマンドラインで指定できると良いのがだが…\nadbを直接起動すればコマンドラインで設定できるけど。</p>\n\n  <p>タグ<code class=\"language-plaintext highlighter-rouge\">python</code>がpythonプログラム内のログ、その他は実行時の制御を行っている部分らしい。<br />\nまた、プログラム内のprintによるメッセージ出力もここに表示される。</p>\n</blockquote>\n\n<p>ログファイルの最後の部分には以下のように出力されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> I python  : Traceback (most recent call last):\n I python  :   File \"/work/Buildozer/block2/.buildozer/android/app/main.py\", line 34, in <module>\n I python  :   File \"/work/Buildozer/block2/.buildozer/android/platform/build-arm64-v8a_armeabi-v7a/build/python-installs/myapp/arm64-v8a/pygame/__init__.py\", line 70, in __getattr__\n I python  : NotImplementedError: sprite module not available (ImportError: dlopen failed: cannot locate symbol \"alphablit_alpha_sse2_argb_surf_alpha\" referenced by \"/data/data/org.test.myapp/files/app/_python_bundle/site-packages/pygame/surface.so\"...)\n I python  : Python for android ended.\n</code></pre></div></div>\n\n<p>どうやらpygameの初期化時に<code class=\"language-plaintext highlighter-rouge\">alphablit_alpha_sse2_argb_surf_alpha</code>が見つからないということらしい。<br />\n単にバージョン変えるだけではダメで、ちゃんとレシピも修正しないといけないらしい。</p>\n\n<h1 id=\"python-for-androidのバージョンを下げてみる成功\">python for androidのバージョンを下げてみる(成功)</h1>\n\n<p>python 3.10以下にして試してみることも考えたが、同様にレシピの変更なしで動くとは思えないので\npython for androidのバージョンを下げて試してみることにする。</p>\n\n<p>作成済みのファイルを削除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> .buildozer bin buildozer.spec mk.log\n</code></pre></div></div>\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>buildozer.spec を以下の内容で修正。<br />\n<code class=\"language-plaintext highlighter-rouge\">p4a.branch = release-2022.12.20</code> と指定してrelease-2022.12.20を使用するように設定している。<br />\nこのバージョンは python 3.9.9 を使用している。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gi\">+++ block3/buildozer.spec       2025-04-04 12:28:23.302885362 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n<span class=\"p\">@@ -321,7 +321,7 @@</span>\n #p4a.fork = kivy\n\n # (str) python-for-android branch to use, defaults to master\n<span class=\"gd\">-#p4a.branch = master\n</span><span class=\"gi\">+p4a.branch = release-2022.12.20\n</span>\n # (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch\n #p4a.commit = HEAD\n</code></pre></div></div>\n\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n<p>しばらく待つと、以下のように表示されたので、buildは成功したようである。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Android packaging done!\n# APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<p>なので、実行してみる。<br />\nWindows側でadbサーバを起動しておき(前のセクションで起動してれば再度実行する必要なし)、以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、動いた。<br />\nメデタシメデタシ。<br />\nログがファイルに格納され続けてしまうので、早めにCTRL+Cで止めておきましょう。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのスクロール可能なラベルのカスタムウィジェット</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのスクロール可能なラベルのカスタムウィジェット</h1>\n      <p>PythonプログラムでGUIを作成するkivyでスクロール可能なラベルのカスタムウィジェットを作ったメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>でお試しプログラムを作っていた時、\nログ出力をスクロール可能にしたい(TeraTermみたいなターミナル表示のイメージ)と思い作ってみたけれど、\n汎用的に使えそうな気がしたのでカスタムウィジェットとしてまとめてみた。</p>\n\n<h1 id=\"解説\">解説</h1>\n<p>解説するほど理解してないけど…<br />\nkivyでは文字列を表示するのにLabelウィジェットを使うらしい(AndroidStudioでいうことろのTextView?)。<br />\nで、表示をスクロールするにはScrollViewウィジェットを使う(AndroidStudioでもScrollView)。<br />\n文字列をスクロールするには、ScrollViewの中にLabelを配置してやれば良いのだけれど、「配置しておしまい」という訳でもなく、\n色々と細々と下処理が必要になる。</p>\n\n<p>まずは、表示をどの程度残すか。TeraTermやWindowsTerminalでもスクロールバッファ行数や履歴のサイズとして指定する項目。<br />\nこれを設定できないと際限なく表示が増えてしまうので。<br />\nこれを実現するため、表示内容をdequeに保存し、新規行を追加した際にあふれた分を自動的に破棄するようにしている。</p>\n\n<p>また、テキストが表示領域からあふれた際に自動的にスクロールするようにするため、ラベルの<code class=\"language-plaintext highlighter-rouge\">texture_size</code>プロパティが変更された際に\nイベントハンドラ<code class=\"language-plaintext highlighter-rouge\">update_label_size</code>がコールされるように設定。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"n\">texture_size</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_label_size</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>ここでラベルのサイズをテクスチャサイズに合わせて変更している。<br />\nまた、このときラベルサイズがスクロールビューのサイズを超えた時、<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>に設定することで\n最下行を表示できるようにしている。<br />\nなお、ラベルサイズがスクロールビューのサイズ以下の時に<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>にしてしまうと下付き表示になってしまうため、\nこの条件では<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">1,0</code>にしている。<br />\nラベルサイズがスクロールビューのサイズ以上の時に常に<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>にすると\n以前の内容を確認するためにスクロールしている状態で新しい行が表示されると最下行までスクロールしてしまうので、\n<code class=\"language-plaintext highlighter-rouge\">0.0</code>に設定するのはスクロールビューのサイズを超えた時だけにしている。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">ScrollLabel</code>クラスをインポートして使ってください。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">scrolllabel</span> <span class=\"kn\">import</span> <span class=\"n\">ScrollLabel</span>\n</code></pre></div></div>\n\n<p>設定できるプロパティは<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>のプロパティに<code class=\"language-plaintext highlighter-rouge\">rows</code>(バッファ行数)を追加しています。<br />\nプロパティに<code class=\"language-plaintext highlighter-rouge\">rows</code>は初期化時にのみ変更可能です。\n初期化後(実際は最初のテキスト出力後)は変更してもバッファ行数に反映されません。</p>\n\n<p>テキストを追加するには<code class=\"language-plaintext highlighter-rouge\">add_text(text)</code>を使用します。\n引数<code class=\"language-plaintext highlighter-rouge\">end</code>を指定することで行末文字を変更できます(デフォルトは<code class=\"language-plaintext highlighter-rouge\">\\n</code>)。  <br />\nテキストを消去するには<code class=\"language-plaintext highlighter-rouge\">clear_text()</code>を使用します。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7.js?file=scrolllabel.py\"></script>\n</dev>\n\n<p>また、gistには実際に使用する際の例(レイアウトに Kv language使用/python使用)も載せてあるのでよろしかったら見てください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>AndroidでpythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>AndroidでpythonでBLE</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerでBLE通信アプリを作ってみたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2025/04/04/Buildozer_2.html\">Buildozerでブロック崩しを作る</a>ではゲームを作ってみたが、次はペリフェラルを使ってみたくなるのが人情というもの。<br />\n<a href=\"https://bleak.readthedocs.io/en/latest/\" target=\"_blank\">Bleak</a>というモジュールがクロスプラットフォームでAndroidでも使えるらしい。<br />\nということで、Bleakを使ってBLEを使用するアプリを作って、それをBuildozerでAndroidアプリ化してみる。</p>\n\n<p>以下、<a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>での環境構築が終わっているものとして進める。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>これまで使用してきたWSL環境だとBluetoothが使用できないので、開発にはRaspberryPi5を使用することにした(Pi3以降なら大丈夫だと思う)。<br />\npyenvで仮想環境作ってkivyとbleakをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<h1 id=\"通信相手の準備\">通信相手の準備</h1>\n<p>通信相手は前に作ったランダム値を送るペリフェラルを使った。<br />\n<a href=\"https://github.com/ippei8jp/MultiBLE/tree/main/micropython\" target=\"_blank\">ここ</a>のble_RandomSensor3.py を\nRascberryPi PICO や ESP32 の micropython で動かしておく。</p>\n\n<p>micropythoの使い方は以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは下の「開く」をクリックすると表示されます。<br />\nダウンロードする場合は<a href=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1\" target=\"_blank\">こちら</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nimportしている<code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>は\n<a href=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7\" target=\"_blank\">ここ</a>\nにあります。</p>\n</blockquote>\n\n<p>用意するファイルはこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── kivy_ble.py\n└── scrolllabel.py\n</code></pre></div></div>\n\n<p>↓をクリックするとソースが開きます。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1.js\"></script>\n</dev>\n\n<h1 id=\"raspberrypiで実行\">RaspberryPiで実行</h1>\n<p>まずはPythonスクリプトが動くことを確認するために、RaspBerryPiで動かしてみる。<br />\n通信相手がいないと動かないので、事前に上の通信相手を実行しておく。</p>\n\n<p>RaspberyPi上でkivy_ble.pyを実行するとウィンドウが開くので、connectボタンをクリックする。<br />\nペリフェラルをスキャンが開始され、最初に見つかったデバイスに接続される。<br />\nさらにDATA1とDATA2のNotifyハンドラが登録され、受信データがウィンドウ右上の表示領域に表示される。<br />\ndisconnectボタンをクリックすると切断される。<br />\nQUITボタンをクリックするとプログラム終了。<br />\nウィンドウ下半分のログ表示領域には情報が表示される。この領域はスクロール可能。</p>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>と同様の手順でAndroidアプリ化していく。</p>\n\n<h2 id=\"ファイルの準備\">ファイルの準備</h2>\n\n<ul>\n  <li>BuidozerがインストールされたWSLの仮想マシンに作業ディレクトリを作成</li>\n  <li>作業ディレクトリに 上で作成した<code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code> <code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>をコピー</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code>を <code class=\"language-plaintext highlighter-rouge\">main.py</code> にリネーム</li>\n  <li>RaspberryPiの≪Bleakインストール先≫>/bleak/backends/p4android/recipes を 作業ディレクトリにコピー(ディレクトリまるごと)\n    <blockquote>\n      <p>[!NOTE]\nBleakのインストール先ディレクトリは以下のコマンドで確認できます</p>\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"bleak \"</span>\n</code></pre></div>      </div>\n    </blockquote>\n  </li>\n</ul>\n\n<p>-または以下でもOK</p>\n<blockquote>\n  <p>[!NOTE]</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> recipes/bleak\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/__init__.py\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/fix_setup.py\n</code></pre></div>  </div>\n</blockquote>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer init</code> を実行して<code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>を生成する</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>に以下の修正を加える</li>\n</ul>\n\n<dev class=\"accordion_head\"></dev>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- buildozer.spec.org  2025-04-09 07:58:44.836709400 +0900\n</span><span class=\"gi\">+++ buildozer.spec      2025-04-17 08:12:06.676451390 +0900\n</span><span class=\"p\">@@ -1,10 +1,10 @@</span>\n [app]\n\n # (str) Title of your application\n<span class=\"gd\">-title = My Application\n</span><span class=\"gi\">+title = BLE Demo\n</span>\n # (str) Package name\n<span class=\"gd\">-package.name = myapp\n</span><span class=\"gi\">+package.name = bledemo\n</span>\n # (str) Package domain (needed for android/ios packaging)\n package.domain = org.test\n<span class=\"p\">@@ -22,7 +22,7 @@</span>\n #source.exclude_exts = spec\n\n # (list) List of directory to exclude (let empty to not exclude anything)\n<span class=\"gd\">-#source.exclude_dirs = tests, bin, venv\n</span><span class=\"gi\">+source.exclude_dirs = tests, bin, venv, recipes\n</span>\n # (list) List of exclusions using pattern matching\n # Do not prefix with './'\n<span class=\"p\">@@ -37,7 +37,13 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements =\n+    python3,\n+    kivy,\n+    bleak,\n+    typing_extensions,\n+    async_to_sync,\n+    async-timeout\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n<span class=\"p\">@@ -95,7 +101,14 @@</span>\n\n # (list) Permissions\n # (See https://python-for-android.readthedocs.io/en/latest/buildoptions/#build-options-1 for all the supported syntaxes and properties)\n<span class=\"gd\">-#android.permissions = android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)\n</span><span class=\"gi\">+android.permissions =\n+    BLUETOOTH,\n+    BLUETOOTH_SCAN,\n+    BLUETOOTH_CONNECT,\n+    BLUETOOTH_ADMIN,\n+    ACCESS_FINE_LOCATION,\n+    ACCESS_COARSE_LOCATION,\n+    ACCESS_BACKGROUND_LOCATION\n</span>\n # (list) features (adds uses-feature -tags to manifest)\n #android.features = android.hardware.usb.host\n<span class=\"p\">@@ -330,7 +343,7 @@</span>\n #p4a.source_dir =\n\n # (str) The directory in which python-for-android should look for your own build recipes (if any)\n<span class=\"gd\">-#p4a.local_recipes =\n</span><span class=\"gi\">+p4a.local_recipes = ./recipes\n</span>\n # (str) Filename to the hook for p4a\n #p4a.hook =\n</code></pre></div></div>\n\n<ul>\n  <li>最終的に作業ディレクトリは以下のようになる\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>≪作業ディレクトリ≫\n├── buildozer.spec\n├── main.py\n├── scrolllabel.py\n└── recipes\n     └── bleak\n         ├── __init__.py\n         └── fix_setup.py\n</code></pre></div>    </div>\n    <h2 id=\"build\">build</h2>\n    <p>以下のコマンドでbuidする</p>\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"インストール実行\">インストール&実行</h2>\n<p>Windows側でadbサーバを起動しておき、以下を実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>connectボタンを最初にクリックした時、「この端末の位置情報へのアクセスをBLE Demoに許可しますか?」と聞かれたら「許可」をクリック\n(Androidのバージョンによって違うかもしれん。ターゲットAPIレベルで決まるんだっけ?)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのButtonの色を変更する</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのButtonの色を変更する</h1>\n      <p>kivyのButtonの色を変更する方法あれこれ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nボタン<code class=\"language-plaintext highlighter-rouge\">Button</code>の色を変更しようとすると、なかなか大変なので色々試してみたメモ。</p>\n\n<h1 id=\"画像ファイルを使用して変更する\">画像ファイルを使用して変更する</h1>\n\n<p>これが通常の方法。<br />\nプロパティ<code class=\"language-plaintext highlighter-rouge\">background_normal</code>、<code class=\"language-plaintext highlighter-rouge\">background_down</code>、<code class=\"language-plaintext highlighter-rouge\">background_disabled_normal</code>、<code class=\"language-plaintext highlighter-rouge\">background_disabled_down</code>に\nそれぞれに表示する画像ファイルを指定する。<br />\n単色で表示するなら1✕1pixelの画像ファイルでかまわない。</p>\n\n<h2 id=\"ソース\">ソース</h2>\n<p>ソースはこんな感じ。<br />\n別途画像ファイル<code class=\"language-plaintext highlighter-rouge\">lightgray.png'</code>、<code class=\"language-plaintext highlighter-rouge\">red.png</code>、<code class=\"language-plaintext highlighter-rouge\">gray.png</code>をカレントディレクトリに用意しておく。</p>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。</p>\n<dev class=\"accordion_head_close\"></dev>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.app</span> <span class=\"kn\">import</span> <span class=\"n\">App</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.button</span> <span class=\"kn\">import</span> <span class=\"n\">Button</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.lang</span> <span class=\"kn\">import</span> <span class=\"n\">Builder</span>\n\n    <span class=\"c1\"># GUIlレイアウト\n</span>    <span class=\"n\">Layout</span> <span class=\"o\">=</span> <span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">'''\n# この中はインデントに意味があるので余計なインデントを入れてはいけない\nBoxLayout:\n    orientation:'horizontal'\n    \n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n    Button:\n        id              : button_test\n        text            : \"TEST\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_test()\n        background_normal: 'lightgray.png'\n        background_down: 'red.png'\n        background_disabled_normal: 'gray.png'\n        background_disabled_down: 'gray.png'\n\n    Button:\n        id              : button_ctrl\n        text            : \"Ena/Dis\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_ctrl()\n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n'''</span>\n    <span class=\"p\">)</span>\n\n    <span class=\"k\">class</span> <span class=\"nc\">MyApp</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n        <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n            <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">__init__</span><span class=\"p\">()</span>\n            \n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span> <span class=\"o\">=</span> <span class=\"n\">Layout</span><span class=\"p\">.</span><span class=\"n\">ids</span><span class=\"p\">.</span><span class=\"n\">button_test</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_ctrl</span> <span class=\"o\">=</span> <span class=\"n\">Layout</span><span class=\"p\">.</span><span class=\"n\">ids</span><span class=\"p\">.</span><span class=\"n\">button_ctrl</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"n\">Layout</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">on_test</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'pressed'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">on_ctrl</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span><span class=\"p\">.</span><span class=\"n\">disabled</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span><span class=\"p\">.</span><span class=\"n\">disabled</span>\n            \n    <span class=\"n\">MyApp</span><span class=\"p\">().</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"動作\">動作</h2>\n\n<p>実行すると、Buttonが2つ表示され、TESTボタンが指定されたファイルのイメージで表示される。<br />\nEna/DisボタンをクリックするとTESTボタンのDisable/Enableが切り替えらる。</p>\n\n<h1 id=\"base64エンコードデータで指定\">Base64エンコードデータで指定</h1>\n\n<p>画像ファイルを使用すると、使用する色の分だけ画像ファイルを用意し、処理を流用する度に\n忘れずにすべてのファイルをコピーしないといけない。<br />\nそこで、画像ファイルをbase64エンコードした文字列をpyファイル(またはkvファイル)に保存する方法を試してみる。</p>\n\n<p>まず、上で用意したpngファイルを以下のコマンドでbase64エンコード(前に特定の文字列を付加)する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"data:image/png;base64,</span><span class=\"sb\">`</span><span class=\"nb\">base64</span> <span class=\"nt\">-w</span> 0 ≪pngファイル≫<span class=\"sb\">`</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n<p>付加されている<code class=\"language-plaintext highlighter-rouge\">data:image/png;base64,</code>は続くデータがpngイメージであることを示している。</p>\n\n<p>出力された文字列を以下のようにファイル名の代わりに記載する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        background_normal           : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2M4fPjwfwAH3wNJzT7giwAAAABJRU5ErkJggg=='\n        background_down             : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAANSURBVBhXY3gro/IfAAVUAi3GPZKdAAAAAElFTkSuQmCC'\n        background_disabled_normal  : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2Oor6//DwAFewJ9z0FqqgAAAABJRU5ErkJggg=='\n        background_disabled_down    : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2Oor6//DwAFewJ9z0FqqgAAAABJRU5ErkJggg=='\n</code></pre></div></div>\n\n<p>これにより、pngファイルを削除しても動作するようになる。</p>\n\n<p>ただし、pyファイル(またはkvファイル)が大きくなってしまうことと、一目で指定されている色が把握できないというデメリットがある。</p>\n\n<h1 id=\"canvasbefor-で指定する\">canvas.befor で指定する</h1>\n\n<p>画像ファイルを用意すること自体面倒なので、RGBA値で指定する方法はないかと考えてみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">Label</code>と同様に<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>で背景色を指定してみることを試してみたが、うまくいかなかった。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    Button:\n        ・・・\n        canvas.before:\n            Color:\n                rgba    : (1,0,0,1)\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n</code></pre></div></div>\n<p>これは<code class=\"language-plaintext highlighter-rouge\">Button</code>が<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>をサポートしていないわけではなく、\nちゃんと指定通りに描画しているが、\nその前面に<code class=\"language-plaintext highlighter-rouge\">Button</code>のBackground_XXXが表示されているためらしい。</p>\n\n<p>それならば、Buttonの表示を透明にしてやれば<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>の表示が見えるはずである。<br />\n以下のように変更して試してみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">background_color : (0, 0, 0, 0)</code>が透明色にしている部分で、<br />\n<code class=\"language-plaintext highlighter-rouge\">background_XXX</code>をヌル文字列にしているのはすべてのピクセルを(255,255,255,255)にするためであるが、\n透明になるのであまり関係ないかもしれない。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    Button:\n        ・・・\n        background_normal           : ''\n        background_down             : ''\n        background_disabled_normal  : ''\n        background_disabled_down    : ''\n        background_color            : (0, 0, 0, 0) # 透明\n        canvas.before:\n            Color:\n                rgba    : (1,0,0,1)\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n</code></pre></div></div>\n<p>これでボタンが赤色になった。<br />\nしかし、これでばボタンを押下した時やDisableにした時に色が変化しない。</p>\n\n<p>そこで、さらに以下のようにして押下した時やDisableにした時に色が変わるようにしてみた。<br />\n<code class=\"language-plaintext highlighter-rouge\">canvas.before.Color.rgba</code>を <code class=\"language-plaintext highlighter-rouge\">self.disabled</code>と<code class=\"language-plaintext highlighter-rouge\">self.state</code>によって変更している。<br />\n下にGUIリソース定義部分全体を記載しておく。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 分かりやすいようにグローバル変数で定義しておく\n#:set BG_COLOR_NORMAL   (0.75, 0.75, 0.75, 1.0)\n#:set BG_COLOR_DOWN     (1.00, 0.00, 0.00, 1.0)\n#:set BG_COLOR_DISABLED (0.50, 0.50, 0.50, 1.0)\n\nBoxLayout:\n    orientation:'horizontal'\n    \n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n    Button:\n        id              : button_test\n        text            : \"TEST\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_test()\n        background_normal           : ''\n        background_down             : ''\n        background_disabled_normal  : ''\n        background_disabled_down    : ''\n        background_color            : (0, 0, 0, 0) # 透明\n        canvas.before:\n            Color:\n                rgba    : BG_COLOR_DISABLED if self.disabled else BG_COLOR_NORMAL if self.state == 'normal' else BG_COLOR_DOWN\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n    Button:\n        id              : button_ctrl\n        text            : \"Ena/Dis\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_ctrl()\n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n</code></pre></div></div>\n\n<h1 id=\"カスタムボタンウィジェットを作成する\">カスタムボタンウィジェットを作成する</h1>\n\n<p>上でとりあえず目的は達成されたが、ボタンを配置する度に上記のような設定を書くのは面倒なので、\nカスタムボタンウィジェットを作成してみる。</p>\n\n<h2 id=\"ソース-1\">ソース</h2>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/98907d88de7106b1c30a0be4b39aa77f\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/98907d88de7106b1c30a0be4b39aa77f.js\"></script>\n</dev>\n\n<h2 id=\"解説\">解説</h2>\n<p>上の「canvas.befor で指定する」の方法をkv言語を使用せずpythonで定義している。<br />\nそれぞれの色を自由に変更できるようにプロパティを用意した。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_normal</code>   通常時の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_down</code>     押下時の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_disabled</code> 無効時の色</li>\n</ul>\n\n<p>また、そのままだとボタンを並べて表示したときに境界が分からなくなるので、枠線を描画するため、以下のプロパティを用意した。<br />\nデフォルトは黒で幅1。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">border_color</code>    枠線の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">border_width</code>    枠線の幅</li>\n</ul>\n\n<p>初期化時にボタン本体の背景を透明にし、<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>に描画命令を追加して背景の描画(背景色と枠線)することと、\n状態、位置、プロパティが変化したときに描画パラメータを再設定する処理をbindしている。<br />\nbindした処理では状態や位置に合わせて<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>の処理のパラメータを変更している。</p>\n\n<p>枠線を描画するための<code class=\"language-plaintext highlighter-rouge\">Line</code>はwidth×2の幅で描画されるようなので、本来の矩形のwidthの半分だけ内側に描画されるようにしている。</p>\n\n<p>GUIレイアウトを定義するときは、通常のButtonと同様のプロパティ設定で配置できる。<br />\nもちろん、上の通常時の色、押下時の色、無効時の色を変更したい場合は追加で指定すれば良い。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのSpinnerをカスタマイズ</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのSpinnerをカスタマイズ</h1>\n      <p>kivyのSpinner(ドロップダウンリスト)をカスタマイズする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nSpinner(ドロップダウンリスト)の項目の表示がすべて同じ色で現在選択されている項目がどれか一目で分からなかったので\n選択されている項目の色が変わるようにカスタマイズしてみた。</p>\n\n<p><a href=\"/memoBlog/2025/04/26/kivy_2.html\">kivyのButtonの色を変更する</a>ではButtonをカスタマイズして\n簡単に背景色を変更できるようにしたので、それを使えばわりとお手軽にできそうな感じ。</p>\n\n<h1 id=\"カスタマイズ内容\">カスタマイズ内容</h1>\n<ul>\n  <li>ドロップダウンの項目の表示色を選択中のものとそれ以外のもので分ける</li>\n  <li>それらの色(背景/文字)はプロパティで指定する</li>\n  <li>ドロップダウンの項目の表示高さをプロパティで指定する</li>\n</ul>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7.js\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyではドロップダウンリスト(クリックすると選択項目がぺろっと出てくるやつ)を表示するのにSpinnerウィジェットを使う。<br />\nで、クリックすると設定された項目が表示されるのだけれど、すべて同じ色(通常時、クリックした時、無効化した時の色はそれぞれ画像で指定できる)\nで表示され、現在どれを選択しているのかが分かり難い。<br />\nそこで、現在選択されている項目の色(画像でなく)を変更できるようにカスタマイズする。</p>\n\n<p>色指定に関して、<code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと項目を表示するための<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスはどちらも<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスを継承しているので、\n<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを同時に継承することで<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスに関連する処理を置き換えられる。</p>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスを作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスは特に追加する処理などはない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinnerOption</span><span class=\"p\">(</span><span class=\"n\">SpinnerOption</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n    <span class=\"k\">pass</span>\n</code></pre></div></div>\n\n<p>次に <code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinner</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinner</span><span class=\"p\">(</span><span class=\"n\">Spinner</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>追加するプロパティ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">item_selected_bg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の背景色\n</span>    <span class=\"n\">item_selected_fg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_unselected_bg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 非選択項目の背景色\n</span>    <span class=\"n\">item_unselected_fg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_height</span>          <span class=\"o\">=</span> <span class=\"n\">NumericProperty</span><span class=\"p\">(</span><span class=\"s\">'48dp'</span><span class=\"p\">)</span>               <span class=\"c1\"># 項目の高さ(デフォルトは48dp)\n</span></code></pre></div></div>\n\n<p>コンストラクタでは<code class=\"language-plaintext highlighter-rouge\">option_cls</code>のデフォルト値を<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>に設定し、基底クラスのコンストラクタを実行。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"s\">'option_cls'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">kwargs</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 項目表示用クラスが指定されていなければCustomSpinnerOptionを指定\n</span>            <span class=\"n\">kwargs</span><span class=\"p\">[</span><span class=\"s\">'option_cls'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">CustomSpinnerOption</span>\n        \n        <span class=\"c1\"># 基底クラスの初期化\n</span>        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">CustomSpinner</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>その後、追加した各プロパティと<code class=\"language-plaintext highlighter-rouge\">text</code>プロパティの変更時の処理をバインドする。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span>\n                    <span class=\"n\">text</span>                <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_bg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_bg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_fg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_fg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_height</span>         <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 項目高さ\n</span>                <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの項目の色などを変更する処理を追加。<br />\nこの処理が各プロパティの変更時の処理としてバインドされる。</p>\n\n<p>項目の一覧は<code class=\"language-plaintext highlighter-rouge\">self._dropdown.container.children</code>か<code class=\"language-plaintext highlighter-rouge\">self._dropdown.children</code>にあるので判断して取得。</p>\n\n<p>選択されている項目か否かは各項目の<code class=\"language-plaintext highlighter-rouge\">text</code>と<code class=\"language-plaintext highlighter-rouge\">self.text</code>が一致しているかどうかで判断できるので、\nこの条件で設定する色を変更。<br />\nまた、項目すべてをループするので、ついでに項目高さ(<code class=\"language-plaintext highlighter-rouge\">height</code>)も変更しておく。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ドロップダウン内の項目の高さ/背景色/文字色を更新\n</span>    <span class=\"k\">def</span> <span class=\"nf\">update_dropdown_background</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">text</span>\n        <span class=\"c1\"># 項目のリストを取得\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        \n        <span class=\"c1\"># 各項目の背景色/文字色を変更\n</span>        <span class=\"k\">for</span> <span class=\"n\">item</span> <span class=\"ow\">in</span> <span class=\"n\">items</span><span class=\"p\">:</span>\n            <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_height</span>                      <span class=\"c1\"># 項目高さ\n</span>            <span class=\"k\">if</span> <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">==</span> <span class=\"n\">text</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_bg</span>    <span class=\"c1\"># 選択中の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_fg</span>    <span class=\"c1\"># 選択中の文字色\n</span>            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_bg</span>  <span class=\"c1\"># 非選択の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_fg</span>  <span class=\"c1\"># 非選択中の文字色\n</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの更新処理をオーバーライド。<br />\nこの処理はドロップダウンの新規作成時や項目追加時にコールされる。<br />\nここに上のドロップダウンの項目の色などを変更する処理のコールを追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">_update_dropdown</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">_update_dropdown</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 項目の背景色等を更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>ついでに項目の追加処理を追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># 項目の追加\n</span>    <span class=\"k\">def</span> <span class=\"nf\">add_item</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">values</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>以上でカスタマイズは終了。</p>\n\n<h1 id=\"動作確認プログラム\">動作確認プログラム</h1>\n<p>このファイルを単体で実行すれば動作確認プログラムが動作する。<br />\n動作確認ではAddボタンをクリックする度にドロップダウンリストの項目が追加されるようになっている。<br />\nSpinnerのボタンをクリックするとドロップダウンリストが表示され、現在選択されている項目が他の色で表示されている。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyで画面遷移</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyで画面遷移</h1>\n      <p>kivyで画面遷移する方法について</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\n実行時に画面を切り替えて使用する方法について試した時のメモ。<br />\nついでにAndroidアプリ化もしてみた。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\n(multi_screenって名前はなんか違う気もするけど、複数画面を制御するってことでヨシとしとこう)</p>\n\n<h2 id=\"メイン処理スクリーンマネージャのソース\">メイン処理/スクリーンマネージャのソース</h2>\n<p>multi_screen.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=multi_screen.py\"></script>\n</dev>\n\n<h2 id=\"第1画面のソース\">第1画面のソース</h2>\n<p>screen1.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen1.py\"></script>\n</dev>\n\n<h2 id=\"第2画面のソース\">第2画面のソース</h2>\n<p>screen2.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen2.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyで画面を切り替えて使用するには、<code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承したクラスを使用し、ここに各画面を登録し、\n<code class=\"language-plaintext highlighter-rouge\">self.current</code>に表示する画面の名前(<code class=\"language-plaintext highlighter-rouge\">name</code>)を設定することで切り替えるらしい。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>今回は日本語を使ってみようと思うので、日本語フォントをインストール。<br />\n有名どころではNotoSansCJKとかTAKAOとか。<br />\nubuntuだと以下でインストールできる。<br />\nNotoSansCJK は Androidでもインストールされていることが多いのかな?(手元のちょっと古いAndroidには入ってた)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n<span class=\"c\"># または</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n<p>あと、テキスト入力も試してみるので、クリップボード操作のためのライブラリをインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>xclip\n</code></pre></div></div>\n\n<h2 id=\"multi_screenpy\">multi_screen.py</h2>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">multi_screen.py</code>の内容について。</p>\n\n<p>今回は日本語を使ってみるので、フォントディレクトリの登録と日本語対応フォントをデフォルトフォントに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">get_system_fonts_dir</span><span class=\"p\">()</span>                                        <span class=\"c1\"># フォントディレクトリにシステムフォントディレクトリを登録\n</span><span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'NotoSansCJK-Regular.ttc'</span><span class=\"p\">)</span>  <span class=\"c1\"># デフォルトフォントを設定\n</span></code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承した<code class=\"language-plaintext highlighter-rouge\">ControlScreenManager</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ControlScreenManager</span><span class=\"p\">(</span><span class=\"n\">ScreenManager</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">ControlScreenManager</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># 画面間で共有する変数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n</code></pre></div></div>\n<p>ネットで検索すると画面間で共有する変数を画面間で直接やりとりする例があったが、\nソースの再利用性などを考えてスクリーンマネージャで管理することにした。<br />\nそのための設定/取得メソッド</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ターゲット文字列の設定\n</span>    <span class=\"k\">def</span> <span class=\"nf\">set_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"n\">text</span>\n    \n    <span class=\"c1\"># ターゲット文字列の取得\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span>\n</code></pre></div></div>\n\n<p>画面切り替え処理<br />\nこれも画面から他の画面に直接遷移している例があるけど、\n一旦スクリーンマネージャでうけとってから\n遷移した方が分かりやすいと思う。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># screen1への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">SlideTransition</span><span class=\"p\">(</span><span class=\"n\">direction</span><span class=\"o\">=</span><span class=\"s\">'left'</span><span class=\"p\">,</span> <span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen1'</span>\n        \n    <span class=\"c1\"># screen2への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen2</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">FadeTransition</span><span class=\"p\">(</span><span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen2'</span>\n</code></pre></div></div>\n\n<p>アプリケーションクラス</p>\n\n<p>アプリケーションクラスのbuildメソッドでは上で定義したスクリーンマネージャのインスタンスに\n各画面のインスタンスを登録し、そのインスタンスをリターンする。</p>\n\n<p>KV言語で書く方法もあるけど、画面切り替えのときに使用する名前をここで定義できるので\nソースの見通しが良くなって好み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ScreenManager1</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># スクリーンマネージャの生成\n</span>        <span class=\"n\">sm</span> <span class=\"o\">=</span> <span class=\"n\">ControlScreenManager</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 画面1を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen1</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen1'</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 画面2を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen2</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen2'</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">sm</span>\n</code></pre></div></div>\n\n<h2 id=\"screen1py\">screen1.py</h2>\n\n<p>レイアウトの定義</p>\n\n<p>kvファイルにレイアウトを書く例が多いけど、こう書くとレイアウトと処理をまとめて書けるので好み。</p>\n\n<blockquote>\n  <p>[!NOTE]\n最近知ったけど、色指定は(rr, gg, bb, aa)(各値は0~1)と書かれている例が多いけど、\n色名(“black”とか”red”とか。指定できる色名は kivyインストールディレクトリの<code class=\"language-plaintext highlighter-rouge\">util.py</code>で定義されている<code class=\"language-plaintext highlighter-rouge\">hex_colormap</code>を参照)\nの他、”#RRGGBBAA”でも指定可能(AAは省略可能)。\nどちらも文字列指定なのでダブルクォーテーションまたはシングルクォーテーションで囲む必要あり。</p>\n\n  <p>また、サイズ類は<code class=\"language-plaintext highlighter-rouge\">dp(36)</code>みたいな書き方もできるけど、文字列で<code class=\"language-plaintext highlighter-rouge\">\"36dp\"</code>と書くこともできる。\nサイズ類は数値で指定すると単位は<code class=\"language-plaintext highlighter-rouge\">px</code>になる。</p>\n</blockquote>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen1>:\n    ・・・・\n            bg_color_normal : \"#585858ff\"       # \"coloe_name\" or \"#RRGGBB\" or \"#RRGGBAA\" or (rr, gg, bb, aa) で指定\n    ・・・・\n            item_height          : '36dp'   # 数値で指定したときの単位はpx\n    ・・・・\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nAndroidアプリ化する場合、テキスト入力が下の方にあるとソフトキーボードが出てきたときに見えなくなるので\n上の方に配置しておく方が無難。<br />\nなんかうまくやる方法があるのかもしれんけど、現状分かってない。</p>\n</blockquote>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>class Screen1(Screen):\n</code></pre></div></div>\n\n<p>あとは<code class=\"language-plaintext highlighter-rouge\">Screen1</code>クラス内で動作を定義していけば良い。<br />\n画面切り替え処理はkv言語で直接スクリーンマネージャの処理をコールすると訳わかめになるので\n一旦このクラス内で受け取ってスクリーンマネージャの処理をコールするようにしている。<br />\nこの辺は好みの問題なので、お好きにどうぞ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'switch_to_screen1'</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">switch_to_screen1</span><span class=\"p\">()</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nスクリーンマネージャはScreen派生クラスの<code class=\"language-plaintext highlighter-rouge\">self.manager</code>で取得できる。</p>\n</blockquote>\n\n<h2 id=\"screen2py\">screen2.py</h2>\n\n<p>こちらも同様にレイアウトを定義しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen2>:\n    ・・・・\n</span></code></pre></div></div>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">Screen2</span><span class=\"p\">(</span><span class=\"n\">Screen</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>画面が切り替わる前にScreen1で設定した文字列を取得したいので、<code class=\"language-plaintext highlighter-rouge\">on_pre_enter()</code>をオーバーライドする。<br />\n文字列をScreen1から直接取ると画面構成変えた時に困るので、スクリーンマネージャ経由で取得するようにしている。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">on_pre_enter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"c1\"># 表示用ラベルを書き換え\n</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">get_target_string</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"NONE\"</span>       <span class=\"c1\"># 空文字が来たらNONEに書き換え\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">text</span><span class=\"si\">}</span><span class=\"s\"> が選択されました'</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">python multi_screen.py</code>で実行。<br />\n一番上のドロップダウンリストで項目を選択し、2番目の「Go to Screen 2」ボタンを押すとScreen2に切り替わる。<br />\nScreen2では画面下側の領域にScreen1のドロップダウンリストで選択した文字列が表示される。\n「Go to Screen 1」ボタンでScreen1に戻る。<br />\nScreen1のテキスト入力欄に文字列を入力し、「ADD」ボタンをクリックするとドロップダウンリストに入力した文字列が追加される。<br />\nもちろん、その文字列を選択してScreen2に切り替えればその文字列が表示される。</p>\n\n<blockquote>\n  <p>[!NOTE]\nLunuxでは日本語入力できないみたい。ただしコピペは可能なので他のところで入力してコピペすればOK。<br />\nAndroidではそのまま日本語も入力できる。</p>\n</blockquote>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>の手順でAndroidアプリ化もできる。<br />\nここの準備が終わっていれば以下のコマンドでOK。</p>\n\n<h2 id=\"multi_screenpyをリネーム\">multi_screen.pyをリネーム</h2>\n<p>python for androidはエントリーポイントがmain.pyに固定らしいので、リネーム</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mv </span>multi_screen.py main.py\n</code></pre></div></div>\n\n<h2 id=\"buildozerspec-の生成\">buildozer.spec の生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>今回は特に編集の必要なし。\n<code class=\"language-plaintext highlighter-rouge\">title</code>、<code class=\"language-plaintext highlighter-rouge\">package.name</code>、<code class=\"language-plaintext highlighter-rouge\">package.domain</code>なんかは必要なら変更してちょ。</p>\n\n<h2 id=\"build実行\">build実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動する)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪SDK Platform-Tools <span class=\"k\">for </span>Windowsを展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>で、実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、Android上で動作した。メデタシメデタシ。<br />\n文字入力もちゃんと動いてるし、改造したボタンやスピナーも動いてる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyでドラッグで並べ替えできるリスト</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyでドラッグで並べ替えできるリスト</h1>\n      <p>kivyでドラッグで並べ替えできるリストを作った時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nドラッグで並べ替えできるリスト(AndroidでよくあるUI、<code class=\"language-plaintext highlighter-rouge\">RecycleView</code>と<code class=\"language-plaintext highlighter-rouge\">ItemTouchHelper</code>で作るんだったかな?)\nを作ってみた時のメモ。<br />\n<a href=\"https://maausa.marurm.com/wp-content/uploads/RecyclerView.gif\" target=\"_blank\">ちょっと違うけど、大体こんな感じ</a></p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nreorderablelist.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=reorderablelist.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>ソースは、表示する項目を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>と\nリスト全体を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>で構成される。<br />\n(あと、単体実行で動作するテストプログラム)<br />\n動作としては、</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>に<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を追加していきリスト化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code> をドラッグすることで並べ替え</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を左右にスワイプすることでハンドラ実行(デフォルトでは右スワイプで項目削除)\nといった感じ。</li>\n</ul>\n\n<p>テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>を<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>で囲んでスクロール可能にしています。\nスクロール不要ならそのまま配置しても可(テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">with_scroll</code>を<code class=\"language-plaintext highlighter-rouge\">False</code>に設定)。</p>\n\n<h2 id=\"reorderablelist\">ReorderableList</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>はリスト全体を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承したクラス。</p>\n\n<h3 id=\"追加したプロパティ\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>item_bg</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>item_fg</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>list_bg</td>\n      <td>リストの背景色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\n(<code class=\"language-plaintext highlighter-rouge\">orientation</code>は<code class=\"language-plaintext highlighter-rouge\">\"vertical\"</code>固定(項目を縦方向に並べるため)、\n<code class=\"language-plaintext highlighter-rouge\">size_hint_y</code>は<code class=\"language-plaintext highlighter-rouge\">None</code>固定(ScrollViewに包むため))\nのほか、<br />\n背景色の設定と、スクロール可能にするためminimum_height変更時の処理のbindを行っている。</p>\n\n<h3 id=\"項目追加処理\">項目追加処理</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">add_item</code>が項目追加処理。<br />\nパラメータは<code class=\"language-plaintext highlighter-rouge\">cls</code>で項目表示に使用するクラス(デフォルトは<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>)と、項目表示クラスの初期化パラメータを受け取る。<br />\nこれは項目に表示する内容を柔軟に切り替えられるよう、項目表示クラスを<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を継承したクラスに切り替えられるようにするため。</p>\n\n<h3 id=\"レイアウト処理\">レイアウト処理</h3>\n<p>kivyでは、レイアウトの変更命令と実際に変更が行われるまでにディレイがある。<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">add_widget(wid)</code> して直後にwid.posを読み出すと実際に追加されたあとの位置が読み出せない。<br />\nこれは、<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>では処理の予約だけ行い、実際に描画が行われるのは別のところ(<code class=\"language-plaintext highlighter-rouge\">mainloop</code>?)で\n他のウィジェットのレイアウト結果を五月雨式に反映していくため、\n描画結果がposに反映されるまでタイムラグが発生するためと思われる。</p>\n\n<p>そこで、<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>のレイアウトが変更され、処理が終了したタイミングで子ウィジェットに\nレイアウト完了を通知できるよう<code class=\"language-plaintext highlighter-rouge\">do_layout()</code>をオーバライドし、基底クラスの処理が完了した後\n各子ウィジェットの<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>をコールしている。</p>\n\n<h2 id=\"reorderableitem\">ReorderableItem</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>はリストに表示する項目を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスと<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承している。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスはドラッグ処理を実現するクラス。<br />\nもう一つの基底クラスを<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>とすることで、派生クラスのレイアウトを柔軟に設定できるようにしている。</p>\n\n<h3 id=\"追加したプロパティ-1\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>text</td>\n      <td>項目に表示する文字列</td>\n    </tr>\n    <tr>\n      <td>bg_color</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>fg_color</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ-1\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\nのほか、<br />\n項目内部の構築(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)、\n背景色の設定と、pos/size変更時にドラッグ範囲を変更する処理のbind、\nインスタンス変数の設定を行っている</p>\n\n<h3 id=\"内部ウィジェットの追加処理add_inner_widget\">内部ウィジェットの追加処理(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)</h3>\n<p>項目の内部の表示を構築する処理。<br />\nデフォルトではLabelを1個追加している。<br />\n項目の表示内容を変更したい場合は、派生クラスでこの処理をオーバライドし、\n必要な内容を追加していく。</p>\n\n<h3 id=\"ドラッグ開始処理on_touch_down\">ドラッグ開始処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_down()</code>)</h3>\n<p>まず、基底クラスのドラッグ開始処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ対象としての処理(インスタンス変数の設定)を行い、<br />\n自身の描画Canvasを親ウィジェット(<code class=\"language-plaintext highlighter-rouge\">self.parent</code>)のcanvasからcanvas.afterに繋ぎかえる。\nこれはドラッグ中の表示が前面に表示されるようにするためである。</p>\n\n<blockquote>\n  <p>[!NOTE]\n通常、add_widget()すると追加されたウィジェットの描画Canvasは親ウィジェットのCanvasに繋がれる。<br />\nこの親ウィジェットのCanvasに繋がれた描画ウィジェットは後から繋がれたものが前面に表示される。<br />\n(縦方向のBoxLayoutの場合下に表示されているウィジェットが前に表示される)<br />\n重ならない表示であれば問題ないが、ドラッグを行うとドラッグ中のウィジェットが背面に表示されることがある。<br />\nそこで、ドラッグ中のウィジェット他のウィジェットより前面に表示するため、CanvasからCanvas.afterに繋ぎかえ、前面に表示されるようにする。<br />\n仕様を読む限り、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index, canvas='after')</code>でadd_widget時にcanvas.afterに接続できるようなのだが、\n実際にはバグ(仕様制限?)により、indexが0のときのみcanvasパラメータが有効になるらしい。<br />\nこれを回避するため、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index)</code>で通常通りウィジェットを追加した後、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">after</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>として描画Canvasを繋ぎかえている。\ncanvas.afterに繋いだ描画Canvasをcanvasに戻す場合は、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">cur_index</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">children</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>    <span class=\"c1\"># canvas.after から canvasへ繋ぎかえるため\n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">remove_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>                 <span class=\"c1\"># 一旦削除して(canvasかcanvas.afterは自動的に判別してくれる) \n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"o\">=</span><span class=\"n\">cur_index</span><span class=\"p\">)</span>   <span class=\"c1\"># 再度同じ場所に挿入\n</span></code></pre></div>  </div>\n  <p>と実行する。  <code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>は描画Canvasがどこに繋がっていても探して削除してくれるので、\nそのまま実行して問題ない。</p>\n</blockquote>\n\n<h3 id=\"ドラッグ中処理on_touch_move\">ドラッグ中処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_move()</code>)</h3>\n<p>まず、基底クラスのドラッグ中処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ中の処理を行う。<br />\n親ウィジェットに繋がっている子ウィジェットをサーチして、自分以外で自分の中心がウィジェットの表示範囲内に入っているウィジェットを探す\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>)<br />\n自分の上端が対象ウィジェットの上端を超えたか、自分の下端が対象ウィジェットの下端を超えた場合は自分と対象ウィジェットを入れ替える。<br />\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>だけで判断すると、自分より高さが高いウィジェットと入れ替えるときに不都合が起こる)<br />\n位置を交換するには、自分を一旦削除(<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>)して、対象ウィジェットの位置(<code class=\"language-plaintext highlighter-rouge\">i</code>)に繋ぐ(<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>)。<br />\nその後、ドラッグを継続するので、ドラッグ開始時と同様に描画Canvasをcanvas.afterに繋ぎかえる。</p>\n\n<h3 id=\"ドラッグ終了処理on_touch_up\">ドラッグ終了処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_up()</code>)</h3>\n\n<p>まず、基底クラスのドラッグ終了処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ終了の処理を行う。<br />\nドラッグ開始/ドラッグ中処理でcanvas.afterに繋ぎかえた描画Canvasをcanvasに戻すために一旦<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>してから\n<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>する(これによりドラッグにより表示が移動していた対象ウィジェットが通常位置に戻る)。<br />\nその後、対象ウィジェットの表示位置がドラッグ開始時と変わっていなく、ドラッグした距離が設定値を超えている場合は\nスワイプ処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>または<code class=\"language-plaintext highlighter-rouge\">do_swipe_left()</code>)を実行する。</p>\n\n<h3 id=\"右へswipeしたときの処理do_swipe_right\">右へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、対象ウィジェットを削除する。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"左へswipeしたときの処理do_swipe_right\">左へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、デバッグ用にログ出力のみ。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"親ウィジェットのレイアウト完了時処理done_parent_layout\">親ウィジェットのレイアウト完了時処理(<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>)</h3>\n<p>親ウィジェットのレイアウト完了時に子ウィジェットすべてのこのメソッドがコールされる。<br />\nドラッグ中であれば必要な処理(現在位置の記憶とドラッグ中位置への移動)を行う。</p>\n\n<h1 id=\"サンプルプルグラム\">サンプルプルグラム</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nサンプルプルグラム</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=test1.py\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
        "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSB</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSB</h1>\n      <p>WSLでUSBを使った時のメモ(バージョン 2.5.7.0)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLのバージョンが2.5.7.0でカーネルバージョンが6.6.87.1-1になってカーネルの再ビルドしなくても\n色々なUSBデバイスが使えるようになったので試してみた時のメモ。</p>\n\n<p>参考:<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb\" target=\"_blank\">USB デバイスを接続する</a></p>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"windows側の準備\">windows側の準備</h2>\n<h3 id=\"usbipd-winのインストール\">usbipd-winのインストール</h3>\n<p><a href=\"https://github.com/dorssel/usbipd-win/releases\" target=\"_blank\">usbipd-winのgithub</a>からダウンロード(使用したのは5.10)<br />\nインストールはファイルをダウンロードして実行するだけ。<br />\nWindowsTerminarが開いている場合は一旦すべて閉じる(PATHの変更を有効にするため)</p>\n\n<h2 id=\"ubuntu側の準備\">Ubuntu側の準備</h2>\n<h3 id=\"systemdの有効化\">systemdの有効化</h3>\n\n<p>systemdを有効にするため、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に以下の設定を追加。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<h3 id=\"仮想usbホストコントローラインタフェースのインストール\">仮想USBホストコントローラインタフェースのインストール</h3>\n<p>ネットワーク経由でUSBデバイスを共有することを可能にするため、仮想USBホストコントローラインタフェース(vhci-hcd)をインストール\n(ドライバの組み込み)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/modules-load.d/usb.conf</code> (ファイル名は何でも可)を以下の内容で作成し、WSLの再起動。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vhci-hcd\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nお試しで1回だけ読み込むなら以下。この場合は再起動不要(というか再起動したら消える)。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo modprobe vhci-hcd\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"usbユーティリティのインストール\">USBユーティリティのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">lsusb</code>とか使いたいので、インストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>usbutils\n</code></pre></div></div>\n\n<h3 id=\"仮想マシンの再起動\">仮想マシンの再起動</h3>\n<p>設定を有効にするため、仮想マシンを再起動する。<br />\n開いているすべての仮想マシンを閉じた後、Windwos側で <code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行し、<br />\n<code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>ですべて仮想マシンのSTATEが<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていることを確認し仮想マシンを再度実行。</p>\n\n<h4 id=\"systemdが起動していることを確認する\">systemdが起動していることを確認する</h4>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>systemctl\n</code></pre></div></div>\n<p>起動していればサービス一覧が表示される。<br />\n起動していなければ以下のようなメッセージが表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>System has not been booted with systemd as init system (PID 1). Can't operate.\nFailed to connect to bus: ホストが落ちています\n</code></pre></div></div>\n\n<h4 id=\"vhci-hcdが組み込まれていることを確認する\">vhci-hcdが組み込まれていることを確認する</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsmod\n</code></pre></div></div>\n<p>表示の中に<code class=\"language-plaintext highlighter-rouge\">vhci_hcd</code>があることを確認。<br />\nなければ組み込みの設定を確認。</p>\n\n<h1 id=\"usbカメラを使ってみる\">USBカメラを使ってみる</h1>\n<p>今回は エレコムの UCAM-DLA200HBK を使用。<br />\nかなり古いカメラなのでもう売ってないけど…<br />\nUVC仕様のカメラなら基本的に同じはず。</p>\n\n<h2 id=\"ubuntu側の準備-1\">Ubuntu側の準備</h2>\n<p>今回はカメラなので、自身にvideoグループを追加<br />\n(要 再ログイン、シャットダウンは不要)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> video\n</code></pre></div></div>\n\n<h3 id=\"guvcviewのインストール\">guvcviewのインストール</h3>\n<p>表示ツールは何でもいいけど、とりあえずguvcviewで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>guvcview \n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-1\">Windows側の準備</h2>\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行\">Ubuntu側の実行</h2>\n\n<p>USB機器が割り当てられたことを確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 002: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n</code></pre></div></div>\n\n<p>デバイスノードも確認しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> <span class=\"nt\">-la</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1\n</code></pre></div></div>\n\n<p>実際に表示してみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">LANG</code>が<code class=\"language-plaintext highlighter-rouge\">ja_JP.UTF8</code>とかのままだと文字化けしてしまうので、Cに変更して実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示されるが、何も表示されない\nコンソールには「V4L2_CORE: Could not grab image (select timeout): リソースが一時的に利用できません」と表示され続ける</p>\n\n<p>GuvcviewウィンドウのVideo Controls をクリックし、</p>\n<ul>\n  <li>Frame Rate を15/1 fps</li>\n  <li>Rsolution を 160x120</li>\n  <li>Camera Output を MJPEG<br />\nにすると表示されるけど、あまり実用的ではない…</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nこれらのパラメータが選択できるかは使用するカメラによる。<br />\nPCのスペック等によって、もうちょっと大きいサイズでも表示できることがある。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n日本語で表示するには、例えば以下のように日本語フォントをインストールして\nLANGを指定せずに実行すれば良い。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"windows側の後始末\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n<h2 id=\"ということで\">ということで</h2>\n<p>あまり実用的とは言い難い結果となってしまった。</p>\n\n<h1 id=\"usbカメラをubuntu-pcからエクスポートしてみる\">USBカメラをUbuntu PCからエクスポートしてみる</h1>\n<p>試しに、Ubuntu PCからUSBカメラをエクスポートしてWSLで表示してみる。</p>\n\n<blockquote>\n  <p>[!NOTE]\n「Netive UbuntuあるならWSL使わんでも良いやん」という気もするが…</p>\n</blockquote>\n\n<h2 id=\"navive-ubuntuの準備\">Navive Ubuntuの準備</h2>\n\n<h3 id=\"カメラを接続\">カメラを接続</h3>\n<p>USBカメラを接続し、認識されているか確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 003 Device 006: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>デバイスノードの確認。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ。<br />\nカメラが他にも接続されているので2×2表示されてるけど…<br />\n今回接続されたのは2と3のはず(今はこれを使わないので気にしない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1  /dev/video2  /dev/video3\n</code></pre></div></div>\n\n<p>必要ならguvcviewをインストールして試してみてちょ。</p>\n\n<h3 id=\"linux-toolsのインストール\">linux-toolsのインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div></div>\n<p>usbipを実行してみる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div></div>\n\n<p>※ linux-tools-≪バージョン≫-generic をインストールしろと言われたら従う。例えば</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-6.5.0-41-generic\n</code></pre></div></div>\n\n<h3 id=\"ドライバの組み込みとdaemonの起動\">ドライバの組み込みとdaemonの起動</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbip-host        <span class=\"c\"># ドライバ組み込み</span>\n<span class=\"nb\">sudo </span>usbipd <span class=\"nt\">-D</span>                  <span class=\"c\"># daemon起動</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n起動時に自動で組み込み&実行したいときはsystemdでサービス登録するとできそうだけど、<br />\n本筋じゃないのでやめとく。<br />\n<a href=\"https://github.com/furbrain/systemd-usbip/blob/master/usbipd.service\" target=\"_blank\">ここ</a>\nとか参考になるかも。</p>\n</blockquote>\n\n<h3 id=\"接続されているデバイスを表示\">接続されているデバイスを表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip list <span class=\"nt\">--local</span>         <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<p>こんな感じで表示される</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\n - busid 3-11 (056e:700a)\n   Elecom Co., Ltd : unknown product (056e:700a)\n・・・\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n表示される製品名等が不明確な場合は<code class=\"language-plaintext highlighter-rouge\">lsusb</code>の結果と突き合わせてみると良い。<br />\n(IDはどちらも表示されているので、これを頼りに)</p>\n</blockquote>\n\n<h3 id=\"バインド\">バインド</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip <span class=\"nb\">bind</span> <span class=\"nt\">--busid</span> 3-11    <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<h2 id=\"wsl-ubuntuでの操作\">WSL Ubuntuでの操作</h2>\n\n<h3 id=\"linux-toolsのインストール-1\">linux-toolsのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">usbip</code>はWindows側でインストールしたusbipd-winに含まれているのでインストール不要。<br />\n別途aptでインストールしても使えるけど結構メンドクサイ。<br />\n使いたくなることもあるかもしれんので、手順は残しておく。</p>\n\n<blockquote>\n  <p>[!NOTE]</p>\n\n  <p>usbipが入っているパッケージをインストール</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div>  </div>\n  <p>usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>たぶんこんなメッセージが出る</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>WARNING: usbip not found for kernel 6.6.87.1-microsoft\n\n  You may need to install the following packages for this specific kernel:\n    linux-tools-6.6.87.1-microsoft-standard-WSL2\n    linux-cloud-tools-6.6.87.1-microsoft-standard-WSL2\n\n  You may also want to install one of the following packages to keep up to date:\n    linux-tools-standard-WSL2\n    linux-cloud-tools-standard-WSL2\n</code></pre></div>  </div>\n  <p>しかし、指定されたパッケージをインストールしようとしても「そんなもんはない」と怒られる。<br />\nしかたないのでゴマカシ。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /usr/lib/linux-tools\n\n<span class=\"nb\">ls</span> <span class=\"nt\">-la</span>\n合計 12\ndrwxr-xr-x  3 root root 4096  6月  6 13:11 <span class=\"nb\">.</span>\ndrwxr-xr-x 65 root root 4096  6月  6 13:11 ..\ndrwxr-xr-x  2 root root 4096  6月  6 13:11 6.8.0-60-generic    ← これを覚えておく\n</code></pre></div>  </div>\n  <p>isbipを実行した時のメッセージとlsしたときのディレクトリ名から以下のようなシンボリックリンクを作成する<br />\n(カーネルバージョンが変わると変更しないといけないので注意)</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ln</span> <span class=\"nt\">-s</span> 6.8.0-60-generic 6.6.87.1-microsoft-standard-WSL2\n</code></pre></div>  </div>\n\n  <p>再度usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>USAGEが表示されたらOK。<br />\nまたWARNINGが表示されたらシンボリックリンクの名前が間違っていると思うので、再確認。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nusbipコマンドへのpathを設定してもsudoで実行するときは無効なので、設定せずfullpathで指定する</p>\n</blockquote>\n\n<h3 id=\"アタッチ可能なバス番号を調べる\">アタッチ可能なバス番号を調べる</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip list <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫\n</code></pre></div></div>\n<p>こんな感じで表示される(BUSIDは例。以下同じ)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Exportable USB devices\n======================\n - ≪UbuntuPCのIPアドレス≫\n       3-11: Elecom Co., Ltd : unknown product (056e:700a)\n           : /sys/devices/pci0000:00/0000:00:14.0/usb3/3-11\n           : Miscellaneous Device / ? / Interface Association (ef/02/01)\n</code></pre></div></div>\n<h3 id=\"アタッチする\">アタッチする</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip attach <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫ <span class=\"nt\">--busid</span> 3-11\n</code></pre></div></div>\n\n<h3 id=\"確認\">確認</h3>\n<p>アタッチできたか確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 001 Device 003: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>前と同様にguvcviewを実行してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示され、画像が表示される。<br />\nそれなりに大きなサイズに切り替えても表示できている。</p>\n\n<h3 id=\"後片付け\">後片付け</h3>\n<p>usbipのポートの確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip port\n</code></pre></div></div>\n<p>こんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Imported USB devices\n====================\nPort 00: <Port in Use> at High Speed(480Mbps)\n       Elecom Co., Ltd : unknown product (056e:700a)\n       1-1 -> unknown host, remote port and remote busid\n           -> remote bus/dev 003/006\n</code></pre></div></div>\n<p>ポートは0であることが分かる。</p>\n\n<p>デタッチする</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo /mnt/c/Program\\ Files/usbipd-win/WSL/usbip detach --port 0\n</code></pre></div></div>\n\n<h3 id=\"まとめ\">まとめ</h3>\n<p>ということで、どうも、USBIPD-WINの転送速度が遅いようだ。</p>\n\n<h1 id=\"bluetoothを使ってみる\">Bluetoothを使ってみる</h1>\n<p>カメラはビミョーな結果だったので、今度はBluetoothで試してみる。\n使用したのは Buffalo BSBT4D09BK(4.0+EDR/LEのアダプタ、中身はCSR製)。<br />\nこれも結構古いのでもう売ってない。  中身がCSRのアダプタなら動く可能性高い。<br />\nRealtekのも使えそうだけど、試してないのでなんとも…</p>\n\n<h2 id=\"ubuntu側の準備-2\">Ubuntu側の準備</h2>\n<p>今回はBluetoothなのでBluetooth関連のライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>bluez\n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-2\">Windows側の準備</h2>\n<p>USBipd-win</p>\n\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行-1\">Ubuntu側の実行</h2>\n\n<h3 id=\"usb機器が割り当てられたことを確認する\">USB機器が割り当てられたことを確認する。</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 003: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)\n</code></pre></div></div>\n\n<h3 id=\"動かしてみる\">動かしてみる</h3>\n<p>ローカルデバイスの一覧表示をしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>hcitool dev\n</code></pre></div></div>\n<p>例えばこんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Devices:\n        hci0    XX:XX:XX:XX:XX:XX\n</code></pre></div></div>\n\n<p>スキャンしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bluetoothctl\n</code></pre></div></div>\n<p>bluetoothctlが起動され、プロンプトが<code class=\"language-plaintext highlighter-rouge\">[bluetooth]#</code>になる。<br />\nスキャンしてデバイス一覧を見てみる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>scan on\n≪スキャンされたデバイスが表示される≫\n≪しばらく待つ≫\nscan off\n≪表示が止まる≫\n\nlist\n≪スキャンされたデバイスが表示される≫\n\nexit\n≪終了してshellに戻る≫\n</code></pre></div></div>\n\n<h3 id=\"pythonで動かしてみる\">pythonで動かしてみる。</h3>\n<p>pyenvでpythonをインストールする場合は\n<a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a>\n の注意書きにあるように、コンパイル前に以下を実行しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<p>新しくプログラム作るのは面倒なので以前作った <br />\n<a href=\"/memoBlog/2025/04/21/Buildozer_3.html\" target=\"_blank\">AndroidでpythonでBLE</a> <br />\nを実行してみる。</p>\n\n<p>必要なモジュール類をインストールして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libmtdev-dev\npip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<p>実行</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">python</span> <span class=\"n\">kivy_ble</span><span class=\"p\">.</span><span class=\"n\">py</span>\n</code></pre></div></div>\n\n<p>動いた。メデタシメデタシ。</p>\n\n<h2 id=\"windows側の後始末-1\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n<p>USB接続のSDカードリーダを使えばRaspberryPiのブート用SDカードをWSLにマウントして操作することも可能なはず。<br />\nメンドクサくなってきたので試すのはやめておくけど。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
      ],
      "label": "posts",
      "permalink": "/:categories/:year/:month/:day/:title:output_ext"
    }
  ],
  "html_pages": [
    "# site変数\n```\nsite = \n{{ site | inspect }}\n```\n\n# site.tags変数\n```\nsite.tags = \n{{ site.tags | inspect }}\n```\n\n# site.tags のキー 一覧\n{% assign tag_keys = \"\" | split: \"|\" %}\n{% for item in site.tags %}\n  {% assign tag_keys = tag_keys | push: item[0] %}\n{% endfor %}\n\n```\n{{ tag_keys  | inspect }}\n```\n\n# site.posts[1]変数\n```\nsite.posts[1] = \n{{ site.posts[1] | inspect }}\n```\n<!-- {% comment %}  HTMLのコメントだけだとLiquidの処理は止まらないので、コメント中にでっかいデータが出力されてしまう\n# site.tags[0]変数\n\n```\n{{ site.tags[\"サンプル\"] | inspect }}\n```\n\n# site.tags.keys変数\n\n```\n{{ site.tags.keys | inspect }}\n```\n\n# site.tags変数\n\n```\n{{ site.tags | inspect }}\n```\n# site.tags[\"サンプル\"]変数\n\n```\n{{ site.tags[\"サンプル\"] | inspect }}\n```\n\n# site.tags[\"サンプル\"][0]変数\n\n```\n{{ site.tags[\"サンプル\"][0] | inspect }}\n```\n# page.tags | array_to_sentence_string\n\n```\n{{ page.tags | array_to_sentence_string }}\n```\n{% endcomment %}-->\n",
    "Dockerコンテナを開発環境として使用する場合にイメージ作成時に設定しておくと便利なことなど。  \n\n以下、特に断りのない限りベースイメージはubuntu。  \nおそらくdebianでも同じだと思う。  \n\n# sudo を使えるようにする  \n\nDockefileに以下を記述  \n```bash\nRUN apt update && apt -y install sudo \\\n    && echo «ユーザ名» ALL=\\(root\\) NOPASSWD:ALL > /etc/sudoers.d/«ユーザ名» \\\n    && chmod 0440 /etc/sudoers.d/«ユーザ名»\n```\n>[!NOTE] \n> exec時に--userオプション付けてrootで入ればいいんだけどね。  \n> 逐一別ウィンドウでexecするのは面倒なので。  \n> あと、sudoをパスワードなしで実行できるようにしておかないと悲しいことになるので注意。  \n\n# bashの補完機能を有効にする  \n\nDockefileに以下を記述  \n```bash\nRUN apt update && apt install bash-completion \\\n    && echo \". /usr/share/bash-completion/bash_completion\" >> /etc/bash.bashrc\n```\n\n# コマンドヒストリのサーチ機能を^p/^nにマッピングする  \n\nDockefileに以下を記述  \n(リダイレクト先はユーザのホームディレクトリの.bashrcでも可)  \n```bash\nRUN echo -e \"\\\nbind '\\\"\\C-n\\\": history-search-forward' \\n\\\nbind '\\\"\\C-p\\\": history-search-backward'\\n\\\n\">> /etc/bash.bashrc\n```\n\nこのままだと、^pを2回押さないと順方向サーチができないので  \nホストの .docker/config.json に以下を記載しておく。  \n```\n{\n    \"detachKeys\": \"ctrl-\\\\\"\n}\n```\n>[!NOTE]\n> コンテナからのデタッチキーが``^\\``に変更される。  \n> 詳細は「Docker detachKeys」で検索。  \n\n\n# 日本語を文字化けしないようにする  \n\nDockefileに以下を記述  \n```bash\nRUN echo -e \"\\\nexport LANG=C.UTF-8\nexport LANGUAGE=en_US:\n\">> /etc/bash.bashrc\n```\n>[!NOTE]\n> LANG=ja_JP.UTF-8 だとダメ。\n\n# Dockerコンテナ内にpingがなかったら\n\nコンテナ作成後に気が付いたら、以下でping他をインストールする。  \n```bash\napt update\napt install iputils-ping  net-tools\n```\n",
    "# git\n\n## checkoutしてブランチを作成する\n```bash\ngit checkout -b «ブランチ名» refs/tags/«タグ名»\n```\n\n## ブランチを切り替える\n```bash\ngit checkout «ブランチ名»\n```\n\n## リモートリポジトリと同期する\n\n必要ならmasterブランチに切り替えてから実行する ``git checkout master``\n\n```bash\ngit pull\n```\n\n## ブランチ間のdiff\n```bash\ngit diff «比較元ブランチ名» «比較先ブランチ名» [ファイル名 | ディレクトリ名]\n```\n\n## 管理対象外のファイルを表示する\n\n管理対象外のファイルをすべて表示する\n\n```bash\ngit ls-files --others\n```\n\n管理対象外のファイルを.gitignoreの無視ファイルを反映して表示する\n\n```bash\ngit ls-files --others --exclude-standard\n```\n\n# こんなページもあるよ\n[VSCodeでのGitの基本操作まとめ](https://qiita.com/y-tsutsu/items/2ba96b16b220fb5913be){:target=\"_blank\"}\n\n",
    "# Googleドライブ上のファイルを直接ダウンロードする\n\nスクリプト上でgoogleドライブの共有ファイルをwget(やcurl)で取得する方法  \n共有リンクをwgetにそのまま渡すとヘッダとか色々くっついて保存されてしまうので。  \n\n## ファイルIDの取得\n以下のいずれかの手順でファイルIDを取得する  \nこの「ほげほげ」の部分がファイルIDを示している。下記2つの「ほげほげ」は同一のハズ。\n\n> googleドライブ上の共有したいファイルを右クリック→共有可能なリンクを取得  \n> クリップボードに 以下のリンクが保存される  \n> ``https://drive.google.com/open?id=ほげほげ ``  \n\n\n> 共有設定で以下のリンクが取得できる  \n> ``https://drive.google.com/file/d/ほげほげ/view?usp=sharing``  \n\n## ファイルのダウンロード\n以下のコマンドで取得できる。  \nFILE_IDとFILE_OUTは1回しか使わないから、コマンドに直接書けばいいんだけど、下のとの整合のために使っておく。  \n```bash\nFILE_ID=ほげほげ\nFILE_OUT=保存ファイル名\nwget \"https://drive.google.com/uc?export=download&id=${FILE_ID}\" -O ${FILE_OUT}\nunset FILE_ID\nunset FILE_OUT\n```\n## 大きなファイルのダウンロード\n大きなファイルの場合、上記の方法でダウンロードしようとすると「ウィルススャンできんけどダウンロードする?」なページが取得されてしまう。  \nで、以下のコマンドで取得する。  \n```bash\nFILE_ID=ほげほげ\nFILE_OUT=保存ファイル名\nwget --load-cookies /tmp/cookies.txt \"https://drive.google.com/uc?export=download&confirm=$(wget --quiet --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate \"https://drive.google.com/uc?export=download&id=${FILE_ID}\" -O - | sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\\1\\n/p')&id=${FILE_ID}\" -O ${FILE_OUT} && rm -rf /tmp/cookies.txt\nunset FILE_ID\nunset FILE_OUT\n```\n>[!NOTE]\n> $()の内側のwgetで一度ダウンロード要求を送って、「ウィルススャンできんけどダウンロードする?」なページを取得。  \n> このときのcookieを保存しておく(--save-cookies オプション)。  \n> 取得したページの実際のファイルのダウンロードへのリンク部分から「confirm=XXXX」の部分を取り出し。  \n> で、その時のcookieとXXXXの部分を使用して外側のwgetでファイルを取得する。  \n> 最後に不要になったcookie保存ファイルを削除。  \n",
    "",
    "# pyenvのインストール\n\n[pyenvのインストール]({{ site.baseurl }}/2019/06/27/pyenv.html)  \n\n## pyenv-virtualenvでベースバージョンにインストールされたパッケージを参照できるようにする\n\n以下のように``--system-site-packages``オプションを指定する。  \n```bash\npyenv virtualenv --system-site-packages «バージョン» «仮想環境名»\n```\n\n\n\n# csvファイルをエクセルファイルに変換する\n\n[csvファイルをエクセルファイルに変換する]({{ site.baseurl }}/2020/06/29/csv2xls.html)  \n\n\n# pipでインストールしたモジュールの依存関係の確認方法\n\npipでインストールしたモジュールの依存関係を知りたいときがたまにある。  \nそんな場合は、以下の手順で。  \n\nまずは必要なモジュールのインストール  \n```bash\npip install pipdeptree\n```\n\n以下を実行  \n```bash\npipdeptree\n```\n参考:[Python: pipdeptree でパッケージの依存関係を調べる](https://blog.amedama.jp/entry/2016/05/29/182402?fbclid=IwAR1HwuEEKG3-lbCYNJeDBpwgBDZsNae3Ww6GYwrMCFjXt7kqo5-iAyaOXNI)\n\nちなみに、依存関係の矛盾がないかだけ確認したいなら、以下のコマンドでも可能。  \nこっちは特にインストールする必要はない。  \n```bash\npip check\n```\n\n# sudo で pyenv環境のpythonを使用する方法\n通常、pyenv環境を設定していてもsudoでroot権限でスクリプトを実行するとsystemのpython(``/usr/bin/python*``)で実行される。  \nsudoでもpyenvで指定したバージョンのpythonで実行するには``/etc/sudoers`` の ``secure_path=``の先頭に以下を追加する  \n```\n«pyenvインストールディレクトリ»/plugins/pyenv-virtualenv/shims:«pyenvインストールディレクトリ»/shims:«pyenvインストールディレクトリ»/bin:\n```\n例えばこんな感じ。  \n```\n/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:\n```\n\n実行の際は ``-E``オプションをつけて環境変数を引き継いで実行する。  \n```\nsudo -E python ~\n```\nこの方法でpyenvコマンドも使えるようになる(``pyenv local``くらいしか使い道はないけど)  \n\n\n",
    "# ダウンロードページ\n[Raspberry Pi OS](https://www.raspberrypi.com/software/operating-systems/){:target=\"_blank\"}  \n<small>ページ構成がコロコロ変わるので、このリンクもいつまで正しいやら...</small>\n\n# ドキュメント\n[Raspberry Pi Documentation](https://www.raspberrypi.com/documentation/computers/){:target=\"_blank\"}  \n\n\n# Raspberry Pi OS(64bit)のインストール\n[Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール]({{ site.baseurl }}/2022/02/25/raspios_64_20220128.html){:target=\"_blank\"}  \n\n# SDカードイメージファイルの作成\n[Raspbian SDカードイメージファイルの作成(改訂版)]({{ site.baseurl }}/2021/07/18/sd_image_2.html){:target=\"_blank\"}  \n\n# Raspbian Busterのインストール【旧バージョン】\n[Raspbian Busterのインストール]({{ site.baseurl }}/2019/08/31/raspbian_buster_1.html){:target=\"_blank\"}  \n[Raspberry Pi OS(May 7th 2021)のインストール]({{ site.baseurl }}/2021/07/17/raspios_20210507.html){:target=\"_blank\"}  \n\n\n# Raspbian Buster Lite版のインストール【旧バージョン】\n[Raspbian Buster Lite版のインストール]({{ site.baseurl }}/2019/09/13/raspbian_buster_2.html){:target=\"_blank\"}  \n\n# モバイル ホットスポットでRaspberryPiをネットに接続\n[モバイル ホットスポットでRaspberryPiをネットに接続]({{ site.baseurl }}/2019/09/12/mobilehotspot.html){:target=\"_blank\"}  \n\n# VNCタイムアウトの変更\nRasPiにWindowsからVNC Viewerでつないでいると、しばらくほったらかしにすると切断されてしまう。  \nこれを防ぐには、  \n\n- RasPi側のタスクバーのVNCのアイコンを右クリック → Options... → Expert   \n- パラメータで「IdleTimeout」を探す\n- 設定値を「0」に変更(デフォルトは3600(=60分)になっている)\n\nこれでタイムアウトで切断されなくなる  \n\n# IPv6の無効化\n- ``/etc/sysctl.conf``に以下を追加する  \n```\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\n```\n- 以下を実行する  \n```bash\nsudo sysctl -p\n```\n\n# Windowsの共有フォルダのマウント\n\n## Windows側の準備\nWindows側でネットワーク共有したいフォルダを共有に出しておく。  \nめんどくさいのでEveryone フルアクセスで共有に出しておく(自宅なら問題ないでしょう)  \n\n## RasberryPi側でのマウント\n```bash\nsudo mount -t cifs «ネットワークパス» «マウントポイント» -o uid=«linuxのユーザ名»,gid=«linuxのグループ名»,user=«Windowsのユーザ名»,password=«Windowsのパスワード»\n```\n\n【注意】  \n- ネットワークパスのマシン名はNetBIOSの名前(MY_PC)ではなく、mDNSで解決できる名前(MY_PC.local)なので注意。もちろん、IPアドレス直接指定でも問題なし。\n- Everyonで共有に出してあってもanonymousでアクセス出来るわけではないらしいので、Windowsのユーザ名とパスワードは必要。\n- uidとgidは指定してないとオーナがrootになってしまうので、フォルダ内のファイルに書き込みたい場合は指定が必要。\n\n\n例えば、こんな感じ。  \n```bash\nmount -t cifs //MY_PC.local/Share1 /mnt -o uid=hoge,gid=hoge,user=fuga,password=fugafuga\n```\n\n参考: <https://qazsedcftf.blogspot.com/2019/12/raspberry-pi_21.html>\n\n# バージョン情報の取得\n\n## ハードウェアの情報\n```bash\ncat /proc/device-tree/model\nRaspberry Pi 4 Model B Rev 1.2\n```\n\n## カーネルバージョン等の情報\n```bash\n~$ uname -a\nLinux Pi4 5.10.17-v7l+ #1421 SMP Thu May 27 14:00:13 BST 2021 armv7l GNU/Linux\n```\n\n## ディストリビューションやバージョンの情報\n```bash\n~$ lsb_release -a\nNo LSB modules are available.\nDistributor ID: Raspbian\nDescription:    Raspbian GNU/Linux 10 (buster)\nRelease:        10\nCodename:       buster\n```\n\n\n\n\n\n\n\n",
    "このページのソース:<https://raw.githubusercontent.com/ippei8jp/memoBlog/master/misc/sample.md>\n\n# 見出し1\n\n## 見出し2\n\n### 見出し3\n\n#### 見出し4\n\n##### 見出し5\n\n###### 見出し6\n\n本文1  \n改行後\n\n本文2\n\nほげ(見出し1の別の書き方)\n=======================\n\nふが(見出し2の別の書き方)\n-----------------------\n\n\n# 番号なしリスト\n\n- リスト1\n    - ネスト リスト1_1\n        - ネスト リスト1_1_1\n        - ネスト リスト1_1_2\n    - ネスト リスト1_2\n- リスト2\n- リスト3\n\n# 番号付きリスト\n\n1. 番号付きリスト1\n    1. 番号付きリスト1_1\n    1. 番号付きリスト1_2\n1. 番号付きリスト2\n1. 番号付きリスト3\n\n# 水平線\n\n---\n\n# 強調\n\n通常 *emで強調* 通常  \n通常 **strongで強調** 通常  \n通常 ***em+strongで強調*** 通常  \n\n通常 ~~取り消し線~~ 通常  \n\n# 表\n\n|項目1|項目2|項目3|\n|:--|:--:|--:|\n|align left|align center|align right|\n|a|b|c|\n|=|=|=|\n|フッター1|フッター2|フッター3|\n\n# ノートブロック\n> [!NOTE]\n> This is a NOTE\n\n> [!WARNING]\n> This is a WARNING\n\n> [!ERROR]\n> This is a ERROR\n\n> [!TIP]\n> This is a TIP\n\n> [!IMPORTANT]\n> This is IMPORTANT\n\n> Other\n> This is other note\n\n> Other\n> This is other note\n>> Other nested\n>> This is other note2\n>\n>> [!TIP]\n>> This is a TIP\n\n\n# コードブロック\n\n```python\n# 言語指定あり\nprint(\"Hello world!\")\n```\n\n```\n# 言語指定なし\nprint(\"Hello world!\")\n```\n\n<!-- ファイル名を付けたいときはこれを指定-->\n{% include filename.html filename=\"hoge.py\" %}\n```python\n# 言語指定あり スクロールバーあり\nprint(\"Hello world!\")\n\"\"\"\n12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n\"\"\"\n```\n\n# コメント\n\nコメント(その1)の上\n{::comment}\nここはコメントなので表示されることはありません。\nHTMLには出力されます。\n{:/comment}\nコメント(その1)の下\n\n\nコメント(その2)の上\n{% comment %}\nここはコメントなので表示されることはありません。\nHTMLにも出力されません。\n{% endcomment %}\nコメント(その2)の下\n\n\n# 参照\n\n[Markdown (kramdown) のリファレンス](http://mae0003.github.io/markdown/2015/06/21/kramdownRefference)\n\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n",
    "# ファイル(ファイルマネージャ)のアドレスバーをテキスト形式にする\nファイルマネージャのアドレスバーが気持ち悪いので、見慣れたテキスト形式にしたい場合は以下のコマンドで。  \n```bash\ngsettings set org.gnome.nautilus.preferences always-use-location-entry true\n```\n>[!NOTE]\n> 一時的にテキスト形式にした場合は「CTRL+L」  \n\n\n# これまでに apt でインストールしたパッケージを調べる\n\n\n``apt`` でインストールされたパッケージ一覧は ``apt list --installed ``で取得できるけど、  \n自分で入れたのか関連パッケージで入ったのかがイマイチよくわからないのと、  \n実際にどんなパッケージ名でインストールすれば良いのかが分かりにくいので。  \n\n```bash\nzgrep -1 install `ls -tr /var/log/apt/history.log*`\n```\n\nlsのオプションで``-tr``を指定しているのでタイムスタンプが古いファイルから検索される(つまり``apt``実行の古い順)。  \nコマンドラインの一つ前の行に実行日時、一つ後ろの行に実行者が入っているので、これを目安に必要な情報をピックアップできる。  \n\"install\" をgrepで引っかけているので、たまに余計なのも引っかかるけど、ご愛敬ということで(笑)。  \n\nアンインストールしたのは別途調べないといけないけど…  \nremoveとpurgeで引っかければいけるかな?  \nこんな感じ。  \n\n```bash\nzgrep -1 -e remove -e purge `ls -tr /var/log/apt/history.log*`\n```\n\n> [!NOTE]\n現在インストール済みパッケージを知りたいだけなら以下でも大丈夫。  \n```bash\napt list --installed\n```\n手動でインストールしたものだけ取得したい場合は以下(つまり、関連パッケージとしてインストールされたものを除く)。  \n```bash\napt list --installed | grep -v 自動\n```\n\n# ファイルがどのパッケージに含まれているかを調べる方法\n\nコマンドを実行して○○が見つからないと言われて、どのパッケージをインストールすれば良いのか分からないときに。  \n\n最初に``apt-file``をインストール  \n```bash\nsudo apt install apt-file\n```\n\n実行前に以下でパッケージ情報を更新しておく。そんなに頻繁にやらなくても良い。  \n```bash\nsudo apt-file update \n```\n\nで、以下で検索。  \n```bash\napt-file search ○○\n```\n\n逆にパッケージに含まれるファイル一覧を取得したい場合は以下。  \n```bash\napt-file show <パッケージ名>\n```\n\n# リソースモニタツール netdataのインストール\n\n## ツールのインストール  \n```bash\nsudo apt update\nsudo apt install netdata\n```\n\n## 設定変更\nリモートマシンからブラウズできるように、``/etc/netdata/netdata.conf``の\n``bind socket to IP``の設定値を``0.0.0.0`` に変更する。\n\n## サービスの再起動\n設定を変更したので再起動。  \n```bash\nsudo systemctl restart netdata \n```\n\nあとはブラウザで対象マシンのポート19999 にアクセスすればOK  \n```\nhttp://192.168.XXX.XXX:19999\n```\n\n\n\n# VirtualBox上のUbuntuとclipboardの共有がおかしくなったときの対処方法\n\nVirtualBox上のUbuntuでclipboardの共有の動作がおかしくなることがある。  \nその場合、以下で対応可能。  \n\n- 現状のプロセスを確認\n\n```bash\nps aux | grep 'VBoxClient --clipboard' | grep -v grep\n```\n\n- プロセスが存在することを確認\n\n- プロセスのkill\n\n```bash\npkill -f 'VBoxClient --clipboard'\n```\n\n- プロセスの再起動\n\n```bash\n/usr/bin/VBoxClient --clipboard\n```\n\nこれで正常にclipboardの共有ができるようになるはず。  \n\n\n# ubuntu 18.04 で IPv6を無効にする方法\n\nubuntu 18.04 では IPv6を無効にする方法には、以下の手順で行う。  \n\n- ``/etc/sysctl.d/99-sysctl.conf`` に以下の内容を追加。\n\n```\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\nnet.ipv6.conf.lo.disable_ipv6  =  1\n```\n\n- サービスの再読み込み\n\n```bash\nsudo sysctl -p\n```\n\n- ``/etc/rc.local`` に以下を追記(なければ新規作成)\n\n```\n#!/bin/bash\n/etc/init.d/procps restart\n\nexit 0\n```\n\n- 新規作成した場合は実行属性を追加  \n\n```bash\nsudo chmod 755 /etc/rc.local\n```\n\nこれで起動の度にIPv6は無効になる。  \n\n参考: [Ubuntu 18.04 で ipv6 を無効にする](https://www.rough-and-cheap.jp/ubuntu/ubuntu18_04_howto_diseable_ipv6/?fbclid=IwAR3_ZYqE7IJOg-1FMczHdoJ7zztDrVojHfU8VF-Zbu6e1cRT-6IGg3hVtIA)\n\n\n# lessのオプション\n\nlessのオプションで便利そうなもの一覧。  \n\n- ANSI Color Escape Sequenceを色表示する(-R)\n- 検索ワードの大文字小文字を区別しない(-i)\n    - 検索ワードに大文字を含めると区別するようになる。\n- 画面右端で折り返さない(-S)\n    - 矢印キー(←→) で横スクロールできる。\n- ファイル名、現在の表示位置などを表示する(-M)\n- 行番号表示(-N)\n\nデフォルトのオプションを指定するには ``.bachrc`` に以下のように追加しておけば良い。  \n```bash\nexport LESS=\"-iMR\"\n```\n\nlsやgrepの出力をlessしたときも色付きで表示する方法\n```bash\nls --color=always | less -R\ngrep --color=always if .bashrc | less -R\n```\n\n``.bashrc`` に 以下を設定しておくと便利かと思ったけど...  \nただし、同時にlessのデフォルトオプションに``-R`` を指定しておかないと悲しいことになる。  \nでも、ファイルにリダイレクトしたときに悲しいことになるので、やめておいた方が無難...  \n\n```bash\nexport LS_OPT='--color=always' \nexport GREP_OPT='--color=always' \nalias ls='ls ${LS_OPT}'\nalias grep='grep ${GREP_OPT}'\n```\n# ファイルの\"START\" から \"END\" までを抽出する\n\n```bash\nsed -n \"/START/,/END/p\" «ファイル名»\n```\n\n# bashスクリプトのコメント\n\n## ブロックコメント\n\nブロックコメントそのものは存在しないが、ヒアドキュメントを応用すれば出来る。  \n具体的には、コメント部分を``<<キーワード`` と``キーワード``で囲む。\n\n```bash\n<< キーワード\n~~コメント~~\nキーワード\n```\n\n例えばこんな感じ。  \n\n```bash\n<< __BLOCK_COMMENT__\n~~コメント 1 行目~~\n~~コメント 2 行目~~\n・・・・・・\n~~コメント n 行目~~\n__BLOCK_COMMENT__\n```\n\n## インラインコメント\n\nコマンドの一部を一時的に削除したい場合など、インラインコメントを使用したい場面がある。  \n例えば、C言語で``func(~/* コメントアウト */,~)``とする場面のこと。  \nこれをbashスクリプトで実現するには、コマンド置換を応用する。  \nコマンド置換とは、コマンドを`` ` `` と `` ` `` で囲んでその出力を別のコマンドのパラメータとする方法のこと。  \n具体的には、行コメントをコマンド置換で挿入する。  \n置換されたコマンドはコメントなので結果なにもせずに返ってくるので、その部分は無視される。\n\nただ、この書き方はとても汚いので、一時的使用にとどめておくのがベター。  \n\n\n```bash\ncommand arg1 arg2 `#コメントアウト` arg3 ・・・\n```\n\n例えばこんな感じ。  \n\n```bash\nls  `#-l`  /etc\n```\n\nシェル変数の設定など、コマンドの前にコマンド置換があるとうまく動かない場合は、以下のようにコマンド置換の後ろに``;``を挿入する。  \n\n```bash\n`# comment`;var=hoge\n```\n\n# bashのファイル名補完の区切り文字を追加する方法\n\n#### シチュエーション\nたとえば、``HOGE_PATH=/path/to/hoge``と入力したいとき、途中でファイル名の補完処理ができない。  \n今まで、一旦スペース挟んで入力して、戻ってスペース削除するという手順を踏んでいて、  \nこれが地味にストレス...  \n\n##### ソリューション\n``~/.bashrc`` に以下の1行を追加\n```bash\nIFS='«追加したい文字»'$IFS\n```\n\nシチュエーションのように``=``を区切り文字として追加したい場合は、こんな感じ  \n```bash\nIFS='='$IFS\n```\n\n##### ちなみに\n設定内容を確認するには以下。  \n```bash\necho -n \"$IFS\" | od -c\n```\n\n##### ちなみに2\nデフォルトの設定に戻すには以下。\n先頭に``$``で、シングルクォート``'`` で囲むこと。\n```bash\nIFS=$' \\t\\n'\n```\n\n##### 言い訳の先取\nなんか悪影響出たら元に戻そう。。。  \n\n\n# 端末(ターミナル)ウィンドウの起動方法によって初期処理を変更する\n## 端末(ターミナル)ウィンドウの環境変数を設定してbashを起動するプロファイルを作成する\n\n- まず現在の設定で端末を開く  \n- メニューの<span style=\"border: 1px solid;\">編集</span> → <span style=\"border: 1px solid;\">Preferences</span> を選択  \n- 左側でベースにするプロファイルの右端の▼をクリックして<span style=\"border: 1px solid;\">Clone...</span>を選択  \n- 名前を入力(例えばopenVINO)して<span style=\"border: 1px solid;\">Clone</span> をクリック\n- 作成したプロファイルをクリックして右側上のタブで<span style=\"border: 1px solid;\">コマンド</span>を選択  \n- <span style=\"border: 1px solid;\">□ SHELLの代わりにカスタム・コマンドを実行する(N)</span> にチェックを入れる  \n- <span style=\"border: 1px solid;\">カスタムコマンド</span>に``/usr/bin/env myUseSetting=OPENVINO bash``と入力  \n  ここで、``myUseSetting=OPENVINO`` が設定したい環境変数\n- その他のタブはお好みで変更 \n- <span style=\"border: 1px solid;\">閉じる</span>をクリック  \n\n## 環境変数によって.bashrcの処理を変更する\n\n``~/.bashrc`` に環境変数に応じた処理を追加  \n\n```bash\nif [[ ${«設定した環境変数»} = \"«期待する文字列»\" ]]; then\n    «環境変数に応じた処理»\nfi\n```\n\nたとえば、こんな感じ。  \n```bash\nif [[ ${myUseSetting} = \"OPENVINO\" ]]; then\n    source /opt/intel/openvino/bin/setupvars.sh\n    echo \"========== bash for openINO ==========\"\nfi\n```\n\n試してみる。  \n以下のコマンドを実行。  \n```bash\ngnome-terminal --profile=«作成したプロファイル名»\n```\n\nたとえば、こんな感じ。  \n```bash\ngnome-terminal --profile=openVINO\n```\n\n起動した端末(ターミナル)ウィンドウで追加した初期処理が実行されていることを確認。  \n通常起動の端末(ターミナル)ウィンドウで追加した初期処理が実行されていないことも確認した方がいいかも。  \n\n## キーボードショートカットで作成したプロファイルの端末(ターミナル)を起動する\n\n- 「設定」を開き、左側で<span style=\"border: 1px solid;\">デバイス</span> →<span style=\"border: 1px solid;\">キーボード</span>と選択する  \n- <span style=\"border: 1px solid;\">名前</span>に適当な名前を設定  \n- <span style=\"border: 1px solid;\">コマンド</span>に先ほど試したコマンドを入力  \n- <span style=\"border: 1px solid;\">ショートカットの設定...</span>をクリックし、設定したいキーの組み合わせを押す  \n  - 既に設定済みのキーの組み合わせは使用できない  \n- 右上の<span style=\"border: 1px solid;\">追加</span>をクリックして完了  \n\nデスクトップで設定したキーの組み合わせを押して起動することを確認\n\n## メニューに作成したプロファイルの端末(ターミナル)を起動するアイコンを追加する\n\n以下の手順で新しい``.desktop``ファイルを作成すればよい。  \n\n- 元になる``desktop``ファイルから新しい``desktop``ファイルを作成  \n```bash\nsudo cp gnome-terminal.desktop «新しいdesktopファイル»\n```\n\n- 新しい``desktop``ファイルの設定を変更する\n  - ``Name``に適当な名称(この名称で表示されるので、分かりやすい名前で)を入力  \n  - ``Exec``に前に試したコマンドを入力。  \n    例えば、こんな感じ。  \n    ```diff\n    --- gnome-terminal.desktop\t2018-05-30 22:03:45.000000000 +0900\n    +++ openvino.desktop\t2020-06-17 12:26:37.403276823 +0900\n    @@ -1,9 +1,9 @@\n    [Desktop Entry]\n    -Name=Terminal\n    +Name=bash for openVINO\n    Comment=Use the command line\n    Keywords=shell;prompt;command;commandline;cmd;\n    TryExec=gnome-terminal\n    -Exec=gnome-terminal\n    +Exec=gnome-terminal --profile=openVINO\n    Icon=utilities-terminal\n    Type=Application\n    X-GNOME-DocPath=gnome-terminal/index.html\n    ```\n- アクティビティで``Name``で設定した名前を検索すればアイコンが出てくるのでクリックして起動  \n\n\nちなみに、作成したアイコンをデスクトップに置くことも可能(その他の物でもできるけど)  \n\n- 配置したい``desktop``ファイルを``~/デスクトップ``ディレクトリにコピーして実行属性を付ける\n```bash\ncp /usr/share/applications/openvino.desktop ~/デスクトップ/\nchmod +x ~/デスクトップ/openvino.desktop \n```\n  - 実行属性を付けないと以下のダイアログで<span style=\"border: 1px solid;\">キャンセル</span>しか選べないので注意  \n- デスクトップ上のアイコンをダブルクリック\n  - <span style=\"border: 1px solid;\">信用できないアプリケーションのランチャー</span>ダイアログが出るので、  \n  - <span style=\"border: 1px solid;\">信頼して起動</span>をクリック  \n  - (2回目以降はダブルクリックだけで起動できる)\n\n\n\n# カレントディレクトリ下のファイルの全角文字等を抽出する\n\n```bash\ngrep -r -n -v '^[[:cntrl:][:print:]]*$' .\n```\n\n# GUIで設定した項目の変更キーの確認\n\n設定変更の前後で``dconf``コマンドで値一覧を取得し、その差分を確認することで変更キーが分かる。  \n```bash\ndconf dump / > before.txt\n# 設定変更\ndconf dump / > after.txt\n\ndiff -u before.txt after.txt\n```\n\nキーが分かれば、以後は以下のコマンドで設定変更できる。  \nスクリプトなどに記載する場合に便利。  \n```bash\ngsettings set «キー» «値»\n```\n\n# ディストリビューションのバージョン確認\n\n以下のコマンドで確認できる。  \n\n```bash\nlsb_release -a\n```\n\nこんな感じで表示される  \n\n```bash\nNo LSB modules are available.\nDistributor ID: Ubuntu\nDescription:    Ubuntu 20.04.2 LTS\nRelease:        20.04\nCodename:       focal\n```\n最初の1行は特に気にしなくて良い。  \nLSB(Linux Standard Base)がインストールされていると、もっと細かい情報が表示されるらしい。",
    "# エクスプローラーの右クリックメニューをカスタマイズ\n\n以下のページに詳しい説明がある。  \n- [エクスプローラーの右クリックメニューをカスタマイズする](https://ascii.jp/elem/000/000/953/953807/){:target=\"_blank\"}  \n  - わりと全体的な話    \n- [あなただけの右クリックで、ストレスフリーな開発を](https://qiita.com/NumLocker/items/f8016f1aed7207b850fb){:target=\"_blank\"}  \n  - 詳細な設定項目など  \n  - フォルダの右クリックとかデスクトップの右クリックなんかも記載アリ  \n\n順序を指定したい場合は``position``キーで ``Top``/``Middle``/``Bottom`` を指定することでできるが、あくまで3種類だけ(下のリンクの[ここ](https://qiita.com/NumLocker/items/f8016f1aed7207b850fb#6-7-%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC%E3%81%AE%E8%A1%A8%E7%A4%BA%E4%BD%8D%E7%BD%AE%E3%81%AE%E5%A4%89%E6%9B%B4)){:target=\"_blank\"}。  \n表示順序はshellの下のキーがASCIIコード順(?)になるらしいので、  \n同一ポジション内でさらに順序を指定したい場合は、キーに``1_``、``2_``みたいな接頭辞を付けて表示順を固定できるみたい。  \nでも、このままだと接頭辞がついたままの項目でメニューに表示されるので、``(既定)``キーに表示する文字列を設定しておけばOK。  \n\n# Windowsでメニューを出したままアクティブウィンドウをキャプチャ\n\n以下の手順でメニューを出したままアクティブウィンドウをキャプチャできる\n1. ALTキーを押す\n2. ALTキーを押したままCTRLキーを押す\n3. ALTキーとCTRLキーをを押したままメニューをマウスで操作する\n4. CTRLキーだけ放す\n5. ALTキーを押したままPRINT SCREENを押す\n\n# WindowsでX-serve\n\n- [WindowsでX-serve]({{ site.baseurl }}/2019/11/26/VcXsrv.html)\n\n# モバイル ホットスポット\n\n- [モバイル ホットスポットでRaspberryPiをネットに接続]({{ site.baseurl }}/2019/09/12/mobilehotspot.html)\n\n\n# PC起動時にネットワークドライブの再接続に失敗する場合の自動リカバリ\n\nPCの起動時にネットワークドライブの再接続に失敗する場合、以下の手順で自動でリカバリできる。  \n手順は以下。  \n\n- ```%SystemDrive%\\Scripts\\MapDrives.ps1```を以下の内容で作成    \n{% include filename.html filename=\"c:\\Scripts\\MapDrives.ps1\" %}\n```powershell\n$i=3\nwhile($True){\n    $error.clear()\n    $MappedDrives = Get-SmbMapping |where -property Status -Value Unavailable -EQ | select LocalPath,RemotePath\n    foreach( $MappedDrive in $MappedDrives)\n    {\n        try {\n            New-SmbMapping -LocalPath $MappedDrive.LocalPath -RemotePath $MappedDrive.RemotePath -Persistent $True\n        } catch {\n            Write-Host \"There was an error mapping $MappedDrive.RemotePath to $MappedDrive.LocalPath\"\n        }\n    }\n    $i = $i - 1\n    if($error.Count -eq 0 -Or $i -eq 0) {break}\n\n    Start-Sleep -Seconds 30\n\n}\n```\n- ```%SystemDrive%\\Scripts\\MapDrives.cmd```を以下の内容で作成    \n{% include filename.html filename=\"%SystemDrive%\\Scripts\\MapDrives.cmd\" %}\n```powershell\ndate /T > \"%TEMP%\\MapDrivers.txt\"\ntime /T >> \"%TEMP%\\MapDrivers.txt\"\nPowerShell -Command \"Set-ExecutionPolicy -Scope CurrentUser Unrestricted\" >> \"%TEMP%\\MapDrivers.txt\" 2>&1 \nPowerShell -File \"%SystemDrive%\\Scripts\\MapDrives.ps1\" >> \"%TEMP%\\MapDrivers.txt\" 2>&1\n```\n- スタートアップフォルダに```%SystemDrive%\\Scripts\\MapDrives.cmd```のショートカットを置く    \n- 作成したショートカットのプロパティを開いて「ショートカット」タブの「実行時の大きさ」を「最小化」に変更しておく。    \n\n参考: [Windows 10、バージョン 1809 において、マップされたネットワークドライブの再接続に失敗する場合がある](https://support.microsoft.com/ja-jp/help/4471218/mapped-network-drive-may-fail-to-reconnect-in-windows-10-version-1809?fbclid=IwAR3FHRrLbLXn8rp_qigZW46oeAWs22x6Uqh-0Nu7psOKDA45UlOo7a9wlg0){:target=\"_blank\"}\n\n\n# ファイルをロックしているプログラムを特定する\n\nWindowsでファイル削除しようとしたら、「このファイルはロックされています」と言われてイラっとしたときに\nこれを使うとイッパツ解消(と行かないこともないことはない)。\n\n[ファイルの削除を妨げているアプリを特定、ロックを解除できるアプリ「LockHunter」](https://forest.watch.impress.co.jp/docs/review/1222040.html?fbclid=IwAR133Iw2vfGX_e9fnBhm3soJ3iRdY65YOPh02tRa_IkG_ntVWAxesZuFORQ){:target=\"_blank\"}  \n\n# Windows Terminalをインストールする\n\nWindows Terminalのインストールは Microsoft Store で「Windows Terminal」で検索してインストールするだけでOK。  \n\n## 参考サイト  \n\nTIPS色々    : [Windows Terminal Tips](https://qiita.com/whim0321/items/6a6b11dea54642bd6724){:target=\"_blank\"}  \nNYAGOSを使う: [Windows Terminal で nyagos を使おう](https://zenn.dev/zetamatta/books/5ac80a9ddb35fef9a146/viewer/a3f5c9){:target=\"_blank\"}  \n色々        : [1からマスター! Windows Terminal入門](https://news.mynavi.jp/itsearch/series/hardware/1_windows_terminal.html){:target=\"_blank\"}  \n\n## 設定例\n設定ファイルは以下にある。  \n``C:\\Users\\<<USER>>\\AppData\\Local\\Packages\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\LocalState\\settings.json``  \n\n設定変更例:\n- フォント/フォントサイズ/ウィンドウサイズ変更\n- ShellにNYAGOSを追加\n- デフォルトをNYAGOSに変更\n\n```diff\n--- settings_org.json   2021-01-31 05:45:34.767869400 +0900\n+++ settings.json       2021-01-31 06:46:38.275728600 +0900\n@@ -8,7 +8,11 @@\n {\n     \"$schema\": \"https://aka.ms/terminal-profiles-schema\",\n\n-    \"defaultProfile\": \"{61c54bbd-c2c6-5271-96e7-009a87ff44bf}\",\n+    \"defaultProfile\": \"{19ddaf5e-e045-481a-bf88-37f7ebe66292}\",\n+\n+    // window size\n+    \"initialCols\": 80,\n+    \"initialRows\": 55,\n\n     // You can add more global application settings here.\n     // To learn more about global settings, visit https://aka.ms/terminal-global-settings\n@@ -28,10 +32,22 @@\n         \"defaults\":\n         {\n             // Put settings here that you want to apply to all profiles.\n+            // \"fontFace\": \"源真ゴシック等幅 Regular\",\n+            \"fontFace\": \"BIZ UDゴシック\",\n+            \"fontSize\": 12\n         },\n         \"list\":\n         [\n             {\n+                  \"guid\": \"{19ddaf5e-e045-481a-bf88-37f7ebe66292}\",\n+                  \"hidden\": false,\n+                  \"name\": \"NYAGOS 4.4.9\",\n+                  \"commandline\": \"C:\\\\wintools\\\\nyagos-4.4.9_2\\\\nyagos.exe\",\n+                  \"icon\": \"C:\\\\wintools\\\\nyagos-4.4.9_2\\\\nyagos.png\",\n+                  \"cursorShape\": \"vintage\",\n+                  \"startingDirectory\": \"c:\\\\\"\n+            },\n+            {\n                 // Make changes here to the powershell.exe profile.\n                 \"guid\": \"{61c54bbd-c2c6-5271-96e7-009a87ff44bf}\",\n                 \"name\": \"Windows PowerShell\",\n```\n\n## misc\n### NYAGOSのアイコンが表示されないので、表示されるようにする\n- EXEファイルからアイコンを抽出してpngファイルで保存しておく\n  - アイコン抽出には[Icon Ripper](https://www.vector.co.jp/soft/winnt/amuse/se513590.html){:target=\"_blank\"}が使える(インストール不要)\n- ``settings.json`` に ``\"icon\" : ~ `` でアイコン設定しておく。\n\n# NYAGOSのカスタマイズ\n\nNYAGOSのリポジトリはこちら:<https://github.com/zetamatta/nyagos>  \n\n\n## ヒストリ補完機能を追加する\n\n[nyagosでヒストリ補完する](https://qiita.com/nocd5/items/7cfc2441868442838148) のソースを  \n``nyagos.exe``のあるディレクトリの``nyagos.d``ディレクトリの下に``h_search.lua``として格納しておく。  \n\n参照先がなくなると困るので、ここに再掲しておく。  \n\n{% include filename.html filename=\"h_search.lua\" %}\n```lua\n-- ヒストリ補完機能\nnyagos.bindkey(\"C_N\",\n    function(this)\n        search_history(this, false)\n    end\n)\n\nnyagos.bindkey(\"C_P\",\n    function(this)\n        search_history(this, true)\n    end\n)\n\nfunction search_history(this, is_prev)\n    -- カーソル位置が一番左の場合は通常のnext/prev\n    if this.pos == 1 then\n        if is_prev == true then\n            this:call(\"PREVIOUS_HISTORY\")\n        else\n            this:call(\"NEXT_HISTORY\")\n        end\n        this:call(\"BEGINNING_OF_LINE\")\n        return nil\n    end\n\n    -- 検索キーワード\n    local search_string = this.text:sub(1, this.pos - 1)\n\n    -- 重複を除いたhistoryリストの取得\n    local history_uniq = {}\n    local is_duplicated = false\n    local hist_len = nyagos.gethistory()\n    for i = 1, hist_len do\n        local history\n        -- 新しい履歴がリスト後ろに残るよう末尾からサーチ\n        history = nyagos.gethistory(hist_len - i)\n        for i, e in ipairs(history_uniq) do\n            if history == e or history == search_string then\n                is_duplicated = true\n            end\n        end\n        if is_duplicated == false then\n            if is_prev == true then\n                table.insert(history_uniq, history)\n            else\n                table.insert(history_uniq, 1, history)\n            end\n        end\n        is_duplicated = false\n    end\n\n    -- 入力と完全一致する履歴を探す\n    -- 完全一致する履歴を起点にすることで\n    -- (見かけ上)インクリメンタルな検索にする\n    local hist_pos = 0\n    for i, e in ipairs(history_uniq) do\n        if e == this.text then\n            hist_pos = i\n            break\n        end\n    end\n\n    -- 前方一致する履歴を探す\n    local matched_string = nil\n    for i = hist_pos + 1, #history_uniq do\n        if history_uniq[i]:match('^' .. search_string .. '.*') then\n            matched_string = history_uniq[i]\n            break\n        end\n    end\n\n    -- 見つかった履歴を出力\n    -- 見つからなければ、検索キーワードを出力\n    this:call(\"KILL_WHOLE_LINE\")\n    if (matched_string ~= nil) then\n        this:insert(matched_string)\n    else\n        this:insert(search_string)\n    end\n    this:call(\"BEGINNING_OF_LINE\")\n    for i = 1, this.pos - 1 do\n        this:call(\"FORWARD_CHAR\")\n    end\nend\n```\n"
  ],
  "documents": [
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>python の async/await</title>\n  </head>\n  <body>\n    <header>\n      <h1>python の async/await</h1>\n      <p>python の async/awaitってどう動くんだっけ?</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h2 id=\"python-の-asyncawaitってどう動くんだっけ\">python の async/awaitってどう動くんだっけ?</h2>\n\n<p>と思ったので、ちょっとテストプログラムを書いて試してみた。</p>\n\n<p>asyncioはnon-preemptiveなので、最近のpreemptiveに慣れ切った脳ミソにはややこしい。</p>\n\n<p>preemptiveなプログラムを書きたければ、threadingを使えば良い。適材適所というやつだ。</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">asyncio</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n\n<span class=\"n\">argvs</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span>  <span class=\"c1\"># コマンドライン引数を格納したリストの取得\n</span><span class=\"n\">argc</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">)</span> <span class=\"c1\"># 引数の個数\n</span>\n<span class=\"k\">if</span> <span class=\"n\">argc</span> <span class=\"o\">></span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"mi\">5</span>        <span class=\"c1\"># テストケース\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"testCase = \"</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">testCase</span><span class=\"p\">))</span>\n\n<span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>           <span class=\"c1\"># 念のため宣言だけしておく\n</span>\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">sub</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub start        \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub wakeup       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"mi\">42</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"n\">task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">sub</span><span class=\"p\">())</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"k\">await</span> <span class=\"n\">task</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">task</span>\n    \n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main wakeup      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main2</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 start      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 wakeup     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n\n<span class=\"c1\"># =============================================================================\n</span><span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>     <span class=\"c1\"># 開始時刻を記憶\n</span><span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">or</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">4</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">wait</span><span class=\"p\">([</span><span class=\"n\">main</span><span class=\"p\">(),</span> <span class=\"n\">main2</span><span class=\"p\">()]))</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">5</span> <span class=\"p\">:</span>\n    <span class=\"n\">loop</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">get_event_loop</span><span class=\"p\">()</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"unknown test case!!\"</span><span class=\"p\">)</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n\n<p>以下のようにコマンドラインからテストケース番号を指定して実行する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python test.py <testCase>\n</code></pre></div></div>\n\n<h2 id=\"実行結果\">実行結果</h2>\n<h3 id=\"testcase1\">testCase=1</h3>\n\n<p>基本的なパターン、というか、全然非同期実行になってないけど。。。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code>→ <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p>awaitが付いていると、その場でタスクに実行権を渡し、そのタスクが終了するまで待つ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 1\ntestCase <span class=\"o\">=</span>  1\nbefor create     0.00026416778564453125\nafter create     0.00034689903259277344\nbefor call       0.00040340423583984375\nsub start        0.00047469139099121094\nsub wakeup       2.0033931732177734\nafter call       2.0035252571105957\nmain wakeup      3.004753351211548\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase2\">testCase=2</h3>\n\n<p>基本的なパターン、こっちが非同期実行として本命。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code>を実行するときに<code class=\"language-plaintext highlighter-rouge\">await</code>を付けない。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">await</code>が付いていないと、その場でタスクに実行権を渡さず、自分の実行を中断する部分か終了するまでそのまま実行する。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> 呼び出し箇所では即時実行されず、sleep(2)で <code class=\"language-plaintext highlighter-rouge\">main</code> の実行が中断されたところで <code class=\"language-plaintext highlighter-rouge\">sub</code> へ切り替わる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> で <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> が実行されると実行されるタスクがなくなるので、イベントループは実行可能タスク待ちになる。</p>\n\n<p>1秒後、<code class=\"language-plaintext highlighter-rouge\">main</code> が起床するので、そのままmainが終了される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> で イベントループは <code class=\"language-plaintext highlighter-rouge\">main</code> の終了を待っているので、<code class=\"language-plaintext highlighter-rouge\">sub</code> が実行中でも無関係にイベントループを終了してしまい、\n <code class=\"language-plaintext highlighter-rouge\">sub</code> の残りは実行されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 2\ntestCase <span class=\"o\">=</span>  2\nbefor create     0.0002646446228027344\nafter create     0.00034308433532714844\nbefor call       0.00039768218994140625\nafter call       0.0004489421844482422\nsub start        0.0005385875701904297\nmain wakeup      1.0014407634735107\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase3\">testCase=3</h3>\n\n<p>testCase=2 でsubの残りも実行するには?と思って試したパターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で、即座に <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main2())</code> を実行してみた。</p>\n\n<p>見事失敗。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→ <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p>どうやら、 <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で イベントループは一旦 <code class=\"language-plaintext highlighter-rouge\">close</code> されてしまうらしい。</p>\n\n<p>単にtestCase=2の後ろにmain2の実行を付け加えただけになってしまった。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 3\ntestCase <span class=\"o\">=</span>  3\nbefor create     0.00029540061950683594\nafter create     0.0003790855407714844\nbefor call       0.0004353523254394531\nafter call       0.00048828125\nsub start        0.0005817413330078125\nmain wakeup      1.0015552043914795\nmain2 start      1.0021519660949707\nmain2 wakeup     4.0038042068481445\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase4\">testCase=4</h3>\n\n<p>testCase=3 の失敗挽回パターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でmainとmain2をまとめてみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でまとめたタスクがすべて終了するまでイベントループは<code class=\"language-plaintext highlighter-rouge\">close</code> されないので、<code class=\"language-plaintext highlighter-rouge\">sub</code>は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> と <code class=\"language-plaintext highlighter-rouge\">main2</code> のどちらが先に実行されるかは規定されていない様子。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 4\ntestCase <span class=\"o\">=</span>  4\nmain2 start      0.0003325939178466797\nbefor create     0.0004305839538574219\nafter create     0.0005018711090087891\nbefor call       0.0005679130554199219\nafter call       0.0006389617919921875\nsub start        0.0007307529449462891\nmain wakeup      1.002068042755127\nsub wakeup       2.002253293991089\nmain2 wakeup     3.003903388977051\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase5\">testCase=5</h3>\n\n<p>testCase=3 の失敗挽回パターン その2。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.get_event_loop()</code> でイベントループを取得し、<code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> でそれぞれのタスクを実行してみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> → イベントループ終了\nとなっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> ではタスクが終了してもイベントループはcloseされないので、同じイベントループで<code class=\"language-plaintext highlighter-rouge\">main2</code>が実行される。\n結果、<code class=\"language-plaintext highlighter-rouge\">sub</code> は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> が終了するまで <code class=\"language-plaintext highlighter-rouge\">main2</code> は実行(起動)されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 5\ntestCase <span class=\"o\">=</span>  5\nbefor create     0.0002574920654296875\nafter create     0.0003345012664794922\nbefor call       0.00038933753967285156\nafter call       0.0004410743713378906\nsub start        0.0005307197570800781\nmain wakeup      1.0010528564453125\nmain2 start      1.0011804103851318\nsub wakeup       2.002350330352783\nmain2 wakeup     4.002865314483643\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 18.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 18.04のインストール</h1>\n      <p>Ubuntu 18.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Facebook noteに書いておいたら、消されちゃったみたいなので、メモから再度作成<br />\nメモから書き起こしているので、細かいところが違うかも。<br />\n最新版では変更されている箇所があるかも。</p>\n\n<p>VirtualBox へのインストール前提で書いてます。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-1804-インストール媒体の入手\">Ubuntu 18.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら</p>\n\n<p><a href=\"https://www.ubuntulinux.jp/download)\">https://www.ubuntulinux.jp/download)</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを2048MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシーを選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"nb\">sudo </span>apt dist-upgrade <span class=\"o\">(</span>必要なら<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが</p>\n\n<h4 id=\"amazonなんちゃらのやつ\">amazonなんちゃらのやつ</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove ubuntu-web-launchers\n</code></pre></div></div>\n\n<h4 id=\"ツール類\">ツール類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n</code></pre></div></div>\n\n<h4 id=\"ゲーム類\">ゲーム類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h4 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-panel\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n一旦再起動して<br />\nサインインボタン横の歯車ボタンで「GNOME Flashback (Metacity)」を選択してログインする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!IMPORTANT]\n「GNOME Flashback(Compiz)」だとうまく動かない。<br />\n以前はログアウトだけで良かったはずなんだけど、<br />\n再起動しないとダメみたい</p>\n</blockquote>\n\n<h4 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h4>\n<blockquote>\n  <p>[!TIP]\n端末を起動し、メニューの「編集」→「Preferences」を選択<br />\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\nCustom font にチェックを入れ、その右側でフォントを選ぶ<br />\n    Ubuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n</blockquote>\n\n<h4 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj\n<span class=\"nb\">sudo mkdir</span> /work1\n<span class=\"nb\">sudo mkdir</span> /work2\n<span class=\"nb\">sudo mkdir</span> /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h4 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h4>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h4 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h4 id=\"bashの設定変更\">bashの設定変更</h4>\n<p>~/.bashrcに以下を追記</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n</code></pre></div></div>\n\n<h4 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/metacity/edge-tiling                false<br />\n       /org/gnome/mutter/edge-tiling                  false<br />\n       /org/gnome/shell/overrides/edge-tiling         false</p>\n</blockquote>\n\n<h4 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferences/auto-rise             false<br />\n       /org/gnome/descktop/wm/preferences/focus-mode            sloppy or mouse<br />\n       /org/gnome/descktop/wm/preferences/rise-on-click         true</p>\n</blockquote>\n\n<h4 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/nautilus/desktop/trash-icon-visible         false<br />\n       /org/gnome/nautilus/desktop/home-icon-visible          false</p>\n</blockquote>\n\n<h4 id=\"日本語入力\">日本語入力</h4>\n<ul>\n  <li>右上のJaまたはMoと書かれたアイコンをクリック→テキスト入力設定を選択</li>\n  <li>インストールされている言語の管理をクリック</li>\n  <li>「言語サポートが完全にはインストールされていません」と出るので<br />\n「インストール」をクリック</li>\n  <li>一旦log offして再log in</li>\n  <li>右上のJaまたはMoと書かれたアイコンをクリック\n    <ul>\n      <li>Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)</li>\n    </ul>\n  </li>\n  <li>キーボードの全角/半角キーで切り替えられるようになる</li>\n</ul>\n\n<h4 id=\"sambaのインストール\">sambaのインストール</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h4 id=\"nfsのインストール\">NFSのインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h4 id=\"apache-のインストール\">apache のインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>apache2\n<span class=\"nb\">mkdir</span> /proj/wwwroot\n</code></pre></div></div>\n\n<p>/etc/apache2/apache2.conf に以下を追加<br />\n<Directory ~と書いてあるところがあるので、その並びに追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><Directory /proj/wwwroot/>\n    Options Indexes FollowSymLinks\n    AllowOverride None\n    Require all granted\n</Directory>\n</code></pre></div></div>\n\n<p>/etc/apache2/sites-available/000-default.conf の以下を修正</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>DocumentRoot /proj/wwwroot\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/apache2 restart\n</code></pre></div></div>\n\n<h3 id=\"以上でインストールは終了\">以上でインストールは終了</h3>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hosts は書き換えられないので、手動で書き換える</p>\n</blockquote>\n\n<p>IPアドレスの変更(固定アドレスにしたい場合)</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのインストール</h1>\n      <p>pyenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>システムのpythonのバージョンを変更したり、モジュールの変更をしたりするとシステム上のスクリプトの動作に影響が出る場合があるので、pyenvで個別のpython環境を構築するのがベター。<br />\nさらに、virtualenvプラグインを使うと、同じpythonのバージョンでもそれぞれに別のモジュールをインストールできる、仮想環境を構築できる。</p>\n\n<p>なお、pyenvはpythonをバイナリインストールできなくて、ソースからコンパイルするので、インストールにはそれなりに時間がかかる(RasPi2で1~2時間くらい?)。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<h3 id=\"必要なモジュールをインストール\">必要なモジュールをインストール</h3>\n<p>インストールに必要なモジュールをインストールする。</p>\n<ul>\n  <li>Bullseye以降ではこちら<br />\n(<code class=\"language-plaintext highlighter-rouge\">python-openssl</code> →  <code class=\"language-plaintext highlighter-rouge\">python3-openssl</code>)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>Buster以前ではこちら\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"bluetoothを使用する場合\">bluetoothを使用する場合</h3>\n<p>bluetoothを使用する場合は以下も必要</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以前、 ubuntuの場合は以下と書いていたが、<code class=\"language-plaintext highlighter-rouge\">libbluetooth3-dev</code>は<code class=\"language-plaintext highlighter-rouge\">libbluetooth-dev</code>の別名定義だったので上のコマンドでOKのはず。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth3-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"pyenv本体とvirtualenvプラグインのインストール\">pyenv本体とvirtualenvプラグインのインストール</h2>\n\n<p>pyenv本体とvirtualenvプラグインをインストール。<br />\nついでにupdateプラグインも入れとく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>pyenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n<span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>Raspbianでは以下も追加<br />\nnumpyをimportしたとき、undefined symbol: PyFPE_jbuf でエラーになる対策。<br />\n参考: <a href=\"https://research.itplants.com/?p=2437\">https://research.itplants.com/?p=2437</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"--enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-fpectl\"</span>\n</code></pre></div></div>\n\n<p>Ubuntuでは以下を追加しておく(デフォルトだとShared Library のimportでエラーになる)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h2 id=\"sudoでpyenv環境を実行するように設定する\">sudoでpyenv環境を実行するように設定する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo</code>でpythonを実行すると、pyenvの設定に関係なくsystemのpythonが実行されてしまいます。<br />\nこれを防ぐためには、<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers</code>の<code class=\"language-plaintext highlighter-rouge\">Defaults secure_path</code>に以下のpathを追加します。</p>\n\n<ul>\n  <li>«pyenvインストール先»/plugins/pyenv-virtualenv/shims:</li>\n  <li>«pyenvインストール先»shims:</li>\n  <li>«pyenvインストール先»/bin:</li>\n</ul>\n\n<p>具体的には以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 変更前\nDefaults  secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n    ↓\n# 変更後\nDefaults  secure_path=\"/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n</code></pre></div></div>\n<ul>\n  <li></li>\n</ul>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"pyenvでインストールできるバージョンの一覧を表示\">pyenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span> \n</code></pre></div></div>\n\n<h3 id=\"pythonのインストール\">pythonのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.4\n</code></pre></div></div>\n\n<p>・・・ 気長に待つ。 ・・・</p>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global 3.6.4\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-V</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境の構築\">仮想環境の構築</h3>\n\n<p>色々試したあとに、インストールしたモジュールをチャラにしたいときを考えて、仮想環境を構築しておく。<br />\nここでは、python 3.6.4を使用して 仮想環境名 mypython を作成。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.6.4 mypython\n</code></pre></div></div>\n\n<p>デフォルトをmypythonに変更する場合は以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global mypython\n</code></pre></div></div>\n\n<h3 id=\"pipのバージョンアップ\">pipのバージョンアップ</h3>\n\n<p>「pipが古い~」と言われる前にバージョンアップ。ついでにsetuptoolsとwheelも。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n<blockquote>\n  <p>[!IMPORTANT]\nベース環境をバージョンアップしても、仮想環境に引き継がれないので、仮想環境毎に実行が必要。</p>\n</blockquote>\n\n<h3 id=\"ローカルバージョンの設定\">ローカルバージョンの設定</h3>\n\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは3.4.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">local</span> <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"i2cを使用する場合raspi\">I2Cを使用する場合(RasPi)</h1>\n\n<p>RaspberryPi環境で、I2Cを使うためのsmbusモジュールは、通常 <code class=\"language-plaintext highlighter-rouge\">sudo apt install python3-smbus</code> でインストールするが、これだとpyenv環境にインストールできない。<br />\nこれはsmbus2をインストールして使用することで回避できる。\nインストールは以下のように実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>smbus2\n</code></pre></div></div>\n<p>ちなみに、pyenv 環境へのモジュールのインストールには <code class=\"language-plaintext highlighter-rouge\">sudo</code> は不要。/usr 下へのインストールではないので。</p>\n\n<p>で、プログラムソース側はsmbusのインストール部分を以下のように修正。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus</span>\n<span class=\"k\">except</span> <span class=\"nb\">ImportError</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus2</span> <span class=\"k\">as</span> <span class=\"n\">smbus</span>\n</code></pre></div></div>\n\n<p>smbus2 だけにしても良いけど、smbus でも動作できるようにしておくのがベターかな。</p>\n\n<h1 id=\"pyenvのバージョンアップ\">pyenvのバージョンアップ</h1>\n<p>pythonの新しいバージョンがリリースされ、それをインストールしたい場合など、pyenvのバージョンアップが必要。<br />\npyenv-updateをインストールしておけば(上記手順でインストール済み)、以下のコマンドですべてのプラグインを含めてバージョンアップしてくれる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv update\n</code></pre></div></div>\n\n<h2 id=\"古い方法\">古い方法</h2>\n<p>pyenv-updateをインストールしていない場合は以下の手順でそれぞれのリポジトリをpullする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit pull\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのpythonを使いたい場合は以下のように実行\">システムのpythonを使いたい場合は以下のように実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv version\n</code></pre></div></div>\n\n<h3 id=\"pyenvでインストールされているpythonのバージョン仮想環境を確認\">pyenvでインストールされているpythonのバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"pyenv自体のバージョン確認\">pyenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"pyenvで使用できるコマンドの確認\">pyenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv commands\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>nodenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>nodenvのインストール</h1>\n      <p>nodenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonのpyenvと同様にNode.jsのバージョン管理システムのnodenvを使用する。<br />\n(両方インストールするくらいならanyenvを使えという説もあるが…)</p>\n\n<p>他にもnvmやnodebrewなんてのもあるらしい。nodenvはディレクトリごとにローカルバージョンを設定できてとても便利なのでおススメ。<br />\nnodeenv(eが2つ)という超マイナーなのもあるけど、間違わないように。</p>\n\n<p>Node.jsはリポジトリにバイナリパッケージが用意されているバージョンはバイナリインストールできる。用意されていないバージョンはソースからコンパイルされるが、必要なライブラリ類のインストールなど必要。ここでは手順は割愛。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>インストールに必要なモジュールをインストールする。インストール済みならスキップして可。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>git\n</code></pre></div></div>\n\n<h2 id=\"nodenv本体のインストール\">nodenv本体のインストール</h2>\n\n<p>nodenv本体をインストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\ngit clone git://github.com/nodenv/nodenv.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/nodenv/node-build.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>nodenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"nodenvでインストールできるバージョンの一覧を表示\">nodenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install</span> <span class=\"nt\">-l</span>\n</code></pre></div></div>\n<p>バイナリインストールできるか確認したい場合は以下。<br />\nバイナリがなければソースからコンパイルされるが、時間がかかるのが嫌な場合に(大抵のバージョンはバイナリが用意されているようだ)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"nt\">-r</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/share/\n<span class=\"c\"># ただし、uname -m が x86_64 | amd64 | i686-64 のときはx64に置き換える</span>\n</code></pre></div></div>\n\n<h3 id=\"nodejsのインストール\">Node.jsのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install </span>10.15.3 \n</code></pre></div></div>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv global 10.15.3\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境について\">仮想環境について</h3>\n\n<p>pyenvと異なり、nodenvは仮想環境をサポートしていない。<br />\nNode.jsはローカルモジュールのインストールが簡単なので、仮想環境を構築しなくても個々のディレクトリでローカルモジュールをインストールすることで仮想環境相当のことが実現できる。</p>\n\n<h3 id=\"npmのバージョンアップ\">npmのバージョンアップ</h3>\n\n<p>「npmが古い~」と言われる前にバージョンアップ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> npm\n</code></pre></div></div>\n\n<h3 id=\"ローカルで使用するバージョンの設定\">ローカルで使用するバージョンの設定</h3>\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは9.11.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">local</span> <バージョン名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv shell <バージョン名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"nodenvのバージョンアップ\">nodenvのバージョンアップ</h1>\n\n<p>Node.jsの新しいバージョンがリリースされ、それをインストールしたい場合など、nodenvのバージョンアップが必要。<br />\n<strong>下記その2の方がおススメ。こっちの手順は参考までに。</strong></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/\ngit pull\n</code></pre></div></div>\n<p>実行後、ターミナルを開きなおす</p>\n\n<h1 id=\"nodenvのバージョンアップ-その2\">nodenvのバージョンアップ その2</h1>\n<p>nodenv-updateをインストールしておけば、<code class=\"language-plaintext highlighter-rouge\">nodenv update</code>を実行するだけですべてのプラグインを含めてバージョンアップしてくれるので、おススメ。インストール方法は下記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/nodenv/nodenv-update.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/nodenv-update\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのnodejsを使いたい場合\">システムのNode.jsを使いたい場合</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv version\n</code></pre></div></div>\n\n<h3 id=\"nodenvでインストールされているnodejsのバージョンを確認\">nodenvでインストールされているNode.jsのバージョンを確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"nodenv自体のバージョン確認\">nodenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"nodenvで使用できるコマンドの確認\">nodenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv commands\n</code></pre></div></div>\n\n<h3 id=\"nodenvのヘルプの表示\">nodenvのヘルプの表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">help</span>\n\n<span class=\"c\"># 各コマンドのヘルプを表示するには以下</span>\nnodenv <span class=\"nb\">help</span> <<span class=\"nb\">command</span><span class=\"o\">></span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 16.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 16.04のインストール</h1>\n      <p>Ubuntu 16.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 16.04 のインストール手順のメモです。<br />\nVirtualBox へのインストール前提で書いてます。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-1604-インストール媒体の入手\">Ubuntu 16.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら</p>\n\n<p><a href=\"http://old-releases.ubuntu.com/releases/16.04.5/\">http://old-releases.ubuntu.com/releases/16.04.5/</a></p>\n\n<p>ファイル一覧の下の方の<br />\n<a href=\"http://old-releases.ubuntu.com/releases/16.04.5/ubuntu-16.04.5-desktop-amd64.iso\">「ubuntu-16.04.5-desktop-amd64.iso」</a><br />\nを選択する</p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを1024MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動し、画面の明るさとロックを選択<br />\n「次の時間アイドル状態が続けば画面をオフにする」を「しない」に設定。<br />\n「ロックする」を「オフ」に設定。</p>\n</blockquote>\n\n<h3 id=\"ap-getよりaptが使いやすい\">ap-getよりaptが使いやすい</h3>\n\n<p>最初から入ってたっけ??<br />\n入ってなかったら以下で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>apt\n</code></pre></div></div>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"nb\">sudo </span>apt dist-upgrade <span class=\"o\">(</span>必要なら<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p>終わったらリブート</p>\n\n<h3 id=\"gccとかmakeとかは最初からインストールされているはず\">gccとかmakeとかは最初からインストールされているはず</h3>\n\n<p>入っていない場合は以下でインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<h4 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h2 id=\"使わないパッケージをアンインストール\">使わないパッケージをアンインストール</h2>\n\n<p>使わないパッケージはディスクの肥やしになるだけでなく、余計なアップデートで時間を食うので、以下の感じでアンインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove <package name>\n</code></pre></div></div>\n<p>インストール済みのパッケージは以下で確認できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--manual-installed</span>\n</code></pre></div></div>\n\n<p>依存関係によってインストールされたパッケージも含めて確認するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span>\n</code></pre></div></div>\n\n<h4 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-panel\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n一旦ログアウトして<br />\nサインインボタン横のUbuntuアイコンで「GNOME Flashback (Compiz)」を選択してログインする<br />\n選択した内容は次回起動時も覚えている。</p>\n</blockquote>\n\n<h4 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h4>\n<blockquote>\n  <p>[!TIP]\n端末を起動し、メニューの「編集」→「設定」を選択<br />\n「プロファイル」タブを選択<br />\n使用中のプロファイル(最初のは「default」)を選択し、「編集」をクリック<br />\n「全般」タブの「フォントを指定する」 にチェックを入れ、その右側でフォントを選ぶ<br />\n        Takao ゴシック Regular あたりがおススメ<br />\nついでに「起動時の端末サイズ」も修正しておくとよい</p>\n</blockquote>\n\n<h4 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj\n<span class=\"nb\">sudo mkdir</span> /work1\n<span class=\"nb\">sudo mkdir</span> /work2\n<span class=\"nb\">sudo mkdir</span> /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h4 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h4>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h4 id=\"bashの設定変更\">bashの設定変更</h4>\n<p>~/.bashrcに以下を追記</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n</code></pre></div></div>\n\n<h4 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>compizconfig-settings-manager \n</code></pre></div></div>\n<p>アプリケーション→システムツール→Preference→CompizeConfigSettingsManager でプログラム起動<br />\nウィンドウ・マネジメントのGridのチェックをはずす</p>\n\n<h4 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferenceを選択<br />\n    auto-rise             false<br />\n    focus-mode            sloppy or mouse<br />\n    rise-on-click         true</p>\n</blockquote>\n\n<h4 id=\"ウィンドウのボタンの位置を右側にする\">ウィンドウのボタンの位置を右側にする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferenceを選択<br />\n    「button-layout」に 「menu:minimize,maximize,close」を設定</p>\n</blockquote>\n\n<h4 id=\"日本語入力\">日本語入力</h4>\n<ul>\n  <li>アプリケーション→システムツール→システム設定→言語サポートを選択</li>\n  <li>「言語サポートが完全にはインストールされていません」と出るので<br />\n「インストール」をクリック</li>\n  <li>一旦ログアウトして再ログイン</li>\n  <li>アプリケーション→システムツール→システム設定→テキスト入力設定を選択</li>\n  <li>入力ソースタブを選択</li>\n  <li>左下の+ボタンを押してMozc(Fcitx)を選択して追加ボタンを押す</li>\n</ul>\n\n<h4 id=\"sambaのインストール\">sambaのインストール</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h4 id=\"nfsのインストール\">NFSのインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認(IPアドレスは環境に合わせて変更してね)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h4 id=\"apache-のインストール\">apache のインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>apache2\n<span class=\"nb\">mkdir</span> /proj/wwwroot\n</code></pre></div></div>\n\n<p>/etc/apache2/apache2.conf に以下を追加<br />\n<Directory ~と書いてあるところがあるので、その並びに追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><Directory /proj/wwwroot/>\n    Options Indexes FollowSymLinks\n    AllowOverride None\n    Require all granted\n</Directory>\n</code></pre></div></div>\n\n<p>/etc/apache2/sites-available/000-default.conf の以下を修正</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>DocumentRoot /proj/wwwroot\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/apache2 restart\n</code></pre></div></div>\n\n<h3 id=\"以上でインストールは終了\">以上でインストールは終了</h3>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"nmcliが入ってなかったら以下でインストール\">nmcliが入ってなかったら以下でインストール</h3>\n\n<p>入ってたか、入れたか、何かの依存関係で入ったか覚えてない…</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>network-manager\n</code></pre></div></div>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hostnameを直接エディタで書き換えても可。</p>\n</blockquote>\n\n<h3 id=\"etchosts-の変更\">/etc/hosts の変更</h3>\n<p>旧ホスト名を「old_hostname」、新しいホスト名を「new_hostname」とした場合、以下のコマンドで書き換えられる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/old_hostname/new_hostname/'</span> /etc/hosts\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nエディタで書き換えても可。/etc/hostsを開いて旧ホスト名を新しいものに書き換える。</p>\n</blockquote>\n\n<h3 id=\"ipアドレスの変更固定アドレスにしたい場合\">IPアドレスの変更(固定アドレスにしたい場合)</h3>\n<blockquote>\n  <p>[!TIP]\nシステム設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん。<br />\nなんかこんな感じ。</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"各接続の設定値の表示\">各接続の設定値の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show  <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n<p>「”有線接続 2”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n<p>「”有線接続 2”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n<p>「”有線接続 3”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h1 id=\"共有フォルダの設定とマウント\">共有フォルダの設定とマウント</h1>\n\n<h2 id=\"virtualboxでの共有フォルダの設定\">VirtualBoxでの共有フォルダの設定</h2>\n\n<ul>\n  <li>仮想マシン→設定で設定ダイアログを表示\n    <ul>\n      <li>「共有フォルダ」で「共有フォルダの追加」ボタンをクリック\n        <ul>\n          <li>「フォルダーのパス」に共有するフォルダを指定</li>\n          <li>「フォルダ名」に名前を付ける(例:Share))</li>\n          <li>その他は空欄のまま</li>\n          <li>「OK」をクリック</li>\n        </ul>\n      </li>\n      <li>「OK」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"マウントポイントの作成\">マウントポイントの作成</h2>\n\n<p>マウントポイントを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /Share\n</code></pre></div></div>\n\n<h2 id=\"手動でマウント\">手動でマウント</h2>\n\n<p>以下のコマンドでマウントできる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> vboxsf Share /Share/\n</code></pre></div></div>\n\n<p>アンマウントするときはこちら。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount /Share/\n</code></pre></div></div>\n\n<h2 id=\"自動でマウント\">自動でマウント</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/fstab</code> に以下の内容を追加。\nこれで、起動時に自動でマウントされる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Share /Share vboxsf defaults 0 0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>rbenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>rbenvのインストール</h1>\n      <p>rbenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonに対するpyenvのようにrubyのバージョンを変更したり、個別にモジュールを管理したりできるrbenvを導入する。<br />\nあと、モジュールをインストールする <code class=\"language-plaintext highlighter-rouge\">gem install</code> に <code class=\"language-plaintext highlighter-rouge\">sudo</code> を付けなくても良いのも地味に便利。<br />\ngemset(pyenvの仮想環境のようなもの)を作って個別にモジュール管理すれば、色々インストールして訳わからん状態になったときでも、一旦チャラにして観光構築をやりなおせる。</p>\n\n<p>なお、rbenvはrubyをバイナリインストールできなくて、ソースからコンパイルするので、インストールにはそれなりに時間がかかる。</p>\n\n<p>以下の手順はUbuntu 16.04で動作確認した。他のバージョンでは、特にインストールの準備に微妙な違いがあるかもしれない。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>インストールに必要なモジュールをインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>git autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev\n</code></pre></div></div>\n\n<h2 id=\"rbenv本体とプラグインのインストール\">rbenv本体とプラグインのインストール</h2>\n\n<p>rbenv本体とプラグインをインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">RBENV_ROOT</span><span class=\"o\">=</span>/proj/.rbenv    <span class=\"c\"># 環境に合わせて修正してね</span>\ngit clone https://github.com/sstephenson/rbenv.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/sstephenson/ruby-build.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/ruby-build\ngit clone git://github.com/jf/rbenv-gemset.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-gemset\ngit clone https://github.com/sstephenson/rbenv-gem-rehash.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-gem-rehash\ngit clone https://github.com/rkh/rbenv-update.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-update\n</code></pre></div></div>\n<p>rbenv-gemset をインストールすることで、個別のモジュール環境を構築できる。pyenvのvirtualenvみたいな感じ。<br />\nrbenv-gem-rehashをインストールすることで、バージョン切り替えやgemのインストールの度にrbenv rehash を実行しなくてもよくなる。<br />\nrbenv-updateをインストールすることで、<code class=\"language-plaintext highlighter-rouge\">rbenv uppppdate</code> でrbenvと各プラグインのアップデートができる。</p>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>rbenvの設定のため、~/.bashrc に以下を追加。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">RBENV_ROOT</span><span class=\"o\">=</span>/proj/.rbenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$RBENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>rbenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h1 id=\"設定と使い方\">設定と使い方</h1>\n\n<h3 id=\"rbenvでインストールできるバージョンの一覧を表示\">rbenvでインストールできるバージョンの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span>\n</code></pre></div></div>\n\n<h3 id=\"rubyのインストール\">rubyのインストール</h3>\n\n<p>インストールしたいバージョンを指定して実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">install </span>2.6.3\n</code></pre></div></div>\n\n<p>・・・ 気長に待つ。 ・・・</p>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<p>デフォルトで使用したいバージョンを指定して実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv global 2.6.3\n</code></pre></div></div>\n\n<p>念のため指定したバージョンが実行されることを確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ruby <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h3 id=\"gemsetの作成\">gemsetの作成</h3>\n\n<p>色々試したあとに、インストールしたモジュールをチャラにしたいときを考えて、gemset(仮想環境みたいなもん)を構築しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset create 《ベースバージョン》 《gemset名》\n</code></pre></div></div>\n\n<p>例えば、ruby 2.6.3 に test1 という名前のgemsetを作成する場合。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset create 2.6.3 test1\n</code></pre></div></div>\n\n<p>gemsetはインストールされた各バージョンに紐づいて作成される。</p>\n\n<h3 id=\"gemsetの設定\">gemsetの設定</h3>\n\n<p>gemsetはディレクトリ毎に指定する。<br />\nカレントディレクトリに設定されたgemset(なければその親、さらに親と探す)と\nカレントのRubyバージョンが使用される。<br />\nカレントのRubyのバージョンに指定されたgemsetが存在しなければ新しくgemsetを作成するが、中身は空。<br />\nなので、gemsetを指定したときは、同時に <code class=\"language-plaintext highlighter-rouge\">rbenv local</code> でローカルバージョンも指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> 《設定したいディレクトリ》\nrbenv <span class=\"nb\">local</span> 《バージョン》\nrbenv gemset init 《gemset名》\n</code></pre></div></div>\n<p>gemset名を省略するとカレントディレクトリ名と同じ名前でgemsetが作成され、そのgemsetに設定される</p>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\nrbenv gemset init test1\n</code></pre></div></div>\n\n<h3 id=\"作成されたgemsetの一覧表示\">作成されたgemsetの一覧表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset list\n</code></pre></div></div>\n<p>こんな感じで表示される。Rubyのバージョンが異なれば同名のgemsetも作成できる。<br />\nただし、中身は別物。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>rbenv gemset list\n2.3.8:\n  test1\n2.6.3:\n  test1\n</code></pre></div></div>\n\n<h3 id=\"カレントディレクトリで有効なgemsetの確認\">カレントディレクトリで有効なgemsetの確認</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset active\n</code></pre></div></div>\n\n<p>ついでにRubyのバージョンも確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv version\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>rbenv gemset active\nenv1 global\n<span class=\"nv\">$ </span>rbenv version\n2.6.3 <span class=\"o\">(</span><span class=\"nb\">set </span>by /*******/.ruby-version<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"gemsetの指定を無効にするにはrbenv-gemsets-ファイルを削除する\">gemsetの指定を無効にするには.rbenv-gemsets ファイルを削除する</h3>\n\n<p>コマンドで指定を無効にできないので、指定ファイルを手動で削除する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> .rbenv-gemsets\n</code></pre></div></div>\n<p>使用するgemsetを変更したい場合、すでにgemset設定済みのディレクトリでは再設定できない。<br />\n一旦gemsetの指定を無効にしてから、再度 <code class=\"language-plaintext highlighter-rouge\">rbenv gemset init ~</code> する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n\n<h3 id=\"gem関連の設定を確認\">gem関連の設定を確認</h3>\n\n<p>gem関連の設定(GEM_PATHSなど)を確認したいときは以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem <span class=\"nb\">env</span>\n</code></pre></div></div>\n<h3 id=\"helpの表示\">helpの表示</h3>\n\n<p>rbenv 全体のヘルプ(コマンドの確認など)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">help</span>\n</code></pre></div></div>\n\n<p>各コマンドのヘルプ(パラメータやオプションの確認など)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">help</span> 《コマンド》\n</code></pre></div></div>\n\n<h1 id=\"メモ\">メモ</h1>\n\n<h3 id=\"rehashについて\">rehashについて</h3>\n\n<p>設定を変えたりした場合は以下を実行する必要があるが、rbenv-gem-rehashをインストールしてあれば必要なタイミングで自動で行われるので不要。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv rehash \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのローカル環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのローカル環境での実行</h1>\n      <p>github pagesをローカル環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行することができる。</p>\n\n<p>以下の手順はUbuntu 16.04で動作確認した。他のバージョンでは、特にインストールの準備に微妙な違いがあるかもしれない。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<p>apt または rbenvでrubyをインストールしておく。</p>\n\n<p>aptの場合は以下(nativeなライブラリを使うので-devパッケージをインストール) 。<br />\nrbenvの場合は<a href=\"/memoBlog/2019/07/07/rbenv.html\">rbenvのインストール</a>参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ruby-dev\n</code></pre></div></div>\n\n<p>bundlerをインストールする。bundlerはNode.jsでいうところのnpmのうち、package.jsonでローカルインストールしたモジュールを管理する部分に相当するもの(かな?)。<br />\naptでrubyをインストールした場合はrootでインストール必要があるので、<code class=\"language-plaintext highlighter-rouge\">sudo</code>を付けて実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem <span class=\"nb\">install </span>bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span>\n</code></pre></div></div>\n\n<p>モジュールをローカルにインストールすることもできる。<br />\nその場合は以下で。<br />\n–pathオプションのパラメータはお好みで変更してちょ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span> <span class=\"nt\">--path</span> gems\n</code></pre></div></div>\n\n<p>このとき、<code class=\"language-plaintext highlighter-rouge\">_config.yml</code>の以下の部分にモジュールのインストール先(上の例では<code class=\"language-plaintext highlighter-rouge\">gems</code>)を追加しておく(追加しないとjekyll実行時にエラーになる)。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<div style=\"text-align: center;\">↓</div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [gems, server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n\n<h2 id=\"サーバ起動\">サーバ起動</h2>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./server.sh\n</code></pre></div></div>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>ブラウザ(firefoxとchromeで動作確認した。IEでは動かない。Edgeはよーわからん)を起動し、サーバを起動しているマシンのport 4000に接続。このとき、ブラウザはサーバと同じマシンである必要はない。</p>\n\n<h2 id=\"サーバの停止\">サーバの停止</h2>\n\n<p>CTRL+cで停止。</p>\n\n<h2 id=\"サーバの-listen-port-の変更\">サーバの listen port の変更</h2>\n\n<p>必要ならサーバの listen port を変更できる。<br />\nserver.sh 内のコマンドの <code class=\"language-plaintext highlighter-rouge\">--port</code> オプションを変更すればOK.</p>\n\n<h1 id=\"ディレクトリ構成\">ディレクトリ構成</h1>\n\n<p>ディレクトリ構成は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── _config.yml                             jekyllの設定ファイル\n├── Gemfile                                 bundlerの管理ファイル\n├── _layouts                                ページレイアウト用HTMLファイル置き場\n│   ├── default.html                           デフォルト使用\n│   ├── toppage.html                           トップページ用\n│   └── debug.html                             デバッグページ用\n│                                                 どのレイアウトを使うかは各MarkdownファイルのFront-matterで指定する\n├── _includes                               共通で使用するレイアウトはここに置いておく\n│   └── footer.html\n├── _posts                                   投稿記事置き場\n│   ├── 2019-06-22-asyncawait.md\n│   ├── ・・・・\n│   └── YYYY-MM-DD-title.md                     ブログの投稿記事  ファイル名は年-月-日-タイトル とする。\n├── _sass                                    sassのインクルードファイルを置いておく\n│   └── _my_theme.scss                          大本のテーマ設定用sassファイル\n├── assets\n│   ├── css\n│   │   ├── jquery.floatingscroll.css      jQuery の floatingscroll プラグインのCSSファイル\n│   │   └── style.scss                     このページのメインのcssになるsassファイル\n│   └── js\n│       ├── jquery.floatingscroll.min.js    jQuery の floatingscroll プラグインのスクリプトファイル\n│       └── main.js                         各ページで実行するjavascriptファイル\n├── index.md                                 トップページ\n├── misc                                     以下にその他のページデータを置く\n│   ├── debug.md\n│   └── sample.md\n├── favicon.ico                              favicon画像\n├── compile.sh                               サイト構築のみ行うスクリプト\n├── server.sh                                サーバ起動用スクリプト(サイト構築も同時に行う)\n└── _site                                    以下にサイト構築データが生成される\n</code></pre></div></div>\n\n<h1 id=\"投稿記事のファイル名\">投稿記事のファイル名</h1>\n\n<p>投稿記事のファイル名は<code class=\"language-plaintext highlighter-rouge\">YYYY-MM-DD-title.拡張子</code>とする。<br />\nそれ以外のファイル名を付けると無視される。</p>\n\n<p>日付、タイトルは後述のFrontMatterに設定があればそちらが優先される。</p>\n\n<h1 id=\"front-matterの構成\">Front Matterの構成</h1>\n\n<p>Front Matterの主な項目は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>---\ntitle: XXXX                タイトル  指定無ければファイル名のタイトル部分が使用される\ndate: 2019-07-07           日付 指定無ければファイル名の日付部分が使用される\ntags: [\"YYY\",\"ZZZ\"]        タグを指定  このタグでトップページでカテゴリを選択できる 大文字/小文字は区別される\nlayout: toppage            使用するレイアウト 指定無ければdefaultが使用される\nexcerpt: xxxxxx            抜粋  トップページのタイトルの下に表示される\n---\n</code></pre></div></div>\n\n<h1 id=\"あとはお好きに変更してちょ\">あとはお好きに変更してちょ</h1>\n\n<p>自分のリポジトリにpushして、そのリポジトリの設定でgithub pagesを有効にすればいっちょ上がり。</p>\n\n<p>ちなみに、ファイルが一つもないリポジトリではgithub pagesを有効にできないので、ダミーでもいいからファイルをpushしてから設定すること。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git + samba環境</title>\n  </head>\n  <body>\n    <header>\n      <h1>git + samba環境</h1>\n      <p>gitのローカルリポジトリをsamba環境で使用する際の注意事項</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>gitのローカルリポジトリをsamba経由で見ると、ファイルのAttributeの実行属性が変更されたと誤検出してしまうことがある。\nそんなときは、以下のコマンドでファイルのAttributeを無視するように設定すれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--unset</span> core.filemode\ngit config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>サーバ側は以下を一回だけ実行しておけばサーバ側でのAttributeの管理は有効になる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<p>意図的に実行属性を設定したい場合などは、サーバ側で<code class=\"language-plaintext highlighter-rouge\">git add</code>する。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのWindows環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのWindows環境での実行</h1>\n      <p>github pagesをWindows環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行できるようにした(<a href=\"/memoBlog/2019/07/17/githubpages.html\">参照</a>)が、\nわざわざUbuntu立ち上げるのが面倒になってきたので、Windows上で実行できるようにしてみた。</p>\n\n<h1 id=\"何はともあれrubyのインストール\">何はともあれRubyのインストール</h1>\n<p>Windows版Rubyをインストールしないとはじまらないので、\n<a href=\"https://www.ruby-lang.org/ja/\">Rubyの総本山</a> から(RubyInstaller のダウンロード](https://rubyinstaller.org/downloads/)\nへ行ってダウンロード。<br />\nWITH DEVKIT を選んでおく方が良いらしい。<br />\nバージョンは最新で良いでしょう(私は Ruby+Devkit 2.6.3-1 (x64) を選びました)。</p>\n\n<p>ダウンロードしたらなんとなーくインストーラ実行して案内にしたがってなんとな~く進んでちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\ngccも要るのかな?Rubyインストール時にMSYS64環境がインストールされるみたいなので、大丈夫かな?<br />\nちなみに、うちの環境はmingw-w64が入ってる。</p>\n</blockquote>\n\n<p>とりあえずbundlerはグローバルに入れとく。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem install bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。<br />\n一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをローカルにインストールする。<br />\nUbuntuみたいにrdenv環境じゃないので、グローバル環境はなるべく汚染したくないので、<code class=\"language-plaintext highlighter-rouge\">--path</code>指定してローカルにインストールする。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div></div>\n\n<p>あるいは、<code class=\"language-plaintext highlighter-rouge\">install.cmd</code>に登録してあるので、そっちを実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRubyのバージョンを変更したり、ディレクトリを移動した場合はgemsディレクトリを削除してから</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div>  </div>\n  <p>を実行する</p>\n</blockquote>\n\n<p>windows対応にあたって、リポジトリの _config.yml と .gitignore は対処済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>サーバ起動</p>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\\server.cmd\n</code></pre></div></div>\n\n<p>もちろん、エクスプローラなどから <code class=\"language-plaintext highlighter-rouge\">server.cmd</code> をダブルクリックして実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこのときのキモ、jekyll実行前に以下を実行してRubyのエンコードをUTF-8に設定している。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>set RUBYOPT=--encoding=UTF-8`  \n</code></pre></div>  </div>\n  <p>これがないとエンコードエラーが発生する。<br />\n環境変数で設定しておけば逐一設定しなくても良いが、どうせcmdファイル書いてあるので、ついでに設定している。</p>\n</blockquote>\n\n<p>firewallが警告を表示するので、許可してちょ。<br />\nまごまごしてるとjekyllがエラー終了しちゃうけど、その後でも許可してしまえば次回からは大丈夫。</p>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>以降は<a href=\"/memoBlog/2019/07/17/githubpages.html\">こっち</a>を見てちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(RaspberryPi編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(RaspberryPi編)</h1>\n      <p>過去のブログ(RaspberryPi編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"センサ接続gpio\">センサ接続/GPIO</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4f2290b79f3005f839afe798c424fadd\">BOSCH 9軸センサ bmx055 ドライバ(Node.js用) </a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/310580fc726f8b2315d2a81486cbe551\">RaspberryPi向けBOSCH 温度/湿度/気圧センサ(BME280)、9軸センサ(加速度/ジャイロ/地磁気)(BMX055)動作確認プログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/dc6f4c0987e462ca94f003b8d20ea456\">RaspberryPi向けGPIO操作テストプログラム</a></li>\n</ol>\n\n<h1 id=\"webサーバ\">WEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/e37a1d11ac25cf7e421f4d6c32d9a03c\">RaspberryPi向けWEBサーバ&センサテストプログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/18ee6da1c77671949e881eb45dda6edf\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/b23849cf9b82b83fe0c2df22836b6c27\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ/ついでに3D姿勢計算もブラウザでやるっちゃ</a></li>\n</ol>\n\n<h1 id=\"もう一つのwebサーバ\">もう一つのWEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/bcaa47ce1b04bd6b8285e553d6fb9f4f\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/11cc216ffde610e26a5b8cd4ee5b599b\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js/webサーバにExpressを使ってサッパリと</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/8179edb10867faf98e233a52965a9e53\">Raspbianのシリアルコンソールでloginするとイケてないのを改善する</a></li>\n</ol>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(Windows編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(Windows編)</h1>\n      <p>過去のブログ(Windows編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"リモートデバッグ\">リモートデバッグ</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4784a559cb0e78d060fe01d69a3c829d\">windowsのVisualStudioCodeでRasPiのNode.jsをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/aed3ddde84d76cca5c5be62df1120f81\">windowsのVisualStudioCodeでRasPiのPythonをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/46e92ee968b99174c1e1fa3199465877\">VisualStudioCodeのリモート開発が使えるようになったらしいので試してみる</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/c9bf43575d8fce47233bf191b21fbaad\">NW.jsによるWebアプリのデスクトップアプリ化</a></li>\n</ol>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その1)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その1)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Intel NCStick用TinyYOLOの<a href=\"http://jellyware.jp/kurage/movidius/c13_tinyyolo_run.html\">解説記事</a>を見かけた。<br />\n<a href=\"https://github.com/movidius/ncappzoo/blob/ncsdk2/caffe/TinyYolo/run.py\">ソース</a>を読んでみたが、\n結構難解で(特にnumpy回り)、自分の鶏頭でも思い出せるように調べた結果をメモしてみた。<br />\nNCStick持ってないから実際に動かしてないけど。。。</p>\n\n<p>リポジトリは <a href=\"https://github.com/movidius/ncappzoo\">https://github.com/movidius/ncappzoo</a> だが、このソースはmasterブランチには存在しない。必ずncsdk2ブランチを選択すること。<br />\n<code class=\"language-plaintext highlighter-rouge\">git clone</code> する場合は要注意。</p>\n\n<p>どっか行っちゃうといけないので、ソースのコピーを<a href=\"TinyYOLO_src\">ここ</a>にも置いておく。</p>\n\n<h1 id=\"モジュールのインポート\">モジュールのインポート</h1>\n\n<p>特に難しいことはしてない。mvncがNCStickのドライバ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">mvnc</span> <span class=\"kn\">import</span> <span class=\"n\">mvncapi</span> <span class=\"k\">as</span> <span class=\"n\">mvnc</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n</code></pre></div></div>\n\n<h1 id=\"ファイル名定義\">ファイル名定義</h1>\n\n<p>13行目<br />\n<code class=\"language-plaintext highlighter-rouge\">input_image_file</code> : ここに書かれたファイルを読み込んで認識する。<br />\n<code class=\"language-plaintext highlighter-rouge\">tiny_yolo_graph_file</code> : ニューラルネットのネットリスト(?)  ニューロンの接続情報と重みが入っていると思われる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">input_image_file</span><span class=\"o\">=</span> <span class=\"s\">'../../data/images/nps_chair.png'</span>\n<span class=\"n\">tiny_yolo_graph_file</span><span class=\"o\">=</span> <span class=\"s\">'./graph'</span>\n</code></pre></div></div>\n\n<h1 id=\"認識用の画像サイズ定義\">認識用の画像サイズ定義</h1>\n\n<p>17行目<br />\nニューラルネットに入力する画像サイズ。任意のサイズの画像をこのサイズにリサイズしてから入力する。<br />\nこのサイズはニューラルネット構築の際に決定された値。Graphファイルに紐づいた値と考えられる。</p>\n\n<p>Grid分割数が7×7で、1Grid当たりの画像サイズが64pixelなので、7×64 = 448 でおのずと決まる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">NETWORK_IMAGE_WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n<span class=\"n\">NETWORK_IMAGE_HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n</code></pre></div></div>\n\n<h1 id=\"ncstickの出力を整理する処理ルーチンfilter_objects\">NCStickの出力を整理する処理ルーチン(filter_objects)</h1>\n\n<p>35行目<br />\n<a href=\"TinyYOLO_2\">別ページ</a></p>\n\n<h1 id=\"重なったボックス情報を削除するためのマスク情報配列を取得get_duplicate_box_mask\">重なったボックス情報を削除するためのマスク情報配列を取得(get_duplicate_box_mask)</h1>\n\n<p>109行目<br />\n<a href=\"TinyYOLO_3\">別ページ</a></p>\n\n<h1 id=\"バウンティングボックス情報の単位変換boxes_to_pixel_units\">バウンティングボックス情報の単位変換(boxes_to_pixel_units)</h1>\n\n<p>129行目<br />\n<a href=\"TinyYOLO_4\">別ページ</a></p>\n\n<h1 id=\"2つのboxの重なり比率を計算get_intersection_over_union\">2つのBOXの重なり比率を計算(get_intersection_over_union)</h1>\n\n<p>163行目<br />\n<a href=\"TinyYOLO_3\">別ページ</a></p>\n\n<h1 id=\"認識結果の表示ルーチンdisplay_objects_in_gui\">認識結果の表示ルーチン(display_objects_in_gui)</h1>\n\n<p>203行目<br />\n<a href=\"TinyYOLO_5\">別ページ</a></p>\n\n<h1 id=\"mainルーチン\">mainルーチン</h1>\n\n<h3 id=\"関数の先頭とオープニングメッセージ\">関数の先頭とオープニングメッセージ</h3>\n\n<p>255行目</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Running NCS Caffe TinyYolo example'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickドライバのオプション設定\">NCStickドライバのオプション設定</h3>\n<p>258行目</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Set logging level to only log errors\n</span>    <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">global_set_option</span><span class=\"p\">(</span><span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">GlobalOption</span><span class=\"p\">.</span><span class=\"n\">RW_LOG_LEVEL</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickの検出とオープン\">NCStickの検出とオープン</h3>\n\n<p>260行目<br />\nなかったらエラー終了。<br />\n複数見つかった場合は最初のものをオープンする。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">devices</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">enumerate_devices</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'No devices found'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"mi\">1</span>\n    <span class=\"n\">device</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Device</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"nb\">open</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h3 id=\"graphファイルの読み込み\">Graphファイルの読み込み</h3>\n\n<p>267行目<br />\n14行目で設定したGraphファイルを読み込んで、NCStickドライバに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\">#Load graph from disk and allocate graph via API\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tiny_yolo_graph_file</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'rb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">graph_from_disk</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Graph</span><span class=\"p\">(</span><span class=\"s\">\"Tiny Yolo Graph\"</span><span class=\"p\">)</span>\n    <span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span> <span class=\"o\">=</span> <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">allocate_with_fifos</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"n\">graph_from_disk</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"入力画像の読み込みと前処理\">入力画像の読み込みと前処理</h3>\n\n<p>276行目</p>\n<ul>\n  <li>13行目で設定した画像ファイルを読み込んむ(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>結果表示用にオリジナルサイズのままコピーを取っておく(<code class=\"language-plaintext highlighter-rouge\">display_image</code>)</li>\n  <li>NCStickに入力する画像サイズにリサイズ(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>各画素の値をfloat32型に変換(<code class=\"language-plaintext highlighter-rouge\">input_image</code>  元データは<code class=\"language-plaintext highlighter-rouge\">int</code>)</li>\n  <li>さらに各画素の値を0.0~1.0に正規化(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>色並びをBGRからRGBに再配列(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">input_image_file</span><span class=\"p\">)</span>\n    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span><span class=\"p\">,</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">INTER_LINEAR</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">divide</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"mf\">255.0</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>  <span class=\"c1\"># convert to RGB\n</span></code></pre></div></div>\n\n<h3 id=\"ncstick-による処理\">NCStick による処理</h3>\n\n<p>284行目<br />\nNCStickに前処理した画像を入力し、計算結果を得る。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">input_image</code>の各要素はfloat32型に変換して入力する。(既に変換済みな気もするが…)<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">input_image</code>そのものの型は <code class=\"language-plaintext highlighter-rouge\">numpy.ndarray</code>。<br />\nニューラルネットの処理本体の処理は実質この2行だけ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Load tensor and get result.  This executes the inference on the NCS\n</span>    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">queue_inference_with_fifo_elem</span><span class=\"p\">(</span><span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span><span class=\"p\">,</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">output</span><span class=\"p\">,</span> <span class=\"n\">userobj</span> <span class=\"o\">=</span> <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">read_elem</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickの出力を整理する\">NCStickの出力を整理する</h3>\n\n<p>288行目<br />\n<code class=\"language-plaintext highlighter-rouge\">filter_objects</code>(35行目)で  NCStickの出力を整理する。<br />\n<a href=\"TinyYOLO_2\">別ページ</a>を参照。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">output.astype(np.float32)</code> : NCStickの出力をfloat32にキャストした配列(1次元)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image.shape[1]     </code> : 画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image.shape[0]     </code> : 画像高(448)</li>\n</ul>\n\n<p>得られるデータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> : 整理された認識結果</li>\n</ul>\n\n<p><code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">filtered_objs</span> <span class=\"o\">=</span> <span class=\"n\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">output</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<h3 id=\"認識結果の表示\">認識結果の表示</h3>\n\n<p>290行目<br />\n<code class=\"language-plaintext highlighter-rouge\">display_objects_in_gui</code> (203行目)で 表示用イメージと整理された認識結果を表示。<br />\n<a href=\"TinyYOLO_5\">別ページ</a>を参照。<br />\nパラメータは<br />\n<code class=\"language-plaintext highlighter-rouge\">display_image</code> : 表示用画像\n<code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> : 整理された認識結果</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Displaying image with objects detected in GUI'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Click in the GUI window and hit any key to exit'</span><span class=\"p\">)</span>\n    <span class=\"c1\">#display the filtered objects/boxes in a GUI window\n</span>    <span class=\"n\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"後片付け\">後片付け</h3>\n\n<p>295行目<br />\n各クローズ処理。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">fifo_in</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Finished'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"mainルーチン呼び出し\">mainルーチン呼び出し</h1>\n\n<p>お約束の処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その2)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ncstickの出力を整理する処理ルーチンfilter_objects\">NCStickの出力を整理する処理ルーチン(filter_objects)</h1>\n\n<p>35行目<br />\nNCStickの生の出力を整理して、各Gridが何と認識したのか整理して出力する。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">inference_result  </code> : NCStickの出力をfloat32にキャストした配列(1次元×要素数1470)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image_width </code> : 画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image_height</code> : 画像高(448)</li>\n</ul>\n\n<p>出力は</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs</code> : 整理された認識結果</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<h2 id=\"各パラメータのサイズ\">各パラメータのサイズ</h2>\n\n<p>37行目<br />\nこのサイズはニューラルネット構築の際に決定された値。<br />\nGraphファイルに紐づいた値と考えられる。<br />\nなので、グローバル変数で定義しておいてパラメータで渡す方が良さそうだが。。。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">num_inference_results </code> :  NCStickの出力のサイズ(1470 : 未使用)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">network_classifications</code> : 各クラスのラベル(認識結果の名称)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">num_classifications  </code> :  その個数(20)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">grid_size             </code> :  画像のGrid分割数(7)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_per_grid_cell   </code> :  各グリッドに割り当てられたバウンティングボックス数(2)</li>\n</ul>\n\n<p>以下は認識結果を整理するためのパラメータ。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">probability_threshold </code> :  認識結果の確率の閾値。これ以下の確率は無視する。</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># the raw number of floats returned from the inference (GetResult())\n</span>    <span class=\"n\">num_inference_results</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># the 20 classes this network was trained on\n</span>    <span class=\"n\">network_classifications</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">\"aeroplane\"</span><span class=\"p\">,</span> <span class=\"s\">\"bicycle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bird\"</span><span class=\"p\">,</span> <span class=\"s\">\"boat\"</span><span class=\"p\">,</span> <span class=\"s\">\"bottle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bus\"</span><span class=\"p\">,</span> <span class=\"s\">\"car\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"cat\"</span><span class=\"p\">,</span> <span class=\"s\">\"chair\"</span><span class=\"p\">,</span> <span class=\"s\">\"cow\"</span><span class=\"p\">,</span> <span class=\"s\">\"diningtable\"</span><span class=\"p\">,</span> <span class=\"s\">\"dog\"</span><span class=\"p\">,</span> <span class=\"s\">\"horse\"</span><span class=\"p\">,</span> <span class=\"s\">\"motorbike\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"person\"</span><span class=\"p\">,</span> <span class=\"s\">\"pottedplant\"</span><span class=\"p\">,</span> <span class=\"s\">\"sheep\"</span><span class=\"p\">,</span> <span class=\"s\">\"sofa\"</span><span class=\"p\">,</span> <span class=\"s\">\"train\"</span><span class=\"p\">,</span><span class=\"s\">\"tvmonitor\"</span><span class=\"p\">]</span>\n\n    <span class=\"n\">probability_threshold</span> <span class=\"o\">=</span> <span class=\"mf\">0.07</span>\n\n    <span class=\"n\">num_classifications</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">network_classifications</span><span class=\"p\">)</span> <span class=\"c1\"># should be 20\n</span>\n    <span class=\"n\">grid_size</span> <span class=\"o\">=</span> <span class=\"mi\">7</span> <span class=\"c1\"># the image is a 7x7 grid.  Each box in the grid is 64x64 pixels\n</span>    <span class=\"n\">boxes_per_grid_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span> <span class=\"c1\"># the number of boxes returned for each grid cell\n</span></code></pre></div></div>\n\n<h2 id=\"すべての確率配列\">すべての確率配列</h2>\n\n<p>55行目<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)×クラス数(20) で、一旦0クリアしておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">all_probabilities</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<h2 id=\"各クラスの確率配列\">各クラスの確率配列</h2>\n\n<p>60行目<br />\n<code class=\"language-plaintext highlighter-rouge\">classification_probabilities</code> : NCStickの出力から各クラスの確率配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×クラス数(20)<br />\n入力側は1次元配列なので、要素 0 ~ 979 (980個 = 7×7×20)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classification_probabilities</span> <span class=\"o\">=</span> \\\n        <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">980</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n    <span class=\"n\">num_of_class_probs</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"各バウンティングボックスの確率配列\">各バウンティングボックスの確率配列</h2>\n\n<p>65行目<br />\n<code class=\"language-plaintext highlighter-rouge\">box_prob_scale_factor</code> : NCStickの出力から各バウンティングボックスの確率配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)<br />\n入力側は1次元配列なので、要素 980 ~ 1077 (98個 = 7×7×2)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_prob_scale_factor</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">980</span><span class=\"p\">:</span><span class=\"mi\">1078</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<h2 id=\"各バウンティングボックスの座標サイズ情報配列\">各バウンティングボックスの座標/サイズ情報配列</h2>\n\n<p>68行目<br />\nNCStickの出力から各バウンティングボックスの座標/サイズ情報配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)×XY幅高さ(4)<br />\n入力側は1次元配列なので、要素 1078 ~ 1469 (392個 = 7×7×2×4)<br />\n<code class=\"language-plaintext highlighter-rouge\">all_boxes</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n      [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n<p>幅と高さがイメージサイズに対する比率の平方根な理由は謎。。。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># get the boxes from the results and adjust to be pixel units\n</span>    <span class=\"n\">all_boxes</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">1078</span><span class=\"p\">:],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>69行目<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_to_pixel_units</code>(129行目)で<br />\n各バウンティングボックスの座標/サイズ情報配列を、入力画像幅(448)、入力画像高(448)、グリッドサイズ(7)からピクセル単位に変換</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">all_boxes</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">boxes_to_pixel_units</code> 実行後の <code class=\"language-plaintext highlighter-rouge\">all_boxes</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n\n<p>これらの配列の再配列のイメージはこんな感じ。<br />\n<img src=\"/memoBlog/misc/TinyYOLO_2_1.png\" alt=\"結果の再配列のイメージ\" /></p>\n\n<p>72行目<br />\n各グリッドに対する各クラスの確率と各バウンティングボックスの確率を乗じてすべての確率配列を生成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities</code> は Grid_Y × Grid_X × BBox × NumClass の4次元配列。<br />\nデータはバウンティングボックスごとの各クラスのスコアを示している。<br />\n(バウンティングボックスの確率 × クラスの確率)<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [     0.5488,     0.7152,     0.6028,     0.5449,     0.4237,     0.6459, ]\n      [     0.4376,     0.8918,     0.9637,     0.3834,     0.7917,     0.5289, ]\n    ]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">for</span> <span class=\"n\">box_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">):</span> <span class=\"c1\"># loop over boxes\n</span>        <span class=\"k\">for</span> <span class=\"n\">class_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">):</span> <span class=\"c1\"># loop over classifications\n</span>            <span class=\"n\">all_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">,</span><span class=\"n\">class_index</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">class_index</span><span class=\"p\">],</span><span class=\"n\">box_prob_scale_factor</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>77行目<br />\nすべての確率のマスク配列<code class=\"language-plaintext highlighter-rouge\">probability_threshold_mask</code>を生成する。<br />\nデータはall_probabilitiesの要素の値がprobability_threshold以上であればTrue、未満ならFalseが入っている。<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [ True, True, True, True, False, True, ]\n      [ False, True, True, False, True, True, ]\n    ]\n    ・・・・\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"o\">>=</span><span class=\"n\">probability_threshold</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">),</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">probability_threshold</span>\n</code></pre></div></div>\n\n<p>78行目<br />\n<code class=\"language-plaintext highlighter-rouge\">box_threshold_mask</code> は 4 × 閾値を超えたスコアの数 の 2次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_boxes</code>、<code class=\"language-plaintext highlighter-rouge\">all_probabilities</code>から有効なデータを取り出すためのマスクデータ。<br />\n<code class=\"language-plaintext highlighter-rouge\">probability_threshold_mask</code>で要素が<code class=\"language-plaintext highlighter-rouge\">true</code>のもの(=ゼロでないもの)のインデックス一覧をに格納する。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[0][n]</code> : n番目の閾値を超えたスコアを持つY方向のグリッド番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[1][n]</code> : n番目の閾値を超えたスコアを持つX方向のグリッド番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[2][n]</code> : n番目の閾値を超えたスコアを持つバウンティングボックス番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[3][n]</code> : n番目の閾値を超えたスコアを持つクラス番号</li>\n</ul>\n\n<p>つまり、<br />\n    <code class=\"language-plaintext highlighter-rouge\">all_boxes[box_threshold_mask[0][n]][box_threshold_mask[1][n]][box_threshold_mask[2][n]]</code><br />\n    <code class=\"language-plaintext highlighter-rouge\">all_probabilities[box_threshold_mask[0][n]][box_threshold_mask[1][n]][box_threshold_mask[2][n]][0または1]</code><br />\nがそれぞれn番目の閾値を超えたスコアを持つバウンティングボックスの座標/大きさ情報とスコア(バウンティングボックスごとのペア)を持つ</p>\n\n<p>データ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [ 0, 0, 0, 0, 0, 0, ・・・・\n  [ 0, 0, 0, 0, 0, 0, ・・・・]\n  [ 0, 0, 0, 0, 0, 1, ・・・・]\n  [ 0, 1, 2, 3, 5, 1, ・・・・]\n]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">nonzero</span><span class=\"p\">(</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">gx_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">gy_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">bb_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">cls_list</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n                        <span class=\"n\">gy_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">gy_list</span><span class=\"p\">,</span>  <span class=\"n\">gy</span><span class=\"p\">)</span>\n                        <span class=\"n\">gx_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">gx_list</span><span class=\"p\">,</span>  <span class=\"n\">gx</span><span class=\"p\">)</span>\n                        <span class=\"n\">bb_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">bb_list</span><span class=\"p\">,</span>  <span class=\"n\">bb</span><span class=\"p\">)</span>\n                        <span class=\"n\">cls_list</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">cls_list</span><span class=\"p\">,</span> <span class=\"n\">cls</span><span class=\"p\">)</span>\n    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">gy_list</span><span class=\"p\">,</span> <span class=\"n\">gx_list</span><span class=\"p\">,</span> <span class=\"n\">bb_list</span><span class=\"p\">,</span> <span class=\"n\">cls_list</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>79行目<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 閾値を超えたスコアの数 × 4 の 2次元配列</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n]</code>    : n番目の閾値を超えたスコアを持つバウンティングボックスの座標/サイズ情報のセット\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][0]</code> : X座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][1]</code> : Y座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][2]</code> : 幅(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][3]</code> : 高さ(pixel単位)</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">((</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">),</span> <span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i0</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span> <span class=\"p\">:</span>\n        <span class=\"n\">box_info</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]]</span>\n        <span class=\"n\">box_info</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">box_info</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n        <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">,</span> <span class=\"n\">box_info</span><span class=\"p\">,</span> <span class=\"n\">axis</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>80行目<br />\n・・・  う~ん ・・・</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p>なんか複雑な式なのでちょっと分割してみる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tmp_data</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">tmp_data</code> は Grid_Y × Grid_X × BBox の3次元配列<br />\nデータは各グリッドにBBoxずつ定義されたバウンティングボックスの各クラスに対するスコアの中から最大値を持つ要素のインデックス(=クラス番号)</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">np.argmax()</code>は配列要素の最大値を取るメソッド。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities[GY][GX][BB][CLS]</code>の4次元配列に対してaxis=3を指定して実行していて、<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities[gy][gx][bb][0~NumCls]</code>の最大値を持つ要素のインデックスを <code class=\"language-plaintext highlighter-rouge\">tmp_data[gy][gx][bb]</code>に格納する</p>\n\n<p>データ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [ 1, 2, ]\n    [ 1, 2, ]\n    [ 3, 1, ]\n    [ 2, 0, ]\n    [ 4, 2, ]\n    [ 2, 4, ]\n    [ 0, 5, ]\n  ]\n  ・・・\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code> は 閾値を超えたスコアの数 の 1次元配列<br />\nデータは各グリッドのスコアが最大のクラス番号を格納した1次元配列\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ 1, 1, 1, 1, ・・・\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tmp_data</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_cell</span><span class=\"p\">),</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">].</span><span class=\"n\">tolist</span><span class=\"p\">()</span>\n                <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">a</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">))</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span>  <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i0</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span> <span class=\"p\">:</span>\n        <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">,</span> <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]])</span>\n</code></pre></div></div>\n\n<p>81行目<br />\n<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code> は 閾値を超えたスコアの数 の 1次元配列。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold[n]</code>    : n番目の閾値を超えたスコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probabilities_above_threshold</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'float'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n                        <span class=\"n\">probabilities_above_threshold</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">,</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>この時点でスコアが閾値を超えたグリッドの情報が</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code></li>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code></li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code></li>\n</ul>\n\n<p>に格納される。これらは 一対一対一 の関係になっている。<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 2次元配列だが、X, Y, WIDTH, HEIGHT のペアの配列と考えればわかりやすい。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above[n]</code>  : n番目の閾値を超えたスコアを持つクラス番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold[n]</code>    : n番目の閾値を超えたスコア</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n]</code>            : n番目の閾値を超えたスコアを持つバウンティングボックスの座標/サイズ情報のセット\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][0]</code>       : X座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][1]</code>       : Y座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][2]</code>       : 幅(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][3]</code>       : 高さ(pixel単位)</li>\n    </ul>\n  </li>\n</ul>\n\n<p>85行目<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort</code> は <code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code> の各要素を降順に並べた際のインデックス番号を取り出した1次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort(~)</code> は 指定された配列 の各要素を昇順に並べた際のインデックス番号を取り出した配列を得るメソッド。<br />\n<code class=\"language-plaintext highlighter-rouge\">[::-1]</code>を付けてあるので降順になる。<br />\nそのままだと<code class=\"language-plaintext highlighter-rouge\">list</code>型になってしまうので、<code class=\"language-plaintext highlighter-rouge\">np.array()</code>で<code class=\"language-plaintext highlighter-rouge\">np.ndarray</code>型に変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">argsort</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argsort</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">))[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>86行目<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort</code>  を使って\n<code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code>、<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code>、<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> から <code class=\"language-plaintext highlighter-rouge\">argsort</code>で示されたインデックスで示された順に取り出す。<br />\n⇒ スコアの降順にそれぞれを並べ変える。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>書き換えるほどでもないので、ま、いっか。</p>\n\n<p>92行目<br />\n<code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code> は <code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> を検索して重なったボックス情報を削除するためのマスク情報配列。<br />\n閾値を超えたスコアの数 の dtype.bool型の1次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">get_duplicate_box_mask()</code> は <a href=\"TinyYOLO_3\">別ページ</a>参照。<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ True, True, False, False, True, ・・・]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 既にスコアの高い順に並べ替えられているので、先頭から検索していって最初の出てきたボックスを優先すれば良い。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">duplicate_box_mask</span> <span class=\"o\">=</span> <span class=\"n\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>95行目<br />\n<code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code>  を使ってそれぞれの配列からダブったデータを削除する。<br />\n<code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code>、<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code>、<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> から <code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code>でTrueの要素だけ取り出す。<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code>は ダブっていない結果の数(最終認識結果の数) × 4 の 2次元配列<br />\nそれ以外は ダブっていない結果の数(最終認識結果の数)の 1次元配列</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>99行目<br />\n最終認識結果をlistにまとめなおしてリターンする。<br />\n<code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classes_boxes_and_probs</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)):</span>\n        <span class=\"n\">classes_boxes_and_probs</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">([</span><span class=\"n\">network_classifications</span><span class=\"p\">[</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]])</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">classes_boxes_and_probs</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その3)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その3)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"重なったボックス情報を削除するためのマスク情報配列を取得get_duplicate_box_mask\">重なったボックス情報を削除するためのマスク情報配列を取得(get_duplicate_box_mask)</h1>\n\n<p>109行目<br />\n重なったボックス情報を削除するためのマスク情報配列を取得する。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_list</code> : バウンティングボックスの座標/サイズ情報のセットの配列<br />\n<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [X座標, Y座標, 幅, 高さ],\n  [X座標, Y座標, 幅, 高さ],\n  ・・・\n]\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>出力は<br />\n重なったボックス情報を削除するためのマスク情報配列。<br />\n閾値を超えたスコアの数 の dtype.bool型の1次元配列。<br />\n出力の配列の構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ True, True, False, False, True, ・・・]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>113行目<br />\n重なっていると判断する重なり比率の閾値</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">max_iou</span> <span class=\"o\">=</span> <span class=\"mf\">0.35</span>\n</code></pre></div></div>\n\n<p>115行目<br />\n重なり判断済みフラグを1で初期化<br />\ndtype=’bool’ で良い気がするが…そうすれば最後のboolへの変換処理が不要になるのに…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">ones</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>117行目<br />\n総当たりチェックを行うためのループ処理<br />\n重なり判断済みフラグが0なら既に重なりBOXとして削除済みなのでスキップ</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n</code></pre></div></div>\n\n<p>120行目<br />\n2つのBOXの重なり比率を計算し、<code class=\"language-plaintext highlighter-rouge\">max_iou</code>より大きければ重なっていると判断する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"k\">if</span> <span class=\"n\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">max_iou</span><span class=\"p\">:</span>\n                <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span>\n</code></pre></div></div>\n<p>123行目<br />\n重なり判断済みフラグをbool型に変換したものを返す</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">filter_iou_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">box_mask</span> <span class=\"o\">></span> <span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">filter_iou_mask</span>\n</code></pre></div></div>\n\n<h1 id=\"2つのboxの重なり比率を計算get_intersection_over_union\">2つのBOXの重なり比率を計算(get_intersection_over_union)</h1>\n\n<p>163行目<br />\nパラメータで与えられる2つのBOXの重なり比率を計算する</p>\n\n<p>パラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_1</code> : ボックス1の座標/サイズ情報</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_2</code> : ボックス2の座標/サイズ情報</li>\n</ul>\n\n<p>各パラメータの配列構成は</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[0]</code> : ボックスのX座標(中心, pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[1]</code> : ボックスのY座標(中心, pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[2]</code> : ボックスの幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[3]</code> : ボックスの高さ(pixel単位)</li>\n</ul>\n\n<p>なお、座標系は  X座標は左端が原点、Y座標は上端が原点</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>166行目<br />\nbox_1 の右端座標 と box_2 の 右端座標 の小さい方 の座標 から<br />\nbox_1 の左端座標 と box_2 の 左端座標 の大きい方 の座標を引く<br />\n    ⇒ 重なっている部分の幅</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">intersection_dim_1</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n</code></pre></div></div>\n\n<p>170行目<br />\nbox_1 の下端座標 と box_2 の下端座標 の小さい方 の座標 から<br />\nbox_1 の上端座標 と box_2 の上端座標 の大きい方 の座標を引く<br />\n    ⇒ 重なっている部分の高さ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">intersection_dim_2</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>173行目<br />\n重なっている部分の幅と高さのどちらかが負数<br />\n    ⇒ 重なっている部分はないので、その面積は0</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">if</span> <span class=\"n\">intersection_dim_1</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">intersection_dim_2</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># no intersection area\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n</code></pre></div></div>\n\n<p>176行目<br />\n重なっている部分の幅と高さのどちらかが正数<br />\n    ⇒ 重なっている部分の面積を計算</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># intersection area is product of intersection dimensions\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span>  <span class=\"n\">intersection_dim_1</span><span class=\"o\">*</span><span class=\"n\">intersection_dim_2</span>\n</code></pre></div></div>\n\n<p>183行目<br />\nbox_1とbox_2の合計面積を計算(box_1の面積 + box_2の面積 - 重なっている部分の面積)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">union_area</span> <span class=\"o\">=</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">intersection_area</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<p>186行目<br />\nbox_1とbox_2の合計面積のうち、重なっている部分の比率を返す。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">iou</span> <span class=\"o\">=</span> <span class=\"n\">intersection_area</span> <span class=\"o\">/</span> <span class=\"n\">union_area</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">iou</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その4)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その4)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"バウンティングボックス情報の単位変換boxes_to_pixel_units\">バウンティングボックス情報の単位変換(boxes_to_pixel_units)</h1>\n\n<p>129行目<br />\n各バウンティングボックスの座標/サイズ情報配列内のデータは各グリッド内の相対位置/相対サイズなので、画像内の座標に変換する。</p>\n\n<p>パラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_list   </code> : 各バウンティングボックスの座標/サイズ情報配列、</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">image_width</code> : 入力画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">image_height</code> : 入力画像高(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">grid_size  </code> : グリッドサイズ(7)<br />\n<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n [\n   [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n   [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n ]\n ・・・\n 同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>変換後の<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>132行目<br />\n定義されたバウンティングボックスの数。<br />\nGraphファイルに紐づいた値と考えられるので、トップレベルで定義しておいた方が分かりやすいと思うのだが。。。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n</code></pre></div></div>\n\n<p>136行目<br />\nグリッド内オフセットから画像内オフセットに変換するための作業用配列を作成。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">)),(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)),(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>う~ん、まとめて書いてあって分かり難いので、分解してみる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">aa</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span>\n    <span class=\"n\">bb</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">aa</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n    <span class=\"n\">cc</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">bb</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">))</span>\n    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">cc</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>としたとき、</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>aa = [\n       [0, 1, 2, 3, 4, 5, 6]\n     ]\nbb = [\n       [0, 1, 2, 3, 4, 5, 6],\n       ・・・\n       同じものがあと13組(合計14組)\n     ]\ncc = [\n       [\n         [0, 1, 2, 3, 4, 5, 6],\n         ・・・\n         同じものがあと6組(合計7組)\n       ],\n       ・・・\n       同じものがあと1組(合計2組)\n     ]\nbox_offset = [\n               [\n                 [0, 0],\n                 [1, 1],\n                 [2, 2],\n                 [3, 3],\n                 [4, 4],\n                 [5, 5],\n                 [6, 6]\n               ],\n               ・・・\n               同じものがあと6組(合計7組)\n             ]\n</code></pre></div></div>\n<p>となる。</p>\n\n<p>139行目<br />\n各グリッドのX座標データにグリッド番号を加算する(画像内絶対位置になる。単位:グリッド)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">box_offset</span>\n</code></pre></div></div>\n\n<p>140行目<br />\n各グリッドのY座標データにグリッド番号を加算する(画像内絶対位置になる。単位:グリッド)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">box_offset</span><span class=\"p\">,(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>141行目<br />\n各グリッドのX座標とY座標データをグリッド数で割る(画像内相対位置になる)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># adjust the lengths and widths\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n</code></pre></div></div>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\">#scale the boxes to the image size in pixels\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n</code></pre></div></div>\n\n<h2 id=\"処理を書き換えてみる\">処理を書き換えてみる</h2>\n<p>なにやら小難しいことをやっているので、実行速度を考えずに分かりやすく書き換えると以下のようになる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units_alt</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>                               <span class=\"c1\"># 定義されたバウンティングボックス数  \n</span>    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>                     <span class=\"c1\"># グリッド縦方向ループ\n</span>        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>                 <span class=\"c1\"># グリッド横方向ループ\n</span>            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>        <span class=\"c1\"># バウンティングボックスループ\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">gx</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span>        <span class=\"c1\"># box_x\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">gy</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span>       <span class=\"c1\"># box_y\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">**</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span>                             <span class=\"c1\"># box_widtn\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">**</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span>                            <span class=\"c1\"># box_height\n</span></code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その5)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その5)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"認識結果の表示ルーチンdisplay_objects_in_gui\">認識結果の表示ルーチン(display_objects_in_gui)</h1>\n\n<p>203行目<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">source_image</code>:入力画像(表示画像)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects</code>:整理された認識結果</li>\n</ul>\n\n<p><code class=\"language-plaintext highlighter-rouge\">filtered_objects</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">source_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objects</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>205行目<br />\n入力画像を表示用に<code class=\"language-plaintext highlighter-rouge\">display_image</code>にコピーする。(もともと入力された<code class=\"language-plaintext highlighter-rouge\">source_image</code>は汚さない。)<br />\n<code class=\"language-plaintext highlighter-rouge\">source_image_width</code>、<code class=\"language-plaintext highlighter-rouge\">source_image_height</code>は入力画像の幅と高さ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n    <span class=\"n\">source_image_width</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">source_image_height</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>209行目<br />\n<code class=\"language-plaintext highlighter-rouge\">NETWORK_IMAGE_WIDTH</code>と<code class=\"language-plaintext highlighter-rouge\">NETWORK_IMAGE_HEIGHT</code> は ニューラルネットに入力した画像サイズ(グローバル変数)。<br />\nどうせなら関数パラメータで渡した方がスマートだと思うが…<br />\n<code class=\"language-plaintext highlighter-rouge\">filtered_objects</code>の各データはこのサイズで定義されているので、表示用に変換するための比率を<code class=\"language-plaintext highlighter-rouge\">x_ratio</code>、<code class=\"language-plaintext highlighter-rouge\">y_ratio</code>として得る。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">x_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_width</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_WIDTH</span>\n    <span class=\"n\">y_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_height</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span>\n</code></pre></div></div>\n\n<p>213行目<br />\nそれぞれのバウンティングボックスに対してのループ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Found this many objects in the image: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)))</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)):</span>\n</code></pre></div></div>\n\n<p>215行目<br />\n認識結果のX座標(中心)、Y座標(中心)、幅、高さを表示用画像のサイズに変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">center_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span> \n        <span class=\"n\">center_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span>\n        <span class=\"n\">half_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n        <span class=\"n\">half_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n</code></pre></div></div>\n\n<p>221行目<br />\nX座標(中心)、Y座標(中心)、幅、高さからX座標(左端)、Y座標(上端)、X座標(右端)、Y座標(右端)に変換。<br />\n表示画像の範囲からはみ出ないように制限処理を付けてある。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">box_left</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">-</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_top</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">-</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_right</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">+</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"n\">source_image_width</span><span class=\"p\">)</span>\n        <span class=\"n\">box_bottom</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">+</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"n\">source_image_height</span><span class=\"p\">)</span>\n\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'box at index '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj_index</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">' is... left: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', top: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_top</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', right: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_right</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', bottom: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_bottom</span><span class=\"p\">))</span>  \n</code></pre></div></div>\n\n<p>229行目<br />\n表示画像にバウンティングボックスの四角を描く。<br />\n色は緑、線幅は2。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">box_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>  <span class=\"c1\"># green box\n</span>        <span class=\"n\">box_thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span> <span class=\"n\">box_bottom</span><span class=\"p\">),</span> <span class=\"n\">box_color</span><span class=\"p\">,</span> <span class=\"n\">box_thickness</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>234行目<br />\n表示画像に認識結果の名称とスコアを書く。<br />\n背景は暗い緑。文字色は白。<br />\n表示位置はバウンティングボックスの上20ピクセルの場所。<br />\nサイズは縦20ピクセル、横バウンティングボックスと同サイズ。<br />\n(バウンティングボックスの上端が20未満の時大丈夫なんだろか?表示が切れるだけ?)<br />\n(バウンティングボックスの右端より認識結果文字列が長いときも?)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">label_background_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">70</span><span class=\"p\">,</span> <span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">70</span><span class=\"p\">)</span> <span class=\"c1\"># greyish green background for text\n</span>        <span class=\"n\">label_text_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>   <span class=\"c1\"># white text\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">20</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"p\">),</span> <span class=\"n\">label_background_color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">' : %.2f'</span> <span class=\"o\">%</span> <span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">5</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"o\">+</span><span class=\"mi\">5</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"n\">label_text_color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>ループはここまで。</p>\n\n<p>239行目<br />\n画像の表示</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">window_name</span> <span class=\"o\">=</span> <span class=\"s\">'TinyYolo (hit key to exit)'</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">display_image</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>242行目<br />\nキー入力待ち。待ち時間は1msec。<br />\n待ち時間内にキーが押されなければ-1が返ってくる。<br />\nキー入力はGUIで表示されたウィンドウにフォーカスが当たっているときのみ有効で、コンソール(ターミナルなど)で入力してもダメ。<br />\n64bitマシンでは、キーコードを使用する場合は値を<code class=\"language-plaintext highlighter-rouge\">& 0xff</code>する必要があるが、入力なしを検出するだけなのでそのままでOK。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"n\">raw_key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>247行目<br />\nウィンドウパラメータの取得。<br />\nウィンドウが閉じられていれば-1.0が返る。表示状態ならウィンドウのアクセプト比が返る。<br />\n×ボタンでウィンドウを閉じたときの対策。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">prop_val</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">getWindowProperty</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">WND_PROP_ASPECT_RATIO</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>247行目<br />\nキー入力があった、または、×ボタンでウィンドウが閉じられたら終了。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">raw_key</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"n\">prop_val</span> <span class=\"o\"><</span> <span class=\"mf\">0.0</span><span class=\"p\">)):</span>\n            <span class=\"c1\"># the user hit a key or closed the window (in that order)\n</span>            <span class=\"k\">break</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Intel NCStick用TinyYOLOの<a href=\"https://github.com/movidius/ncappzoo/blob/ncsdk2/caffe/TinyYolo/run.py\">ソース</a>のコピー</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#! /usr/bin/env python3\n</span>\n<span class=\"c1\"># Copyright(c) 2017 Intel Corporation. \n# License: MIT See LICENSE file in root directory.\n</span>\n<span class=\"kn\">from</span> <span class=\"nn\">mvnc</span> <span class=\"kn\">import</span> <span class=\"n\">mvncapi</span> <span class=\"k\">as</span> <span class=\"n\">mvnc</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n\n\n<span class=\"c1\"># Assume running in examples/caffe/TinyYolo and graph file is in current directory.\n</span><span class=\"n\">input_image_file</span><span class=\"o\">=</span> <span class=\"s\">'../../data/images/nps_chair.png'</span>\n<span class=\"n\">tiny_yolo_graph_file</span><span class=\"o\">=</span> <span class=\"s\">'./graph'</span>\n\n<span class=\"c1\"># Tiny Yolo assumes input images are these dimensions.\n</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n<span class=\"n\">NETWORK_IMAGE_HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n\n\n<span class=\"c1\"># Interpret the output from a single inference of TinyYolo (GetResult)\n# and filter out objects/boxes with low probabilities.\n# output is the array of floats returned from the API GetResult but converted\n# to float32 format.\n# input_image_width is the width of the input image\n# input_image_height is the height of the input image\n# Returns a list of lists. each of the inner lists represent one found object and contain\n# the following 6 values:\n#    string that is network classification ie 'cat', or 'chair' etc\n#    float value for box center X pixel location within source image\n#    float value for box center Y pixel location within source image\n#    float value for box width in pixels within source image\n#    float value for box height in pixels within source image\n#    float value that is the probability for the network classification.\n</span><span class=\"k\">def</span> <span class=\"nf\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># the raw number of floats returned from the inference (GetResult())\n</span>    <span class=\"n\">num_inference_results</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># the 20 classes this network was trained on\n</span>    <span class=\"n\">network_classifications</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">\"aeroplane\"</span><span class=\"p\">,</span> <span class=\"s\">\"bicycle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bird\"</span><span class=\"p\">,</span> <span class=\"s\">\"boat\"</span><span class=\"p\">,</span> <span class=\"s\">\"bottle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bus\"</span><span class=\"p\">,</span> <span class=\"s\">\"car\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"cat\"</span><span class=\"p\">,</span> <span class=\"s\">\"chair\"</span><span class=\"p\">,</span> <span class=\"s\">\"cow\"</span><span class=\"p\">,</span> <span class=\"s\">\"diningtable\"</span><span class=\"p\">,</span> <span class=\"s\">\"dog\"</span><span class=\"p\">,</span> <span class=\"s\">\"horse\"</span><span class=\"p\">,</span> <span class=\"s\">\"motorbike\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"person\"</span><span class=\"p\">,</span> <span class=\"s\">\"pottedplant\"</span><span class=\"p\">,</span> <span class=\"s\">\"sheep\"</span><span class=\"p\">,</span> <span class=\"s\">\"sofa\"</span><span class=\"p\">,</span> <span class=\"s\">\"train\"</span><span class=\"p\">,</span><span class=\"s\">\"tvmonitor\"</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># only keep boxes with probabilities greater than this\n</span>    <span class=\"n\">probability_threshold</span> <span class=\"o\">=</span> <span class=\"mf\">0.07</span>\n\n    <span class=\"n\">num_classifications</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">network_classifications</span><span class=\"p\">)</span> <span class=\"c1\"># should be 20\n</span>    <span class=\"n\">grid_size</span> <span class=\"o\">=</span> <span class=\"mi\">7</span> <span class=\"c1\"># the image is a 7x7 grid.  Each box in the grid is 64x64 pixels\n</span>    <span class=\"n\">boxes_per_grid_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span> <span class=\"c1\"># the number of boxes returned for each grid cell\n</span>\n    <span class=\"c1\"># grid_size is 7 (grid is 7x7)\n</span>    <span class=\"c1\"># num classifications is 20\n</span>    <span class=\"c1\"># boxes per grid cell is 2\n</span>    <span class=\"n\">all_probabilities</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># classification_probabilities  contains a probability for each classification for\n</span>    <span class=\"c1\"># each 64x64 pixel square of the grid.  The source image contains\n</span>    <span class=\"c1\"># 7x7 of these 64x64 pixel squares and there are 20 possible classifications\n</span>    <span class=\"n\">classification_probabilities</span> <span class=\"o\">=</span> \\\n        <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">980</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n    <span class=\"n\">num_of_class_probs</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># The probability scale factor for each box\n</span>    <span class=\"n\">box_prob_scale_factor</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">980</span><span class=\"p\">:</span><span class=\"mi\">1078</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># get the boxes from the results and adjust to be pixel units\n</span>    <span class=\"n\">all_boxes</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">1078</span><span class=\"p\">:],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n    <span class=\"n\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">all_boxes</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># adjust the probabilities with the scaling factor\n</span>    <span class=\"k\">for</span> <span class=\"n\">box_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">):</span> <span class=\"c1\"># loop over boxes\n</span>        <span class=\"k\">for</span> <span class=\"n\">class_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">):</span> <span class=\"c1\"># loop over classifications\n</span>            <span class=\"n\">all_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">,</span><span class=\"n\">class_index</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">class_index</span><span class=\"p\">],</span><span class=\"n\">box_prob_scale_factor</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">])</span>\n\n\n    <span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"o\">>=</span><span class=\"n\">probability_threshold</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">nonzero</span><span class=\"p\">(</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">)</span>\n    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># sort the boxes from highest probability to lowest and then\n</span>    <span class=\"c1\"># sort the probabilities and classifications to match\n</span>    <span class=\"n\">argsort</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argsort</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">))[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n\n\n    <span class=\"c1\"># get mask for boxes that seem to be the same object\n</span>    <span class=\"n\">duplicate_box_mask</span> <span class=\"o\">=</span> <span class=\"n\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># update the boxes, probabilities and classifications removing duplicates.\n</span>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n\n    <span class=\"n\">classes_boxes_and_probs</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)):</span>\n        <span class=\"n\">classes_boxes_and_probs</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">([</span><span class=\"n\">network_classifications</span><span class=\"p\">[</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]])</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">classes_boxes_and_probs</span>\n\n<span class=\"c1\"># creates a mask to remove duplicate objects (boxes) and their related probabilities and classifications\n# that should be considered the same object.  This is determined by how similar the boxes are\n# based on the intersection-over-union metric.\n# box_list is as list of boxes (4 floats for centerX, centerY and Length and Width)\n</span><span class=\"k\">def</span> <span class=\"nf\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">):</span>\n    <span class=\"c1\"># The intersection-over-union threshold to use when determining duplicates.\n</span>    <span class=\"c1\"># objects/boxes found that are over this threshold will be\n</span>    <span class=\"c1\"># considered the same object\n</span>    <span class=\"n\">max_iou</span> <span class=\"o\">=</span> <span class=\"mf\">0.35</span>\n\n    <span class=\"n\">box_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">ones</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">))</span>\n\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">max_iou</span><span class=\"p\">:</span>\n                <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span>\n\n    <span class=\"n\">filter_iou_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">box_mask</span> <span class=\"o\">></span> <span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">filter_iou_mask</span>\n\n<span class=\"c1\"># Converts the boxes in box list to pixel units\n# assumes box_list is the output from the box output from\n# the tiny yolo network and is [grid_size x grid_size x 2 x 4].\n</span><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># number of boxes per grid cell\n</span>    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n\n    <span class=\"c1\"># setup some offset values to map boxes to pixels\n</span>    <span class=\"c1\"># box_offset will be [[ [0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6]] ...repeated for 7 ]\n</span>    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">)),(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)),(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># adjust the box center\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">box_offset</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">box_offset</span><span class=\"p\">,(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># adjust the lengths and widths\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n\n    <span class=\"c1\">#scale the boxes to the image size in pixels\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n\n\n<span class=\"c1\"># Evaluate the intersection-over-union for two boxes\n# The intersection-over-union metric determines how close\n# two boxes are to being the same box.  The closer the boxes\n# are to being the same, the closer the metric will be to 1.0\n# box_1 and box_2 are arrays of 4 numbers which are the (x, y)\n# points that define the center of the box and the length and width of\n# the box.\n# Returns the intersection-over-union (between 0.0 and 1.0)\n# for the two boxes specified.\n</span><span class=\"k\">def</span> <span class=\"nf\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># one diminsion of the intersecting box\n</span>    <span class=\"n\">intersection_dim_1</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># the other dimension of the intersecting box\n</span>    <span class=\"n\">intersection_dim_2</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">intersection_dim_1</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">intersection_dim_2</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># no intersection area\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># intersection area is product of intersection dimensions\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span>  <span class=\"n\">intersection_dim_1</span><span class=\"o\">*</span><span class=\"n\">intersection_dim_2</span>\n\n    <span class=\"c1\"># calculate the union area which is the area of each box added\n</span>    <span class=\"c1\"># and then we need to subtract out the intersection area since\n</span>    <span class=\"c1\"># it is counted twice (by definition it is in each box)\n</span>    <span class=\"n\">union_area</span> <span class=\"o\">=</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">intersection_area</span><span class=\"p\">;</span>\n\n    <span class=\"c1\"># now we can return the intersection over union\n</span>    <span class=\"n\">iou</span> <span class=\"o\">=</span> <span class=\"n\">intersection_area</span> <span class=\"o\">/</span> <span class=\"n\">union_area</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">iou</span>\n\n<span class=\"c1\"># Displays a gui window with an image that contains\n# boxes and lables for found objects.  will not return until\n# user presses a key.\n# source_image is the original image for the inference before it was resized or otherwise changed.\n# filtered_objects is a list of lists (as returned from filter_objects()\n# each of the inner lists represent one found object and contain\n# the following 6 values:\n#    string that is network classification ie 'cat', or 'chair' etc\n#    float value for box center X pixel location within source image\n#    float value for box center Y pixel location within source image\n#    float value for box width in pixels within source image\n#    float value for box height in pixels within source image\n#    float value that is the probability for the network classification.\n</span><span class=\"k\">def</span> <span class=\"nf\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">source_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objects</span><span class=\"p\">):</span>\n    <span class=\"c1\"># copy image so we can draw on it. Could just draw directly on source image if not concerned about that.\n</span>    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n    <span class=\"n\">source_image_width</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">source_image_height</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"n\">x_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_width</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_WIDTH</span>\n    <span class=\"n\">y_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_height</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span>\n\n    <span class=\"c1\"># loop through each box and draw it on the image along with a classification label\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Found this many objects in the image: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)))</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)):</span>\n        <span class=\"n\">center_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span> \n        <span class=\"n\">center_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span>\n        <span class=\"n\">half_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n        <span class=\"n\">half_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n\n        <span class=\"c1\"># calculate box (left, top) and (right, bottom) coordinates\n</span>        <span class=\"n\">box_left</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">-</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_top</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">-</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_right</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">+</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"n\">source_image_width</span><span class=\"p\">)</span>\n        <span class=\"n\">box_bottom</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">+</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"n\">source_image_height</span><span class=\"p\">)</span>\n\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'box at index '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj_index</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">' is... left: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', top: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_top</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', right: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_right</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', bottom: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_bottom</span><span class=\"p\">))</span>  \n\n        <span class=\"c1\">#draw the rectangle on the image.  This is hopefully around the object\n</span>        <span class=\"n\">box_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>  <span class=\"c1\"># green box\n</span>        <span class=\"n\">box_thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span> <span class=\"n\">box_bottom</span><span class=\"p\">),</span> <span class=\"n\">box_color</span><span class=\"p\">,</span> <span class=\"n\">box_thickness</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># draw the classification label string just above and to the left of the rectangle\n</span>        <span class=\"n\">label_background_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">70</span><span class=\"p\">,</span> <span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">70</span><span class=\"p\">)</span> <span class=\"c1\"># greyish green background for text\n</span>        <span class=\"n\">label_text_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>   <span class=\"c1\"># white text\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">20</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"p\">),</span> <span class=\"n\">label_background_color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">' : %.2f'</span> <span class=\"o\">%</span> <span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">5</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"o\">+</span><span class=\"mi\">5</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"n\">label_text_color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n    <span class=\"n\">window_name</span> <span class=\"o\">=</span> <span class=\"s\">'TinyYolo (hit key to exit)'</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">display_image</span><span class=\"p\">)</span>\n\n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"n\">raw_key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># check if the window is visible, this means the user hasn't closed\n</span>        <span class=\"c1\"># the window via the X button (may only work with opencv 3.x\n</span>        <span class=\"n\">prop_val</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">getWindowProperty</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">WND_PROP_ASPECT_RATIO</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">raw_key</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"n\">prop_val</span> <span class=\"o\"><</span> <span class=\"mf\">0.0</span><span class=\"p\">)):</span>\n            <span class=\"c1\"># the user hit a key or closed the window (in that order)\n</span>            <span class=\"k\">break</span>\n\n\n<span class=\"c1\"># This function is called from the entry point to do\n# all the work.\n</span><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Running NCS Caffe TinyYolo example'</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Set logging level to only log errors\n</span>    <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">global_set_option</span><span class=\"p\">(</span><span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">GlobalOption</span><span class=\"p\">.</span><span class=\"n\">RW_LOG_LEVEL</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"n\">devices</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">enumerate_devices</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'No devices found'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"mi\">1</span>\n    <span class=\"n\">device</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Device</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"nb\">open</span><span class=\"p\">()</span>\n\n    <span class=\"c1\">#Load graph from disk and allocate graph via API\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tiny_yolo_graph_file</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'rb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">graph_from_disk</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Graph</span><span class=\"p\">(</span><span class=\"s\">\"Tiny Yolo Graph\"</span><span class=\"p\">)</span>\n    <span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span> <span class=\"o\">=</span> <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">allocate_with_fifos</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"n\">graph_from_disk</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Read image from file, resize it to network width and height\n</span>    <span class=\"c1\"># save a copy in display_image for display, then convert to float32, normalize (divide by 255),\n</span>    <span class=\"c1\"># and finally convert to convert to float16 to pass to LoadTensor as input for an inference\n</span>    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">input_image_file</span><span class=\"p\">)</span>\n    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span><span class=\"p\">,</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">INTER_LINEAR</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">divide</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"mf\">255.0</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>  <span class=\"c1\"># convert to RGB\n</span>\n    <span class=\"c1\"># Load tensor and get result.  This executes the inference on the NCS\n</span>    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">queue_inference_with_fifo_elem</span><span class=\"p\">(</span><span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span><span class=\"p\">,</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">output</span><span class=\"p\">,</span> <span class=\"n\">userobj</span> <span class=\"o\">=</span> <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">read_elem</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># filter out all the objects/boxes that don't meet thresholds\n</span>    <span class=\"n\">filtered_objs</span> <span class=\"o\">=</span> <span class=\"n\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">output</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Displaying image with objects detected in GUI'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Click in the GUI window and hit any key to exit'</span><span class=\"p\">)</span>\n    <span class=\"c1\">#display the filtered objects/boxes in a GUI window\n</span>    <span class=\"n\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objs</span><span class=\"p\">)</span>\n\n    <span class=\"n\">fifo_in</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Finished'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># main entry point for program. we'll call main() to do what needs to be done.\n</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian Busterのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian Busterのインストール</h1>\n      <p>Raspbian Buster with desktopのインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspbian Buster with desktop」 の 「DownloadZIP」でダウンロードしてSDカードに書き込んでブート。<br />\n(「・・・ and recommended software」 の方ではない)<br />\n以下の手順は、RaspberryPi3 model B+、「Version: July 2019」 で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>は表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nframebuffer_width=1920\nframebuffer_height=1080\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B1 Desktop / CLI\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B3 Splash Screen\n            Would you like to show the splash screen at boot? \n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    5 Interfacing Options        \n        P3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>    \n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n<p>Windows側のクライアントは、<br />\n<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a> \nから VNC Viewerをダウンロード。<br />\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。<br />\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。<br />\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。<br />\n日本語化の手順はこちらを参考に。 <a href=\"http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"c\"># export PYENV_ROOT=/proj/.pyenv</span>\n<span class=\"c\"># export PATH=$PYENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(pyenv init -)\"</span>\n<span class=\"c\"># eval \"$(pyenv virtualenv-init -)\"</span>\n\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"c\"># export NODENV_ROOT=/proj/.nodenv</span>\n<span class=\"c\"># export PATH=$NODENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(nodenv init -)\"</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マウスフォーカスの変更\">マウスフォーカスの変更</h1>\n\n<p>ウィンドウをクリックしないとフォーカスが移動しないのはイライラするので x-mouse相当の設定をする。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/xdg/openbox/lxde-pi-rc.xml</code>の以下の部分をnoからyesに変更。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><followMouse>yes</followMouse>\n</code></pre></div></div>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick2用動作環境の構築</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick2用動作環境の構築</h1>\n      <p>Intel NCStick2用動作環境の構築</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Dセンセの悪魔の囁きに踊らされ、Intel NCStick2をポチってしまった。<br />\nで、動作環境を構築したときのメモを残しておく。</p>\n\n<p>ホストマシンは、RaspberryPi3 model B+ で Raspbian Buster を使用。</p>\n\n<p>Raspbian Busterのインストールは、\n<a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\">Raspbian Busterのインストール</a>\nの手順で行った。</p>\n\n<p><a href=\"http://jellyware.jp/openvino/\">JellyWare:ゼロから学ぶディープラーニング推論</a> \n → <a href=\"http://jellyware.jp/kurage/openvino/c03_setting.html\">ゼロから始めるインストール</a> をマネしただけだが、\nダウンロード先の<strong>URLが微妙に変更</strong>されてたり、\nこのページの説明が<strong>細かすぎてちょっとイラっとした</strong>ので、\n以下に手順の要約を書いておく。</p>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2\n<span class=\"nb\">cd</span> /work/NCS2/\n</code></pre></div></div>\n\n<h2 id=\"openvino-の取得とインストール\">openVINO の取得とインストール</h2>\n\n<p>アーカイブファイル落としてきて、展開するだけ。<br />\nR3がリリースされているようなので、これを使う。(2019/10/01現在)\nちょくちょくリリースされるみたいなので、<a href=\"https://download.01.org/opencv/2019/openvinotoolkit/\">https://download.01.org/opencv/2019/openvinotoolkit/</a>をチェックしてね。<br />\n2020年になったら、~download.01.org/opencv/2020/~ なのかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R3/l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz\n\n<span class=\"c\"># インストール先ディレクトリの作成 & オーナー変更(あとあとめんどくさいので)</span>\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span>  <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n\n<span class=\"c\"># 展開</span>\n<span class=\"nb\">tar </span>xzvf l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span> <span class=\"nt\">--strip-components</span><span class=\"o\">=</span>1\n<span class=\"nb\">sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以下以前の情報</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R2/l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz\n\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo tar</span> <span class=\"nt\">-xf</span> l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz <span class=\"nt\">--strip</span> 1 <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h2 id=\"cmakeのインストール\">cmakeのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n</code></pre></div></div>\n\n<p>他にもmakeとかbuild-essentialとか要るけど、<a href=\"/memoBlog/2019/06/27/pyenv.html\">ここ</a>\nでインストールしたやつがあれば大丈夫っぽい。</p>\n\n<h2 id=\"初期化スクリプトの変更\">初期化スクリプトの変更</h2>\n\n<p>~/.bashrc の最後に以下を追加。<br />\nここでは<code class=\"language-plaintext highlighter-rouge\">${VINO_DIR_TMP}</code>使っちゃダメよ~。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOの設定</span>\n<span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<h2 id=\"初期化スクリプトの変更を反映\">初期化スクリプトの変更を反映</h2>\n\n<p>シリアルコンソールやSSHでlog inしてる場合は、ここで一旦log offして再log in。<br />\nX使ってるならターミナル開きなおす。<br />\nもちろん、<code class=\"language-plaintext highlighter-rouge\">source</code>するだけでも良いけど。<br />\nいちお、.bashrcにちゃんと書けてるか確認の意味で一旦log off or ターミナル開きなおしするのがいいかな。  <br />\n(.bashrcの変更だけなので、再起動までは必要ない) <br />\nlog in時 or 新しいターミナルを開いた時に <code class=\"language-plaintext highlighter-rouge\">[setupvars.sh] OpenVINO environment initialized</code> と表示されることを確認。</p>\n\n<h2 id=\"グループの追加\">グループの追加</h2>\n\n<p>ユーザがグループusersを持っているか確認。(デフォルトなら持ってるハズ) 持ってなかったら追加。<br />\n次のコマンドで追加してくれるっぽいけど。。。</p>\n\n<h2 id=\"udevルールの追加\">udevルールの追加</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sh <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n\n<h2 id=\"いよいよncstick2の登場だ\">いよいよNCStick2の登場だ~~~</h2>\n\n<p>NCStick2をUSBポートにぶっ挿す。<br />\nデカくて他のポートに干渉するので、必要なら延長ケーブルを使ってちょ。</p>\n\n<p>で、認識されたか確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n<span class=\"c\"># こんな感じで表示されるハズ。XXX部分は ぶっ挿したUSBポートで変わる。</span>\n・・・\nBus XXX Device XXX: ID 03e7:2485 Intel Movidius MyriadX\n・・・\n</code></pre></div></div>\n\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n\n<p>とりあえず、ワークディレクトリは<code class=\"language-plaintext highlighter-rouge\">/work/NCS2/</code>を使ってる。<br />\nhome に色々ぶち込むの嫌いなので。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">/work</code>は作成済みで<code class=\"language-plaintext highlighter-rouge\">chown</code>済みとする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ワークディレクトリの作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/sample\n<span class=\"nb\">cd</span> /work/NCS2/sample\n\n<span class=\"c\"># cmakeの実行</span>\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a\"</span> <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/deployment_tools/inference_engine/samples\n\n<span class=\"c\"># makeの実行</span>\nmake <span class=\"nt\">-j2</span> object_detection_sample_ssd\n\n<span class=\"c\"># ネットワークデータの取得</span>\n<span class=\"c\"># shell変数の設定時はスペース入れちゃダメだよ~</span>\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R2/20190716_170000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n\n<span class=\"c\"># 入力ファイルをどっかから持ってきて、<<入力ファイル>>.jpgとしてカレントディレクトリに保存しておく</span>\n<span class=\"c\"># 顔検出のデモなので、人物が何人か写ってる画像を用意してね。</span>\n\n<span class=\"c\"># サンプル実行</span>\n./armv7l/Release/object_detection_sample_ssd  <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> <<入力ファイル>>.jpg\n\n<span class=\"c\"># out_0.bmpができる</span>\n</code></pre></div></div>\n\n<h2 id=\"結果の確認\">結果の確認</h2>\n\n<p>out_0.bmpをテキトーに表示。<br />\n人物の顔が四角で囲まれていることを確認。</p>\n\n<h2 id=\"インストールと動作確認完了\">インストールと動作確認完了</h2>\n\n<p>めでたしめでたし。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WebIOPiをRaspbian Busterで動かす</title>\n  </head>\n  <body>\n    <header>\n      <h1>WebIOPiをRaspbian Busterで動かす</h1>\n      <p>WebIOPiをRaspbian Busterで動かす</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"背景\">背景</h1>\n\n<p>知人がWebIOPiをRaspbian Busterで動かそうとして、Raspbian Stretch では動いたが、Raspbian Busterだと動かないと言っていたので、\n興味本位でデバッグしてみた。</p>\n\n<p>私はこれを使おうと思ってないので、「鳴かぬなら鳴かせてみせようホトトギス」なだけなので、詳しい使い方とかは調べてません。</p>\n\n<h1 id=\"参照\">参照</h1>\n\n<p>そもそものインストール手順は、<br />\n<a href=\"https://www.hiramine.com/physicalcomputing/raspberrypi3/webiopi_install.html\">WebIOPi のインストール</a><br />\n<a href=\"https://www.fabshop.jp/%E9%96%8B%E7%99%BA%E3%81%8C%E7%B5%82%E4%BA%86%E3%81%97%E3%81%9Fwebiopi%E3%82%92%E6%9C%80%E6%96%B0%E3%81%AEraspbian%E3%81%A7%E5%8B%95%E4%BD%9C%E3%81%95%E3%81%9B%E3%82%88%E3%81%86%E3%80%82/?fbclid=IwAR1u1Hq0wSqnDhPnKDeoyf1b2AmrdpO99TLSevUTZ237D5Ny97pliLjlOwU\">開発が終了したWebIOPiを最新のRaspbianで動作させよう。</a><br />\nあたりを参考にしてちょ。</p>\n\n<h1 id=\"いきなり結論\">いきなり結論</h1>\n\n<p>で、まぁ結論から言うと、根本原因は、BusterのPython3がPython3.7にバージョンアップされたこと。<br />\nちなみに、StretchのPython3はPython3.5 。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">python/webiopi/utils/thread.py</code> 内の 関数 <code class=\"language-plaintext highlighter-rouge\">runLoop()</code>の中で<code class=\"language-plaintext highlighter-rouge\">async</code>を変数に使っていたため、SyntaxErrorが発生していた模様。<br />\nPythom3.7では(正確にはPython3.6から)<code class=\"language-plaintext highlighter-rouge\">async</code>は予約語になっているため、エラーとなっていた。</p>\n\n<p>で、変数名を<code class=\"language-plaintext highlighter-rouge\">async</code>からそれ以外(例えば<code class=\"language-plaintext highlighter-rouge\">async_Flag</code>)に変更すれば良い。</p>\n\n<h1 id=\"でpatchファイル\">で、patchファイル</h1>\n\n<p>修正内容のpatchファイルがこちら。<br />\nついでにCプログラムのコンパイルの際に出るワーニングも消すようにちょこっと修正しときました。(こっちの修正は、かなりヤッツケ…)</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/cpuinfo.c WebIOPi-0.7.1/python/native/cpuinfo.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/cpuinfo.c\t2019-09-03 00:04:59.959369913 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/cpuinfo.c\t2019-09-02 23:55:16.207501342 +0900\n</span><span class=\"p\">@@ -35,7 +35,8 @@</span> char *get_cpuinfo_revision(char *revisio\n       return 0;\n \n    while(!feof(fp)) {\n<span class=\"gd\">-      fgets(buffer, sizeof(buffer) , fp);\n</span><span class=\"gi\">+      char* aaa = fgets(buffer, sizeof(buffer) , fp);\n+      aaa = aaa;\n</span>       sscanf(buffer, \"Hardware\t: %s\", hardware);\n       if (strcmp(hardware, \"BCM2708\") == 0)\n          rpi_found = 1;\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/gpio.c WebIOPi-0.7.1/python/native/gpio.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/gpio.c\t2019-09-03 00:04:59.969368480 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/gpio.c\t2019-09-02 23:58:58.757767098 +0900\n</span><span class=\"p\">@@ -23,6 +23,7 @@</span> SOFTWARE.\n #include <stdio.h>\n #include <stdint.h>\n #include <stdlib.h>\n<span class=\"gi\">+#include <unistd.h>\n</span> #include <string.h>\n #include <fcntl.h>\n #include <sys/mman.h>\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/webiopi/utils/thread.py WebIOPi-0.7.1/python/webiopi/utils/thread.py\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/webiopi/utils/thread.py\t2019-09-03 00:04:44.520586361 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/webiopi/utils/thread.py\t2019-09-02 23:54:10.087479478 +0900\n</span><span class=\"p\">@@ -33,14 +33,14 @@</span> def stop(signum=0, frame=None):\n             task.stop()\n                 \n \n<span class=\"gd\">-def runLoop(func=None, async=False):\n</span><span class=\"gi\">+def runLoop(func=None, async_Flag=False):\n</span>     global RUNNING\n     RUNNING = True\n     signal.signal(signal.SIGINT, stop)\n     signal.signal(signal.SIGTERM, stop)\n \n     if func != None:\n<span class=\"gd\">-        if async:\n</span><span class=\"gi\">+        if async_Flag:\n</span>             TASKS.append(Task(func, True))\n         else:\n             while RUNNING:\n</code></pre></div></div>\n\n<p>これを<code class=\"language-plaintext highlighter-rouge\">webiopi-buster.patch</code>として保存し、以下のコマンドを実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch <span class=\"nt\">-p1</span> <span class=\"nt\">-i</span> webiopi-buster.patch\n</code></pre></div></div>\n\n<p>で後は<code class=\"language-plaintext highlighter-rouge\">settup.sh</code>を実行して、その後は参照ページの通り進めれば良い。</p>\n\n<h1 id=\"めでたしめでたし\">めでたしめでたし</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その1)</h1>\n      <p>Node-REDのインストール他のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDをインストールや、フローを作成する際の手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"ubuntu-に-node-red-をインストールする\">ubuntu に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejsとnpmのインストール\">Node.jsとnpmのインストール</h2>\n\n<p>自動起動とかやらないなら、Node.js は nodenv とか使っても良い気がするが、\n念のためシステムに直接インストールしておく。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">apt install</code> だと古いバージョンになってしまうので、<br />\nnコマンド をインストールし、<br />\nnコマンドで安定版をインストールする。<br />\nその後、<code class=\"language-plaintext highlighter-rouge\">apt</code> でインストールしたNode.jsは削除。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n\n<span class=\"c\"># nコマンドのインストール</span>\n<span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> n\n\n<span class=\"c\"># 安定版のインストール</span>\n<span class=\"nb\">sudo </span>n stable\n\n<span class=\"c\"># aptでインストールしたnode.jsをアンインストール</span>\n<span class=\"nb\">sudo </span>apt purge <span class=\"nt\">-y</span> nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h2 id=\"node-redのインストール\">Node-REDのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> <span class=\"nt\">--unsafe-perm</span> node-red node-red-admin\n</code></pre></div></div>\n\n<p>どうも、ノードの追加とかすると、npmのキャッシュをアクセスするときにpermission deniedと言われてしまうみたいなので、\n以下のコマンドで .npm ディレクトリ以下の所有権を自分にしておく。<br />\n(キャッシュだから削除しても良い気がするが)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> ~/.npm\n</code></pre></div></div>\n\n<h2 id=\"起動\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"停止\">停止</h2>\n\n<p>CTRL-Cで停止する。</p>\n\n<h2 id=\"参考\">参考</h2>\n\n<p><a href=\"https://qiita.com/seibe/items/36cef7df85fe2cefa3ea\">https://qiita.com/seibe/items/36cef7df85fe2cefa3ea</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"windows10-に-node-red-をインストールする\">Windows10 に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npmの-インストール\">Node.js と npmの インストール</h2>\n\n<ul>\n  <li><a href=\"https://nodejs.org/ja/\">Node.jsのサイト</a>からWindows版をダウンロードします。\n  推奨版(2019/09/16現在、10.16.3 LTS)をダウンロードしてください。<br />\n  (もし、別のプラットフォームのものが必要なら上部のメニューの「ダウンロード」からダウンロードします)</li>\n  <li>ダウンロードしたnode-vXX.XX.XX-YY.msiを実行してインストーラを起動し、インストールします。\n  特に迷うところはないと思います。大体、そのまま「次へ」で大丈夫。</li>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell を起動します。\n  念のため、<code class=\"language-plaintext highlighter-rouge\">node -v</code> を実行して、<code class=\"language-plaintext highlighter-rouge\">v10.16.3</code>と表示されることを確認します。\n  次にnpmのアップデートを行います。以下のコマンドを実行してください。( 2019/09/16現在、6.11.3 でした)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g npm\n</code></pre></div></div>\n<h2 id=\"node-redのインストール-1\">Node-REDのインストール</h2>\n\n<ul>\n  <li>コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してインストールします。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g --unsafe-perm node-red\n</code></pre></div></div>\n\n<ul>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してNode-REDを起動します。<br />\n実行したウィンドウは閉じないでください。閉じるとNode-REDが終了してしまいます。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>なお、初めてNode-REDを起動したとき、\n『このアプリの機能のいくつかがWindows Defender ファイアウォールでブロックされています』\nと警告が表示されることがある。</p>\n\n<p>この場合、\n「通信を許可するネットワーク」を選択して「アクセスを許可する」をクリック\nすれば良い。</p>\n\n<h2 id=\"ちょっとヒトコトメモ\">ちょっとヒトコトメモ</h2>\n\n<p>(ぜんぜんヒトコトじゃないけど。。。)</p>\n\n<p>Node-REDを起動したPCからのアクセス(ブラウザ接続など)は成功するのに、\n外部PCやRaspberryPi(もちろん、同一サブネット上の)からのアクセス(ブラウザやWebsocket接続)が失敗する場合がある。</p>\n\n<p>考えられる原因は色々あるが、最も多そうな原因のひとつにファイアウォールでのブロックが考えられる。<br />\n上の警告ダイアログでアクセス許可した際に、プライベートネットワークのみに通信を許可していて、\nかつ、現在接続されているネットワークがパブリックネットワークである場合である。</p>\n\n<p>ファイアウォールでのブロックされているかは<strong>Node-REDを起動した状態</strong>で以下のコマンドで確認できる。</p>\n\n<ul>\n  <li>RaspberryPiの場合</li>\n</ul>\n\n<p>以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 《IPアドレス》 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 192.168.1.2 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、コマンドが終了しないので、CTRL+Cで終了する。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">Connection to 《IPアドレス》 《ポート番号》port [tcp/*] succeeded!</code>と表示される。</p>\n\n<ul>\n  <li>Windowsの場合</li>\n</ul>\n\n<p>Windows Poewrshellで(コマンドプロンプトでは不可)以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 《IPアドレス》  <span class=\"nt\">-port</span> 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 192.168.1.2 <span class=\"nt\">-port</span> 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : False</code>と表示される。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : True</code>と表示される。</p>\n\n<p>これを解決するには、Node-REDを実行しているWindows PCで<br />\n「コントロールパネル」→「Windows Defender ファイアウォール」を開き、<br />\n左側のリストから「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック<br />\n「設定の変更」をクリック\n下のリストから「Node.js: Server-side JavaScript」の右側 パブリックのチェックボックスにチェックを入れる<br />\n「OK」をクリック</p>\n\n<p>この状態で再度RaspberryPi または PCからファイアウォールでのブロックの確認を実行し、ブロックされていないことを確認してください。</p>\n\n<h1 id=\"raspbian-に-node-red-をインストールする\">Raspbian に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npm-と-node-red-のインストール\">Node.js と npm と Node-RED のインストール</h2>\n\n<p>インストールスクリプトを実行すればイッパツで解決。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストールスクリプトの取得</span>\nwget  https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered\n\n<span class=\"c\"># 必要なら中身確認してね</span>\n\n<span class=\"c\"># インストールスクリプトの実行</span>\nbash update-nodejs-and-nodered \n</code></pre></div></div>\n\n<h2 id=\"起動-1\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-start \n</code></pre></div></div>\n<p>CTRL-Cでログ表示のみ止まる(Node-RED自体は動作したまま)</p>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"ログ表示\">ログ表示</h2>\n\n<p>Node-RED で console.log などを実行したときは、ログに表示される。<br />\n<code class=\"language-plaintext highlighter-rouge\">node-red-start</code>したままなら表示されるが、CTRL-Cでログ表示を止めていた場合は\n以下のコマンドでログ表示を再開できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-log\n</code></pre></div></div>\n\n<h2 id=\"停止-1\">停止</h2>\n\n<p>Node-RED自体を停止する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-stop\n</code></pre></div></div>\n\n<h2 id=\"参考-1\">参考</h2>\n\n<p><a href=\"https://qiita.com/utaani/items/7155c62d6c5e96822afb\">https://qiita.com/utaani/items/7155c62d6c5e96822afb</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"フローの操作\">フローの操作</h1>\n\n<h2 id=\"フローを保存するエクスポート\">フローを保存する(エクスポート)</h2>\n\n<p>作成したフローは保存することができます。<br />\nしばらく使わないフローを削除したり、別の環境にコピーする場合に保存しておくと良いでしょう。</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「書き出し」→「クリップボード」をクリック →書き出しダイアログが表示される\n    <ul>\n      <li>書き出す範囲を「現在のタブ」「すべてのタブ」から選択。(フローの一部を選択していた場合は「選択したフロー」も選択可能)</li>\n      <li>その下にはその時のJSONファイルの内容が表示されていますので、ここから</li>\n      <li>さらにその下で出力形式を「インデントのないJSONフォーマット」「インデント付きのJSONフォーマット」から選択。多少ファイルサイズが増減しますが、どちらを選んでも特に問題になるようなことはないでしょう。「インデント付き」の方が目視で確認しやすいと思います。</li>\n      <li>「ダウンロード」をクリックすると、ブラウザのファイル保存(ダウンロード)ダイアログが開くので、保存処理を行う(このときのファイル名はflows.json固定なので、必要に応じて保存後リネームしてください)</li>\n      <li>または、「書き出し」をクリックすると、クリップボードへコピーされるので、直接 別の環境の読み込みダイアログやエディタへペーストすることも可能</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"フローを読み込むインポート\">フローを読み込む(インポート)</h2>\n\n<p>保存したフローは読み込んで使用することができます(当然か)</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「読み込み」→「クリップボード」をクリック →読み込みダイアログが表示される\n    <ul>\n      <li>「読み込むファイルを選択してください」をクリックして読み込むファイルを選択 → ファイルの内容がその下のエディットボックスに表示される</li>\n      <li>または、その下のエディットボックスにJSONデータをペースト</li>\n      <li>読み込み先を「現在のタブ」「新規のタブ」から選択(「選択したフロー」で保存してないとどっちでも同じ気がする)</li>\n      <li>「読み込み」をクリック</li>\n    </ul>\n  </li>\n  <li>読み込まれるので、内容を確認。必要なら修正。</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"フローを削除する\">フローを削除する</h2>\n\n<p>使用しなくなったフローをいつまでも残しておくとトラブルの元ですから、削除しましょう。<br />\n(念のため保存しておくのを忘れずに)</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、削除したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>左上の「削除」をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(次回デプロイするまで処理は残っているので注意)</li>\n</ul>\n\n<h2 id=\"フローを一時的に停止する\">フローを一時的に停止する</h2>\n\n<p>後で使うから削除したくはないけど、今デバッグしてる作業の邪魔になる、というような場合、\n作成したフローを削除せずに一時的に停止することができます。</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、停止したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>状態を「無効」にする</li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(デプロイしないといつまで経っても停止しないので注意)</li>\n</ul>\n\n<p>再開する場合は上記手順と同じで、状態を「有効」にする。</p>\n\n<h2 id=\"フローを全削除する\">フローを全削除する</h2>\n\n<p>色々フローを作成したけど、一回チャラにしてやりなおしたいときは、\n一旦Node-REDを停止(ブラウザ切断だけじゃなく、サーバプログラムを停止)して\n以下の2つのファイルを削除する</p>\n\n<ul>\n  <li>~/.node-red/flows_《ホスト名》.json</li>\n  <li>~/.node-red/.flows_《ホスト名》.json.backup</li>\n</ul>\n\n<p>もちろん、念のためバックアップ取っておくのが好ましい。<br />\nバックアップから復元すれば元通りになるはず。</p>\n\n<p>その後、Node-Redを起動すると、フローが綺麗さっぱり消えているハズ。</p>\n\n<h2 id=\"その2以降のフローの例について\">その2以降の「フローの例」について</h2>\n\n<p>「フローの例」に書かれたJSONコードはテスト用に作成したフローをエクスポート(書き出し)したものです。<br />\nこのコードの表示部分にマウスを乗せると、右上に「Copy」ボタンが表示されますので、このボタンをクリックしてください。JSONコードがクリップボードにコピーされます(マウスをドラッグしての選択は不要)。</p>\n\n<p>この状態で、上記<strong>フローを読み込む(インポート)</strong>に示した方法でフローをインポートするとフローがコピーされます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n複数のフローをインポートした場合、既に存在するノードと同名のノードは別のノードとして生成されます。このとき、名前に「(_1)」などの別ノードを識別できるような記号は付きません。<br />\n特に、WebsocketのノードやDashboardのタブ/グループはシステムの動作や見た目に影響しますので、注意してください。<br />\n自動でよしなにする方法はありませんので、手動でチマチマと修正してください。<br />\nサイドバー(右側のペイン)の「▼」ボタンをクリックし、ノードの設定を表示でノードの設定を表示し、<br />\n各ノードの右側の数字をクリックすると、そのノードを参照しているノードの一覧が表示されます。<br />\nさらにそのノード一覧の各ノードをダブルクリックすると、そのノードが点滅表示されるので、そのノードのプロパティで参照先を変更すれば良いでしょう。</p>\n\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その2)</h1>\n      <p>Node-REDのメモ GPIO & I2C編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIO操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDはRaspberryPiで起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"raspberrypiでgpio出力\">RaspberryPiでGPIO出力</h1>\n<ul>\n  <li>パレット(左側のペイン)の「Raspberry Pi」の下の「rpi gpio」(出力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で出力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「出力形式」で「デジタル出力」を選択</li>\n      <li>デプロイしたときに端子状態を初期化したい場合は「端子の状態を初期化」をチェック\n        <ul>\n          <li>「端子の初期状態レベル」を選択</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「LED_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>トリガノードはGPIOから出力する値(0 または 1)を出力する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"51e0a206.805964\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_OUT\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"597df548.0311f4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"89834ee2.89e27\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b020b32.e26818\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"21621e60.e300ba\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_1\",\n        \"pin\": \"22\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"87abb89b.307418\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7ae7810.959a88\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 220,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでgpio入力\">RaspberryPiでGPIO入力</h1>\n\n<ul>\n  <li>パレットの「Raspberry Pi」の下の「rpi gpio」(入力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で入力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「抵抗」で端子に接続するプルアップ/ダウン種別を選択\n        <ul>\n          <li>端子の初期化時に内部のプルアップ/ダウン抵抗のどちらを有効にするかを選択</li>\n          <li>ボード上で処理してれば「なし」を選ぶ</li>\n        </ul>\n      </li>\n      <li>デバウンスにチャタリング除去時間を設定</li>\n      <li>デプロイしたときに端子状態を読み込みたい場合は「~初期状態を読み込む」をチェック</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「SWITCH_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力信号を処理するノードを接続\n    <ul>\n      <li>処理ノードへはGPIOから入力された値(0 または 1)が入力される</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1385085c.ab8648\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_IN\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"e9177a48.70b74\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"932b0e92.05cdd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"932b0e92.05cdd8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f31f20e.4b6d28\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW1\",\n        \"pin\": \"16\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d27c860d.7de3a8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d27c860d.7de3a8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 160,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでi2cを使用する\">RaspberryPiでI2Cを使用する</h1>\n\n<h2 id=\"事前準備\">事前準備</h2>\n\n<p>以下はターミナルやコンソールでの作業</p>\n\n<ul>\n  <li>I2Cを有効化する\n    <ul>\n      <li>リブートは不要らしい</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config\n    5 Interfacing Options\n        P5 I2C\n            Would you like the ARM I2C interface to be enabled?\n            に対して<はい>を選択\n            The ARM I2C interface is enabled\n            と表示されるので<了解>\n    <Finish>\n</code></pre></div></div>\n<ul>\n  <li>I2Cデバイスアクセス用ツールをインストールする</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>i2c-tools\n</code></pre></div></div>\n\n<ul>\n  <li>i2cバスをスキャンしてみる(RasbberryPi2/3のI2Cバスはバス1が出てる。古いのだと0のもあるらしい)</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#   ↓結果(例)</span>\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00:          <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n10: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n20: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n30: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n40: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n50: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n60: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n70: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> 76 <span class=\"nt\">--</span>\n<span class=\"c\"># 76がBME280(Bosch温湿度センサ)</span>\n</code></pre></div></div>\n\n<ul>\n  <li>I2Cデバイスのレジスタをリードしてみる</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cget <span class=\"nt\">-y</span> 1 0x76 0xd0\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ↓ 結果</span>\n0x60\n<span class=\"c\"># レジスタ 0xd0(CHIP ID)をリードするとデバイスのID 0x60が読める</span>\n</code></pre></div></div>\n\n<h2 id=\"bme280用ノードをインストールする\">BME280用ノードをインストールする</h2>\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「bme280」と入力</li>\n  <li>下に検索結果が出るので。「node-red-contrib-bme280」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\n2019/09/13現在、何やらインストール時にエラーになるが、<br />\nモジュールのコンパイル時にwarning/noteが出ているだけのようなので、インストール自体はできているようだ。<br />\nとりあえず下記サンプルは動いているので、大丈夫でしょう。</p>\n</blockquote>\n\n<h2 id=\"bme280を使用するフローを作成する\">BME280を使用するフローを作成する</h2>\n<ul>\n  <li>パレットの「入力」の下の「Bme280」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Bme280」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略するとBme280が表示される</li>\n        </ul>\n      </li>\n      <li>Bus# にバス番号(1)を設定</li>\n      <li>I2C Address にI2Cアドレス(0x76)を設定</li>\n      <li>Topicが必要なら設定(デフォルトはbme280)</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>信号を処理するノードを出力側に接続\n    <ul>\n      <li>Bme280ノードの出力メッセージの内容は以下の通り</li>\n    </ul>\n  </li>\n</ul>\n\n<table>\n  <thead>\n    <tr>\n      <th>変数名</th>\n      <th>値の例</th>\n      <th>項目</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>msg.topic</td>\n      <td>“bme280”</td>\n      <td>ノードの設定で設定したTopic</td>\n    </tr>\n    <tr>\n      <td>msg.payload.temperature_C</td>\n      <td>34.23</td>\n      <td>温度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.humidity</td>\n      <td>54.402349427117336</td>\n      <td>湿度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.pressure_hPa</td>\n      <td>1013.9016246356634</td>\n      <td>気圧</td>\n    </tr>\n    <tr>\n      <td>msg.payload.model</td>\n      <td>“BME280”</td>\n      <td>センサ名</td>\n    </tr>\n  </tbody>\n</table>\n\n<ul>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n    {\n        \"id\": \"e4065603.3c6dc\",\n        \"type\": \"tab\",\n        \"label\": \"BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c0602bca.110b8\",\n        \"type\": \"Bme280\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"8b845ce5.ec2fd\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b845ce5.ec2fd\",\n        \"type\": \"debug\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 630,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"cdbf55ce.3aa94\",\n        \"type\": \"inject\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"c0602bca.110b8\"\n            ]\n        ]\n    }\n]\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その3)</h1>\n      <p>Node-REDのメモ TCP通信編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでTCP通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"udpで送信\">UDPで送信</h1>\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「送信」で出力するメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト)/「ブロードキャストメッセージ」/「マルチキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で送信先ポート番号を設定\n        <ul>\n          <li>受信プログラムが待ち受けしているポート番号を指定</li>\n        </ul>\n      </li>\n      <li>「アドレス」に送信先アドレス(名前 or IPアドレス)を指定</li>\n      <li>さらにその右で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>特定のポートから送信したいときは「ローカルポートを使用」を選択し、その右に送信元ポート番号を指定する\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n          <li>通常は「ローカルポートをランダムに使用」で大丈夫</li>\n        </ul>\n      </li>\n      <li>入力データがBase64エンコードされたBufferオブジェクトの場合は「Base64形式のペイロードを複合」にチェックを入れる\n        <ul>\n          <li>入力データがBase64文字列かをチェックするだけで、ここでデータを変換するわけではない(?)</li>\n          <li>通常はチェックしないでOK</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると送信先アドレスとポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>送信データを作成するノードを接続\n    <ul>\n      <li>UDPノードはmsg.payloadを送信する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"udpで受信\">UDPで受信</h1>\n<ul>\n  <li>パレットの「入力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「待ち受け」で受信待ちするするメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト or マルチキャスト)/「ブロードキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で受信待ちポート番号を設定\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n        </ul>\n      </li>\n      <li>「種類」で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>「出力」で受信したデータをどのような形式で次段のノードに出力するかを選択する\n        <ul>\n          <li>「バイナリバッファ」を選択すると受信したデータをそのままbufferオブジェクトとして出力</li>\n          <li>「文字列」を選択すると受信したデータをStringオブジェクトにデコードする</li>\n          <li>「Base64文字列」を選択すると受信したデータをBase64 Stringオブジェクトにデコードする</li>\n          <li>「Base64文字列」と「文字列」は内部でtoStringのencodingに’base64’を指定するか’utf8’を指定するかの違い(?)</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると受信待ちポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>受信データを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"2506be7d.1b5332\",\n        \"type\": \"tab\",\n        \"label\": \"UDP\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"44364ec0.0b59b8\",\n        \"type\": \"udp out\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"addr\": \"localhost\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"outport\": \"\",\n        \"base64\": false,\n        \"multicast\": \"false\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"20cee006.2fee4\",\n        \"type\": \"inject\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"\",\n        \"payloadType\": \"date\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 150,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"44364ec0.0b59b8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"eb875fd8.7aa5f8\",\n        \"type\": \"udp in\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"multicast\": \"false\",\n        \"group\": \"\",\n        \"datatype\": \"utf8\",\n        \"x\": 160,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"a6b72636.514e2\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a6b72636.514e2\",\n        \"type\": \"debug\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 140,\n        \"wires\": []\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"httpでrest-api\">HTTPでREST API</h1>\n\n<h2 id=\"http入力ノードの作成\">HTTP入力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「入力」の下の「http」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「メソッド」でメソッド種別を選択\n        <ul>\n          <li>ここでは「GET」で設定を進める(他のメソッドは他所で調べてね)</li>\n        </ul>\n      </li>\n      <li>「URL」でエンドポイント(要はパス)を設定</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとメソッドとURLが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>レスポンスを作成するノード(下記)を接続</li>\n</ul>\n\n<h2 id=\"レスポンス生成ノードの作成\">レスポンス生成ノードの作成</h2>\n\n<p>ここでは、簡単にfunctionノードで固定文字列を返すものを作っています。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると空欄になるので、なるべく識別できる名前を付けましょう</li>\n        </ul>\n      </li>\n      <li>「コード」に処理するプログラムを記述\n        <ul>\n          <li>msg.payloadに表示するページの本文を設定する</li>\n          <li>例えば以下</li>\n        </ul>\n      </li>\n      <li>「名前」の横のアイコンをクリックすると作成したノードの保存/読み込みが出来る\n        <ul>\n          <li>コードは <code class=\"language-plaintext highlighter-rouge\">~/.node-red/lib/functions/</code> に指定したフォルダとファイル名で保存される</li>\n          <li>保存したコードは別のノードで読み込むことができる</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"dl\">\"</span><span class=\"s2\"><h1> ぼ~っと生きてんじゃね~よ! </H1></span><span class=\"dl\">\"</span><span class=\"p\">;</span>\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h2 id=\"http出力ノードの作成\">HTTP出力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「出力」の下の「http response」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「http」と表示される</li>\n        </ul>\n      </li>\n      <li>必要なら「状態コード」を設定</li>\n      <li>必要なら「ヘッダ」を設定</li>\n      <li>シンプルな処理の場合、何も設定しなくてもOK</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"入力レスポンス生成出力を接続\">入力、レスポンス生成、出力を接続</h2>\n\n<ul>\n  <li>上記で作成したノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"ブラウザでアクセス接続\">ブラウザでアクセス接続</h2>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/《HTTP入力ノードに設定したURL》 に接続\n    <ul>\n      <li>ブラウザにレスポンス生成ノードで作成したメッセージが表示される</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"7508e635.c8bf48\",\n        \"type\": \"tab\",\n        \"label\": \"HTTP_REST\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c7938d8a.3ae9d\",\n        \"type\": \"http in\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"url\": \"/rest_api_1\",\n        \"method\": \"get\",\n        \"upload\": false,\n        \"swaggerDoc\": \"\",\n        \"x\": 160,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"fb01d5fd.b76918\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fb01d5fd.b76918\",\n        \"type\": \"function\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"ぼ~っと生きてんじゃね~よ!\",\n        \"func\": \"msg.payload = \\\"<h1> ぼ~っと生きてんじゃね~よ! </H1>\\\";\\nreturn msg;\\n\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 430,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"8d3518af.f9da7\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d3518af.f9da7\",\n        \"type\": \"http response\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"statusCode\": \"\",\n        \"headers\": {},\n        \"x\": 690,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"86c0f820.b0a56\",\n        \"type\": \"debug\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 700,\n        \"y\": 120,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"websocketでデータを送受信\">Websocketでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにwscatを使うこととします。<br />\nwscat は 以下のコマンドでインストールできます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> wscat\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信クライアント\">Websocketでデータ送信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「種類」 で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「URL」 でサーバのURLを設定(例: ws://PiDev25.local:5000/ws/data01)</li>\n          <li>「送信/受信」でペイロードのみ送受信するか、メッセージ全体を送受信するかを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5000で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5000\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5000 (press CTRL+C to quit)\nclient connected\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"75e44664.73e018\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"49b725b6.0e0934\",\n        \"type\": \"websocket out\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"99ad88ce.8bcf7\",\n        \"x\": 600,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"762ccf62.73a48\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fe2498d8.71c17\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47ef3c99.d6eefc\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f97b4d60.afc278\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6d15d519.6289ec\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"87c94e6f.db3458\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"175e465.15aaa3a\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e7c2219c.07acf8\",\n        \"type\": \"debug\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"99ad88ce.8bcf7\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5000/ws/data01\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信サーバ\">Websocketでデータ送信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata1 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest1で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wstest1\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-3\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"22d6d63b.99a952\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"d64e2a6a.27ead8\",\n        \"type\": \"websocket out\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"server\": \"d7536de3.b48578\",\n        \"client\": \"\",\n        \"x\": 520,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"79358fcc.5a5a68\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"cd6acb87.0a77\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7991d417.429124\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ee88046b.37b298\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7eac2c2e.6fa39c\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"650517e9.5e34a8\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d197151e.8b01e\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5871022e.6bbb1c\",\n        \"type\": \"debug\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d7536de3.b48578\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wstest1\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信クライアント\">Websocketでデータを受信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>URL でサーバのURLを設定(例: ws://PiDev25.local:5002/ws/wsdata2)</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-2\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5002で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5002\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5002 (press CTRL+C to quit)\nclient connected\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-4\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a45bd125.622fb8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"24a93730.cf2a7\",\n        \"type\": \"websocket in\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"server\": \"45ba6028.84fc88\",\n        \"client\": \"\",\n        \"x\": 220,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"15576052.1536\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"15576052.1536\",\n        \"type\": \"debug\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"45ba6028.84fc88\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5002/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信サーバ\">Websocketでデータを受信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata2 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-3\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest2で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wsdata2\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-5\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"15604b9.9721eb4\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"80f59585.469758\",\n        \"type\": \"websocket in\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"server\": \"11528a5d.783b0e\",\n        \"client\": \"\",\n        \"x\": 140,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"f37c8fe9.6307c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f37c8fe9.6307c\",\n        \"type\": \"debug\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"11528a5d.783b0e\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その4)</h1>\n      <p>Node-REDのメモ Dashboard編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでDashboardでUIを作成するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"dashboardをインストールする\">Dashboardをインストールする</h1>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-dashboard」と入力</li>\n  <li>下に検索結果が出るので。「node-red-dashboard」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するボタン\">Dashboard のUIを作成する(ボタン)</h1>\n\n<ul>\n  <li>パレット(左側のペイン)の「dashboard」の下の「button」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「button」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「名前」は適当に設定</li>\n          <li>「タブ」 で「新規に ui_tab を追加…」を選択してその右の編集ボタンをクリック\n            <ul>\n              <li>適当に値を設定する</li>\n              <li>右上の「追加」をクリック</li>\n            </ul>\n          </li>\n          <li>または、既存のタブを選択</li>\n          <li>右上の「追加」をクリック</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Icon」「Tooltip」「Colour」「Background」はオプションなので空欄のままで可</li>\n      <li>「Payload」 に クリックされたときに送信するデータを設定</li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"ブラウザでdashboardのuiに接続する\">ブラウザでDashboardのUIに接続する</h1>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/ui に接続\n    <ul>\n      <li>Dashboardが表示されるハズ\n        <ul>\n          <li>複数のタブがある場合、左上の3本線メニュー(≡)から切り替えられる</li>\n        </ul>\n      </li>\n      <li>ボタンをクリックしたらフローが動作する。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するスライダ\">Dashboard のUIを作成する(スライダ)</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「slider」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「slider」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Tooltip」はオプションなので空欄のままで可</li>\n      <li>「Range」に値の最小値、最大値、刻みを設定</li>\n      <li>「Output」を設定\n        <ul>\n          <li>「continuously while sliding」:操作中、一定時間ごとにメッセージを出力</li>\n          <li>「only on release」:スライダを離したとき(値を確定したとき)にメッセージを出力</li>\n        </ul>\n      </li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"dashboardでゲージグラフを表示する\">Dashboardでゲージグラフを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「guage」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「guage」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>デフォルトの<code class=\"language-plaintext highlighter-rouge\">{{value}}</code>では受信したデータのpayload(<code class=\"language-plaintext highlighter-rouge\">msg.payload</code> )が使用される</li>\n          <li>payloadがobjectの場合、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.XXX}}</code>のように指定すると特定の変数が表示できる</li>\n          <li>このとき、<code class=\"language-plaintext highlighter-rouge\">{{</code> と <code class=\"language-plaintext highlighter-rouge\">}}</code> は波括弧を2つ重ねたもの。波括弧1つだと正常に処理されないので、注意</li>\n          <li>表示する数値の有効桁数を設定したい場合は以下のようにフィルタを設定\n            <ul>\n              <li>小数点以下1桁まで表示:<code class=\"language-plaintext highlighter-rouge\">{{value | number:1 }}</code></li>\n              <li>整数部のみ表示:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:0 }}</code></li>\n              <li>10の位へ丸める:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:-1 }}</code></li>\n            </ul>\n          </li>\n          <li>単位を表示するなど、決まった文字列を追加したい場合は「<code class=\"language-plaintext highlighter-rouge\">{{・・・}}℃</code>」のように波括弧の外側に追加</li>\n        </ul>\n      </li>\n      <li>「units」 で単位を設定する。温度なら「℃」など。これは数値表示には表示されず、グラフ内部の単位情報として表示される</li>\n      <li>「Range」 でグラフの値の範囲を指定する。「-20」~「40」など。\n        <ul>\n          <li>入力値が範囲外になった場合はグラフが上下限に張り付くだけで、エラーなどにはならない。また値そのものは数値表示される</li>\n        </ul>\n      </li>\n      <li>「Colour gradient」 でグラフの色を指定する。3つの色は下で設定するSectors の範囲に対応する</li>\n      <li>「Sectors」 で 上で指定した色を表示する範囲を設定する\n        <ul>\n          <li>これはオプションなので設定しなくても良い。指定しなかった場合は上の「Range」で指定した値の範囲を3等分して使用される</li>\n        </ul>\n      </li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nValue formatのフィルタの詳細は<a href=\"https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters\">https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters</a>を見ろと書かれていましたが、残念ながら私にはよく分かりませんでした…</p>\n</blockquote>\n\n<h1 id=\"dashboardでテキストを表示する\">Dashboardでテキストを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「text」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「text」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>上記参照</li>\n        </ul>\n      </li>\n      <li>「Layout」でレイアウトを選択。お好みで</li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a226513f.c36b1\",\n        \"type\": \"tab\",\n        \"label\": \"Dashboard_1\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"160486fa.dc7159\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e89b8821.ec65e8\",\n        \"type\": \"debug\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 580,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d4346336.cf1228\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e403fdac.aa3748\",\n        \"type\": \"ui_slider\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"label\": \"温度\",\n        \"tooltip\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 4,\n        \"width\": 0,\n        \"height\": 0,\n        \"passthru\": true,\n        \"outs\": \"all\",\n        \"topic\": \"\",\n        \"min\": \"-30\",\n        \"max\": \"50\",\n        \"step\": 1,\n        \"x\": 140,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"78c10ecb.1eb67\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"78c10ecb.1eb67\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 6,\n        \"width\": 4,\n        \"height\": 4,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{value}}℃\",\n        \"min\": \"-20\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 570,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"84bd2adf.3b5df8\",\n        \"type\": \"ui_text\",\n        \"z\": \"a226513f.c36b1\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 560,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1127e563.00001b\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"6547952b.517b34\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"6547952b.517b34\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ1\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"dashboard-のレイアウトを修正する\">Dashboard のレイアウトを修正する</h1>\n\n<p>ボタンのサイズを小さくしたり、複数のボタンを横に並べたい場合はレイアウトの修正を行う。</p>\n\n<ul>\n  <li>サイドバー(右側のペイン)の「dashboard」ボタン(グラフのアイコン)をクリック</li>\n  <li>配置タブをクリック</li>\n  <li>タブの部分(「ホーム」など)をマウスでポイントし、「レイアウト」をクリック\n    <ul>\n      <li>表示領域の幅を変更するには、右上の「幅」の設定値を変更する。(単位はグリッド数)</li>\n      <li>各要素をドラッグすると、表示位置を入れ替えられる。</li>\n      <li>各要素のサイズを変更するには、\n        <ul>\n          <li>右上の鍵アイコンをクリックして閉じた状態にする(鍵が開いた状態では表示領域幅に一致するように自動変更される)</li>\n          <li>右下に矢印アイコンが表示されるので、これをつまんでサイズを変更</li>\n        </ul>\n      </li>\n      <li>各要素を横並びにしたい場合は、各要素をドラッグして移動する(表示幅に収まらない場合は移動できない)</li>\n      <li>各要素のサイズ/位置はグリッド単位でのみ可能</li>\n      <li>右上の完了をクリック\nー デプロイする</li>\n    </ul>\n  </li>\n</ul>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その5)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをWebsocketで飛ばして、Dashboardでグラフ表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"bme280データをwebsocketで送信raspberrypi\">BME280データをWebsocketで送信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>BME280を使用するフローを作成する</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、送信されるデータはmsg.payloadなので、文字列ではなく、object。<br />\n  (WebsocketのパケットにはobjectをJSON文字列化したものが入る)</p>\n  </li>\n  <li>BME280のデータを送信するためのトリガとなるノードをBME280ノードの入力に接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"411d9021.cb1948\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"72021e21.cce078\",\n        \"type\": \"Bme280\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"571951b6.480168\",\n        \"type\": \"websocket out\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"f24a6df3.ed0608\",\n        \"x\": 660,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4ce01eb0.f1d438\",\n        \"type\": \"debug\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 570,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"480f869f.968e18\",\n        \"type\": \"function\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"DummyData\",\n        \"func\": \"msg.payload = {\\n\\t\\t\\\"temperature_C\\\": Math.floor((Math.random() * (  40 - (-30)) * 100) / 100) + (-30),\\n\\t\\t\\\"humidity\\\":      Math.floor((Math.random() * ( 100 -    0 ) * 100) / 100) +    0,\\n\\t\\t\\\"pressure_hPa\\\":  Math.floor((Math.random() * (1100 -  800 ) * 100) / 100) +  800,\\n\\t\\t\\\"model\\\":\\\"DUMMY\\\"\\n}\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 310,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"c6ba67a3.1c69c\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"72021e21.cce078\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ab623444.9c5148\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"480f869f.968e18\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f24a6df3.ed0608\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/bme280\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからbme280データを受信サーバ\">WebsocketからBME280データを受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノード</li>\n</ul>\n\n<p>これだけでWebsocketからデータは受信できる。<br />\nこのとき、Websocketの受信ノードのmag.payloadはJSON文字列なので、objectに変換してやらないと後段で使用できない。<br />\nそのため、Websocketのノードの出力をjsonノードで変換してやる必要がある。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「json」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「json」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「動作」で「常にJavascriptオブジェクトに変換」を選択</li>\n      <li>プロパティは「msg.payload」を設定(デフォルトのまま)</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとjsonが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力側にWebsocketのノードを接続</li>\n  <li>\n    <p>出力側に受信データを処理するノードを接続</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>この状態でRaspberryPi側でBME280のデータ送信をトリガすれば、受信したデータで処理ノードが実行される</p>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その1サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その1)(サーバ)</h1>\n\n<p>上記、<strong>WebsocketからBME280データを受信(サーバ)</strong>の処理ノードとして</p>\n<ul>\n  <li><strong>その4</strong> の <strong>Dashboardでゲージグラフを表示する</strong>の手順で作成したノードを接続すれば良い。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nこれで理屈的には大丈夫なハズなんだけど、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.pressure_hPa}}</code>を指定すると、値は正常に表示されるけど、グラフが正常に表示されないことがある。。。<br />\nどうやら、この形で指定すると、値が1000を超えるとグラフ表示がおかしくなるようだ。バグか?<br />\n下の(その2)の方法で回避可能。</p>\n</blockquote>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"61238c01.1e1fdc\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"2163c454.8e4654\",\n        \"type\": \"json\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"8a687382.d3a38\",\n                \"54ecaf20.30611\",\n                \"1e9e6439.3de04c\",\n                \"54f5a1ee.e4fb5\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"de53f105.be0bb\",\n        \"type\": \"websocket in\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"2163c454.8e4654\",\n                \"8a687382.d3a38\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8a687382.d3a38\",\n        \"type\": \"debug\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 530,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54ecaf20.30611\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{msg.payload.temperature_C | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 510,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1e9e6439.3de04c\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度\",\n        \"label\": \"%\",\n        \"format\": \"{{msg.payload.humidity| number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 510,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54f5a1ee.e4fb5\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧\",\n        \"label\": \"hPa\",\n        \"format\": \"{{msg.payload.pressure_hPa| number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 510,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"9912b800.6921d8\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その2サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その2)(サーバ)</h1>\n\n<p><strong>(その1)</strong>での不具合を回避するため、msg.payloadのオブジェクト内のそれぞれの変数をバラすfunctionノードを追加する</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「function」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら名前にノード名を設定</li>\n      <li>コードを設定(下記参照)</li>\n      <li>出力数に「3」を設定</li>\n      <li>右上の「完了」をクリック。</li>\n    </ul>\n  </li>\n  <li>これでfunctionノードの出力端子が3個になり、上から温度、湿度、気圧データが出力される。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>// make deep copy\nvar msg_temp  <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_hum   <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_press <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\n\nmsg_temp.topic    <span class=\"o\">=</span> <span class=\"s2\">\"temperature_C\"</span><span class=\"p\">;</span>\nmsg_temp.payload  <span class=\"o\">=</span> msg.payload.temperature_C<span class=\"p\">;</span>\nmsg_hum.topic     <span class=\"o\">=</span> <span class=\"s2\">\"humidity\"</span><span class=\"p\">;</span>\nmsg_hum.payload   <span class=\"o\">=</span> msg.payload.humidity<span class=\"p\">;</span>\nmsg_press.topic   <span class=\"o\">=</span> <span class=\"s2\">\"pressure_hPa\"</span><span class=\"p\">;</span>\nmsg_press.payload <span class=\"o\">=</span> msg.payload.pressure_hPa<span class=\"p\">;</span>\n\n<span class=\"k\">return</span> <span class=\"o\">[</span>msg_temp, msg_hum, msg_press]<span class=\"p\">;</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">var msg_temp  = msg;</code>などとしてはいけない。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">msg_temp</code>は<code class=\"language-plaintext highlighter-rouge\">msg</code>の浅いコピーとなってしまうため、その下で<code class=\"language-plaintext highlighter-rouge\">msg_temp.payload</code>を変更すると、<code class=\"language-plaintext highlighter-rouge\">msg.payload</code>も変更されてしまうことになる。<br />\nこれを防ぐため、深いコピーを作成している。これには<code class=\"language-plaintext highlighter-rouge\">msg</code>をJSON文字列化して、再度パースすることで対応している。</p>\n</blockquote>\n\n<p>フローエディタ上で、どの端子がどの信号か分からなくなるのを防ぐため、端子に名前を付けることができる。<br />\n(付けなくても動作上は問題ない)</p>\n\n<ul>\n  <li>「function」ノードをダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>右上の「完了」ボタンの下にある「外観」ボタン(ウィンドウ表示のアイコン)をクリック</li>\n      <li>ポートラベルの下の出力の下、1、2、3に対して、それぞれ分かりやすい名前を付ける</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>functionノードの入力にjsonノードの出力を接続</li>\n  <li>functionノードのそれぞれの出力にそれぞれを表示するゲージグラフノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"9c09bf08.8c36a8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280_2\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1e53a14c.4133a7\",\n        \"type\": \"json\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"855491ee.723a88\",\n                \"3cee4c1c.c6861c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ada05d07.d2d8b\",\n        \"type\": \"websocket in\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"1e53a14c.4133a7\",\n                \"855491ee.723a88\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"855491ee.723a88\",\n        \"type\": \"debug\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 690,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"51b57ef4.80809\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度2\",\n        \"label\": \"℃\",\n        \"format\": \"{{value | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 670,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"be7cac56.7bcc4\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度2\",\n        \"label\": \"%\",\n        \"format\": \"{{value | number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 670,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"f36e338d.e77e6\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧2\",\n        \"label\": \"hPa\",\n        \"format\": \"{{value | number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 670,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3cee4c1c.c6861c\",\n        \"type\": \"function\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"BME280\",\n        \"func\": \"// make deep copy\\nvar msg_temp  = JSON.parse(JSON.stringify(msg));\\nvar msg_hum   = JSON.parse(JSON.stringify(msg));\\nvar msg_press = JSON.parse(JSON.stringify(msg));\\n\\nmsg_temp.topic    = \\\"temperature_C\\\";\\nmsg_temp.payload  = msg.payload.temperature_C;\\nmsg_hum.topic     = \\\"humidity\\\";\\nmsg_hum.payload   = msg.payload.humidity;\\nmsg_press.topic   = \\\"pressure_hPa\\\";\\nmsg_press.payload = msg.payload.pressure_hPa;\\n\\nreturn [msg_temp, msg_hum, msg_press];\",\n        \"outputs\": 3,\n        \"noerr\": 0,\n        \"x\": 460,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"51b57ef4.80809\"\n            ],\n            [\n                \"be7cac56.7bcc4\"\n            ],\n            [\n                \"f36e338d.e77e6\"\n            ]\n        ],\n        \"inputLabels\": [\n            \"BME280データ\"\n        ],\n        \"outputLabels\": [\n            \"温度\",\n            \"湿度\",\n            \"気圧\"\n        ]\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"34e8ddba.6c67fa\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ2\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>モバイル ホットスポットでRaspberryPiをネットに接続</title>\n  </head>\n  <body>\n    <header>\n      <h1>モバイル ホットスポットでRaspberryPiをネットに接続</h1>\n      <p>Windows10のモバイル ホットスポットでRaspberryPiをネットに接続する手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>お出かけ先でも RaspberryPi を、常に同じWi-Fi AP で接続できるような方法を考える。</p>\n\n<p>一つの案として、Windows10のモバイル ホットスポットを経由して RaspberryPi をネットワークにつなげる。\nこの場合、PCと RaspberryPi はセットで持ち歩くものと考えれば、 \nRaspberryPi は常にPCのモバイル ホットスポットのAPに接続すれば良いことになる。</p>\n\n<p>一つのWi-Fiアダプタを通常接続用とモバイル ホットスポット用でシェアすることはできないので、<br />\nUSBドングルを追加して使用する。</p>\n\n<ul>\n  <li>内蔵Wi-Fi → 通常接続用</li>\n  <li>USBドングル → モバイル ホットスポット用</li>\n</ul>\n\n<p>USBドングルは BUFFALO WLI-UC-GNM2S で確認\nWindowsはWindows10 ver.1903 で確認</p>\n\n<h1 id=\"windows側の事前準備\">Windows側の事前準備</h1>\n\n<p>内蔵Wi-Fi は 通常通り ルータに接続しておく。<br />\nこのとき、どのルータに繋いでいるかは考慮しなくて良いはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPCのルータ接続ダウン時、モバイル ホットスポットは使えない</p>\n</blockquote>\n\n<p>USBドングル BUFFALO WLI-UC-GNM2S はあらかじめドライバをインストールしてWindowsに認識させておく。<br />\n接続先は設定しなくて大丈夫。</p>\n\n<ul>\n  <li>Windowsで「設定」→「ネットワークとインターネット」→「モバイル ホットスポット」を開く\n    <ul>\n      <li>「インターネット接続を共有する」で、ルータに接続しているアダプタを選択</li>\n      <li>「Wi-Fi」を選択</li>\n      <li>「ネットワーク名」と「ネットワーク パスワード」をメモっておく</li>\n      <li>この状態で一番上のスイッチを「オン」にする\n        <ul>\n          <li>スイッチがアクティブカラーになったら準備完了</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"raspberrypi側の事前準備\">RaspberryPi側の事前準備</h1>\n\n<h2 id=\"etcwpa_supplicantwpa_supplicantconf-の修正\">/etc/wpa_supplicant/wpa_supplicant.conf の修正</h2>\n\n<p>モバイル ホットスポットか通常のルータか、どちらか生きてる方に接続にいくように設定する。<br />\n(いつもの環境ならモバイル ホットスポット使わなくて良いように)</p>\n\n<p>以下の「モバイルホットスポットのSSID名」「パスワード」は<br />\n上記でメモった「ネットワーク名」と「ネットワーク パスワード」を記入する。<br />\nダブルクォーテーションで囲むのを忘れないこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">ctrl_interface</span><span class=\"o\">=</span><span class=\"nv\">DIR</span><span class=\"o\">=</span>/var/run/wpa_supplicant <span class=\"nv\">GROUP</span><span class=\"o\">=</span>netdev\n<span class=\"nv\">update_config</span><span class=\"o\">=</span>1\n<span class=\"nv\">country</span><span class=\"o\">=</span>JP\n\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"デフォルトのSSID名\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span><span class=\"s2\">\"パスワード\"</span>\n        <span class=\"nv\">priority</span><span class=\"o\">=</span>3\n<span class=\"o\">}</span>\n\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"モバイルホットスポットのSSID名\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span><span class=\"s2\">\"パスワード\"</span>\n        <span class=\"nv\">priority</span><span class=\"o\">=</span>5\n<span class=\"o\">}</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npriority設定値は大きい方が優先される。<br />\n上記の場合、モバイルホットスポットが生きていればそちらが優先される</p>\n</blockquote>\n\n<h2 id=\"ap再接続用スクリプト\">AP再接続用スクリプト</h2>\n\n<p>モバイル ホットスポット の Enable/Disable を切り替えたとき、<br />\n(RaspberryPiを起動してからモバイルホットスポットを有効にするのを忘れていたことに気がついたなど)\nRaspberryPiのネットワーク設定は自動的に新しい環境に切り替わらない。<br />\nコマンドをチマチマ入力するのも面倒なので、コマンド イッパツで再接続処理するようにしておく。</p>\n\n<p>まず、 ~/wifi_reconnect.sh を以下の内容で作成する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo </span>wlan0 down..\n<span class=\"nb\">sudo </span>ifconfig wlan0 down\n<span class=\"nb\">sleep </span>1\n\n<span class=\"nb\">echo </span>wlan0 up..\n<span class=\"nb\">sudo </span>ifconfig wlan0 up\n<span class=\"nb\">sleep </span>3\n\n<span class=\"nb\">echo </span>re-get IP address...\n<span class=\"nb\">sudo </span>dhcpcd <span class=\"nt\">-k</span>\n<span class=\"nb\">sleep </span>3\n<span class=\"nb\">sudo </span>dhcpcd <span class=\"nt\">-n</span>\n<span class=\"nb\">sleep </span>15\n\n<span class=\"nb\">echo </span>DONE!!\n</code></pre></div></div>\n\n<p>スクリプトファイルに実行属性をつける。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod</span> +x ~/wifi_reconnect.sh\n</code></pre></div></div>\n\n<p>再接続したいタイミングで <code class=\"language-plaintext highlighter-rouge\">~/wifi_reconnect.sh</code>を実行する。<br />\nDHCPのアドレス確定時間分を待っているので、コマンド実行には20秒強かかる。</p>\n\n<h1 id=\"raspberrypiの起動\">RaspberryPiの起動</h1>\n\n<p>上記の準備が整ったら、RaspberryPiを起動する。<br />\n起動後、<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>(他のコマンドでも良いけど)でIPアドレスを確認する。</p>\n\n<ul>\n  <li>192.168.137.XXX になっていればOK</li>\n</ul>\n\n<p>また、PC側で「設定」→「ネットワークとインターネット」→「モバイル ホットスポット」の<br />\n「接続されているデバイス」にRaspberryPiが表示されているハズ。</p>\n\n<h1 id=\"問題点\">問題点</h1>\n\n<h2 id=\"windows10-pcがルータにつながっていないと使えない\">Windows10 PCがルータにつながっていないと使えない</h2>\n\n<p>ルータにつながっていないと、そもそもモバイル ホットスポット がオンできない。<br />\nこれは、ネットワーク環境がまったくない場合(つまりPCとRaspberryPiだけで箱庭環境だけ作りたいとき)は使えない。<br />\n回避策としては、スマホのテザリングでネットワークにつなぐ?\n間違って外部にアクセスしちゃったら、パケ死しそう。。。</p>\n\n<h2 id=\"pcの外側ルータのサブネット内からraspberrypiにアクセスできない\">PCの外側(ルータのサブネット内)からRaspberryPiにアクセスできない</h2>\n\n<p>モバイル ホットスポットのサブネットとルータのサブネットは別なので、<br />\nモバイル ホットスポットのサブネットの外側から内側へのアクセスはできない。<br />\nもちろん、ルータの外側からもアクセスできない。<br />\nRaspberryPiにアクセスできるのはモバイル ホットスポットを提供しているPCのみ。</p>\n\n<h2 id=\"mdnsが使えない\">mDNSが使えない</h2>\n\n<p>モバイル ホットスポットのサブネットとルータのサブネットは別なので、\nルータを超えられないmDNSは名前を取得できない。<br />\n回避策としては、/etc/hosts を名前エラーが出るたびに名前追加するか?</p>\n\n<p>なお、WindowsPCからRaspberryPiへのmDNS参照はできるが、RaspberryPiからWindowsPCへのmDNS参照はできない。</p>\n\n<h1 id=\"結論\">結論</h1>\n\n<p>とりあえず、RaspberryPiにアクセスするのはWindowsPC 1台のみで、<br />\nRaspberryPiからアクセスするはルータの外側のみ、という条件なら使えそう。</p>\n\n<p>う~ん、良いところまで行くんだけど、微妙に不満の残る結果に。。。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その6)</h1>\n      <p>Node-REDのメモ MQTT編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでMQTT通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"mqttでデータを送受信\">MQTTでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにmosquitto broker および mosquitto client toolsを使うこととします。<br />\nこれらは以下のコマンドでインストールできます。</p>\n\n<p>Ubuntuで動作確認。RaspberryPiでも大丈夫なはず。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mosquitto mosquitto-clients\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータ送信publish\">MQTTでデータ送信(Publish)</h2>\n\n<p>MQTTでデータを送信してみます</p>\n\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要なら「名前」を設定\n            <ul>\n              <li>省略するとサーバアドレスとポート番号が表示される</li>\n            </ul>\n          </li>\n          <li>「サーバ」 でブローカのアドレス(またはホスト名)を設定(例: PiDev25.local)</li>\n          <li>「ポート」 でポート番号を設定(一般的な設定なら1883のままで大丈夫)</li>\n          <li>SSL/TLS接続を使用する場合は「SSL/TLS接続を使用」のチェックを入れる</li>\n          <li>クライアントIDを指定したい場合は「クライアント」に設定。通常は空欄で大丈夫</li>\n          <li>キープアライブ時間を「キープアライブ時間」に設定</li>\n          <li>「セッションの初期化」?とりあえず初期設定のままで</li>\n          <li>「旧MQTT 3.1のサポート」?とりあえず初期設定のままで</li>\n          <li>「セキュリティ」タブ、「メッセージ」タブの内容は必要なら設定する。設定しなくても大丈夫</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に送信するトピックを設定\n        <ul>\n          <li>省略すると、トリガノードの出力に設定されているtopicが使用される</li>\n        </ul>\n      </li>\n      <li>「QoS」を「0」/「1」/「2」から選択</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される\n            <ul>\n              <li>トピックも省略されている場合はmqttと表示される</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のようにsubscriberコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> 《トピック》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカからすべてのトピック(“#”)を取得するよう指定しています。<br />\n-v 指定により、対象メッセージのトピックも表示されます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> Pidev25.local <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> <span class=\"s2\">\"#\"</span>\n</code></pre></div></div>\n<p>Node-RED側で mqttの送信をトリガするとmosquitto_subの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>test_data 0\ntest_data 1\ntest_data true\ntest_data false\ntest_data 文字列\ntest_data {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"f580f01a.f771f\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_publish\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"33450bad.82764c\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ea6d9236.74e038\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d7baa4c.08385\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"82148e63.4b97e\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d0b1ac7f.0ac0b\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7e6180b5.f29098\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"test_data\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6f26fe46.a01f58\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"バッファ\",\n        \"topic\": \"test_data\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 140,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d5a5b2db.83462\",\n        \"type\": \"debug\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 500,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"e6218cda.844308\",\n        \"type\": \"mqtt out\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"\",\n        \"qos\": \"\",\n        \"retain\": \"\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 570,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータを受信subscribe\">MQTTでデータを受信(subscribe)</h2>\n\n<p>MQTTでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に受信するトピックを設定\n        <ul>\n          <li>すべてのトピックを受信するには#を設定</li>\n          <li>省略することはできない</li>\n        </ul>\n      </li>\n      <li>「QoS」を設定</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>デプロイ後、ターミナル or コンソールで以下のようにpublisherコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-t</span> 《トピック》 <span class=\"nt\">-m</span> 《メッセージ》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカへ、トピック test_data で、メッセージ test を送信しています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> PiDev25.local <span class=\"nt\">-t</span> <span class=\"s2\">\"test_data\"</span> <span class=\"nt\">-m</span> <span class=\"s2\">\"test\"</span>\n</code></pre></div></div>\n\n<p>コマンドを実行するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"13f22fdd.2e009\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_subscribe\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1760f49a.fd2d3b\",\n        \"type\": \"debug\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 420,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"30229cea.13aba4\",\n        \"type\": \"mqtt in\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"#\",\n        \"qos\": \"2\",\n        \"datatype\": \"auto\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 150,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"1760f49a.fd2d3b\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian Buster Lite版のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian Buster Lite版のインストール</h1>\n      <p>Raspbian Buster with desktopのインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspbian Buster Lite」 の 「DownloadZIP」でダウンロードする。<br />\n以下の手順は、RaspberryPi Zero W、「Version: July 2019」 で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>は表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nframebuffer_width=1280\nframebuffer_height=720\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"ロケールやらタイムゾーンやらの設定\">ロケールやらタイムゾーンやらの設定</h1>\n\n<p>日本語表示や時刻を日本時間に設定するための設定を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    4 Localisation Options\n        I1 Change Locale\n            [ ] ja_JP.UTF-8 UTF-8     でスペースを押して[*] にする\n            TABを押して<Ok>を選んでリターン\n                Default locale for~ と聞かれるので、\n                ja_JP.UTF-8          を選択\n                TABを押して<Ok>を選んでリターン\n    4 Localisation Options\n        I2 Change Timezon\n            Asia\n                Tokyo\n    <Finish>\n</code></pre></div></div>\n\n<p>設定変更を有効にするにはrebootが必要。</p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"c\"># export PYENV_ROOT=/proj/.pyenv</span>\n<span class=\"c\"># export PATH=$PYENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(pyenv init -)\"</span>\n<span class=\"c\"># eval \"$(pyenv virtualenv-init -)\"</span>\n\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"c\"># export NODENV_ROOT=/proj/.nodenv</span>\n<span class=\"c\"># export PATH=$NODENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(nodenv init -)\"</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nSSHなら関係ないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"hdmiコンソール用日本語入力表示環境構築\">HDMIコンソール用日本語入力&表示環境構築</h1>\n\n<p>デフォルトのままだと、HDMIコンソールは日本語の入力はおろか、表示もできない。<br />\nそこで、日本語入力&表示環境を整備する。<br />\nHDMIコンソールで日本語を使わないなら本章は設定不要。</p>\n\n<h2 id=\"フォントのインストール\">フォントのインストール</h2>\n\n<p>フォントをインストールしないと表示できないのでまずはフォントのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk \n</code></pre></div></div>\n\n<h2 id=\"ターミナルエミュレータのインストール\">ターミナルエミュレータのインストール</h2>\n\n<p>デフォルトのターミナルは日本語を表示できないので、日本語対応のターミナルエミュレータを使う。<br />\nネット上にはjfbtermを使用する記事が多いが、jfbtermはイマイチらしいのでfbtermを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fbterm\n</code></pre></div></div>\n\n<h2 id=\"日本語変換システムのインストール\">日本語変換システムのインストール</h2>\n\n<p>日本語入力のためのプログラム。Windowsで言うところのMS-IMEやATOKに相当するもの。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>uim-fep uim-anthy\n</code></pre></div></div>\n\n<h2 id=\"fbtermの設定\">fbtermの設定</h2>\n\n<p>fbtermの設定は、 ~/.fbtermrc で行う。<br />\n<strong>HDMIコンソールから</strong> fbtermを一度起動すると ~/.fbtermrc ができるので、設定変更するときはこれを書き換える。<br />\n例えばこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>font-size<span class=\"o\">=</span>18\n</code></pre></div></div>\n\n<p>fbtermを起動したときに<code class=\"language-plaintext highlighter-rouge\">[input] can’t change kernel keymap table ~</code>と表示されるときは以下を実行すると良い。(表示されるだけで実害はないらしい)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>setcap <span class=\"s1\">'cap_sys_tty_config+ep'</span> /usr/bin/fbterm\n</code></pre></div></div>\n\n<p>または、以下でも良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chmod </span>u+s /usr/bin/fbterm\n</code></pre></div></div>\n\n<p>参考: <a href=\"https://qiita.com/mtomoaki_96kg/items/e5a946fd38f7318d3758?fbclid=IwAR2d8ekXNiD9cqvpqycdfinDZMHZ0OcTmaETTsci1UA9T-aDtc3LvfOiaa0\">https://qiita.com/mtomoaki_96kg/items/e5a946fd38f7318d3758?fbclid=IwAR2d8ekXNiD9cqvpqycdfinDZMHZ0OcTmaETTsci1UA9T-aDtc3LvfOiaa0</a></p>\n\n<h2 id=\"uim日本語変換システムの設定\">uim(日本語変換システム)の設定</h2>\n\n<p>uimでCTRL+SPACEでFEPの切り替えの設定。\n~/.uim に以下の内容を記述(なければ新規作成)。<br />\n参考: <a href=\"https://qiita.com/tukiyo3/items/376e3a2895a71ff9bfc7\">https://qiita.com/tukiyo3/items/376e3a2895a71ff9bfc7</a></p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>(define default-im-name 'anthy)\n(define-key generic-on-key? '(\"<Control> \" \"`\"))\n(define-key generic-off-key? '(\"<Control> \" \"`\"))\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n各行のシングルクォーテーションは1個だけ。文字列として区切っている訳ではない。<br />\n余計なシングルクォーテーションを入れると動かなくなるので注意!!</p>\n</blockquote>\n\n<h2 id=\"起動時にfbtermを起動する\">起動時にfbtermを起動する</h2>\n\n<p>起動時にfbtermを起動するには以下を ~/.profile 、 ~/.bashrc に追加</p>\n\n<h3 id=\"profile\">~/.profile</h3>\n\n<p>最後に以下の内容を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"o\">=</span> <span class=\"s2\">\"linux\"</span> <span class=\"o\">]</span>\n<span class=\"k\">then</span>\n<span class=\"c\">#   FBTERM=1 exec fbterm -- uim-fep</span>\n   <span class=\"nv\">FBTERM</span><span class=\"o\">=</span>1 fbterm <span class=\"nt\">--</span> uim-fep\n   <span class=\"nb\">exit\n</span><span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<p>本当はコメントアウトされてる方の exec を使うようにしないといけないが、現状うまく動かないらしい。<br />\n(Strechでは動いていたと思う)<br />\n仕方ないので、fbtermをbashの子プロセスとして実行するようにしてある。<br />\nこれだとうまく動いている(当然、メモリ消費量は増えるけど)。</p>\n\n<p>また、ログアウトの際にCTRL+Dを2回入力しないといけなくなる(fbtermからのexitとbashからのexit)のを回避するため、 fbterm終了時にexitコマンドを実行している。</p>\n\n<h3 id=\"bashrc\">~/.bashrc</h3>\n\n<p>最後に(でなくてもいいけど)、以下を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>linux<span class=\"p\">)</span>\n        <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$FBTERM</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"nb\">export </span><span class=\"nv\">TERM</span><span class=\"o\">=</span>fbterm\n        <span class=\"p\">;;</span>\n    fbterm<span class=\"p\">)</span>\n        <span class=\"c\"># 何もしない</span>\n        <span class=\"p\">;;</span>\n    <span class=\"k\">*</span><span class=\"p\">)</span>\n        <span class=\"c\"># 何もしない</span>\n        <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n</code></pre></div></div>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian SDカードイメージファイルの縮小</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian SDカードイメージファイルの縮小</h1>\n      <p>Raspbian SDカードイメージファイルの縮小</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2020/10/25/Jetson_nano_backup.html\">Jetson nano のSDカードをバックアップする</a> \nに改訂版を公開しました。そちらを参照してください。</p>\n\n<h1 id=\"イメージファイルの縮小\">イメージファイルの縮小</h1>\n\n<h3>『イメージファイルの縮小』はUbuntuで実行することを前提に書いてあります。</h3>\n\n<p>SDカードに作成した、RaspberryPiのオリジナルのカスタムブートディスク\n(<a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\">Raspbian Busterのインストール</a>、\n<a href=\"/memoBlog/2019/09/13/raspbian_buster_2.html\">Raspbian Buster Lite版のインストール</a>参照)\nは、イメージファイルにバックアップしておくと、\n再度カスタマイズ作業を行わなくても同じ環境を作成できる。</p>\n\n<p>ただ、このイメージファイルはSDカードを丸ごとファイル化するので、元のSDカードより小さなSDカードにコピーできない。<br />\n(スペック上同じ容量のSDカードでも微妙にサイズが違ったりするので入らないことがある)</p>\n\n<p>そこで、イメージファイルを縮小しておけば、小さなSDカードにもコピーできる(コピー時間も短縮できて一石二鳥)。<br />\nこのとき、ディスクイメージ内部のパーティション情報/ファイルシステム情報をきちんと縮小処理しておかないと\nファイルシステムエラーになってしまうので、注意が必要。</p>\n\n<p>今回はSDカードから作成したイメージファイルを<strong>Ubuntuで</strong>縮小処理するスクリプトを書いてみた。<br />\nとりあえず、手元の環境では動いているが、詳細評価したわけではないので、\n実行する場合は自己責任で。</p>\n\n<p>また、途中<strong>エラーチェックは行っていない</strong>ので、エラーが発生していないか、実行結果を注意深く確認すること。</p>\n\n<h2 id=\"virtualbox-共有フォルダのマウント\">Virtualbox 共有フォルダのマウント</h2>\n\n<p>SDカードのイメージファイルは大きいので、共有フォルダを使ってWindows側のフォルダをアクセスできるようにしておけばディスク領域を圧迫しなくて済む。<br />\nVirtualbox側で共有フォルダ「Share」を作成済みで、/Shareディレクトリにマウントする場合は以下のコマンドで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> vboxsf Share /Share/\n</code></pre></div></div>\n\n<h2 id=\"ツールのインストール\">ツールのインストール</h2>\n\n<p>イメージファイル内のパーティションをそれぞれloopデバイスに割り当てるツールを使用する。<br />\n以下のコマンドでインストールできる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>kpartx\n</code></pre></div></div>\n\n<h2 id=\"スクリプト\">スクリプト</h2>\n\n<p>以下のスクリプトを適当な名前(例えば<code class=\"language-plaintext highlighter-rouge\">shrink_img.sh</code>)で保存し、実行する(<code class=\"language-plaintext highlighter-rouge\">bash shrink_img.sh</code>)。<br />\n実行する前に使用するファイル名を設定すること。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: left\">変数</th>\n      <th style=\"text-align: left\">内容</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: left\">WORK_IMG_FILE</td>\n      <td style=\"text-align: left\">作業用イメージファイルのファイル名</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: left\">NEW_IMG_FILE</td>\n      <td style=\"text-align: left\">小さくしたイメージファイルのファイル名</td>\n    </tr>\n  </tbody>\n</table>\n\n<p>WORK_IMG_FILE で指定したファイルは書き変えられるので、オリジナルのイメージファイルは 別途残しておくこと。</p>\n\n<p>内部で<code class=\"language-plaintext highlighter-rouge\">sudo</code>を実行しているので、パスワードを聞かれたら入力する。</p>\n\n<p>途中、『警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?』と聞かれたら「y」を入力する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># イメージファイル</span>\n<span class=\"nv\">WORK_IMG_FILE</span><span class=\"o\">=</span>/Share/tmp.img            <span class=\"c\"># 作業ファイル</span>\n<span class=\"nv\">NEW_IMG_FILE</span><span class=\"o\">=</span>/Share/shrink.img          <span class=\"c\"># 縮小した(作成する)ファイル</span>\n\n<span class=\"c\"># イメージファイルをマッピング(マッピング済みでも問題ない) </span>\n<span class=\"c\"># 前回の操作が終わるのを待つため-sを付けておく</span>\n<span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-asv</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span>\n\n<span class=\"c\"># loopデバイス名を取得</span>\n<span class=\"c\"># 前回の操作が終わるのを待つため-sを付けておく</span>\n<span class=\"nv\">tmp_var</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-ls</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">LOOP_DEV</span><span class=\"o\">=</span>/dev/mapper/<span class=\"k\">${</span><span class=\"nv\">tmp_var</span><span class=\"p\">[6]</span><span class=\"k\">}</span>          <span class=\"c\"># 結果の位置は決め打ちで(姑息だけど)</span>\n\n<span class=\"c\"># 要求するブロックサイズの取得</span>\n<span class=\"nv\">tmp_var</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>resize2fs <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">req_fs_block</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">tmp_var</span><span class=\"p\">[-1]</span><span class=\"k\">}</span>                 <span class=\"c\"># サイズは結果の最後に入っている</span>\n\n<span class=\"c\"># パーティション情報の取得</span>\n<span class=\"nv\">part_info</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>parted <span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> unit B print<span class=\"sb\">`</span>\n<span class=\"c\"># 1行毎に分割</span>\n<span class=\"nv\">line</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">part_info</span><span class=\"p\">//;/ </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># ext4のパーティション番号を探す</span>\n<span class=\"nv\">part_number</span><span class=\"o\">=</span>0\n<span class=\"nv\">part_start</span><span class=\"o\">=</span>0\n<span class=\"nv\">target_type</span><span class=\"o\">=</span><span class=\"s2\">\"ext4\"</span>\n<span class=\"k\">for </span>l <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span> <span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各要素に分割</span>\n    <span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">l</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n    <span class=\"nv\">elm_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[0]</span><span class=\"k\">}</span>             <span class=\"c\"># パーティション番号</span>\n    <span class=\"nv\">elm_start</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[1]//B/</span><span class=\"k\">}</span>          <span class=\"c\"># ついでに最後のBを取り除いておく</span>\n    <span class=\"nv\">elm_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>               <span class=\"c\"># ファイルシステムタイプ</span>\n    <span class=\"c\"># echo $elm_number $elm_start $elm_type</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n        if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n            <span class=\"c\"># 対象のパーティションが見つかった</span>\n            <span class=\"nv\">part_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_number</span><span class=\"k\">}</span>\n            <span class=\"nv\">part_start</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_start</span><span class=\"k\">}</span>\n            <span class=\"nb\">break\n        </span><span class=\"k\">fi\n    fi\ndone\nif</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"o\">=</span> 0 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"s2\">\"のパーティションが見つかりませんでした\"</span>\n<span class=\"k\">else</span>\n    <span class=\"c\"># 新しいパーティション終了位置を計算</span>\n    <span class=\"nv\">new_fs_block</span><span class=\"o\">=</span><span class=\"k\">$((</span>req_fs_block <span class=\"o\">+</span> <span class=\"m\">100000</span><span class=\"k\">))</span>             <span class=\"c\"># 少し余裕(100000block=390MB)を持たせる</span>\n    <span class=\"nv\">new_fs_byte</span><span class=\"o\">=</span><span class=\"k\">$((</span>new_fs_block <span class=\"o\">*</span> <span class=\"m\">4096</span><span class=\"k\">))</span>                <span class=\"c\"># byteに換算</span>\n    <span class=\"nv\">part_end</span><span class=\"o\">=</span><span class=\"k\">$((</span>part_start <span class=\"o\">+</span> new_fs_byte <span class=\"o\">+</span> <span class=\"m\">2048</span><span class=\"k\">))</span>       <span class=\"c\"># さらに少し余裕を持たせる</span>\n    <span class=\"nv\">img_size_mb</span><span class=\"o\">=</span><span class=\"k\">$((</span><span class=\"o\">(</span>part_end <span class=\"o\">/</span> <span class=\"o\">(</span><span class=\"m\">1024</span> <span class=\"o\">*</span> <span class=\"m\">1024</span><span class=\"k\">))</span> + 10<span class=\"o\">))</span>    <span class=\"c\"># MBに換算 ついでにしつこいくらいに余裕を持たせる </span>\n\n    <span class=\"nb\">set</span> <span class=\"nt\">-x</span>          <span class=\"c\">#--------------------------------------</span>\n\n    <span class=\"c\"># ファイルシステムとパーティションの縮小</span>\n    <span class=\"nb\">sudo </span>e2fsck <span class=\"nt\">-f</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span> \n    <span class=\"nb\">sudo </span>resize2fs <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">new_fs_block</span><span class=\"k\">}</span>\n    parted <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> unit B resizepart <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">part_end</span><span class=\"k\">}</span>\n\n    <span class=\"c\"># 縮小コピー</span>\n    <span class=\"nb\">dd </span><span class=\"k\">if</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> <span class=\"nv\">of</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">NEW_IMG_FILE</span><span class=\"k\">}</span> <span class=\"nv\">count</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">img_size_mb</span><span class=\"k\">}</span> <span class=\"nv\">bs</span><span class=\"o\">=</span>1M\n\n    <span class=\"nb\">set</span> +x          <span class=\"c\">#--------------------------------------</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># マッピング解除</span>\n<span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-d</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span>\n \n</code></pre></div></div>\n\n<h1 id=\"新しいイメージファイルでブートsdを作る\">新しいイメージファイルでブートSDを作る</h1>\n\n<p>縮小したイメージファイルから作成したSDカードはSDカードの容量をすべて使用できるようになっていない。<br />\nそこで、コピーしたSDカードでブートした後、パーティションを拡張する必要がある。</p>\n\n<h2 id=\"sdカードへの書き込みは通常通り\">SDカードへの書き込みは通常通り</h2>\n\n<h2 id=\"書き込んだsdカードでブートする\">書き込んだSDカードでブートする</h2>\n\n<h2 id=\"sdカードのパーティション拡張\">SDカードのパーティション拡張</h2>\n\n<p>色々手順がめんどっちいので、スクリプト作成してみた。<br />\nとりあえず、手元の環境では動いているが、詳細評価したわけではないので、\n実行する場合は自己責任で。</p>\n\n<p>以下のスクリプトを適当な名前(例えば<code class=\"language-plaintext highlighter-rouge\">expand_partition.sh</code>)で保存し、実行する(<code class=\"language-plaintext highlighter-rouge\">bash expand_partition.sh</code>)<br />\n成功したらリブートすること。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># ターゲットのデバイス</span>\n<span class=\"nv\">target_device</span><span class=\"o\">=</span>/dev/mmcblk0\n\n<span class=\"c\"># パーティション情報の取得</span>\n<span class=\"nv\">part_info</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>parted <span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span> unit s print free<span class=\"sb\">`</span>\n\n<span class=\"c\"># 1行毎に分割</span>\n<span class=\"nv\">line</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">part_info</span><span class=\"p\">//;/ </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 最終行</span>\n<span class=\"c\"># declare -i last_index=${#line[@]}-1</span>\n<span class=\"c\"># last_line=${line[$last_index]}</span>\n<span class=\"nv\">last_line</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[</span><span class=\"k\">$((${#</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span><span class=\"o\">-</span><span class=\"m\">1</span><span class=\"k\">))</span><span class=\"p\">]</span><span class=\"k\">}</span>\n\n<span class=\"c\"># :で区切られた各要素に分割</span>\n<span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">last_line</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 変数名付け替え</span>\n<span class=\"c\"># last_number=${elm[0]}</span>\n<span class=\"c\"># last_start=${elm[1]}</span>\n<span class=\"nv\">last_end</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[2]</span><span class=\"k\">}</span>\n<span class=\"c\"># last_size=${elm[3]}</span>\n<span class=\"nv\">last_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>\n\n<span class=\"c\"># 確認</span>\n<span class=\"c\"># echo last_number=  $last_number</span>\n<span class=\"c\"># echo last_start=   $last_start</span>\n<span class=\"c\"># echo last_end=     $last_end</span>\n<span class=\"c\"># echo last_size=    $last_size</span>\n<span class=\"c\"># echo last_type=    $last_type</span>\n\n<span class=\"c\"># 最後のパーティションがfreeか確認</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">last_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> free <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># ext4のパーティション番号を探す</span>\n    <span class=\"nv\">part_number</span><span class=\"o\">=</span>0\n    <span class=\"nv\">target_type</span><span class=\"o\">=</span><span class=\"s2\">\"ext4\"</span>\n    <span class=\"k\">for </span>l <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span> <span class=\"p\">;</span> <span class=\"k\">do</span>\n        <span class=\"c\"># 各要素に分割</span>\n        <span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">l</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n        <span class=\"nv\">elm_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[0]</span><span class=\"k\">}</span>\n        <span class=\"nv\">elm_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n            <span class=\"c\"># echo $elm_number $elm_type</span>\n            <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n                </span><span class=\"nv\">part_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_number</span><span class=\"k\">}</span>\n                <span class=\"nb\">break\n            </span><span class=\"k\">fi\n        fi\n    done\n    if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"o\">=</span> 0 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"ext4のパーティションが見つかりませんでした\"</span>\n    <span class=\"k\">else</span>\n        <span class=\"c\"># リサイズの実行</span>\n        <span class=\"nb\">set</span> <span class=\"nt\">-x</span>\n        <span class=\"nb\">sudo </span>parted <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span> resizepart <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">last_end</span><span class=\"k\">}</span>\n        <span class=\"nb\">sudo </span>resize2fs <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span>p2\n        <span class=\"nb\">set</span> +x\n        <span class=\"nb\">echo</span> <span class=\"s2\">\"リブートしてください\"</span>\n    <span class=\"k\">fi\nelse\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"最終パーティションがfreeではありません\"</span>\n<span class=\"k\">fi</span>\n \n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その7)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その7)</h1>\n      <p>Node-REDのメモ 応用編 GPIO+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIOの入出力データをWebsocketで飛ばして、Dashboardから操作/Dashboardで表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"gpio入出力データをwebsocketで送受信raspberrypi\">GPIO入出力データをWebsocketで送受信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>RaspberryPiでGPIO出力</strong>、<strong>RaspberryPiでGPIO入力</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>、<strong>Websocketでデータを受信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、GPIO入力データをそのまま送信すると、受け取り側で「0はON?それともOFF?」となってしまうので、GPIO入力の0/1をON/OFFの文字列に変換するファンクションノードを追加している。\n  また、GPIO出力側も同様に、送信側から送られてきたON/OFFの文字列をGPIO出力データの1/0の数値に変換するファンクションノードを挿入している。<br />\n  ターゲットボードの正論理/負論理が変更になった場合はこれらのファンクションノードで調整すれば良い。</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"6e229d5a.774af4\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"109b9bce.e015e4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 730,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4834db5b.5c24d4\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": true,\n        \"x\": 190,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"3ff59514.52c732\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7d90bda.d7b4b8\",\n        \"type\": \"websocket in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"47e24d88.c603e4\",\n        \"x\": 280,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"a38bd8a1.0a5bd8\",\n                \"5e99ea44.cfdac4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9bc37a7.e1e9808\",\n        \"type\": \"websocket out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"c4985621.1edb48\",\n        \"x\": 830,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"a38bd8a1.0a5bd8\",\n        \"type\": \"debug\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 730,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3ff59514.52c732\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"1/0→OFF/ON\",\n        \"func\": \"if (msg.payload) {\\n    msg.payload = 'OFF';\\n}\\nelse {\\n    msg.payload = 'ON';\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"9bc37a7.e1e9808\",\n                \"a38bd8a1.0a5bd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5e99ea44.cfdac4\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"OFF/ON→0/1\",\n        \"func\": \"if (msg.payload == 'OFF') {\\n    msg.payload = 0;\\n}\\nelse {\\n    msg.payload = 1;\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"109b9bce.e015e4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47e24d88.c603e4\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/led0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"c4985621.1edb48\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/sw0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからgpio入出力データを送受信サーバ\">WebsocketからGPIO入出力データを送受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータ送信(サーバ)</strong>、<strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノードに<strong>その4</strong> の <strong>Dashboard のUIを作成する(ボタン)</strong>、<strong>Dashboardでテキストを表示する</strong>で作成したノードを接続すれば良い。</li>\n</ul>\n\n<p>この状態でRaspberryPi側でスイッチをON/OFFすると、Dashboardの「SW」の文字列のON/OFFが切り替わる。\nまた、DashboardのLLED_ON/LED_OFFのボタンをクリックすると、LEDが点灯/消灯する</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"ca6a740f.4d43b8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_GPIO\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"ac19aeee.9f8f5\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 260,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"2098e31e.e6832c\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 270,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8db70b6.86a1178\",\n        \"type\": \"ui_text\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 610,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f45af19.269e\",\n        \"type\": \"websocket in\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"fad64a63.6141a\",\n        \"client\": \"\",\n        \"x\": 270,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"8db70b6.86a1178\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"299e8287.226e6e\",\n        \"type\": \"websocket out\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"d7b33218.4a1f28\",\n        \"client\": \"\",\n        \"x\": 630,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"95b08556.d2cce\",\n        \"type\": \"debug\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 610,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"b7e42e0e.52bdb\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"1b4acf7b.a194c9\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"fad64a63.6141a\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/sw0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"d7b33218.4a1f28\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/led0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"1b4acf7b.a194c9\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ3\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node.jsでGoogle spreadsheet にデータを書き込む</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node.jsでGoogle spreadsheet にデータを書き込む</h1>\n      <p>Node.jsでGoogle spreadsheet にデータを書き込む</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Node.jsでGoogle spreadsheet にデータを書き込む方法。<br />\nサンプルプログラムを<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>に置きました。</p>\n\n<p>Google Drive API を サービスアカウントで操作する方法を取りました。</p>\n\n<p>OAuth認証を使う方法は事前準備がめんどっちいので、パス。<br />\nAPIキー認証はリードはできたけど、ライトが出来んかった。あと、シートを公開しないといけないが、やな感じだった。</p>\n\n<h1 id=\"詳細\">詳細</h1>\n\n<p>詳細は\n<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>\nのREADME おひび ソースコードを参照してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その8)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その8)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Google spreadsheet</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをGoogle spreadsheet に記録するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"google-spreadsheet用ノードのインストール\">Google spreadsheet用ノードのインストール</h2>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-contrib-viseo-google-」と入力</li>\n  <li>下に検索結果が出るので、「node-red-contrib-viseo-google-authentication」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら続けて「node-red-contrib-viseo-google-spreadsheet」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h2 id=\"googleの準備\">Googleの準備</h2>\n\n<p><a href=\"https://techblog.lclco.com/entry/2018/11/30/120000\">具体的な手順はこちらを参考にしてくだされ。</a> (コードの実装の手前まで)  <br />\nただし、<span style=\"color: red; \">有効にするAPI</span>は「Google Drive API」ではなく、「<span style=\"color: red; \">Google Sheets API</span>」なので、注意!!</p>\n\n<h3 id=\"認証情報の作成\">認証情報の作成</h3>\n\n<ul>\n  <li><a href=\"https://console.developers.google.com/project\">Google Developers Console</a> でプロジェクトを作成</li>\n  <li>Google Sheets APIを有効化</li>\n  <li>認証情報(サービスアカウント キー)を作成</li>\n  <li>保存された認証情報の秘密鍵をダウンロード<br />\n  このファイルはセキュリティ上 <strong>超重要</strong> なので、まちがって公開しないように!!!!<br />\n  ・・・・公開して後悔…なんちゃって(^^ゞ</li>\n</ul>\n\n<h3 id=\"記録用スプレッドシートの作成\">記録用スプレッドシートの作成</h3>\n\n<ul>\n  <li><a href=\"https://drive.google.com/drive/u/0/my-drive\">Google Drive</a>から記録するスプレッドシートを作成する(マイドライブからgoogleスプレッドシートを選択すると新規ファイルが作成される)</li>\n  <li>作成されたスプレッドシートに共有ユーザ(サービスアカウントキーのメールアドレス)を追加。権限を編集者、通知のチェックははずしてOKする</li>\n  <li>必要ならシートの追加や名前の変更を行っておく(以下ではシート名が「BME280」になっているものとして説明)</li>\n  <li>1行目に項目名を入れておく。ここではA列から「epoch」「日付」「温度」「湿度」「気圧」としている</li>\n  <li>B列(「日付」の列)を選択し、メニューから「表示形式」→「数値」→「日時」を選択(これをやらないと時刻が見えない))</li>\n  <li>作成されたスプレッドシートのID(URLの docs.google.com/spreadsheets/d/<span style=\"color: red; \">この部分</span>/edit~)をメモしておく</li>\n</ul>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"bme280ノード\">BME280ノード</h3>\n\n<ul>\n  <li><strong>その2</strong>の<strong>BME280を使用するフローを作成する</strong>と同様の手順でBME280ノードを作成する</li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>出力側にFunctionノードを接続\n  コードは以下。<br />\n  あとで時刻を使用しやすいようにエポック時刻で記録するようにしている。<br />\n  また、エポック時刻のままだとスプレッドシーで見たときに日時が分かり難いので、エポック時刻から日時に変更する計算式を入れておく。(ここで直接文字列にすることもできるが)<br />\n  また、Google Sheetsノードの入力はArrayである必要があるようで、Ayyayでラップしておく。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">var</span> <span class=\"nx\">date</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">epoch</span> <span class=\"o\">=</span> <span class=\"nx\">date</span><span class=\"p\">.</span><span class=\"nx\">getTime</span><span class=\"p\">();</span>\n<span class=\"c1\">// msg.payload.date  = date.toString();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">date</span>  <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">=indirect(\"R[0]C[-1]\", false) / (1000*60*60*24) + (9/24) + DATE(1970, 1, 1)</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">];</span>\n\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に上でメモっておいたスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:z」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>set dataのときは使用されないようだ</li>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n        </ul>\n      </li>\n      <li>「Action」に「Set Data」を選択し、その右は「Append」を選択</li>\n      <li>「input」は「msg」を選択し、「payload」を入力</li>\n      <li>「Fields」で「Select」を選択</li>\n      <li>その下に「key」と入力欄が表示されるので、「epoch」と入力し、「追加」をクリック</li>\n      <li>「date」と入力し、「追加」をクリック</li>\n      <li>「temperature_C」と入力し、「追加」をクリック</li>\n      <li>「humidity」と入力し、「追加」をクリック</li>\n      <li>「pressure_hPa」と入力\n        <ul>\n          <li>このデータの並びが入力のプロパティ名とスプレッドシートのセルの並びに対応する</li>\n        </ul>\n      </li>\n      <li>outputもよー分からんけど、とりあえず「msg」を選択し、「_output」にしておく\n        <ul>\n          <li>set dataのときは処理結果が入るようだ</li>\n          <li>get dataのときはリード結果が入るようだ</li>\n        </ul>\n      </li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>このノードの入力にファンクションノードの出力を接続</li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、温度等を測定、スプレッドシートに送信される。<br />\nスプレッドシートを確認すれば、そのデータが記録されているハズである。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1a4f21c6.53e09e\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+spreadsheet\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"b4e73f33.99aec8\",\n        \"type\": \"Bme280\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 220,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"a54ed898.2a114\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"b74c37d3.63a48\",\n        \"type\": \"inject\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 90,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"b4e73f33.99aec8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a54ed898.2a114\",\n        \"type\": \"function\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"データ整形\",\n        \"func\": \"var date = new Date();\\nmsg.payload.epoch = date.getTime();\\n// msg.payload.date  = date.toString();\\n// msg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\",false)/1000/60/60/24 + 9/24 + DATE(1970,1,1)';\\nmsg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\", false) / (1000*60*60*24) + (9 / 24) + DATE(1970, 1, 1)';\\n\\nmsg.payload = [msg.payload];\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 390,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"6a4f8cc4.882e54\",\n                \"adad9a.88697a68\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6a4f8cc4.882e54\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:z\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"set\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": false,\n        \"fields\": \"select\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"epoch\",\n            \"date\",\n            \"temperature_C\",\n            \"humidity\",\n            \"pressure_hPa\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"payload\",\n        \"output\": \"__output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 620,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"93209cb1.cd86\"\n            ],\n            [\n                \"9a8717a8.88bae8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"93209cb1.cd86\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9a8717a8.88bae8\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 220,\n        \"wires\": []\n    },\n    {\n        \"id\": \"adad9a.88697a68\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 850,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その9)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その9)</h1>\n      <p>Node-REDのメモ 応用編 Google spreadsheet Read</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGoogle spreadsheet からデータを取得したときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><strong>その8</strong> に従って準備済みであるものとする。</p>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で作成済みの認証情報を選択するか、「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に操作対象のスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:zzz」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n          <li>Rangeのフォーマットはシート名!開始セル:終了セル\n            <ul>\n              <li>開始セルと終了セルを両方省略することは可能(片方のみ省略は不可のよう)。<br />\nこの場合、シート全体が取得される。ただし、↑のように特定のシート名はダメかもしれない。</li>\n              <li>開始セル/終了セルはカラム名と行番号で構成されるが、カラム名か行番号は省略可能。\nたぶん、こんな感じ。\n                <ul>\n                  <li>開始カラム名を省略するとAが指定されたとみなす</li>\n                  <li>開始行番号を省略すると1が指定されたとみなす</li>\n                  <li>終了カラム名を省略すると最終カラム(zzz?)が指定されたとみなす</li>\n                  <li>終了行番号を省略すると最終行が指定されたとみなす</li>\n                </ul>\n              </li>\n              <li>大きな範囲を指定しても、以降空白セルであった場合は無視される(有効なデータがある範囲だけ読み込まれる)</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n          <li>プロパティ名はシート名_開始セル_終了セル</li>\n          <li>globalに記録しておけば、キャッシュとして使用出来て、なんども同じデータを読まなくて済む、という使い方かな?</li>\n        </ul>\n      </li>\n      <li>\n        <p>「Action」に「Get Data」を選択し、その右は「By line」を選択</p>\n      </li>\n      <li>「Labels」の「First line for labels」を選択しすると、outputの型がDictionaryになる。指定したセル範囲の開始カラム(シート全体の開始カラムではない)がキー名となる。<br />\n 選択しなければ、outputの型がArrayになる</li>\n      <li>「Labels」の「First column for labels」を選択しすると、outputの各要素の型がDictionaryになる。指定したセル範囲の開始行(シート全体の開始行ではない)の内容がキー名となる。<br />\n 選択しなければ、outputの各要素の型がArrayになる</li>\n      <li>\n        <p>この2つ、なんか逆な気もするけど…</p>\n      </li>\n      <li>outputにリード結果が入る。とりあえず「msg」を選択し、「_output」にしておく\n内容は「Labels」の設定内容によって変わる</li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>設定内容と取得内容の関係はよくワカランので、色々試してみてください。<br />\n現実的には、細かくデータを取得してどうこうするより、シート全体を取得して処理するような使い方になるのかな??</p>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、スプレッドシートの内容が取得されるハズ。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"5eb2475f.ea747\",\n        \"type\": \"tab\",\n        \"label\": \"spreadsheet_read\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"60d62f37.80a8a\",\n        \"type\": \"inject\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"bba510f2.5bb2d8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e183b4f0.c372f\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"37bd743e.1ca96c\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"bba510f2.5bb2d8\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"spreadsheet read\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:zzz\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"get\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": true,\n        \"fields\": \"all\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"\",\n        \"output\": \"_output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 290,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"e183b4f0.c372f\"\n            ],\n            [\n                \"37bd743e.1ca96c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PythonでIntel NCStick2</title>\n  </head>\n  <body>\n    <header>\n      <h1>PythonでIntel NCStick2</h1>\n      <p>PythonでIntel NCStick2を操作する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"事前準備\">事前準備</h1>\n<p>何はなくともPythonが必要。<br />\n実際には3.7.4を使用して動作確認。</p>\n\n<p>Pythonはpyenvでインストールしておくのが便利。インストール方法は \n<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a> を参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\npyenvとの相性が悪いらしく、pyenvで3.7.xがインストールされていると\n(python3.7コマンド自体は存在するので;実行自体はエラーで返ってくるが)、\nsetupvars.shでPYTHONPATHにpython3.7用pathが設定されてしまう。\nプログラム中で<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>でpathを追加しても、sys.pathの末尾に追加されてしまい、\n先に設定された3.7用モジュールがインポートされてしまう。\nもし、他のバージョンのpythonで実行する場合は<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">sys.path.insert</code>で\npathの先頭に追加するようにしないといけないようだ(試してないけど)。</p>\n\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n    <span class=\"err\">↓</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>ということで、下のプログラムソースの<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>の行は不要。</p>\n</blockquote>\n\n<h2 id=\"モジュールのインストール\">モジュールのインストール</h2>\n\n<p>必要なモジュール類をインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgfortran-6-dev\npip <span class=\"nb\">install </span>numpy\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h2 id=\"ワークディレクトリ\">ワークディレクトリ</h2>\n\n<p>色々共通で使いたいサイズのでっかいファイルがあるので、ワークディレクトリを以下の構成で作成しておく。<br />\n以降のopenVINO関連の投稿もこのディレクトリ構成を使うようにする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># C++プログラム湯尾</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++\n<span class=\"c\"># pythonプログラム用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/python\n<span class=\"c\"># モデルデータ用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP16\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP32\n</code></pre></div></div>\n\n<h1 id=\"参考\">参考</h1>\n\n<p><del>パクった</del> 参考にしたのは以下のあたり<br />\n解説や実行方法などはこっちを参照してちょ(相変わらずの他力本願ぶり…))</p>\n\n<ul>\n  <li><a href=\"http://jellyware.jp/openvino/\">JELLYWARE ゼロから学ぶディープラーニング推論</a>\n    <ul>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c07_ie_emotion.html\">Inference Engineを学んで感情分類</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c08_face_detection.html\">リアルタイム顔検出</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c09_emotion_app.html\">リアルタイム感情分析アプリ</a></li>\n    </ul>\n  </li>\n</ul>\n\n<p>顔検出+感情分類の参照元はカメラキャプチャした画像を処理しているけど、手元に適当なカメラがなかったので、JPEGファイルで実行するようにしてある(こっちの方が余計な処理なくて分かりやすいかな、と思ったのもある)。</p>\n\n<h1 id=\"感情分類\">感情分類</h1>\n\n<p>感情分類のプログラムを試す。</p>\n\n<h3 id=\"準備\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/emotions-recognition-retail-0003/FP16/emotions-recognition-retail-0003\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する顔画像(顔部分のみ切り出し)をPHOTO/face.jpgとして保存しておく。</p>\n\n<h3 id=\"プログラム\">プログラム</h3>\n\n<p>試したソースはこちら。<br />\nPCのubuntuで実行するための処理も追加済み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/face.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 結果取り出し\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>\n<span class=\"c1\"># 結果の最大値を持つインデックスを取得\n</span><span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 結果表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">結果'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">index_max</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"c1\"># 結果の詳細表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">詳細'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'スコア:</span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出\">顔検出</h1>\n\n<p>顔検出のプログラムを試す。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-1\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-1\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n\n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-1\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_detect.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_detect.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_detect.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出感情分類\">顔検出+感情分類</h1>\n\n<p>上の2つを合体させ、顔検出した結果に感情分類を実行する。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-2\">準備</h3>\n\n<p>モデルデータは上の2つをそのまま使用。</p>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-2\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出 + 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n# 日本語表示にはPillow使うとかしないといけないので、英語で。\n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# バウンティングボックスとラベルを表示する関数\n</span><span class=\"k\">def</span> <span class=\"nf\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ラベル領域サイズ\n</span>    <span class=\"n\">LABEL_W</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">12</span>    <span class=\"c1\"># 等幅フォントじゃないので正確ではないけど、大体こんな感じ\n</span>    <span class=\"n\">LABEL_H</span> <span class=\"o\">=</span> <span class=\"mi\">14</span>                <span class=\"c1\"># こっちもトライアンドエラーで微調整\n</span>    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">IMAGE_W</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">IMAGE_H</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># バウンディングボックス表示 \n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ラベル表示位置(X)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">IMAGE_W</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">IMAGE_W</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_W</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">xmin</span>\n    \n    <span class=\"c1\"># ラベル表示位置(Y)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span>\n    \n    <span class=\"c1\"># 文字列背景描画(塗りつぶし)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">label_x</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 文字列描画(座標は文字の左下)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX_SMALL</span><span class=\"p\">,</span> <span class=\"mf\">0.8</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n    \n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。特にminは補正しないとエラーになる\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 顔領域のみ切り出し \n</span>    <span class=\"n\">frame_face</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">[</span> <span class=\"n\">ymin</span><span class=\"p\">:</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">:</span><span class=\"n\">xmax</span> <span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 入力データフォーマットへ変換 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame_face</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span>   <span class=\"c1\"># サイズ変更 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">img_face</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img_face</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>    \n    <span class=\"c1\"># 推論実行 \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img_face</span><span class=\"p\">})</span>\n    \n    <span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>    \n    <span class=\"c1\"># 出力値が最大のインデックスを得る \n</span>    <span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"c1\"># print(list_emotion[index_max])\n</span>    <span class=\"n\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-2\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<h1 id=\"考察\">考察</h1>\n\n<p>基本パターンはこんな感じ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># モジュールのロード\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># 初期化\n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"s\">\"MYRIAD\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み\n</span><span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"s\">'xmlファイル'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"s\">'binファイル'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 推論実行 \n# imgは入力データ、Numpy配列 ndarray型\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># outが出力データ、Numpy配列 ndarray型\n</span>\n</code></pre></div></div>\n\n<p>入出力データの並びは読み込んだモデルに依存する。<br />\n入力データのサイズやRGB並び順などを合わせる。<br />\n(モデルに入力する際にリサイズすれば、元の画像ファイルのサイズは任意で良い。)<br />\n出力データはそのままでは「何のこっちゃ?」なので、きちんと整形してやる必要がある。</p>\n\n<p>ここに学習済みデータが色々登録されているらしい。<br />\n<a href=\"https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html\">https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html</a></p>\n\n<p>TensorflowやCaffeで作成した学習済みデータを変換することもできるらしいが、やり方はこれから調査。</p>\n\n<h1 id=\"参考情報\">参考情報</h1>\n<p><a href=\"https://software.intel.com/en-us/articles/OpenVINO-RelNotes\">openVINO toolkit リリースノート</a><br />\n<a href=\"https://git.uni-paderborn.de/rnagle/dldt/tree/noctua_plugin_develop\">openVINO toolkit リポジトリ</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>改訂版はこちら→<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></p>\n\n<p>caffeモデルなどをopenVINOへ変換するには、フルパッケージが必要らしい。<br />\nでもって、フルパッケージはRaspberryPiでは使用できなくて、WindowsやLinux、macOSが必要。<br />\nということで、openVINO フルパッケージをubuntu 18.04にインストールする。 <br />\n(16.04でも大丈夫かもしれないけど、今回は18.04を使う。LTSじゃないのはやめといた方が良さそう)</p>\n\n<h1 id=\"ダウンロード--インストール前半\">ダウンロード & インストール前半</h1>\n\n<p>ダウンロードはこの辺を参考に。。。<br />\n<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758</a><br />\nなにやら登録しないといけないらしい。</p>\n\n<p>ダウンロードしたら、てきとーなところに展開して、インストーラを実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\n2910.10 「2019 R3.1」がリリースされた。ファイル名は「l_openvino_toolkit_p_2019.3.376.tgz」</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf /Share/l_openvino_toolkit_p_2019.3.334.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2019.3.334\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n\n<p>nextをクリックしていけば大丈夫(Agreeするとこはあるけど)。<br />\nあとで色々インストールしろと言われるけど、あとでやるので無視して大丈夫<br />\n・・・・しばらく待つ・・・・<br />\nいったんFinishするとブラウザが表示される<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h1 id=\"インストール後半--動作確認\">インストール後半 & 動作確認</h1>\n\n<h2 id=\"install-external-software-dependenciesとな\">「Install External Software Dependencies」とな?</h2>\n\n<p>なんか実行してインストールしろってことらしい。<br />\nroot権限で実行しないとエラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh\n</code></pre></div></div>\n\n<p>なんか色々インストールされるっぽい。<br />\n中身はOSのディストリビューションとバージョンでインストールパッケージを切り替えてインストールしてるらしい。</p>\n\n<h2 id=\"set-the-environment-variablesとな\">「Set the Environment Variables」とな?</h2>\n\n<p>環境変数の設定らしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<p>~/.bashrcに追加しておくと良いとのことなので、そうする。</p>\n\n<h2 id=\"configure-the-model-optimizerとな\">「Configure the Model Optimizer」とな?</h2>\n\n<p>モデルオプティマイザの設定。<br />\nこれが欲しかったのよ。</p>\n\n<p>必要なpipモジュールをインストールするらしい。<br />\n必要なものだけインストールすることもできるけど、一括でインストールしといた方が手間がかからないでしょう。</p>\n\n<p>pyenvを使ってると、<code class=\"language-plaintext highlighter-rouge\">sudo pip3</code>されると、systemのpip3が動いてしまい、pyenv環境にモジュールがインストールされない。<br />\nスクリプトの中で必要なコマンドだけ実行する(随分スッキリしちゃったなぁ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\n</code></pre></div></div>\n\n<p>バージョン不一致とか言われたら、適宜バージョン合わせてアップグレードorダウングレードしてちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nsetuptoolsは<code class=\"language-plaintext highlighter-rouge\">pip install -U setuptools</code>でOKなはず。<br />\nnumpyは<code class=\"language-plaintext highlighter-rouge\">mxnet 1.3.1 has requirement numpy<1.15.0,>=1.8.2, but you'll have numpy 1.17.3 which is incompatible.</code>と言われるのだけど、tensorflow 1.15.0だとnumpy 1.16.0以上を要求する。<br />\nとりあえず、tenssorflowを1.13.1にしてnumpyを1.14.6にしてみて様子見。<br />\n現状のバージョン一覧は以下。これを<code class=\"language-plaintext highlighter-rouge\">requirements.txt</code>として保存し、<code class=\"language-plaintext highlighter-rouge\">pip install -r requirements.txt</code>するとこのバージョンでそろえてくれるはず。</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.8.1\nastor==0.8.0\ncertifi==2019.9.11\nchardet==3.0.4\ndecorator==4.4.0\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.1.7\ngraphviz==0.8.4\ngrpcio==1.24.3\nh5py==2.10.0\nidna==2.8\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.0\nMarkdown==3.1.1\nmock==3.0.5\nmxnet==1.3.1\nnetworkx==2.3\nnumpy==1.14.6\nonnx==1.6.0\nopt-einsum==3.1.0\npipdeptree==0.13.2\nprotobuf==3.6.1\nrequests==2.22.0\nsix==1.12.0\ntensorboard==1.13.1\ntensorflow==1.13.1\ntensorflow-estimator==1.13.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4\nurllib3==1.25.6\nWerkzeug==0.16.0\nwrapt==1.11.2\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nオリジナルの方法はこちら</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"run-the-verification-scripts-to-verify-installationとな\">「Run the Verification Scripts to Verify Installation」とな?</h2>\n\n<p>なになに、実行必須?たしかにapt installが実行される。<br />\nなら、タイトルに “to Verify Installation” とか書くなよ!</p>\n\n<p>build前に<code class=\"language-plaintext highlighter-rouge\">apt install</code> と <code class=\"language-plaintext highlighter-rouge\">pip install</code>が走る。</p>\n\n<p>こっちもpyenv使ってるとpipで悲しいことになるので、先にpipだけ実行しておく。<br />\nスクリプト側でもpipが走ってsystemのモジュールが追加されるが、悪影響はないと思うので、そのままにしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div></div>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n./demo_squeezenet_download_convert_run.sh\n</code></pre></div></div>\n\n<p>・・・・こんなことをやってるらしい・・・・</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">target_precision</code> は FP16 になっている</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">apt install</code> で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pip install</code>で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/open_model_zoo/tools/downloaderdownloader.py</code>でモデルのダウンロードを行う\n    <ul>\n      <li>ダウンロード済みならスキップ»</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/model_optimizer/mo.py</code>でモデル変換を行う\n    <ul>\n      <li>変換済みならスキップ»</li>\n    </ul>\n  </li>\n  <li>サンプルプログラムのbuild</li>\n  <li>サンプルプログラム(classification_sample_async)の実行<br />\n  実行結果はこんな感じ</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./classification_sample_async -d CPU -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/openvino_models/ir/FP16//public/squeezenet1.1/squeezenet1.1.xml \n\n[ INFO ] InferenceEngine: \n\tAPI version ............ 2.1\n\tBuild .................. custom_releases/2019/R3_cb6cad9663aea3d282e0e8b3e0bf359df665d5d0\n\tDescription ....... API\n[ INFO ] Parsing input parameters\n[ INFO ] Parsing input parameters\n[ INFO ] Files were added: 1\n[ INFO ]     /opt/intel/openvino/deployment_tools/demo/car.png\n[ INFO ] Creating Inference Engine\n\tCPU\n\tMKLDNNPlugin version ......... 2.1\n\tBuild ........... 30677\n\n[ INFO ] Loading network files\n[ INFO ] Preparing input blobs\n[ WARNING ] Image is resized from (787, 259) to (227, 227)\n[ INFO ] Batch size is 1\n[ INFO ] Loading model to the device\n[ INFO ] Create infer request\n[ INFO ] Start inference (10 asynchronous executions)\n[ INFO ] Completed 1 async request execution\n[ INFO ] Completed 2 async request execution\n[ INFO ] Completed 3 async request execution\n[ INFO ] Completed 4 async request execution\n[ INFO ] Completed 5 async request execution\n[ INFO ] Completed 6 async request execution\n[ INFO ] Completed 7 async request execution\n[ INFO ] Completed 8 async request execution\n[ INFO ] Completed 9 async request execution\n[ INFO ] Completed 10 async request execution\n[ INFO ] Processing output blobs\n\nTop 10 results:\n\nImage /opt/intel/openvino/deployment_tools/demo/car.png\n\nclassid probability label\n------- ----------- -----\n817     0.8364176   sports car, sport car\n511     0.0945683   convertible\n479     0.0419195   car wheel\n751     0.0091233   racer, race car, racing car\n436     0.0068038   beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon\n656     0.0037315   minivan\n586     0.0025940   half track\n717     0.0016044   pickup, pickup truck\n864     0.0012045   tow truck, tow car, wrecker\n581     0.0005833   grille, radiator grille\n\n[ INFO ] Execution successful\n\n[ INFO ] This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool\n</code></pre></div></div>\n\n<ul>\n  <li>終了</li>\n</ul>\n\n<p>もういっちょでも実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh\n</code></pre></div></div>\n\n<p>やってることは前のと同じ。<br />\nこっちはopenVINOのモデルをダウンロードするので、モデル変換はない。<br />\n最終的に実行しているデモプログラムはこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./security_barrier_camera_demo -d CPU -d_va CPU -d_lpr CPU -i /opt/intel/openvino/deployment_tools/demo/car_1.bmp -m ~/openvino_models/ir/FP16/intel/vehicle-license-plate-detection-barrier-0106/FP16/vehicle-license-plate-detection-barrier-0106.xml -m_lpr ~/openvino_models/ir/FP16/intel/license-plate-recognition-barrier-0001/FP16/license-plate-recognition-barrier-0001.xml -m_va ~/openvino_models/ir/FP16/intel/vehicle-attributes-recognition-barrier-0039/FP16/vehicle-attributes-recognition-barrier-0039.xml \n</code></pre></div></div>\n\n<h2 id=\"gpuやncstick使わないから以下スキップ\">GPUやNCStick使わないから以下スキップ</h2>\n\n<!--\n## 「Run a Sample Application」\n\nNCStickなどVPUベースの環境で実行するにはFP16モデルが必要\nデフォルトはFP32\n\nFP16: 16bit浮動小数点\nFP32: 32bit浮動小数点\n====\nmkdir ~/squeezenet1.1_FP16\ncd ~/squeezenet1.1_FP16\npython3 /opt/intel/openvino/deployment_tools/model_optimizer/mo.py --input_model ~/openvino_models/models/FP32/classification/squeezenet/1.1/caffe/squeezenet1.1.caffemodel --data_type FP16 --output_dir .\n\n====\n\n\n\n\n./classification_sample_async -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/squeezenet1.1_FP16/squeezenet1.1.xml -d CPU\n-->\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openCV で MPEG再生</title>\n  </head>\n  <body>\n    <header>\n      <h1>openCV で MPEG再生</h1>\n      <p>python + openCV でMPEGファイルを再生する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>python + openCV で MPEGファイルを再生するには、以下のようにread→imshowを繰り返せば良い。<br />\nしかし、これではフレームレートを考慮していないため、実際の時間とは異なる速度で再生されてしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n<span class=\"k\">while</span> <span class=\"n\">true</span><span class=\"p\">:</span>\n    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"k\">break</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>そこで、フレーム間に待ち時間を確保し、実際の時間と同じになるように再生する方法を考える。</p>\n\n<h1 id=\"フレーム間の待ち時間を決め打ちで待つパターン一番シンプルなパターン\">フレーム間の待ち時間を決め打ちで待つパターン(一番シンプルなパターン)</h1>\n\n<p>最も簡単な方法は、フレーム間に決め打ちでwait処理を挿入する方法である。<br />\nフレームレートは一定であるため、待ち時間も一定になる。<br />\n再生中にキー入力による中止を検出したいので、<code class=\"language-plaintext highlighter-rouge\">time.sleep()</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">cv2.waitKey(delay)</code>を使用している。<br />\n試した環境では、<code class=\"language-plaintext highlighter-rouge\">cv2.waitKey()</code> は 25くらいを指定すると大体30fpsに合うくらいの間隔になる(ちょっと早いかも)。<br />\n設定値はトライ&エラーで設定値を探るしかない。</p>\n\n<p>しかし、MPEG再生しか行わない場合はこれでも問題ないが、フレーム間に他の処理を行うと待ち時間が変わってきてしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./video.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 現在時刻\n</span>    <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"n\">index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># delay = 1         # 最速再生\n</span>    <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"mi\">25</span>          <span class=\"c1\"># それっぽい再生速度になるように決め打ちで\n</span>    \n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">delay</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"前回の時刻からフレーム間の待ち時間を決めるパターン\">前回の時刻からフレーム間の待ち時間を決めるパターン</h1>\n\n<p>前回の表示時刻を覚えておき、今回の表示時刻との間隔がフレームレートに一致するように待ち時間を調整する。<br />\nこれなら、フレーム間に他の処理を挿入しても(その処理時間が一定でなくても)、その処理時間を除いて待ち時間を設定できる。</p>\n\n<p>しかし、挿入した処理がフレームレートを超えてしまうと、回復する術がなく、どんどん遅れていってしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./video.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n        <span class=\"n\">tmp_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 現在時刻\n</span>    <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"n\">index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># 待ち時間計算用起点からの差分とsec/frameから待ち時間決定\n</span>    <span class=\"n\">delta_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">tmp_time</span>\n    <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">sec_per_frame</span> <span class=\"o\">-</span> <span class=\"n\">delta_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(f'delta =  {int(delta_time*1000)}    {delay}')\n</span>    <span class=\"c1\"># 待ち時間がsec/frameを超えてたら最小値に設定\n</span>    <span class=\"k\">if</span> <span class=\"n\">delay</span> <span class=\"o\"><</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n\n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">delay</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># 待ち時間計算用起点\n</span>    <span class=\"n\">tmp_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"経過時間から表示すべきフレームを求めて移動しながら表示するパターン\">経過時間から表示すべきフレームを求めて移動しながら表示するパターン</h1>\n\n<p>現在時刻と再生開始時刻の差から表示すべきフレーム番号を求め、必要であれば<code class=\"language-plaintext highlighter-rouge\">cap.set(cv2.CAP_PROP_POS_FRAMES, index)</code>で読み込みフレームを移動して現在時刻とフレームの同期をとる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">cap.set()</code>は処理に時間がかかるので、無条件で実行すると再生フレームレートが遅くなるため、フレーム飛びが発生したときのみ実行するようにする。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n# filepath = os.path.abspath(\"./video.mp4\") \n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./stopwatch.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 前回表示フレーム番号の更新\n</span>    <span class=\"n\">prev_index</span> <span class=\"o\">=</span> <span class=\"n\">index</span>\n    \n    <span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 現在時刻\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        \n        <span class=\"c1\"># 表示するフレーム位置の取得\n</span>        <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">sec_per_frame</span><span class=\"p\">)</span>\n        <span class=\"c1\"># print(f\"{prev_time}    {cur_time}    {prev_index}    {index}\")\n</span>        <span class=\"k\">if</span> <span class=\"n\">prev_index</span> <span class=\"o\">==</span> <span class=\"n\">index</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 前回と同じフレーム番号ならちょっと待つ\n</span>            <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.001</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"k\">break</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># 表示するフレーム位置が連続するフレームでなければ移動\n</span>    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">!=</span> <span class=\"n\">prev_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># 動作確認0.5秒待ってみる\n</span>    <span class=\"c1\"># time.sleep(0.5)\n</span>\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>YOLOv3を試す</title>\n  </head>\n  <body>\n    <header>\n      <h1>YOLOv3を試す</h1>\n      <p>Native & python でYOLOv3を実行してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"yolov3を試す\">YOLOv3を試す</h1>\n\n<p>YOLOv3をubuntu上で実行してみた。<br />\nopneVINOやNCStickは使用していない。<br />\n単にYOLOv3の動作確認したかった&python実装を探してたら見つかったサイトをトレースしてみただけの話。<br />\npyhton のバージョンは3.7.4</p>\n\n<p>元ネタはこちら→ <a href=\"https://qiita.com/massie_g/items/a2bcfac4fed66b1b0717#yolo-v3-tiny-%E3%83%A2%E3%83%87%E3%83%AB\">https://qiita.com/massie_g/items/a2bcfac4fed66b1b0717#yolo-v3-tiny-%E3%83%A2%E3%83%87%E3%83%AB</a></p>\n\n<p>とりあえず動かしてみた後にpythonのソース読んでみた。<br />\nイメージの読み込みも、結果の描画も、保存もNativeなライブラリをコールしてるだけだ… <br />\n完全なwrapperだ。。。<br />\nやりたかったこととちょっと違う。。。orz….</p>\n\n<p>darknetは色々な処理(jpegファイルの操作とか)を自前で実装しているので、\n色々ライブラリをインストールしなくて良いのは助かるんだけど、\n他の処理系に移植するのはめんどくさそうなんだな。。。</p>\n\n<p>ということで、さくっと試した手順だけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">WORKDIR</span><span class=\"o\">=</span>/work1/YOLO\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>\ngit clone https://github.com/pjreddie/darknet.git\n<span class=\"nb\">cd </span>darknet\nwget https://pjreddie.com/media/files/yolov3.weights\nwget https://pjreddie.com/media/files/yolov3-tiny.weights\n<span class=\"nb\">cd</span> ..\ngit clone https://github.com/mganeko/python3_yolov3.git\n<span class=\"nb\">cp</span> ./python3_yolov3/darknet-tiny-label.py ./darknet/python/\n<span class=\"nb\">cd </span>darknet\nmake\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>/darknet/libdarknet.so /usr/lib/libdarknet.so\n\n<span class=\"c\"># YOLOv3 native版の実行</span>\n./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg\n<span class=\"c\"># predictions.jpg が認識結果</span>\n<span class=\"nb\">mv </span>predictions.jpg predictions_yolo.jpg \n\n<span class=\"c\"># tinyYOLOv3 native版の実行</span>\n./darknet detect cfg/yolov3-tiny.cfg yolov3-tiny.weights data/dog.jpg\n<span class=\"c\"># predictions.jpg が認識結果</span>\n<span class=\"nb\">mv </span>predictions.jpg predictions_tiny.jpg\n\n<span class=\"c\"># tinyYOLOv3 python版の実行</span>\npython python/darknet-tiny-label.py \n<span class=\"c\"># detect_result.jpg が認識結果</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO</h1>\n      <p>darknetのモデルデータをopenVINOのモデルデータに変換し、tinyYOLOで画像認識を行う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOの2019 R3.1 がリリー(2019.10.29現在、ubuntu用のみ)スされ、YOLOのサンプルプログラムが用意されていたので、tinyYOLOを実行してみた。</p>\n\n<p>参考:<a href=\"https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html\">https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html</a></p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"darknetのモデルデータをopenvinoのモデルデータに変換\">darknetのモデルデータをopenVINOのモデルデータに変換</h1>\n\n<p>上記参考サイトの手順に従って、darknetのtinyYOLOモデルデータをopenVINOのモデルデータに変換する。</p>\n\n<h2 id=\"darknet--tensorflow-変換のためのプログラム取得\">darknet → tensorflow 変換のためのプログラム取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2\ngit clone https://github.com/mystic123/tensorflow-yolo-v3.git\n<span class=\"nb\">cd </span>tensorflow-yolo-v3/\ngit checkout ed60b90\n</code></pre></div></div>\n\n<h2 id=\"darknet-tinyyoloモデルデータ取得\">darknet tinyYOLOモデルデータ取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://raw.githubusercontent.com/pjreddie/darknet/master/data/coco.names\nwget https://pjreddie.com/media/files/yolov3-tiny.weights\n</code></pre></div></div>\n\n<h1 id=\"darknet--tensorflow-モデルデータ変換\">darknet → tensorflow モデルデータ変換</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python convert_weights_pb.py <span class=\"nt\">--class_names</span> coco.names <span class=\"nt\">--data_format</span> NHWC <span class=\"nt\">--weights_file</span> yolov3-tiny.weights <span class=\"nt\">--tiny</span>\n<span class=\"nb\">mv </span>frozen_darknet_yolov3_model.pb yolo_v3_tiny.pb\n</code></pre></div></div>\n\n<h2 id=\"モデルデータを変換\">モデルデータを変換</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP16 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div></div>\n\n<p>/work/NCS2/openvino_models/FP16ディレクトリに yolo_v3_tiny.bin yolo_v3_tiny.mapping yolo_v3_tiny.xml の3つが出来る</p>\n\n<blockquote>\n  <p>[!NOTE]\nFP32で計算する場合はこちら<br />\nNCStick使用時はFP16のみサポートなので、FP16で作っておくと使い回しできて楽。<br />\nそんなに認識精度が変わるわけでもなさそうだし。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP32\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP32 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"ラベルデータもコピー\">ラベルデータもコピー</h2>\n\n<p>pbファイルにはラベルデータが入っているはずだが、この後の変換でラベルデータは欠落するらしい。<br />\n後のプログラムのためにファイル名変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>coco.names <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels\n</code></pre></div></div>\n\n<h2 id=\"デモプログラムをコピー\">デモプログラムをコピー</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ..\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_yolov3_async <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>object_detection_demo_yolov3_async/\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>MP4ファイルのパスが絶対パスでないと正常にオープンできない対策(ubuntuではやらなくても大丈夫)</li>\n  <li>1フレームあたりの処理時間の計測と表示処理を追加</li>\n  <li>認識枠の表示色変更(ちょっと見難かったので)</li>\n  <li>計測データ表示処理の並べ替え(ソースが見難かったので。フレーム時間の追加以外の動作は変更なし)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py.org\t2019-10-29 05:08:34.982999999 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"p\">@@ -210,7 +210,8 @@</span>\n     else:\n         labels_map = None\n \n<span class=\"gd\">-    input_stream = 0 if args.input == \"cam\" else args.input\n</span><span class=\"gi\">+    # input_stream = 0 if args.input == \"cam\" else args.input\n+    input_stream = 0 if args.input == \"cam\" else os.path.abspath(args.input)\n</span> \n     is_async_mode = True\n     cap = cv2.VideoCapture(input_stream)\n<span class=\"p\">@@ -234,6 +235,8 @@</span>\n     next_request_id = 1\n     render_time = 0\n     parsing_time = 0\n<span class=\"gi\">+    frame_time = 0\n+    prev_time = time()\n</span> \n     # ----------------------------------------------- 6. Doing inference -----------------------------------------------\n     log.info(\"Starting inference...\")\n<span class=\"p\">@@ -263,6 +266,8 @@</span>\n \n         # Start inference\n         start_time = time()\n<span class=\"gi\">+        frame_time = start_time - prev_time         # 1フレームの処理時間\n+        prev_time = start_time\n</span>         exec_net.start_async(request_id=request_id, inputs={input_blob: in_frame})\n         det_time = time() - start_time\n \n<span class=\"p\">@@ -303,8 +308,9 @@</span>\n             # Validation bbox of detected object\n             if obj['xmax'] > origin_im_size[1] or obj['ymax'] > origin_im_size[0] or obj['xmin'] < 0 or obj['ymin'] < 0:\n                 continue\n<span class=\"gd\">-            color = (int(min(obj['class_id'] * 12.5, 255)),\n-                     min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span><span class=\"gi\">+            # color = (int(min(obj['class_id'] * 12.5, 255)),\n+            #          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n+            color = (255, 128, 128)\n</span>             det_label = labels_map[obj['class_id']] if labels_map and len(labels_map) >= obj['class_id'] else \\\n                 str(obj['class_id'])\n \n<span class=\"p\">@@ -322,16 +328,17 @@</span>\n         # Draw performance stats over frame\n         inf_time_message = \"Inference time: N\\A for async mode\" if is_async_mode else \\\n             \"Inference time: {:.3f} ms\".format(det_time * 1e3)\n<span class=\"gi\">+        frame_time_message = \"Frame time: {:.3f} ms\".format(frame_time * 1e3)\n</span>         render_time_message = \"OpenCV rendering time: {:.3f} ms\".format(render_time * 1e3)\n         async_mode_message = \"Async mode is on. Processing request {}\".format(cur_request_id) if is_async_mode else \\\n             \"Async mode is off. Processing request {}\".format(cur_request_id)\n         parsing_message = \"YOLO parsing time is {:.3f}\".format(parsing_time * 1e3)\n \n<span class=\"gd\">-        cv2.putText(frame, inf_time_message, (15, 15), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200, 10, 10), 1)\n-        cv2.putText(frame, render_time_message, (15, 45), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n-        cv2.putText(frame, async_mode_message, (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5,\n-                    (10, 10, 200), 1)\n-        cv2.putText(frame, parsing_message, (15, 30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n</span><span class=\"gi\">+        cv2.putText(frame, inf_time_message,    (15, 15),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, parsing_message,     (15, 30),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, render_time_message, (15, 45),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, frame_time_message,  (10, int(origin_im_size[0] - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, async_mode_message,  (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n</span> \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n</code></pre></div></div>\n\n<p>上のパッチ内容をa.patchとして保存したとして、以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch object_detection_demo_yolov3_async.py a.patch \n\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\n入力ファイルをmp4に変えるだけ。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしいが、カメラないので未確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>RaspberryPi用はopenVINO 2019R3のまま(2019.10.29現在、R3.1はリリースされていない)だけど、問題なし。</p>\n\n<p>ubuntuで作成した object_detection_demo_yolov3_async ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"静止画の場合-1\">静止画の場合</h2>\n\n<p>実行コマンドは以下。  ubuntuの実行コマンドと比べて、以下の変更がある。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--device MYRIAD</code>を追加</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">--cpu_extension</code>を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合-1\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\nこちらも入力ファイルをmp4に変えるだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p>openCVではMP4ファイルを保存することができる。<br />\nobject_detection_demo_yolov3_async.py に以下の変更を加えることで、認識結果をMP4ファイルに保存することができる。</p>\n\n<p>以下の修正ファイルは簡易的に保存する処理を追加したため、保存ファイル名は決め打ち。 <br />\n汎用的にするなら、オプションで指定できるようにしてもいいかもね。</p>\n\n<p>ただし、実際に保存するタイミングとMP4ファイルのタイムインデックスが一致するわけではないので、\n処理時の見た目と保存ファイルを再生したときの見た目は異なるので注意が必要。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"gi\">+++ record.py\t2019-10-29 11:35:37.296005608 +0900\n</span><span class=\"p\">@@ -218,6 +218,18 @@</span>\n     number_input_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n     number_input_frames = 1 if number_input_frames != -1 and number_input_frames < 0 else number_input_frames\n \n<span class=\"gi\">+    # =====================================================================================\n+    # 幅と高さを取得\n+    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n+    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n+    size = (width, height)\n+    # フレームレート(1フレームの時間単位はミリ秒)の取得\n+    frame_rate = int(cap.get(cv2.CAP_PROP_FPS))\n+    # フォーマット\n+    fmt = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')\n+    writer = cv2.VideoWriter('./outtest.mp4', fmt, frame_rate, size)\n+    # =====================================================================================\n+\n</span>     wait_key_code = 1\n \n     # Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n<span class=\"p\">@@ -342,6 +354,9 @@</span>\n \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n<span class=\"gi\">+        # =====================================================================================\n+        writer.write(frame)\n+        # =====================================================================================\n</span>         render_time = time() - start_time\n \n         if is_async_mode:\n<span class=\"p\">@@ -359,6 +374,10 @@</span>\n             is_async_mode = not is_async_mode\n             log.info(\"Switched to {} mode\".format(\"async\" if is_async_mode else \"sync\"))\n \n<span class=\"gi\">+    # =====================================================================================\n+    writer.release()\n+    # =====================================================================================\n+\n</span>     cv2.destroyAllWindows()\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO(C++版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO(C++版)</h1>\n      <p>tinyYOLOのC++版デモプログラムのbuildと実行</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nのpythonで実行したデモプログラムのC++版をbuild&実行してみる。</p>\n\n<h1 id=\"ubuntu環境での実行\">ubuntu環境での実行</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h2 id=\"デモのソースプログラム\">デモのソースプログラム</h2>\n\n<p>ドライバのインストール先 <code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/deployment_tools/open_model_zoo/demos</code> にあるので、そのまま参照しても良いが、\nソース修正に備えて、ソースをコピっておく(オーナーも変更)と何かと便利。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++/openvino_demo <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos <span class=\"nb\">.</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> demos/\n</code></pre></div></div>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>出力文字列のサイズと位置を調整</li>\n  <li>-saveオプションの追加と認識結果画像ファイルの保存処理の追加</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.hpp.org\t2019-10-31 14:39:14.757039048 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.hpp\t2019-10-31 06:16:49.178945707 +0900\n</span><span class=\"p\">@@ -93,6 +93,7 @@</span>\n /// \\brief Define a flag to disable showing processed video<br>\n /// It is an optional parameter\n DEFINE_bool(no_show, false, no_show_processed_video);\n<span class=\"gi\">+DEFINE_bool(save, false, \"Optional. save image file.\");\n</span> \n /**\n * \\brief This function shows a help message\n<span class=\"p\">@@ -115,4 +116,5 @@</span>\n     std::cout << \"    -iou_t                    \" << iou_thresh_output_message << std::endl;\n     std::cout << \"    -auto_resize              \" << input_resizable_message << std::endl;\n     std::cout << \"    -no_show                  \" << no_show_processed_video << std::endl;\n<span class=\"gi\">+    std::cout << \"    -save                     \" << \"Optional. save image file.\" << std::endl;\n</span> }\n</code></pre></div></div>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.org\t2019-10-31 05:46:38.515000000 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"p\">@@ -197,6 +197,21 @@</span>\n         }\n         // -----------------------------------------------------------------------------------------------------\n \n<span class=\"gi\">+        // =====================================================================================\n+        // 動画ファイルを書き出すためのオブジェクトを宣言する\n+        cv::VideoWriter writer;\n+        // =====================================================================================\n+        // =====================================================================================\n+        if (FLAGS_save) {\n+            double fps    = cap.get(cv::CAP_PROP_FPS);\t\t\t\t// フレームレートを取得\n+            int fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v');\t\t// MP4形式を指定\n+            // * エンコード形式 \"XVID\" = AVI, \"MP4V\" = MPEG4, \"WMV1\" = WMV\n+\n+            // 動画ファイルを書き出すためのファイルをオープンする\n+            writer.open(\"result.mp4\", fourcc, fps, cv::Size(width, height));\n+        }\n+        // =====================================================================================\n+\n</span>         // --------------------------- 1. Load inference engine -------------------------------------\n         slog::info << \"Loading Inference Engine\" << slog::endl;\n         Core ie;\n<span class=\"p\">@@ -356,17 +371,17 @@</span>\n                 std::ostringstream out;\n                 out << \"OpenCV cap/render time: \" << std::fixed << std::setprecision(2)\n                     << (ocv_decode_time + ocv_render_time) << \" ms\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 25), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 255, 0));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 15), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 255, 0));\n</span>                 out.str(\"\");\n                 out << \"Wallclock time \" << (isAsyncMode ? \"(TRUE ASYNC):      \" : \"(SYNC, press Tab): \");\n                 out << std::fixed << std::setprecision(2) << wall.count() << \" ms (\" << 1000.f / wall.count() << \" fps)\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 50), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 0, 255));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 30), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 0, 255));\n</span>                 if (!isAsyncMode) {  // In the true async mode, there is no way to measure detection time directly\n                     out.str(\"\");\n                     out << \"Detection time  : \" << std::fixed << std::setprecision(2) << detection.count()\n                         << \" ms (\"\n                         << 1000.f / detection.count() << \" fps)\";\n<span class=\"gd\">-                    cv::putText(frame, out.str(), cv::Point2f(0, 75), cv::FONT_HERSHEY_TRIPLEX, 0.6,\n</span><span class=\"gi\">+                    cv::putText(frame, out.str(), cv::Point2f(0, 45), cv::FONT_HERSHEY_TRIPLEX, 0.4,\n</span>                                 cv::Scalar(255, 0, 0));\n                 }\n \n<span class=\"p\">@@ -410,7 +425,7 @@</span>\n                         cv::putText(frame,\n                                 (label < static_cast<int>(labels.size()) ?\n                                         labels[label] : std::string(\"label #\") + std::to_string(label)) + conf.str(),\n<span class=\"gd\">-                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 1,\n</span><span class=\"gi\">+                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.4,\n</span>                                     cv::Scalar(0, 0, 255));\n                         cv::rectangle(frame, cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin)),\n                                       cv::Point2f(static_cast<float>(object.xmax), static_cast<float>(object.ymax)), cv::Scalar(0, 0, 255));\n<span class=\"p\">@@ -420,6 +435,11 @@</span>\n             if (!FLAGS_no_show) {\n                 cv::imshow(\"Detection results\", frame);\n             }\n<span class=\"gi\">+            // =====================================================================================\n+            if (FLAGS_save) {\n+                writer << frame;\n+            }\n+            // =====================================================================================\n</span> \n             t1 = std::chrono::high_resolution_clock::now();\n             ocv_render_time = std::chrono::duration_cast<ms>(t1 - t0).count();\n<span class=\"p\">@@ -457,6 +477,11 @@</span>\n         if (FLAGS_pc) {\n             printPerformanceCounts(*async_infer_request_curr, std::cout, getFullDeviceName(ie, FLAGS_d));\n         }\n<span class=\"gi\">+        // =====================================================================================\n+        if (FLAGS_save) {\n+            writer.release();\n+        }\n+        // =====================================================================================\n</span>     }\n     catch (const std::exception& error) {\n         std::cerr << \"[ ERROR ] \" << error.what() << std::endl;\n\n</code></pre></div></div>\n\n<h2 id=\"buildディレクトリの作成とbuild\">buildディレクトリの作成とbuild</h2>\n\n<p>cmakeの実行とbuild</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<p>ちょっと時間がかかる。</p>\n\n<h2 id=\"モデルデータ\">モデルデータ</h2>\n\n<p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nで作成したモデルデータをそのまま使用する。<br />\nラベルデータファイルのファイル名はモデルデータのxmlファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものに固定だが、モデルデータ作成時にコピー済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./intel64/Release/</code>に作成される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./intel64/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-l</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> ../../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>-save オプションを指定すると、認識結果の動画をresult.mp4(ファイル名は固定)に保存する。</p>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>デモプログラムはRasspberryPiでも動作させることができる。<br />\nソースはRaspberryPi側にはないので、ubuntuからコピーする。</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>ubuntuで作成した /work/NCS2/c++/openvino_demo/demos ディレクトリと/work/NCS2/openvino_models ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"buildディレクトリの作成とbuild-1\">buildディレクトリの作成とbuild</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a -Wno-psabi\"</span> ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./armv7l/Release/</code>に作成される。<br />\n入力ファイル(-i オプション)はフルパスで指定すること。相対パスだとファイルが見つからないと怒られる。<br />\n※ 下のパッチを当てると相対パスでも大丈夫になる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./armv7l/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-d</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> /work/NCS2/data/testvideo3.mp4 \n</code></pre></div></div>\n\n<p>なぜか-saveオプションが効かない。。。</p>\n\n<h2 id=\"入力ファイル名に相対パスを使用できるようにするためのパッチ\">入力ファイル名に相対パスを使用できるようにするためのパッチ</h2>\n\n<p>入力ファイル名をrealpath()で絶対パスに変換して使用することで対応。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.1\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-11-01 11:25:29.720856218 +0900\n</span><span class=\"p\">@@ -30,6 +30,9 @@</span>\n #include <ext_list.hpp>\n #endif\n \n<span class=\"gi\">+#include <limits.h>\n+#include <unistd.h>\n+\n</span> using namespace InferenceEngine;\n \n bool ParseAndCheckCommandLine(int argc, char *argv[]) {\n<span class=\"p\">@@ -180,7 +183,23 @@</span>\n \n         slog::info << \"Reading input\" << slog::endl;\n         cv::VideoCapture cap;\n<span class=\"gd\">-        if (!((FLAGS_i == \"cam\") ? cap.open(0) : cap.open(FLAGS_i.c_str()))) {\n</span><span class=\"gi\">+\n+        bool open_status;\n+        if (FLAGS_i == \"cam\") {\n+            open_status = cap.open(0);\n+        }\n+        else {\n+            std::string input_filename;\n+            char input_filename_char[PATH_MAX+1];\n+            if (!realpath(FLAGS_i.c_str(), input_filename_char)) {\n+                throw std::logic_error(\"Cannot get realpath\");\n+            }\n+            input_filename = input_filename_char;\n+            slog::info << \"input filename :\" + input_filename << slog::endl;\n+            open_status = cap.open(input_filename.c_str());\n+\n+        }\n+        if (!open_status) {\n</span>             throw std::logic_error(\"Cannot open input file or camera: \" + FLAGS_i);\n         }\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD</h1>\n      <p>openVINOのSSDのサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>YOLOとは別のアルゴリズムSSDで物体認識するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_ssd_async</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">models.list</code>によると、以下のモデルデータが使用できるらしい。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>face-detection-adas-????\nface-detection-adas-binary-????\nface-detection-retail-????\npedestrian-and-vehicle-detector-adas-????\npedestrian-detection-adas-????\npedestrian-detection-adas-binary-????\nperson-detection-retail-????\nvehicle-detection-adas-????\nvehicle-detection-adas-binary-????\nvehicle-license-plate-detection-barrier-????\n</code></pre></div></div>\n\n<p>ここでは、vehicle-detection-adas-binary-????を使ってみることにする。</p>\n\n<p>以下の手順でモデルデータをダウンロードする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/pedestrian-and-vehicle-detector-adas-0001/FP16/pedestrian-and-vehicle-detector-adas-0001\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>ラベルデータは用意されていないので、ラベルデータを以下の内容で、<code class=\"language-plaintext highlighter-rouge\">${models_diir}/pedestrian-and-vehicle-detector-adas-0001.labels</code>のファイル名で作成する。<br />\nオリジナルでは<code class=\"language-plaintext highlighter-rouge\">--label</code>オプションでラベルデータファイルを指定するようになっているが、\nモデルデータファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものをデフォルトのラベルデータファイルとして認識するように変更しておいた。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>UNKNOWN\nvehicles\npedestrians\nUNKNOWN\n</code></pre></div></div>\n\n<p>どのIDが何を示すか書いてる場所を見つけられなかったんだよなぁ~。<br />\nとりあえず、結果表示から推測するしかないか。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<p>ちょっとのつもりで改造してたら、結構たくさんの変更になったので、ソース全体を掲載しておく。<br />\n(RaspberryPiにはソース入ってないし)<br />\nおもな変更点は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--save</code> <code class=\"language-plaintext highlighter-rouge\">--log</code> <code class=\"language-plaintext highlighter-rouge\">--sync</code> <code class=\"language-plaintext highlighter-rouge\">--no_disp</code> オプションの追加</li>\n  <li>結果解析部分の関数化(後でYOLOと比較しやすいように)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># print(res[out_blob].shape)\n</span>    <span class=\"c1\">#  -> (1, 1, 200, 7)        200:バウンディングボックスの数\n</span>    <span class=\"c1\"># データ構成は\n</span>    <span class=\"c1\"># https://docs.openvinotoolkit.org/2019_R1/_pedestrian_and_vehicle_detector_adas_0001_description_pedestrian_and_vehicle_detector_adas_0001.html\n</span>    <span class=\"c1\"># の「outputs」を参照\n</span>    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"n\">out_blob</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]:</span>     <span class=\"c1\"># このループは200回まわる\n</span>        <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>                       <span class=\"c1\"># confidence for the predicted class(スコア)\n</span>        <span class=\"k\">if</span> <span class=\"n\">conf</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">:</span>      <span class=\"c1\"># 閾値より大きいものだけ処理\n</span>            <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n            <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 表示色\n</span>            <span class=\"c1\"># color = (min(class_id * 12.5, 255), min(class_id * 7, 255), min(class_id * 5, 255))\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>            <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># バウンディングボックスとラベル、スコアを表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">det_label</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">conf</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">%\"</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Demo supports only single output topologies\"</span>\n\n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"c1\"># SSDのinputsは1とは限らないのでスキャンする\n</span>    <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">for</span> <span class=\"n\">blob_name</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">:</span>\n        <span class=\"c1\"># print(f'{blob_name}   {net.inputs[blob_name].shape}')\n</span>        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">4</span><span class=\"p\">:</span>\n            <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">2</span><span class=\"p\">:</span>\n            <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"nb\">RuntimeError</span><span class=\"p\">(</span><span class=\"s\">\"Unsupported {}D input layer '{}'. Only 2D and 4D input layers are supported\"</span>\n                               <span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">),</span> <span class=\"n\">blob_name</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    <span class=\"k\">if</span> <span class=\"n\">img_info_input_blob</span><span class=\"p\">:</span>\n        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">img_info_input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n\n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span>     <span class=\"o\">=</span> <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span>  <span class=\"o\">=</span> <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span> <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_ssd_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                          <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                          <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でYOLO(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でYOLO(その2)</h1>\n      <p>openVINOのYOLOのプログラムをちょこっと改変</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> のソースを\n<a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> のソースと形状を合わせたもの。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">math</span> <span class=\"kn\">import</span> <span class=\"n\">exp</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-iout\"</span><span class=\"p\">,</span> <span class=\"s\">\"--iou_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Intersection over union threshold for overlapping \"</span>\n                                                       <span class=\"s\">\"detections filtering\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-ni\"</span><span class=\"p\">,</span> <span class=\"s\">\"--number_iter\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Number of inference iterations\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pc\"</span><span class=\"p\">,</span> <span class=\"s\">\"--perf_counts\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Report performance counters\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span>\n                      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-r\"</span><span class=\"p\">,</span> <span class=\"s\">\"--raw_output_message\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Output inference results raw values showing\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">YoloParams</span><span class=\"p\">:</span>\n    <span class=\"c1\"># ------------------------------------------- Extracting layer parameters ------------------------------------------\n</span>    <span class=\"c1\"># Magic numbers are copied from yolo samples\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">param</span><span class=\"p\">,</span> <span class=\"n\">side</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"mi\">3</span> <span class=\"k\">if</span> <span class=\"s\">'num'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'num'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">=</span> <span class=\"mi\">4</span> <span class=\"k\">if</span> <span class=\"s\">'coords'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'coords'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">classes</span> <span class=\"o\">=</span> <span class=\"mi\">80</span> <span class=\"k\">if</span> <span class=\"s\">'classes'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'classes'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">10.0</span><span class=\"p\">,</span> <span class=\"mf\">13.0</span><span class=\"p\">,</span> <span class=\"mf\">16.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">33.0</span><span class=\"p\">,</span> <span class=\"mf\">23.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">61.0</span><span class=\"p\">,</span> <span class=\"mf\">62.0</span><span class=\"p\">,</span> <span class=\"mf\">45.0</span><span class=\"p\">,</span> <span class=\"mf\">59.0</span><span class=\"p\">,</span> <span class=\"mf\">119.0</span><span class=\"p\">,</span> <span class=\"mf\">116.0</span><span class=\"p\">,</span> <span class=\"mf\">90.0</span><span class=\"p\">,</span> <span class=\"mf\">156.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">198.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">373.0</span><span class=\"p\">,</span> <span class=\"mf\">326.0</span><span class=\"p\">]</span> <span class=\"k\">if</span> <span class=\"s\">'anchors'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"p\">[</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">a</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'anchors'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n\n        <span class=\"k\">if</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">:</span>\n            <span class=\"n\">mask</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">idx</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'mask'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">mask</span><span class=\"p\">)</span>\n\n            <span class=\"n\">maskedAnchors</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n            <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">mask</span><span class=\"p\">:</span>\n                <span class=\"n\">maskedAnchors</span> <span class=\"o\">+=</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"n\">maskedAnchors</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">=</span> <span class=\"n\">side</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"o\">=</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span>  <span class=\"c1\"># Weak way to determine but the only one.\n</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">log_params</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># params_to_print = {'classes': self.classes, 'num': self.num, 'coords': self.coords, 'anchors': self.anchors}\n</span>        <span class=\"c1\"># [log.info(\"         {:8}: {}\".format(param_name, param)) for param_name, param in params_to_print.items()]\n</span>        <span class=\"k\">pass</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">entry_index</span><span class=\"p\">(</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">coord</span><span class=\"p\">,</span> <span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">location</span><span class=\"p\">,</span> <span class=\"n\">entry</span><span class=\"p\">):</span>\n    <span class=\"n\">side_power_2</span> <span class=\"o\">=</span> <span class=\"n\">side</span> <span class=\"o\">**</span> <span class=\"mi\">2</span>\n    <span class=\"n\">n</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">//</span> <span class=\"n\">side_power_2</span>\n    <span class=\"n\">loc</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">%</span> <span class=\"n\">side_power_2</span>\n    <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">side_power_2</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">coord</span> <span class=\"o\">+</span> <span class=\"n\">classes</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">entry</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">loc</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"p\">,</span> <span class=\"n\">h_scale</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"p\">):</span>\n    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">w</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">y</span> <span class=\"o\">-</span> <span class=\"n\">h</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">w</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">+</span> <span class=\"n\">h</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"nb\">dict</span><span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"o\">=</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"o\">=</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"o\">=</span><span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"o\">=</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">blob</span><span class=\"p\">,</span> <span class=\"n\">resized_image_shape</span><span class=\"p\">,</span> <span class=\"n\">original_im_shape</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">threshold</span><span class=\"p\">):</span>\n    <span class=\"c1\"># ------------------------------------------ Validating output parameters ------------------------------------------\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    <span class=\"k\">assert</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">==</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"s\">\"Invalid size of output blob. It sould be in NCHW layout and height should \"</span> \\\n                                     <span class=\"s\">\"be equal to width. Current height = {}, current width = {}\"</span> \\\n                                     <span class=\"s\">\"\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ------------------------------------------ Extracting layer parameters -------------------------------------------\n</span>    <span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">orig_im_w</span> <span class=\"o\">=</span> <span class=\"n\">original_im_shape</span>\n    <span class=\"n\">resized_image_h</span><span class=\"p\">,</span> <span class=\"n\">resized_image_w</span> <span class=\"o\">=</span> <span class=\"n\">resized_image_shape</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">predictions</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">flatten</span><span class=\"p\">()</span>\n    <span class=\"n\">side_square</span> <span class=\"o\">=</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n\n    <span class=\"c1\"># ------------------------------------------- Parsing YOLO Region output -------------------------------------------\n</span>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">side_square</span><span class=\"p\">):</span>\n        <span class=\"n\">row</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">//</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"n\">col</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">%</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"k\">for</span> <span class=\"n\">n</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">num</span><span class=\"p\">):</span>\n            <span class=\"n\">obj_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">)</span>\n            <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">scale</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"n\">box_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n            <span class=\"c1\"># Network produces location predictions in absolute coordinates of feature maps.\n</span>            <span class=\"c1\"># Scale it to relative coordinates.\n</span>            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">col</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">0</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">row</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"c1\"># Value for exp is very big number in some cases so following construction is using here\n</span>            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">w_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n                <span class=\"n\">h_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">3</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n            <span class=\"k\">except</span> <span class=\"nb\">OverflowError</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"c1\"># Depends on topology we need to normalize sizes by feature maps (up to YOLOv3) or by input shape (YOLOv3)\n</span>            <span class=\"n\">w</span> <span class=\"o\">=</span> <span class=\"n\">w_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_w</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"n\">h</span> <span class=\"o\">=</span> <span class=\"n\">h_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_h</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">):</span>\n                <span class=\"n\">class_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span>\n                                          <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">+</span> <span class=\"n\">j</span><span class=\"p\">)</span>\n                <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"n\">scale</span> <span class=\"o\">*</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">class_index</span><span class=\"p\">]</span>\n                <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                    <span class=\"k\">continue</span>\n                <span class=\"n\">objects</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">=</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">=</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"o\">=</span><span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"o\">=</span><span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">j</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">,</span>\n                                          <span class=\"n\">h_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_w</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"n\">objects</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n    <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">height_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span>\n    <span class=\"k\">if</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">height_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">*</span> <span class=\"n\">height_of_overlap_area</span>\n    <span class=\"n\">box_1_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">box_2_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">area_of_union</span> <span class=\"o\">=</span> <span class=\"n\">box_1_area</span> <span class=\"o\">+</span> <span class=\"n\">box_2_area</span> <span class=\"o\">-</span> <span class=\"n\">area_of_overlap</span>\n    <span class=\"k\">if</span> <span class=\"n\">area_of_union</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"mi\">0</span>\n    <span class=\"k\">return</span> <span class=\"n\">area_of_overlap</span> <span class=\"o\">/</span> <span class=\"n\">area_of_union</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>                 <span class=\"c1\"># 冒頭でinputは一つでなければエラーになってるので決め打ちで[0]\n</span>    <span class=\"n\">in_frame_shape</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">:]</span>       <span class=\"c1\"># HWC→BCHWに変更してあるので、height/widthはshape[2:]で取得\n</span>    <span class=\"k\">for</span> <span class=\"n\">layer_name</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">.</span><span class=\"n\">items</span><span class=\"p\">():</span>\n        <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">parents</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]].</span><span class=\"n\">shape</span><span class=\"p\">)</span>\n        <span class=\"n\">layer_params</span> <span class=\"o\">=</span> <span class=\"n\">YoloParams</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n        <span class=\"c1\"># log.info(\"Layer {} parameters: \".format(layer_name))\n</span>        <span class=\"n\">layer_params</span><span class=\"p\">.</span><span class=\"n\">log_params</span><span class=\"p\">()</span>\n        <span class=\"n\">objects</span> <span class=\"o\">+=</span> <span class=\"n\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">out_blob</span><span class=\"p\">,</span> \n                                        <span class=\"n\">in_frame_shape</span><span class=\"p\">,</span>\n                                        <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">],</span> \n                                        <span class=\"n\">layer_params</span><span class=\"p\">,</span>\n                                        <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Filtering overlapping boxes with respect to the --iou_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">sorted</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">,</span> <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"k\">lambda</span> <span class=\"n\">obj</span> <span class=\"p\">:</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">reverse</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">iou_threshold</span><span class=\"p\">:</span>\n                <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># Drawing objects with respect to the --prob_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">obj</span> <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span> <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">Detected boxes for batch {}:\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">))</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\" Class ID | Confidence | XMIN | YMIN | XMAX | YMAX | COLOR \"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">origin_im_size</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Validation bbox of detected object\n</span>        <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"c1\"># color = (int(min(obj['class_id'] * 12.5, 255)),\n</span>        <span class=\"c1\">#          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span>        <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n        <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]]</span> <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"ow\">and</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">>=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]</span> <span class=\"k\">else</span> \\\n            <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">])</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span>\n                <span class=\"s\">\"{:^9} | {:10f} | {:4} | {:4} | {:4} | {:4} | {} \"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">det_label</span><span class=\"p\">,</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">color</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]),</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span>\n                    <span class=\"s\">\"#\"</span> <span class=\"o\">+</span> <span class=\"n\">det_label</span> <span class=\"o\">+</span> <span class=\"s\">' '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"s\">' %'</span><span class=\"p\">,</span>\n                    <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.6</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"c1\"># YOLOのoutputsは1ではない\n</span>    \n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Sample supports only YOLO V3 based single input topologies\"</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>     <span class=\"c1\"># inputは一つだけなので決め打ちで[0]\n</span>    \n    <span class=\"c1\">#  Defaulf batch_size is 1\n</span>    <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n    \n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n        \n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span> <span class=\"o\">=</span>      <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span> <span class=\"o\">=</span>   <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span>  <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_yolov3_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                             <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                             <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                             <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-iout</span> IOU_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-ni</span> NUMBER_ITER] <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-r</span><span class=\"o\">]</span>\n                                             <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG]\n                                             <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n  <span class=\"nt\">-iout</span> IOU_THRESHOLD, <span class=\"nt\">--iou_threshold</span> IOU_THRESHOLD\n                        Optional. Intersection over union threshold <span class=\"k\">for\n                        </span>overlapping detections filtering\n  <span class=\"nt\">-ni</span> NUMBER_ITER, <span class=\"nt\">--number_iter</span> NUMBER_ITER\n                        Optional. Number of inference iterations\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_counts</span>    Optional. Report performance counters\n  <span class=\"nt\">-r</span>, <span class=\"nt\">--raw_output_message</span>\n                        Optional. Output inference results raw values showing\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WindowsでX-serve</title>\n  </head>\n  <body>\n    <header>\n      <h1>WindowsでX-serve</h1>\n      <p>WindowsでX-serveを使用するためにVcXsrvを使う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>SSH ログインしたLinuxマシンからX-Windowプログラムを実行したときに、ウィンドウをWindoesマシンに表示する方法。<br />\nUbuntu、RaspberryPiともにOK。</p>\n\n<h1 id=\"vcxsrvのインストール\">VcXsrvのインストール</h1>\n\n<p>このあたりを参考に(といっても、ダウンロードしてインストーラ実行するだけだけど)。<br />\n<a href=\"https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html\">https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html</a></p>\n\n<h1 id=\"設定のメモ\">設定のメモ</h1>\n\n<h2 id=\"リモートマシンからの要求を受け付ける\">リモートマシンからの要求を受け付ける</h2>\n\n<p>リモートマシンからの要求を受け付けるには、起動時に3ページ目で”Disable access control” にチェックを入れる。</p>\n\n<blockquote>\n  <p>[!NOTE]\nC:\\Program Files\\VcXsrv\\X0.hosts にクライアント(Linuxマシン)のIPアドレスを書いておくと、”Disable access control”にチェックを入れなくても良いらしい。<br />\nしかし、サブネット全体を指定するために「192.168.1.」とやってもうまく動かない。。。<br />\n個別に「192.168.1.5」と書いておくとOK</p>\n</blockquote>\n\n<h2 id=\"逐一設定するのがめんどい\">逐一設定するのがめんどい</h2>\n\n<p>4ページ目で”Save configuration”\tをクリックして保存した設定ファイル(拡張子は”.xlaunch”)を実行すれば設定済みの状態で起動できる。</p>\n\n<h2 id=\"linux側の設定\">Linux側の設定</h2>\n\n<p>Linux側では~/.bashrcに以下を追加しておくと、SSHでlog inしたときに自動でDISPLAY変数を設定してくれる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n\t</span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XXX.XXX:0.0\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h2 id=\"その他注意事項\">その他注意事項</h2>\n\n<p>VcXsrvを起動するとキーボードが勝手に変わることがあるらしい。<br />\n日本語入力できなくなったらWindows+SPACEで確認すること。</p>\n\n<h2 id=\"愚痴\">愚痴</h2>\n\n<p>コマンドラインオプションで設定できないか調べてみたが、見つからない。<br />\n「Addituinal parameters」という設定項目があるので、何かしら設定できるはずなんだけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbianのディスクイメージのアーカイブ</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbianのディスクイメージのアーカイブ</h1>\n      <p>Raspbianのディスクイメージのアーカイブのありかをすぐ忘れてしまうのでメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"メモ\">メモ</h1>\n\n<p>Raspbianのディスクイメージのアーカイブは以下にある。<br />\n各バージョン(日付)別にディレクトリ分けされている。<br />\nミラーサイトが爆速なのでおススメ。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>項目</th>\n      <th>URL</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>最新版</td>\n      <td><a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(本家)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_armhf/images/\">https://downloads.raspberrypi.org/raspios_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Full版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_full_armhf/images/\">https://downloads.raspberrypi.org/raspios_full_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_lite_armhf/images/\">https://downloads.raspberrypi.org/raspios_lite_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(ミラーサイト)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Full版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(2020/02以前版)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspbian/images/\">https://downloads.raspberrypi.org/raspbian/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspbian_lite/images/\">https://downloads.raspberrypi.org/raspbian_lite/images/</a></td>\n    </tr>\n  </tbody>\n</table>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO で顔検出(特定人物識別)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO で顔検出(特定人物識別)</h1>\n      <p>openVINOの顔検出(特定人物識別)のサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOで顔検出(特定人物識別)するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"ソースをワークディレクトリにコピー\">ソースをワークディレクトリにコピー</h1>\n\n<p>ファイルのオーナがrootなので、編集しやすいようにワークディレクトリにソースをコピーし、そこで作業する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>face_recognition_demo/\n</code></pre></div></div>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p>いくつかのモデルデータが必要になるので、ダウンロードする。<br />\nワイルドカードでファイル指定したかったので、wgetでなくcurlを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/landmarks-regression-retail-0009/FP16/landmarks-regression-retail-0009.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-reidentification-retail-0095/FP16/face-reidentification-retail-0095.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\n<span class=\"nb\">cd</span> ..\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ncurlは「カレントディレクトリにターゲットと同じファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-O</code> と 「任意のファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-o</code>オプションしかなく、\nwgetの「ターゲットと同じファイル名で保存先ディレクトリを指定して保存」の<code class=\"language-plaintext highlighter-rouge\">-P</code>に相当するオプションがないので、\nカレントディレクトリを保存先に移動してから<code class=\"language-plaintext highlighter-rouge\">-O</code> オプションでコマンドを実行する。</p>\n</blockquote>\n\n<h1 id=\"足りないモジュールのインストール\">足りないモジュールのインストール</h1>\n\n<p>使用するモジュールでこれまでのお試しで未インストールのモジュールがあるのでインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>scipy\n</code></pre></div></div>\n\n<h1 id=\"ソースの修正\">ソースの修正</h1>\n\n<p>ソースはそのままで問題ないが、ちょっと修正しておく。</p>\n\n<p>主な変更内容は以下の通り。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code> オプションの追加と関連処理</li>\n  <li>Unknownと識別できた場合で検出枠の色を変える</li>\n  <li>入力ファイルを絶対パスに変換(不具合対策)</li>\n  <li>出力ファイルのフォーマットのmp4対応を追加(オリジナルはaviのみ対応)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur face_recognition_demo.org/face_recognition_demo.py face_recognition_demo/face_recognition_demo.py\n</span><span class=\"gd\">--- face_recognition_demo.org/face_recognition_demo.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/face_recognition_demo.py\t2019-11-27 06:29:07.507574900 +0900\n</span><span class=\"p\">@@ -62,6 +62,10 @@</span>\n     gallery.add_argument('--run_detector', action='store_true',\n                          help=\"(optional) Use Face Detection model to find faces\" \\\n                          \" on the face images, otherwise use full images.\")\n<span class=\"gi\">+    gallery.add_argument('--run_detector_no_save', action='store_true',\n+                         help=\"(optional) Use Face Detection model to find faces\" \\\n+                         \" on the face images, otherwise use full images.\" \\\n+                         \" not save detected face image.\")\n</span> \n     models = parser.add_argument_group('Models')\n     models.add_argument('-m_fd', metavar=\"PATH\", default=\"\", required=True,\n<span class=\"p\">@@ -142,7 +146,7 @@</span>\n         log.info(\"Building faces database using images from '%s'\" % (args.fg))\n         self.faces_database = FacesDatabase(args.fg, self.face_identifier,\n                                             self.landmarks_detector,\n<span class=\"gd\">-                                            self.face_detector if args.run_detector else None, args.no_show)\n</span><span class=\"gi\">+                                            self.face_detector if args.run_detector or args.run_detector_no_save else None, args.no_show, args.run_detector_no_save)\n</span>         self.face_identifier.set_faces_database(self.faces_database)\n         log.info(\"Database is built, registered %s identities\" % \\\n             (len(self.faces_database)))\n<span class=\"p\">@@ -261,9 +265,8 @@</span>\n             .face_identifier.get_identity_label(identity.id)\n \n         # Draw face ROI border\n<span class=\"gd\">-        cv2.rectangle(frame,\n-                      tuple(roi.position), tuple(roi.position + roi.size),\n-                      (0, 220, 0), 2)\n</span><span class=\"gi\">+        color1 = (0, 220, 0) if identity.id == FaceIdentifier.UNKNOWN_ID else (0, 0, 220)\n+        cv2.rectangle(frame, tuple(roi.position), tuple(roi.position + roi.size), color1, 2)\n</span> \n         # Draw identity label\n         text_scale = 0.5\n<span class=\"p\">@@ -398,19 +401,17 @@</span>\n         try:\n             stream = int(path)\n         except ValueError:\n<span class=\"gd\">-            pass\n</span><span class=\"gi\">+            # 数字でなければ絶対パスに変換\n+            stream = osp.abspath(path)\n</span>         return cv2.VideoCapture(stream)\n \n     @staticmethod\n     def open_output_stream(path, fps, frame_size):\n         output_stream = None\n         if path != \"\":\n<span class=\"gd\">-            if not path.endswith('.avi'):\n-                log.warning(\"Output file extension is not 'avi'. \" \\\n-                        \"Some issues with output can occur, check logs.\")\n</span><span class=\"gi\">+            forcc = cv2.VideoWriter.fourcc(*'mp4v') if path.endswith('.mp4') else cv2.VideoWriter.fourcc(*'MJPG')\n</span>             log.info(\"Writing output to '%s'\" % (path))\n<span class=\"gd\">-            output_stream = cv2.VideoWriter(path,\n-                                            cv2.VideoWriter.fourcc(*'MJPG'), fps, frame_size)\n</span><span class=\"gi\">+            output_stream = cv2.VideoWriter(path, forcc, fps, frame_size)\n</span>         return output_stream\n \n \n<span class=\"gh\">diff -ur face_recognition_demo.org/faces_database.py face_recognition_demo/faces_database.py\n</span><span class=\"gd\">--- face_recognition_demo.org/faces_database.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/faces_database.py\t2019-11-20 06:31:13.481819754 +0900\n</span><span class=\"p\">@@ -36,10 +36,11 @@</span>\n         def cosine_dist(x, y):\n             return cosine(x, y) * 0.5\n \n<span class=\"gd\">-    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False):\n</span><span class=\"gi\">+    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False, no_db_save=False):\n</span>         path = osp.abspath(path)\n         self.fg_path = path\n         self.no_show = no_show\n<span class=\"gi\">+        self.no_db_save = no_db_save\n</span>         paths = []\n         if osp.isdir(path):\n             paths = [osp.join(path, f) for f in os.listdir(path) \\\n<span class=\"p\">@@ -96,7 +97,7 @@</span>\n                     self.add_item(descriptor, label)\n \n     def ask_to_save(self, image):\n<span class=\"gd\">-        if self.no_show:\n</span><span class=\"gi\">+        if self.no_show or self.no_db_save:\n</span>             return None\n         save = False\n         label = None\n<span class=\"p\">@@ -209,12 +210,14 @@</span>\n             match = len(self.database)-1\n         else:\n             filename = \"{}-{}.jpg\".format(label, len(self.database[match].descriptors)-1)\n<span class=\"gd\">-        filename = osp.join(self.fg_path, filename)\n-\n-        log.debug(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n-        if osp.exists(filename):\n-            log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n-        cv2.imwrite(filename, image)\n</span><span class=\"gi\">+        \n+        if name :\n+            filename = osp.join(self.fg_path, filename)\n+            log.info(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n+            if osp.exists(filename):\n+                log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n+            else :\n+                cv2.imwrite(filename, image)\n</span>         return match\n \n     def add_item(self, desc, label):\n</code></pre></div></div>\n\n<h1 id=\"前準備\">前準備</h1>\n\n<p>識別したい顔の画像を適当なディレクトリに保存しておく。ファイル形式はjpgまたはpng。<br />\n一人ずつ1画像で顔部分のみ切り出しておく。<br />\n複数の人の顔を識別したい場合はそれぞれ別々に保存しておく。</p>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"実行用スクリプトの作成\">実行用スクリプトの作成</h2>\n\n<p>実行コマンドが長ったらしくて入力が面倒なので、以下のスクリプト(demo.sh)を作成しておく。<br />\nUbuntuとRaspberrypiを識別して自動でコマンドオプションを変更するようにしてある。 \n作成したら実行属性を付与しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/bin/bash</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"face_recognition_demo.py\"</span>\n\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"       -m_fd models/face-detection-retail-0004.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_lm models/landmarks-regression-retail-0009.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_reid models/face-reidentification-retail-0095.xml\"</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"o\">==</span> <span class=\"s2\">\"armv7l\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Raspberry Pi\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_fd MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_lm MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_reid MYRIAD\"</span>\n<span class=\"k\">else\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Ubuntu\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> --cpu_lib /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so\"</span>\n<span class=\"k\">fi\n\n\nif</span> <span class=\"o\">[</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 0 <span class=\"nt\">-o</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 1 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n\t<span class=\"c\"># パラメータなし/1個はエラー</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\n</span><span class=\"s2\">==== usage ====\"</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"nv\">$0</span><span class=\"s2\"> database_dir input_file [other option(s)]</span><span class=\"se\">\\n\\n\\n</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">exit </span>1\n<span class=\"k\">else\n    </span><span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -fg </span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\"> --input </span><span class=\"k\">${</span><span class=\"nv\">2</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    <span class=\"c\"># 3番目以降すべてのパラメータを追加</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"p\">@</span>:3:<span class=\"p\">(</span><span class=\"nv\">$#-2</span><span class=\"p\">)</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi\n</span><span class=\"nb\">echo</span> <span class=\"s2\">\"python </span><span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\npython <span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n\n<p>第1パラメータに識別子する顔画像を保存したディレクトリ、第2パラメータに入力ビデオファイル名を指定する。<br />\nこれらのパラメータは省略不可。<br />\n追加でオプションを指定したい場合は第3パラメータ以降に指定する。<br />\nたとえば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo.sh data data/video.mp4  <span class=\"nt\">--output</span> result.mp4\n</code></pre></div></div>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python face_recognition_demo.py <span class=\"nt\">-h</span>\nusage: face_recognition_demo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-i</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-o</span> PATH] <span class=\"o\">[</span><span class=\"nt\">--no_show</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-tl</span><span class=\"o\">]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-cw</span> CROP_WIDTH] <span class=\"o\">[</span><span class=\"nt\">-ch</span> CROP_HEIGHT] <span class=\"nt\">-fg</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">--run_detector</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--run_detector_no_save</span><span class=\"o\">]</span>\n                                <span class=\"nt\">-m_fd</span> PATH <span class=\"nt\">-m_lm</span> PATH <span class=\"nt\">-m_reid</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-l</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-c</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]]\n                                <span class=\"o\">[</span><span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]] <span class=\"o\">[</span><span class=\"nt\">-exp_r_fd</span> NUMBER]\n                                <span class=\"o\">[</span><span class=\"nt\">--allow_grow</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit\n\n</span>General:\n  <span class=\"nt\">-i</span> PATH, <span class=\"nt\">--input</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to the input video <span class=\"o\">(</span><span class=\"s1\">'0'</span> <span class=\"k\">for </span>the\n                        camera, default<span class=\"o\">)</span>\n  <span class=\"nt\">-o</span> PATH, <span class=\"nt\">--output</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to save the output video to\n  <span class=\"nt\">--no_show</span>             <span class=\"o\">(</span>optional<span class=\"o\">)</span> Do not display output\n  <span class=\"nt\">-tl</span>, <span class=\"nt\">--timelapse</span>      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Auto-pause after each frame\n  <span class=\"nt\">-cw</span> CROP_WIDTH, <span class=\"nt\">--crop_width</span> CROP_WIDTH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this width\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n  <span class=\"nt\">-ch</span> CROP_HEIGHT, <span class=\"nt\">--crop_height</span> CROP_HEIGHT\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this height\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n\nFaces database:\n  <span class=\"nt\">-fg</span> PATH              Path to the face images directory\n  <span class=\"nt\">--run_detector</span>        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images.\n  <span class=\"nt\">--run_detector_no_save</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images. not save\n                        detected face image.\n\nModels:\n  <span class=\"nt\">-m_fd</span> PATH            Path to the Face Detection model XML file\n  <span class=\"nt\">-m_lm</span> PATH            Path to the Facial Landmarks Regression model XML file\n  <span class=\"nt\">-m_reid</span> PATH          Path to the Face Reidentification model XML file\n\nInference options:\n  <span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Detection model\n                        <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Facial Landmarks\n                        Regression model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Reidentification\n                        model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> PATH, <span class=\"nt\">--cpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For MKLDNN <span class=\"o\">(</span>CPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to a shared library with custom layers\n                        implementations\n  <span class=\"nt\">-c</span> PATH, <span class=\"nt\">--gpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For clDNN <span class=\"o\">(</span>GPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to the XML file with descriptions of the\n                        kernels\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> Be more verbose\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_stats</span>     <span class=\"o\">(</span>optional<span class=\"o\">)</span> Output detailed per-layer performance stats\n  <span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Probability threshold <span class=\"k\">for </span>face\n                        detections<span class=\"o\">(</span>default: 0.6<span class=\"o\">)</span>\n  <span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Cosine distance threshold between two\n                        vectors <span class=\"k\">for </span>face identification <span class=\"o\">(</span>default: 0.3<span class=\"o\">)</span>\n  <span class=\"nt\">-exp_r_fd</span> NUMBER      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Scaling ratio <span class=\"k\">for </span>bboxes passed to face\n                        recognition <span class=\"o\">(</span>default: 1.15<span class=\"o\">)</span>\n  <span class=\"nt\">--allow_grow</span>          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Allow to grow faces gallery and to dump on\n                        disk. Available only <span class=\"k\">if</span> <span class=\"nt\">--no_show</span> option is off.\n</code></pre></div></div>\n\n<p>主なオプションの意味は以下の通り。</p>\n\n<h3 id=\"-m_fd\"><code class=\"language-plaintext highlighter-rouge\">-m_fd</code></h3>\n\n<p>必須。<br />\n顔位置検出モデルファイル</p>\n\n<h3 id=\"ーm_lm\"><code class=\"language-plaintext highlighter-rouge\">ーm_lm</code></h3>\n\n<p>必須。<br />\n顔特徴点検出モデルファイル</p>\n\n<h3 id=\"-m_reid\"><code class=\"language-plaintext highlighter-rouge\">-m_reid</code></h3>\n\n<p>必須。<br />\n顔識別モデルファイル</p>\n\n<h3 id=\"-d_fd\"><code class=\"language-plaintext highlighter-rouge\">-d_fd</code></h3>\n\n<p>顔位置検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_lm\"><code class=\"language-plaintext highlighter-rouge\">-d_lm</code></h3>\n\n<p>顔特徴点検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_reid\"><code class=\"language-plaintext highlighter-rouge\">-d_reid</code></h3>\n\n<p>顔識別に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"--cpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--cpu_lib</code></h3>\n\n<p>CPU用カスタムレイヤライブラリ(?)ファイル</p>\n\n<h3 id=\"--gpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--gpu_lib</code></h3>\n\n<p>GPU用カスタムレイヤライブラリ(?)ファイル(使ったことないからワカラン)</p>\n\n<h3 id=\"-fg\"><code class=\"language-plaintext highlighter-rouge\">-fg</code></h3>\n\n<p>必須。<br />\n識別する顔画像を格納したディレクトリ<br />\nこのディレクトリ内のjpg、pngファイルのみ抽出してくれるので、他のファイルが混在しても大丈夫。</p>\n\n<h3 id=\"--input\"><code class=\"language-plaintext highlighter-rouge\">--input</code></h3>\n\n<p>必須。<br />\n入力ファイル(動画ファイル)を指定する。 <br />\n静止画でもエラーにならないが、一瞬で消えるので、オプション –timelapse でキー入力待ちにするか、\nオプション –outputでファイル出力すると確認できる。<br />\n省略時はカメラが指定される。</p>\n\n<h3 id=\"--output\"><code class=\"language-plaintext highlighter-rouge\">--output</code></h3>\n\n<p>認識結果をファイルに出力する。<br />\n指定しなければファイルは作成されない(表示のみ)。 \n拡張子がmp4のときはMP4(追加した処理)。<br />\nそれ以外はMJPEGで保存(aviにするのが望ましい。それ以外だとffmpegがなんか言うがファイルはできてるっぽい)。</p>\n\n<h3 id=\"--no_show\"><code class=\"language-plaintext highlighter-rouge\">--no_show</code></h3>\n\n<p>画像表示しない。<br />\n通常は–outputと組み合わせて使う。</p>\n\n<h3 id=\"--timelapse\"><code class=\"language-plaintext highlighter-rouge\">--timelapse</code></h3>\n\n<p>1フレーム表示するごとにキー入力待ちになる。</p>\n\n<h3 id=\"--crop_width--crop_height\"><code class=\"language-plaintext highlighter-rouge\">--crop_width</code>、<code class=\"language-plaintext highlighter-rouge\">--crop_height</code></h3>\n\n<p>入力画像を指定したサイズに切り取る。切り取る場所は元画像の中心。<br />\n両方指定しないと無効。</p>\n\n<h3 id=\"--run_detector\"><code class=\"language-plaintext highlighter-rouge\">--run_detector</code></h3>\n\n<p>オプションを指定するとデータベース作成時に顔検出して新たに顔画像を作成してくれる。<br />\nデータベースファイルが全身画像だったり、複数人数が一緒に写っていてもOK。<br />\n1回指定すれば画像が残っているので以降は指定しなくても良い。</p>\n\n<h3 id=\"--run_detector_no_save\"><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code></h3>\n\n<p>追加したオプション<br />\n指定するとデータベース作成時に顔検出するが、顔画像の保存はしない。</p>\n\n<h3 id=\"--verbose\"><code class=\"language-plaintext highlighter-rouge\">--verbose</code></h3>\n\n<p>指定するとloglevelがDEBUGになる</p>\n\n<h3 id=\"--perf_stats\"><code class=\"language-plaintext highlighter-rouge\">--perf_stats</code></h3>\n\n<p>指定するとフレーム毎にパフォーマンスステータスを表示する</p>\n\n<h3 id=\"-t_fd\"><code class=\"language-plaintext highlighter-rouge\">-t_fd</code></h3>\n\n<p>顔位置検出に使用する閾値。省略時は0.6。</p>\n\n<h3 id=\"-t_reid\"><code class=\"language-plaintext highlighter-rouge\">-t_reid</code></h3>\n\n<p>顔識別に使用する閾値。省略時は0.3。</p>\n\n<h3 id=\"-exp_r_fd\"><code class=\"language-plaintext highlighter-rouge\">-exp_r_fd</code></h3>\n\n<p>顔位置検出した枠のサイズを何倍にするか。ギリギリだとうまく行かないから?省略時は1.15</p>\n\n<h3 id=\"--allow_grow\"><code class=\"language-plaintext highlighter-rouge\">--allow_grow</code></h3>\n\n<p>認識画像で知らない顔が出てきたらその都度登録するか確認する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD(その2)</h1>\n      <p>openVINOのSSDのサンプルプログラムのモデルデータを変更してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> でSSDを動かしてみたが、\n検出できるオブジェクトの種類が少なくてちょっと寂しかったので、別のモデルがないか探してみた。</p>\n\n<p>で、調べてみると、openCVのopen_model_zoo以外にもTensorFlowの公式モデルなどをダウンロードして変換するスクリプトが用意されていた。<br />\nで、以下手順。</p>\n\n<h1 id=\"モデルのダウンロードモデルのirへの変換\">モデルのダウンロード&モデルのIRへの変換</h1>\n\n<h4 id=\"テンポラリディレクトリの作成移動\">テンポラリディレクトリの作成&移動</h4>\n\n<p>とりあえず作業用のディレクトリを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/temp\n<span class=\"nb\">cd</span> /work/temp\n</code></pre></div></div>\n\n<h3 id=\"使用できるモデルの一覧を表示\">使用できるモデルの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py  <span class=\"nt\">--print_all</span>\n</code></pre></div></div>\n\n<p>ちなみに、モデル毎の設定は以下にあるので、雰囲気で解読してちょ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>${INTEL_OPENVINO_DIR}/deployment_tools/open_model_zoo/models/public/${modelname}/model.yml\n</code></pre></div></div>\n\n<h3 id=\"このへんのモデルを使ってみる\">このへんのモデルを使ってみる</h3>\n\n<p>なんとなく、mobilenetが小さそうなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssd_mobilenet_v2_coco\n</code></pre></div></div>\n\n<p>または</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssdlite_mobilenet_v2\n</code></pre></div></div>\n\n<p>ssdlightの方がモデルデータが小さい。その分精度は落ちるらしい。<br />\n検出できるオブジェクトの種類は同じ。<br />\n出力は90種類だが、途中欠番があるみたいなので実質80種類くらい。<br />\n変わったところでは「テディベア」なんてのもある。試してみたらちゃんと認識した(あたりまえか…)。<br />\ncocoデータセット<a href=\"http://cocodataset.org/#home\">http://cocodataset.org/#home</a>なので、有名どころですね。<br />\nあ、「80 object categories 91 stuff categories」ってちゃんと書いてある…</p>\n\n<h3 id=\"ダウンロード\">ダウンロード</h3>\n\n<p>まずはダウンロード。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/</code>にモデルがダウンロードされる。</p>\n\n<h3 id=\"モデルデータをirファイルへ変換\">モデルデータをIRファイルへ変換</h3>\n\n<p>もとのモデルデータはTensorFlowで使用するProtocolBuffer形式なので、openVINOで使用できるIR形式に変換する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/converter.py <span class=\"nt\">--precisions</span> FP16 <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/FP16/</code>にIRモデルが出来る。</p>\n\n<h3 id=\"そのままの場所で使用しても良いが他のモデルとまとめておく\">そのままの場所で使用しても良いが、他のモデルとまとめておく</h3>\n\n<p>モデルがあちこちにあると管理しずらくなるので、他のモデルと同じところに置いておく。<br />\n必要なのはxmlとbin。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>public/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>/FP16/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>.<span class=\"o\">{</span>xml,bin<span class=\"o\">}</span> /work/NCS2/openvino_models/FP16/\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">.{xml,bin}</code>のところにスペースなどを入れてしまうとうまく動かないので注意。<br />\n結構「あとで読みやすいように」と入れてしまいがち(特にスクリプト書くとき)なので注意。</p>\n\n<h3 id=\"ラベルファイルの作成\">ラベルファイルの作成</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/work/NCS2/openvino_models/FP16/${modelname}.labels</code>にラベルデータを作成しておく。<br />\nなくても可。<br />\n作り方は後述。</p>\n\n<h3 id=\"実行\">実行</h3>\n\n<p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> の「デモ実行」と同じ手順で\nモデルファイルを差し替えて(<code class=\"language-plaintext highlighter-rouge\">--model</code>オプション)実行すれば良い。</p>\n\n<h1 id=\"ラベルファイルの作成方法\">ラベルファイルの作成方法</h1>\n\n<p>ラベルデータはモデルデータには含まれていないようなので、作成する方法を検討してみた。</p>\n\n<h3 id=\"tensorflowのmodelsモジュールをダウンロード\">tensorflowのmodelsモジュールをダウンロード</h3>\n\n<p>まず、モデルデータの作成情報のあるモジュールをダウンロードしておく。<br />\ngitでなくてもzipをダウンロードして展開しておいても可(ちょっとデカいので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git models_tf\n</code></pre></div></div>\n\n<h3 id=\"作業ディレクトリに移動\">作業ディレクトリに移動</h3>\n\n<p>あとでpythonプログラムを作成するときに色々面倒がないので、作業ディレクトリはココで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models_tf/research\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">object_detection/samples/configs</code>から対応するconfigファイルを探して(なんとなく雰囲気で探せ!)表示<br />\n<code class=\"language-plaintext highlighter-rouge\">label_map_path</code>に記載されたファイルがlabel_mapファイル<br />\nこのとき、PATH_TO_BE_CONFIGURED は <code class=\"language-plaintext highlighter-rouge\">object_detection/data</code> に読み替えること</p>\n\n<p>ssd_mobilenet_v2_cocoの場合は以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/samples/configs/ssd_mobilenet_v2_coco.config\n</code></pre></div></div>\n\n<p>上記ファイルの場合、label_mapは以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/data/mscoco_label_map.pbtxt\"\n</code></pre></div></div>\n\n<p>こにファイルにIDとラベルが定義されているが、そのままラベルファイルとしては認識できない。<br />\nIDには途中抜けがあるので注意(そのままgrepで抜き出してはダメ)</p>\n\n<h2 id=\"ラベルデータ変換プログラムを作成する\">ラベルデータ変換プログラムを作成する</h2>\n\n<p>label_map.pbtxtからラベル一覧を取得するのを手作業で行うのは大変なので、プログラムを作成する。</p>\n\n<h3 id=\"protocのインストール\">protocのインストール</h3>\n\n<p>まずは必要なモジュールのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n</code></pre></div></div>\n\n<h3 id=\"protoファイルからpythonモジュールを作成する\">protoファイルからpythonモジュールを作成する</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>protoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"変換プログラムのソース\">変換プログラムのソース</h3>\n\n<p>label_mapからテーブルを作成するスクリプト(labelmap2labels.py)をカレントディレクトリに作成する。<br />\nやっつけ仕事なので、かなりテキトー(笑)、、、</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">object_detection.utils</span> <span class=\"kn\">import</span> <span class=\"n\">label_map_util</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"==== USAGE ====\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"    python </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> label_map_file\"</span><span class=\"p\">)</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># パラメータが1個でない\n</span>    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_map_file = \"object_detection/data/mscoco_complete_label_map.pbtxt\"\n</span><span class=\"n\">label_map_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># 第一パラメータのファイルが存在しない\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"error: '</span><span class=\"si\">{</span><span class=\"n\">label_map_file</span><span class=\"si\">}</span><span class=\"s\">' not exist</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_mapからカテゴリインデックスを作成\n</span><span class=\"n\">category_index</span> <span class=\"o\">=</span> <span class=\"n\">label_map_util</span><span class=\"p\">.</span><span class=\"n\">create_category_index_from_labelmap</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span>\n\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># print(i)\n</span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">category_index</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">\"name\"</span><span class=\"p\">]</span>\n    <span class=\"k\">except</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'{name}\\t# {i}')\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n    \n<span class=\"c1\"># 個数確認のためにダミーを出力\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スクリプトの実行\">スクリプトの実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.py label_map_file\n</code></pre></div></div>\n\n<p>結果は標準出力へ出力されるので、ファイルにcastして使用する</p>\n\n<p>例:</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.pyobject_detection/data/mscoco_complete_label_map.pbtxt <span class=\"o\">></span> mscoco_complete.labels\n</code></pre></div></div>\n\n<p>出来上がったlabelsファイルを必要なところへコピーして使ってちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>UbuntuをNative環境にインストールする(18.04)</title>\n  </head>\n  <body>\n    <header>\n      <h1>UbuntuをNative環境にインストールする(18.04)</h1>\n      <p>Ubunt(18.04)をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntu-をnative環境virtualboxではなくにインストールする\">Ubuntu をNative環境(Virtualboxではなく)にインストールする</h1>\n\n<p><a href=\"/memoBlog/2019/06/26/install1804.html\">Ubuntu 18.04のインストール</a>ではVirtualbox環境にUbuntuをインストールする手順を書いたが、ここではNative環境にインストールする手順を説明する。</p>\n\n<p>ハードウェア構成としては、Ubuntuを外付けHDDにインストールし、内蔵ディスクのWindowsは消さずにデュアルブート環境にする。<br />\n手順はPCはNECのLavie all-in-oneタイプ(ちょっと古い奴)で確認している。<br />\nBIOS関連など、PC固有の機能に左右される部分は機種によって異なるので注意。</p>\n\n<h2 id=\"前準備\">前準備</h2>\n\n<h3 id=\"hddをgpt化\">HDDをGPT化</h3>\n<p>インストールするHDDのパーティションがMBRだとEFIブートができないので、<br />\n対象ハードディスクのパーテイションテーブルをGPTに変更<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://pc-karuma.net/windows-10-convert-mbr-gpt-disk/\">Windows10 - MBRディスク ⇔ GPTディスクに変換(変更)</a></li>\n</ul>\n\n<h3 id=\"インストールメディアでインストーラ起動\">インストールメディアでインストーラ起動</h3>\n<p>インストールメディアはブータブルUSBメモリを作成すると便利<br />\nブータブルUSBメモリの作成は以下を参照</p>\n<ul>\n  <li><a href=\"https://forest.watch.impress.co.jp/library/software/rufus/?fbclid=IwAR0Ry5oRt3jOegmkkswUQmudtvuleLCkH44-Tx8brnS0VYQJLQLBmGtT5Lw\">窓の杜 Rufus</a></li>\n  <li><a href=\"https://pc-freedom.net/software/how-to-use-rufus/?fbclid=IwAR1bXsLVQviiwpcQSZapci1vgJKF4rFv1nmIh7knZkrdQDJkGh7BLTrcXi4\">RufusでLinuxのインストールメディアを作る</a></li>\n  <li><a href=\"https://rufus.ie/\">本家</a></li>\n</ul>\n\n<p>ダウンロードしたファイルはインストーラではなく、ポータブル版の実行ファイル。<br />\n大体直感的に使えるけど、<strong><em>UEFI モードで起動できるようにするにはパーティション構成でGPTを選択しないといけない</em></strong>らしい。<br />\nGPT にしておけば、UEFI モードでブートするPCのbootデバイスの優先順位をUSBをHDDより高くしておけば対象のHDDからブートできる。</p>\n\n<p>これで逐一CD-Rを焼かなくて済む。<br />\nまた、起動もCD-Rより高速。</p>\n\n<h2 id=\"対象ハードディスクにインストール\">対象ハードディスクにインストール</h2>\n<p>以下を参照。</p>\n<ul>\n  <li><a href=\"https://linuxfan.info/ubuntu-18-04-install-guide\">Ubuntu 18.04 LTSインストールガイド【スクリーンショットつき解説】</a></li>\n</ul>\n\n<h2 id=\"再起動してbiosセットアップメニューを起動\">再起動してBIOSセットアップメニューを起動</h2>\n<p>NEC LAVIEの場合、電源ON時にF2キーを連打し、BIOSセットアップメニューを表示<br />\n「Boot」の「Boot Priority Order」の起動順序で「Ubuntu」を「Windows」の上に持ってくる。<br />\nその後、 saveしてreset。</p>\n\n<h2 id=\"基本的な初期設定\">基本的な初期設定</h2>\n<p>Virtualbox版の手順の<a href=\"/memoBlog/2019/06/26/install1804.html\">Ubuntu 18.04のインストール</a>を参照。<br />\n基本的にこれと同じで大丈夫(GuestAdditionのインストール、grub-pcのインストール先情報の変更を除く)</p>\n\n<h3 id=\"もっと簡単に設定する方法があった\">もっと簡単に設定する方法があった</h3>\n<p>以下の項目はもっと簡単に設定する方法があったのでメモ。</p>\n\n<ul>\n  <li>「ウィンドウが勝手に最大化するのをやめる」</li>\n  <li>「ウィンドウにマウスを乗せるとフォーカスされるようにする」</li>\n  <li>「デスクトップからゴミ箱とホームを消す」</li>\n</ul>\n\n<p>これらの設定はdconf-editorでなく、gnome-tweaksを使うと簡単(dconf-editorでもOK)</p>\n\n<p>gnome-tweaksのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\ngnome-tweaks\n</code></pre></div></div>\n<ul>\n  <li>「ウィンドウにマウスを乗せるとフォーカスされるようにする」\n    <ul>\n      <li>「ウィンドウ」で「ウィンドウフォーカス」を「Sloppy」にする</li>\n    </ul>\n  </li>\n  <li>「デスクトップからゴミ箱とホームを消す」\n    <ul>\n      <li>「デスクトップ」で選択</li>\n    </ul>\n  </li>\n  <li>「CTRLとCapsLockの入れ替えを行う」(Virtualboxではホスト側で入れ替えてたので不要だった)\n    <ul>\n      <li>「キーボードとマウス」で「追加のレイアウトオプション」をクリック\n        <ul>\n          <li>Ctrl position」の「CapsLockをCtrlとして扱う」を選択する。\n            <ul>\n              <li>「CtrlとCapsLockを入れ替える」だとうまく動かないので注意。</li>\n              <li>UnityとGNOME Flashbackでは設定は別らしい。</li>\n              <li>GNOME Flashbackでは「CtrlとCapsLockを入れ替える」でもOK。</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>「ウィンドウが勝手に最大化するのをやめる」\n    <ul>\n      <li>設定項目が見当たらないので、dconf editorで設定する。\n        <ul>\n          <li>dconf editor起動して以下を変更\n            <ul>\n              <li>/org/gnome/metacity/edge-tiling false</li>\n              <li>/org/gnome/mutter/edge-tiling false</li>\n              <li>/org/gnome/shell/overrides/edge-tiling false</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"sshのインストール\">sshのインストール</h1>\n<p>WindowsPCにあるデータをubuntuPCにキーボードで打ち込むのは効率が悪いので、最も簡単なsshでリモートログインできるようにしてみる。</p>\n\n<p>以下のコマンドでsshサーバをインストールし、サーバを開始する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n<p>クライアントからTeraTermなどでsshで対象マシンのポート22に接続する</p>\n\n<h1 id=\"vncで画面共有する\">vncで画面共有する</h1>\n\n<p>sshリモートログインよりもうちょっと使いやすくしたいので、vncで画面共有するようにしてみる。</p>\n\n<p>chrome リモートデスクトップ等とは異なり、コンソールに表示している画面を共有して操作するもの。<br />\n使用したクライアント(VNC-Viewer)がヘボいからなのか、ちょっと反応鈍いけど、<br />\nコンソールで作業していた実行状況を確認したり<br />\n会社でトラブった人のリモートサポートなんかに使えるかも。</p>\n\n<p>やり方自体はとてもシンプル。<br />\n特にインストールとかも必要ない。<br />\n(クライアント側はVNC viewerなどを実行する必要があるけど、こっちもインストールは不要(単体実行))</p>\n\n<p>例によって手順の説明は他力本願(^^ゞ<br />\n参照:</p>\n<ul>\n  <li><a href=\"https://www.yokoweb.net/2019/12/09/ubuntu-18_04-desktop-vnc-remote/\">【Ubuntu 18.04 Desktop】WinやMacパソコンからVNCでリモート接続し画面共有する </a></li>\n</ul>\n\n<p>そのままトレースすればできるけど、ちょっと「ん?」と思ってしまうエラーが。<br />\n同じページの<a href=\"https://www.yokoweb.net/2019/12/09/ubuntu-18_04-desktop-vnc-remote/#toc5\">ココ</a>に解決策がかかれているけど、ちゃんと前もって書いておいてほしいもんだ(笑)。<br />\n解決策の要約は以下の通り。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false</span>\n<span class=\"c\"># 実行後再起動必要</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ndconf editor でも設定可能。<br />\nなので、dconf editorとの設定操作とバッティングしないように注意<br />\ndconf editorで設定する場合は以下<br />\n   /org/gnome/desktop/remote-access/require-encryption</p>\n</blockquote>\n\n<p>あくまで共有なのでコンソール側でGUIログインしてないとつながらない。<br />\n反応鈍いので、普段使いにはちょっとストレスかも。<br />\nchrome リモートデスクトップ使えるならそっち使ったほうがいいかな。</p>\n\n<h1 id=\"chromeリモートデスクトップのインストール\">chromeリモートデスクトップのインストール</h1>\n\n<p>chromeリモートデスクトップ による接続は画面の共有ではなく、新しいセッションによる接続となる(Xclientみたいなもん?)。<br />\nwindowsマシンに接続した場合は表示画面のミラーリングだったが。</p>\n\n<p>chromeのインストール&リモートデスクトップのインストールはWindowsとほぼ同じ。<br />\n以下参考ページ</p>\n<ul>\n  <li><a href=\"https://www.google.com/chrome/\">Google Chrome フェブブラウザ</a></li>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>パソコンでリモート アクセスを設定する</li>\n      <li>パソコンにリモート アクセスする</li>\n    </ul>\n  </li>\n</ul>\n\n<p>接続すると、開始するセッションの選択画面になるので、「Ubuntu」を選択。GNOME Flashbackだとつながらない…なんで??</p>\n\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。このダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></li>\n</ul>\n\n<p>要約すると\n<code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下を入力</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n<h2 id=\"コンソール画面を共有したい場合\">コンソール画面を共有したい場合</h2>\n\n<p>chromeリモートデスクトップでvnc同様のコンソール画面の共有をすることも可能。<br />\n設定方法は以下を参照。</p>\n<ul>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>他のユーザとパソコンを共有する</li>\n    </ul>\n  </li>\n</ul>\n\n<p>この方法だと、アクセスコードの生成(コンソール側)/アクセスコードの入力(リモート側)/アクセス許可(コンソール側)と手続きが少々煩雑(毎回必要)。<br />\n画面共有で操作するにはvncのほうが簡単かな?</p>\n\n<h1 id=\"biosセットアップメニューでのブートマネージャの表示名を変更する\">BIOSセットアップメニューでのブートマネージャの表示名を変更する</h1>\n\n<p>ubuntu をインストールした後、BIOSセットアップメニューでブート優先順位を指定しようとすると<br />\nubuntuのブートマネージャが2つ表示されて、どちらを選べばよいのか見分けがつかない。<br />\n(機種によってはpathが表示されて見分けられるものもあるらしいが、私のPCはそうなってない)</p>\n\n<p>そこで、表示名を変更して見分けがつくようにしてみる。</p>\n\n<p>以下、参考ページ</p>\n<ul>\n  <li><a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1383uefinvnm/uefinvnm.html\">bcdeditでUEFIのブート・エントリの名前を変更する</a></li>\n</ul>\n\n<p>まず、Windowsを起動し、管理者権限でコマンドプロンプト(cmd.exe)を実行する。\nPowerShellではちょっとテクニックが要る(というほど大げさではないが)みたいなので、\nコマンドプロンプトで実行するのが無難。</p>\n\n<p>現在の状態の確認</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /enum firmware\n</code></pre></div></div>\n\n<p>実行結果</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ファームウェアのブート マネージャー\n--------------------------------\nidentifier              {fwbootmgr}\ndisplayorder            {bootmgr}\n                        {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\n                        {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ntimeout                 1\n\nWindows ブート マネージャー\n--------------------------------\n《省略》\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\ubuntu\\shimx64.efi\ndescription             ubuntu\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\Ubuntu\\grubx64.efi\ndescription             ubuntu\n</code></pre></div></div>\n\n<p>表示名を変更する<br />\n指定するuuidは現状の確認で確認したuuidに置き換えること。<br />\ndescriptionが表示名なので、これを好みの名前に変更する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /set {9b7f627e-7edc-11ea-84b2-806e6f6e6963} description  \"ubuntu shimx64\"\nbcdedit /set {9b7f627f-7edc-11ea-84b2-806e6f6e6963} description  \"ubuntu grubx64\"\n</code></pre></div></div>\n\n<p>結果を確認する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /enum firmware\n</code></pre></div></div>\n\n<p>実行結果</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ファームウェアのブート マネージャー\n--------------------------------\nidentifier              {fwbootmgr}\ndisplayorder            {bootmgr}\n                        {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\n                        {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ntimeout                 1\n\nWindows ブート マネージャー\n--------------------------------\n《省略》\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\ubuntu\\shimx64.efi\ndescription             ubuntu shimx64\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\Ubuntu\\grubx64.efi\ndescription             ubuntu grubx64\n</code></pre></div></div>\n\n<p>ちなみに、shimx64.efi と grubx64.efi の違いは、セキュアブートの対応/非対応の違いである。<br />\n通常(セキュアブート有効のハズ)はshimx64.efiで良いと思われる。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://netlog.jpn.org/r271-635/2019/08/uefi_windows10_ubuntu_install.html\">UEFIのWindows 10マシンにUbuntu 18.04を追加インストールしデュアルブート化する</a>\n    <ul>\n      <li>「UbuntuがUEFIのブートメニューに登録されていることを確認」のあたり</li>\n    </ul>\n  </li>\n</ul>\n\n<p>この設定はbuntuを再インストールすると上書きされてしまうので、再度変更する必要がある。</p>\n\n<h1 id=\"grubのboot-menuの表示などの変更方法\">GRUBのboot menuの表示などの変更方法</h1>\n\n<p>デフォルトのubuntuインストール状態では、GRUBのブートメニューが表示されない。<br />\nそこで、ブートメニューを表示するように変更してみる。<br />\nついでに、設定する箇所が同じなので、</p>\n\n<ul>\n  <li>タイムアウトまでの時間の変更(あっ?と思った瞬間にブートされちゃうと悲しいので)</li>\n  <li>スプラッシュスクリーンを表示しなくする(ちゃんとブートしてるか心配なので(笑))</li>\n</ul>\n\n<p>も設定しておく。</p>\n\n<p>まず、ubuntuを起動してターミナル起動</p>\n\n<p>rootでないとできないことなので、rootでbashを実行しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>bash                                     \n</code></pre></div></div>\n\n<p>設定ファイル <code class=\"language-plaintext highlighter-rouge\">/etc/default/grub</code> を以下の内容で変更する</p>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- grub.org\t2020-05-08 06:16:59.908079737 +0900\n</span><span class=\"gi\">+++ grub\t2020-05-08 06:17:13.540255464 +0900\n</span><span class=\"p\">@@ -3,11 +3,11 @@</span>\n # For full documentation of the options in this file, see:\n #   info -f grub -n 'Simple configuration'\n \n<span class=\"gd\">-GRUB_DEFAULT=0\n-GRUB_TIMEOUT_STYLE=hidden\n-GRUB_TIMEOUT=10\n</span><span class=\"gi\">+GRUB_DEFAULT=saved\n+GRUB_TIMEOUT_STYLE=menu\n+GRUB_TIMEOUT=30\n</span> GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`\n<span class=\"gd\">-GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash\"\n</span><span class=\"gi\">+GRUB_CMDLINE_LINUX_DEFAULT=\n</span> GRUB_CMDLINE_LINUX=\"\"\n \n # Uncomment to enable BadRAM filtering, modify to suit your needs\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">GRUB_DEFAULT</code> がデフォルトの選択項目。 <code class=\"language-plaintext highlighter-rouge\">saved</code> は前回選択項目。rebootのときだけ??動きがイマイチわからんかった。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_TIMEOUT_STYLE</code> がメニュー表示形式。<code class=\"language-plaintext highlighter-rouge\">hidden</code> は表示しない、<code class=\"language-plaintext highlighter-rouge\">menu</code> はメニューを表示する。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_TIMEOUT</code> がタイムアウトまでの時間。単位は秒。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_CMDLINE_LINUX_DEFAULT</code> がLinux起動時のコマンドラインオプション。<code class=\"language-plaintext highlighter-rouge\">quiet splash</code> を指定すると起動メッセージを表示せず、スプラッシュスクリーンを表示する。これを削除することで起動メッセージが表示される</p>\n\n<p>変更した設定をcfgファイルに反映する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>grub-mkconfig <span class=\"nt\">-o</span> /boot/grub/grub.cfg            \n</code></pre></div></div>\n\n<p>これで、次回起動時からGRUBのブートメニューが変更される</p>\n\n<p>以下、参考ページ:</p>\n<ul>\n  <li><a href=\"http://www.usupi.org/sysad/202.html\">いますぐ実践! Linux システム管理</a></li>\n</ul>\n\n<p>この項目と直接関係ないけど、起動時にのfsckを実行する方法の参考ページ。</p>\n<ul>\n  <li><a href=\"https://linux.just4fun.biz/?Linux%E7%92%B0%E5%A2%83%E8%A8%AD%E5%AE%9A/%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E9%96%93%E9%9A%94%E3%81%AE%E7%A2%BA%E8%AA%8D\">Linux環境設定/起動時のファイルシステムチェック間隔の確認 </a></li>\n</ul>\n\n<h1 id=\"usb-hdd接続-ubuntuのboot未接続windowsのbootにする方法\">USB-HDD接続→ Ubuntuのboot、未接続→Windowsのbootにする方法</h1>\n\n<p>ubuntuがインストールされたUSB-UDDが接続されていたらubuntuが、接続されていなければ内蔵HDDのWindowsが自動的に起動するようにしてみる。<br />\n(デフォルトのインストール状態だとブート優先順位を変更しないと切り替えられない)<br />\nちょうどFDDブートのような感じ。</p>\n\n<p>BIOSセットアップにより、ブートモードはUEFIブートで、ブート優先順位はubuntuの方を高く設定しておく。</p>\n\n<p>まず、ubuntuを起動する</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/boot/efi/EFI/ubuntu/grub.cfg</code> を以下のように変更する。<br />\nrootでないとアクセスできないので、<code class=\"language-plaintext highlighter-rouge\">sudo bash</code>  して rootでshellを動かして作業するのが良い。</p>\n\n<ul>\n  <li>元のファイル\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>search.fs_uuid 60c491cd-126d-4f4a-a321-84bb2e0d9068 root hd1,gpt1 \nset prefix=($root)'/boot/grub'\nconfigfile $prefix/grub.cfg\n</code></pre></div>    </div>\n  </li>\n  <li>変更後のファイル\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>if search.fs_uuid 60c491cd-126d-4f4a-a321-84bb2e0d9068 root hd1,gpt1 ;then\n set prefix=($root)'/boot/grub'\n configfile $prefix/grub.cfg\nelse\n set timeout_style=menu\n set timeout=0\n menuentry 'Windows Boot Manager (on /dev/sda2)' --class windows --class os $menuentry_id_option 'osprober-efi-2A43-3D28' {\n    insmod part_gpt\n    insmod fat\n    set root='hd0,gpt2'\n    if [ x$feature_platform_search_hint = xy ]; then\n       search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  2A43-3D28\n    else\n       search --no-floppy --fs-uuid --set=root 2A43-3D28\n    fi\n    chainloader /EFI/Microsoft/Boot/bootmgfw.efi\n}\nfi\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>メモ:</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">60c491cd-126d-4f4a-a321-84bb2e0d9068</code>  は ubuntuのインストールされたパーティションのuuidなので、接続したUSB-HDDDのuuidに合わせて変更する。\n    <ul>\n      <li>パーティションのuuidは以下で確認可能。\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"s1\">' \\/boot\\/efi '</span> /etc/mtab         <span class=\"c\"># デバイスファイルを確認する</span>\n<span class=\"nb\">sudo </span>blkid /dev/sda2                   <span class=\"c\"># 確認したデバイスファイルを指定する</span>\n</code></pre></div>        </div>\n      </li>\n      <li>あるいは、元のファイルのuuidをコピるのでもOK。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">2A43-3D28</code>はEFIシステムパーティションのuuidなので、環境に合わせて変更する。\n    <ul>\n      <li>パーティションのuuidは以下で確認可能。\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"s1\">' \\/ '</span> /etc/mtab                  <span class=\"c\"># デバイスファイルを確認する</span>\n<span class=\"nb\">sudo </span>blkid /dev/sdb1                   <span class=\"c\"># 確認したデバイスファイルをしてする</span>\n</code></pre></div>        </div>\n      </li>\n      <li>あるいは、<code class=\"language-plaintext highlighter-rouge\">/boot/grub/grub.cfg</code> の <code class=\"language-plaintext highlighter-rouge\">menuentry 'Windows Boot Manager ~</code>  の部分をパクってきても可。</li>\n    </ul>\n  </li>\n  <li>このファイルはbuntuを再インストールすると上書きされてしまうので、再度編集する必要がある。</li>\n</ul>\n\n<p>処理の解説:<br />\n元のgrub.cfgではUSB-HDDが接続されていなければ <code class=\"language-plaintext highlighter-rouge\">$prefix/grub.cfg</code>  が見つからないので、GRUBメニューが表示されない。<br />\nそこで、<code class=\"language-plaintext highlighter-rouge\">search.fs_uuid</code> の実行結果により、ディスクが見つかったら従来通りの処理、<br />\n見つからなかったらWindows Boot Managerを起動するようにしている。</p>\n\n<h3 id=\"参考情報\">参考情報</h3>\n<p>WindowsからEFIシステムパーティションのファイルを編集するには、このあたりを参考に。</p>\n<ul>\n  <li><a href=\"https://bi.biopapyrus.jp/os/win/dualboot-fix-bootmenu.html\">デュアルブートから Ubuntu を削除する方法</a><br />\nマウントする部分だけね。</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その1</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その1</h1>\n      <p>Google Coral USB Acceleratorのインストールメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<p>参考サイト:\n<a href=\"https://qiita.com/rhene/items/7b34f60b73645d430789\">RaspberryPi 4でCoral USB TPU Accelerator(EdgeTPU)をとりあえず使う</a></p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<h2 id=\"edgetpu用ライブラリのインストール\">EdgeTPU用ライブラリのインストール</h2>\n\n<p>下記コマンドを実行して、EdgeTPU用ライブラリ(ドライバ類)をインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/coral-edgetpu.list\ncurl https://packages.cloud.google.com/apt/doc/apt-key.gpg | <span class=\"nb\">sudo </span>apt-key add -\n\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># 通常版をインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libedgetpu1-std\n<span class=\"c\"># または、最大クロック版</span>\n<span class=\"c\"># sudo apt install libedgetpu1-max</span>\n</code></pre></div></div>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 coral\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral\n<span class=\"nb\">cd</span> /work/coral\npyenv <span class=\"nb\">local </span>coral \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<p>numpyのinstallで失敗するので、以下を実行しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n</code></pre></div></div>\n\n<h2 id=\"tfliteモジュールのインストール\">TFLiteモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install  </span>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nどれをインストールするかは<a href=\"https://www.tensorflow.org/lite/guide/python\">Python quickstart</a>で確認<br />\n========= 例えば、ubuntu/raspbianのときはpythonのバージョンに応じて以下のどれかを指定 ==============</p>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (x86-64)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl</td>\n      </tr>\n    </tbody>\n  </table>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (ARM 32)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl</td>\n      </tr>\n    </tbody>\n  </table>\n</blockquote>\n\n<h2 id=\"coral-usb-acceleratorの接続と確認\">Coral USB Acceleratorの接続と確認</h2>\n\n<p>USBポートに Coral USB Accelerator を接続する</p>\n\n<p>認識されたことを確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下の表示があったら正常に認識されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>«省略»\nBus XXX Device YYY: ID 1a6e:089a Global Unichip Corp. \n«省略»\n</code></pre></div></div>\n\n<h1 id=\"動作確認サンプルプログラム\">動作確認(サンプルプログラム)</h1>\n\n<h2 id=\"サンプルソースのインストール\">サンプルソースのインストール</h2>\n\n<p>Githubからソースをダウンロードする</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/\ngit<span class=\"k\">**</span> clone https://github.com/google-coral/tflite.git\n</code></pre></div></div>\n\n<h2 id=\"サンプルプログラムの実行その1-classification\">サンプルプログラムの実行(その1) classification</h2>\n\n<h3 id=\"プログラムディレクトリへの移動\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/classification/\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh \n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py \n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n<p>結果の例は以下。<br />\n結果は「Ara macao(コンゴウインコ)」と表示されている。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference on Edge TPU is slow because it includes loading the model into Edge TPU memory.\n12.4ms\n4.2ms\n4.1ms\n4.2ms\n4.2ms\n-------RESULTS--------\nAra macao (Scarlet Macaw): 0.77734\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n\n<p><a id=\"CPUonlydiff\"> </a></p>\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合もCoral USB Acceleratorを接続しておかないとエラーになる。<br />\n接続しなくても実行できるようにするには以下のパッチを適用し、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">-cpu</code>オプションを指定する。</p>\n\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/python/examples/classification/classify_image.py b/python/examples/classification/\n</span><span class=\"gi\">> classify_image.py\n</span><span class=\"gh\">index 75f1d76..44fb798 100644\n</span><span class=\"gd\">--- a/python/examples/classification/classify_image.py\n</span><span class=\"gi\">+++ b/python/examples/classification/classify_image.py\n</span><span class=\"p\">@@ -12,7 +12,7 @@</span>\n<span class=\"err\">#</span> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n # See the License for the specific language governing permissions and\n # limitations under the License.\n<span class=\"gd\">-r\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span><span class=\"gi\">+\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span>\n    To run this code, you must attach an Edge TPU attached to the host and\n    install the Edge TPU runtime (`libedgetpu.so`) and `tflite_runtime`. For\n<span class=\"p\">@@ -64,9 +64,12 @@</span> def load_labels(path, encoding='utf-8'):\n       return {index: line.strip() for index, line in enumerate(lines)}\n\n\n<span class=\"gd\">-def make_interpreter(model_file):\n</span><span class=\"gi\">+def make_interpreter(model_file, cpu=False):\n</span>   model_file, *device = model_file.split('@')\n<span class=\"gd\">-  return tflite.Interpreter(\n</span><span class=\"gi\">+  if cpu :\n+    return tflite.Interpreter(model_path=model_file)\n+  else :\n+    return tflite.Interpreter(\n</span>       model_path=model_file,\n       experimental_delegates=[\n           tflite.load_delegate(EDGETPU_SHARED_LIB,\n<span class=\"p\">@@ -92,11 +95,19 @@</span> def main():\n   parser.add_argument(\n       '-c', '--count', type=int, default=5,\n       help='Number of times to run inference')\n<span class=\"gi\">+  parser.add_argument(\n+      '--cpu', action='store_true',\n+      help='use cpu only(default:use with TPU)')\n</span>   args = parser.parse_args()\n\n+  if args.cpu :\n<span class=\"gi\">+    print('**** USE CPU ONLY!! ****')\n+  else :\n+    print('**** USE WITH TPU ****')\n+\n</span>   labels = load_labels(args.labels) if args.labels else {}\n\n-  interpreter = make_interpreter(args.model)\n<span class=\"gi\">+  interpreter = make_interpreter(args.model, args.cpu)\n</span>   interpreter.allocate_tensors()\n\n   size = classify.input_size(interpreter)\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"サンプルプログラムの実行その2-detection\">サンプルプログラムの実行(その2) detection</h2>\n\n<h3 id=\"プログラムディレクトリへの移動-1\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/detection\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール-1\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh\n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行-1\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<p>結果の例は以下。<br />\n以下の表示と同時に認識結果の画像が別ウィンドウで表示される。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference is slow because it includes loading the model into Edge TPU memory.\n27.90 ms\n11.59 ms\n11.36 ms\n11.89 ms\n11.10 ms\n-------RESULTS--------\ntie\n  id:     31\n  score:  0.83984375\n  bbox:   BBox(xmin=226, ymin=417, xmax=290, ymax=539)\nperson\n  id:     0\n  score:  0.83984375\n  bbox:   BBox(xmin=2, ymin=5, xmax=507, ymax=590)\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行-1\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションを指定すると、結果画像を保存するとともに、表示を行う。<br />\n指定しなければ認識だけ行う(結果の画像表示もしない)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションによる出力ファイルの形式は指定した拡張子で決定される。jpgやbmpなど。<br />\nrawデータで出力した場合(拡張子rgb)は、以下のコマンドでjpgやbmpに変換できる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.jpg\n</code></pre></div>  </div>\n\n  <p>または</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.bmp\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合でCoral USB Acceleratorを接続していなくてエラーになる場合は<br />\n<a href=\"#CPUonlydiff\">こちら</a>を参照</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その2</h1>\n      <p>Google Coral USB Accelerator で SSD(Single Shot MultiBox Detector)を実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n一部を除き、基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<h1 id=\"tflite-の-モデルファイルをedgetpu使用モデルに変換する方法\">tflite の モデルファイルをEdgeTPU使用モデルに変換する方法</h1>\n<p>通常のtfliteのモデルファイルはCPUのみ(またはCPU+GPU)を使用するように構成されていて、\nそのまま実行してもEdge-TPUは使用されない。<br />\nそこで、Edge-TPU使用モデルに変換するため、edgetpu_compilerを使用する必要がある。<br />\n(ただし、Ubuntuのみ。RasPi不可。)</p>\n\n<h2 id=\"edgetpu_compiler-のインストール\">edgetpu_compiler のインストール</h2>\n\n<p>CPU使用モデルからEdge-TPU使用モデルに変換するツール<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code>をインストールする。<br />\naptリポジトリの登録はTPUライブラリインストール時に行っているので不要(以下ではコメントアウトしてある)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -</span>\n<span class=\"c\"># echo \"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list</span>\n<span class=\"c\"># sudo apt update</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>edgetpu-compiler\n</code></pre></div></div>\n\n<h2 id=\"使用方法\">使用方法</h2>\n<p>基本的に以下。<br />\ntfliteファイルを喰わせるとファイル名に<code class=\"language-plaintext highlighter-rouge\">_edgetpu</code>を付加したファイルが作成される。<br />\nこれがEdge-TPU使用するモデルファイル。<br />\n詳細は<a href=\"https://coral.ai/docs/edgetpu/compiler/\">Edge TPU Compiler</a> を参照。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>edgetpu_compiler [options] model...\n</code></pre></div></div>\n\n<h1 id=\"事前準備\">事前準備</h1>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n\n<p>openCVをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"ssdを実行してみる\">SSDを実行してみる</h1>\n\n<h2 id=\"作業用ディレクトリの作成移動\">作業用ディレクトリの作成&移動</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral/ssd/\n<span class=\"nb\">cd</span> /work/coral/ssd/\n</code></pre></div></div>\n\n<h2 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h2>\n\n<p>用意されているSSDのモデルをダウンロードし、Edge-TPU使用モデルを作成する。<br />\n実行が終了すると、<code class=\"language-plaintext highlighter-rouge\">models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite</code> ができる。</p>\n\n<ul>\n  <li>ダウンロード元: <a href=\"https://www.tensorflow.org/lite/models/object_detection/overview\">Object detection</a>\nの 「Get Started」の「Download starter model and labels」</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl <span class=\"nt\">-O</span> https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip\nunzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip \n<span class=\"nb\">mv </span>detect.tflite coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># リネームしなくてもいいけど、後でわからなくならないようにリネームしておく</span>\n<span class=\"nb\">mv </span>labelmap.txt coco_ssd_mobilenet_v1_1.0_quant.labels   <span class=\"c\"># 同上</span>\nedgetpu_compiler coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># EdgeTPU使用モデルに変換</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"テスト用画像の準備\">テスト用画像の準備</h2>\n\n<p>適当な画像を<code class=\"language-plaintext highlighter-rouge\">image</code>ディレクトリに用意しておく。<br />\n使用できるファイル形式は<code class=\"language-plaintext highlighter-rouge\">jpg</code>と<code class=\"language-plaintext highlighter-rouge\">mp4</code></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>images\n<span class=\"nb\">cd </span>images/\n<span class=\"c\"># 適当な画像ファイルをダウンロードする</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"ssdのプログラムソース\">SSDのプログラムソース</h2>\n\n<p>以下の内容を<code class=\"language-plaintext highlighter-rouge\">object_detection_demo_ssd.py</code>として保存しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">tflite_runtime.interpreter</span> <span class=\"k\">as</span> <span class=\"n\">tflite</span>\n\n<span class=\"c1\"># shared library\n</span><span class=\"n\">EDGETPU_SHARED_LIB</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n  <span class=\"s\">'Linux'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.so.1'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Darwin'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.1.dylib'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Windows'</span><span class=\"p\">:</span> <span class=\"s\">'edgetpu.dll'</span>\n<span class=\"p\">}[</span><span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">system</span><span class=\"p\">()]</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># interpreter の生成\n</span><span class=\"k\">def</span> <span class=\"nf\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">):</span>\n    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"o\">=</span><span class=\"n\">model_file</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span>\n                <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">model_file</span><span class=\"p\">,</span>\n                <span class=\"n\">experimental_delegates</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n                    <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">load_delegate</span><span class=\"p\">(</span><span class=\"n\">EDGETPU_SHARED_LIB</span><span class=\"p\">)</span>\n                <span class=\"p\">])</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    \n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">output_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_output_details</span><span class=\"p\">()</span>\n    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n\n    <span class=\"n\">tflite_results1</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Locations (Top, Left, Bottom, Right)\n</span>    <span class=\"n\">tflite_results2</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Classes (0=Person)\n</span>    <span class=\"n\">tflite_results3</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Scores\n</span>    <span class=\"n\">tflite_results4</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Number of detections\n</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">tflite_results4</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])):</span>\n        <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        \n        <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>        <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n\n        <span class=\"n\">prob</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results3</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">prob</span> <span class=\"o\">>=</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'Class=</span><span class=\"si\">{</span><span class=\"n\">class_name</span><span class=\"si\">:</span><span class=\"mi\">15</span><span class=\"si\">}</span><span class=\"s\">    Probability=</span><span class=\"si\">{</span><span class=\"n\">prob</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    Location=(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)-(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n            <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span>    <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span>   <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span>  <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 表示色\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 対象物の枠とラベルの描画\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"n\">bottom</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">20</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"o\">+</span><span class=\"mi\">160</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"s\">\"{} ({:.3f})\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">class_name</span><span class=\"p\">,</span> <span class=\"n\">prob</span><span class=\"p\">),</span>\n                        <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># interpreterの構築\n</span>    <span class=\"n\">interpreter</span> <span class=\"o\">=</span> <span class=\"n\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">allocate_tensors</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">input_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()</span>\n    \n    <span class=\"c1\"># 入力データ\n</span>    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">org_frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>                 <span class=\"c1\"># オリジナルのフレームレート\n</span>    <span class=\"n\">org_frame_time</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span> <span class=\"o\">/</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>                <span class=\"c1\"># オリジナルのフレーム時間\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">org_frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルの読み込み\n</span>        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルがない場合\n</span>        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># フレーム数\n</span>    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 実行時間測定用変数の初期化\n</span>    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n    <span class=\"c1\"># フレーム測定用タイマ\n</span>    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># モデルの入力サイズ\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># 画像の前処理 =============================================================================\n</span>        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                          <span class=\"c1\"># 前処理開始時刻\n</span>        \n        <span class=\"c1\"># 画像の読み込み\n</span>        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレームを作成\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># モデル入力用にリサイズ\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>   <span class=\"c1\"># input size of coco ssd mobilenet?\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">]]</span>                          <span class=\"c1\"># BGR -> RGB\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">in_frame</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>                 <span class=\"c1\"># 3D -> 4D\n</span>        \n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>     <span class=\"c1\"># 前処理にかかった時間\n</span>        \n        <span class=\"c1\"># 推論実行 =============================================================================\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"c1\"># 推論本体\n</span>        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">set_tensor</span><span class=\"p\">(</span><span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">],</span> <span class=\"n\">in_frame</span><span class=\"p\">)</span>\n        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">invoke</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>                          <span class=\"c1\"># 推論処理にかかった時間\n</span>        \n        <span class=\"c1\"># 検出結果の解析 =============================================================================\n</span>        <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                               <span class=\"c1\"># 解析処理開始時刻\n</span>        <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n        <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>                    <span class=\"c1\"># 解析処理にかかった時間\n</span>        \n        <span class=\"c1\"># 結果の表示 =============================================================================\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 表示処理開始時刻\n</span>        \n        <span class=\"c1\"># 測定データの表示\n</span>        <span class=\"n\">frame_number_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'frame_number   : </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span>\n        <span class=\"k\">if</span> <span class=\"n\">frame_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span>  <span class=\"s\">'Frame time     : ---'</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Frame time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms    </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> fps'</span>\n        <span class=\"n\">inf_time_message</span>        <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Inference time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">render_time_message</span>     <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Rendering time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">parsing_time_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'parse time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        \n        <span class=\"c1\"># 結果の書き込み\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_number_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>     <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>   <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像の保存\n</span>        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>                 <span class=\"c1\"># 表示処理にかかった時間\n</span>        \n        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"c1\"># フレーム処理終了 =============================================================================\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_key_code</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"make_interpretermodel_file\">make_interpreter(model_file)</h3>\n\n<p>interpreter(認識エンジン)を構築する処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>モデルファイル内に<code class=\"language-plaintext highlighter-rouge\">\"edgetpu-custom-op\"</code>という文字列が含まれていたらTPU使用モデルと判定してTPU使用のための共有ライブラリをダウンロードして初期化する。<br />\nそうでなければCPUのみ使用モデルなので、 共有ライブラリなしで初期化する。</p>\n\n<p>もっと単純にモデルファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>が含まれていたらTPU使用モデルと判定しても良いかもしれない(<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code> は出力ファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>を付加するので)。</p>\n\n<h3 id=\"parse_resultinterpreter-frame-labels_map-args\">parse_result(interpreter, frame, labels_map, args)</h3>\n\n<p>認識結果の解析と結果の表示(検出枠とラベルの描画)</p>\n\n<p>認識結果から検出した座標、クラスID、スコアを取得し、出力画像に描画している。</p>\n\n<p>出力データの構成は<a href=\"https://www.tensorflow.org/lite/models/object_detection/overview#output\">ここ</a>を参照。</p>\n\n<p>どうやらこのモデルは検出個数が10個に設定されているようだ。</p>\n\n<h3 id=\"main\">main()</h3>\n\n<p>メインルーチン</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>タイミング調整部分は、認識処理が速かった場合に結果表示画像の表示時間を実際の入力画像の表示時間に合わせるため、ちょっと小細工を入れてある。</p>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--help</span>\nusage: object_detection_demo_ssd.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT <span class=\"o\">[</span><span class=\"nt\">-l</span> LABELS]\n                                    <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> LABELS, <span class=\"nt\">--labels</span> LABELS\n                        Optional. Labels mapping file\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合edge-tpu使用\">静止画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合edge-tpu使用\">動画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n再生が終了するか、画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n<h2 id=\"静止画の場合cpuのみ\">静止画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合cpuのみ\">動画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その3</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その3</h1>\n      <p>Tensorflow 2.2.0をインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Edge-TPUを直接操作するわけではないが、Tensorflowで作成されたモデルファイルをtflite用に変換する準備として<br />\ntensorflowをインストールする。<br />\nここではVersion 2.2.0を使用する。</p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<p>coral環境に追加インストールでも良いが、今回は別の環境を用意する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_2.2.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_2.2.0\n<span class=\"nb\">cd</span> /work/tf_2.2.0\npyenv <span class=\"nb\">local </span>tf_2.2.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"tensorflow-220-のインストール\">tensorflow 2.2.0 のインストール</h1>\n\n<p>インストールするパッケージはGPUを使わないので-cpu付きパッケージを選択する。<br />\nTensorflowはバージョンによって機能差が激しいので、インストールするバージョンを指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>2.2.0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その4</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その4</h1>\n      <p>tensorflowのモデルファイル(*.pbや*.tflite)の可視化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>tensorflowのモデルファイル( <code class=\"language-plaintext highlighter-rouge\">*.pb</code> や <code class=\"language-plaintext highlighter-rouge\">*.tflite</code> )を可視化する方法について。<br />\n<code class=\"language-plaintext highlighter-rouge\">tensorboard</code> を使う方法などもあるが、最もお手軽と思われる <code class=\"language-plaintext highlighter-rouge\">netron</code> を使用する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれやらなくても、<a href=\"https://lutzroeder.github.io/netron/\">https://lutzroeder.github.io/netron/</a> にアクセスすれば使える。</p>\n</blockquote>\n\n<h1 id=\"netron-の-インストール\">netron の インストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code>をインストールする。<br />\n<code class=\"language-plaintext highlighter-rouge\">netron</code> はtensorflowのバージョンに依存しない(そもそもtensorflow自体に依存してない)のでTensorflow1系、Tenorflow2系 どちらの環境にインストールしてもよい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>netron\n</code></pre></div></div>\n\n<h1 id=\"netron-の-実行\">netron の 実行</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code> を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>netron <span class=\"nt\">--host</span> 0.0.0.0 <span class=\"o\">[</span><span class=\"nt\">--port</span> xxxx]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--host</code> オプションを指定しないとlocalhostからしか接続できないので、他のマシンから接続するときは指定する。<br />\n<code class=\"language-plaintext highlighter-rouge\">--port</code> オプションのデフォルトは8080なので、変更したいときは指定する。</p>\n\n<h1 id=\"モデルファイルの表示\">モデルファイルの表示</h1>\n\n<p>ブラウザ(Winマシンからで可)で実行したマシンのポート8008(またはオプションで指定したxxxx)に接続。<br />\n例:<code class=\"language-plaintext highlighter-rouge\">http://ncc-1701u.local:8080/</code></p>\n\n<p>表示された画面でOpen Model…をクリックして表示するモデルファイルを選ぶ。<br />\nしばらく待つと表示される。<br />\nモデルファイルはブラウザからアップロードするので、ブラウザから参照できる場所になければならない(サーバ側にあってもダメ)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">*.pb</code> ファイルが大きいとうまく表示できないみたい。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その5</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その5</h1>\n      <p>Tensorflow v1.15のインストールとソースからのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はUbuntuだけ。</p>\n\n<h1 id=\"tensorflow-115-のインストール\">Tensorflow 1.15 のインストール</h1>\n\n<p>Tensorflow1系でないと動かない環境とかサンプルとかあるので、<br />\nTensorflow v1.15をインストールする。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_1.15.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_1.15.0\n<span class=\"nb\">cd</span> /work/tf_1.15.0\npyenv <span class=\"nb\">local </span>tf_1.15.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"tensorflow-115-ライブラリのインストール\">Tensorflow 1.15 ライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>1.15\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nGPU使わないので-cpu付きパッケージを選択する</p>\n</blockquote>\n\n<h1 id=\"tensorflow-115-のbuild\">Tensorflow 1.15 のbuild</h1>\n\n<p>Tensorflowのpythonライブラリは<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできるが、\nソースからbuildしないと使えないツールもあるのでbuild環境を整える。</p>\n\n<p>参考: <a href=\"https://www.tensorflow.org/install/source?hl=ja\">ソースからのビルド | Tensorflow</a></p>\n\n<h2 id=\"bazelのインストール\">Bazelのインストール</h2>\n\n<p>Tensorflow をソースからbuildするには<code class=\"language-plaintext highlighter-rouge\">bazel</code>が必要なので、インストールしておく。</p>\n<blockquote>\n  <p>[!NOTE]\nBazelはVer.0.26.1 以下 を使用しないといけない<br />\nVer. 0.26.1はaptでインストールできない</p>\n</blockquote>\n\n<p>参考: <a href=\"https://docs.bazel.build/versions/0.26.0/install-ubuntu.html\">Installing Bazel on Ubuntu</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/bazelbuild/bazel/releases/download/0.26.1/bazel-0.26.1-installer-linux-x86_64.sh\n<span class=\"nb\">chmod</span> +x bazel-0.26.1-installer-linux-x86_64.sh\n./bazel-0.26.1-installer-linux-x86_64.sh <span class=\"nt\">--user</span>\n</code></pre></div></div>\n\n<p>実行ファイルは、<code class=\"language-plaintext highlighter-rouge\">~/bin/bazel</code> になるので、pathが~/binに通ってない場合は、一旦 ログアウトして 再ログイン\n(pathが通ってない場合、configureでエラーになる)</p>\n\n<h2 id=\"必要なpipパッケージのインストール\">必要なpipパッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>six numpy wheel mock <span class=\"s1\">'future>=0.17.1'</span>\npip <span class=\"nb\">install </span>keras_applications <span class=\"nt\">--no-deps</span>\npip <span class=\"nb\">install </span>keras_preprocessing <span class=\"nt\">--no-deps</span>\n</code></pre></div></div>\n\n<h2 id=\"tennsorflowのソースを取得\">tennsorflowのソースを取得</h2>\n\n<p>githubからcloneして V1.15.3 をチェックアウトしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/\ngit clone https://github.com/tensorflow/tensorflow.git\n<span class=\"nb\">cd </span>tensorflow\ngit checkout <span class=\"nt\">-b</span> v1.15.3 refs/tags/v1.15.3\n</code></pre></div></div>\n\n<h1 id=\"buildの設定\">buildの設定</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\n./configure\n<span class=\"c\"># いくつか質問されるので、すべてデフォルト(リターン)を入力</span>\n</code></pre></div></div>\n\n<h1 id=\"buildの実行\">buildの実行</h1>\n<h2 id=\"実行のひな形\">実行のひな形</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build //《対象ディレクトリ》:《ターゲット》\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n※ 対象ディレクトリはカレントディレクトリからの相対パス<br />\n※ ターゲットは対象ディレクトリのBUILDファイルで確認</p>\n</blockquote>\n\n<h2 id=\"例えばこんな感じ\">例えばこんな感じ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel build //tensorflow/lite/toco:toco\nbazel build //tensorflow/python/tools:freeze_graph\nbazel build //tensorflow/tools/graph_transforms:summarize_graph\nbazel build //tensorflow/tools/graph_transforms:transform_graph\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRAMは4GB以上必要かな?<br />\nオプション<code class=\"language-plaintext highlighter-rouge\">--local_ram_resources=2048</code>を指定すると使用するRAMを2GBに限定できる(指定する数値はMB単位)。<br />\n使用するPCのスペックによってかかる時間はマチマチ。<br />\nNativeなUbuntuで4コア8スレッドでも3~4時間程度かかる。<br />\nVirtualboxで1コア使用だと24時間とかかかることも。</p>\n</blockquote>\n\n<h2 id=\"buildしたファイルの実行\">buildしたファイルの実行</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">bazel run</code> で実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nオプションをbazelではなく実行するコマンドに渡すため、<code class=\"language-plaintext highlighter-rouge\">--</code> を入れる必要がある。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel run //tensorflow/lite/toco:toco <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:summarize_graph <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:transform_graph <span class=\"nt\">--</span> «オプション»\n</code></pre></div></div>\n\n<p>絶対パスで実行するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph «オプション»\n</code></pre></div></div>\n\n<p>パスが長いので、以下を設定しておくと便利。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">alias            </span><span class=\"nv\">toco</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">summarize_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">transform_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph'</span>\n</code></pre></div></div>\n\n<h2 id=\"おまけ\">おまけ</h2>\n\n<p>フツーはこっちがメインだが…(^^ゞ<br />\npipでインストールすれば必要ないが、Tensorflowのpipパッケージを作成するにはこちら。<br />\n(オプション変更したいときとか)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build <span class=\"nt\">--config</span><span class=\"o\">=</span>v1 //tensorflow/tools/pip_package:build_pip_package\n./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg\npip <span class=\"nb\">install</span> /tmp/tensorflow_pkg/tensorflow-1.15.3-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール(改訂版)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2020.3対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a>で\nubuntuへのインストール手順を書いたが、今読み返すと結構分かりにくかったので改訂版を書いとく。<br />\n今回はNCS2をubuntuで使えるようにしたので、その手順も追加。<br />\nついでに、今日(2020/06/16)現在の最新版Ver.2020.3での手順確認したので、反映しておく。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<p>参考 :<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">AIを始めよう!OpenVINOのインストールからデモの実行まで[R4対応]</a></p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>何やら登録しないとダウンロードさせてくれないらしい。</p>\n<ul>\n  <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download.html\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a> <br />\nLinux* (supports Ubuntu, CentOS, and Yocto Project)を選択\n    <ul>\n      <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download/linux.html\">Free Download</a>  <br />\n<span style=\"border: 1px solid;\">Register & Download</span>をクリック\n        <ul>\n          <li><a href=\"https://software.seek.intel.com/openvino-toolkit?os=linux\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a><br />\n必要事項を記入して<span style=\"border: 1px solid;\">Submit</span>をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>openVINO用のpython環境を用意しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work1/\npyenv virtualenv 3.7.7 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p>あとで「入ってない」って言われるので先にインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev\n</code></pre></div></div>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>ダウンロードしたファイルを展開してインストールスクリプトを実行する。<br />\n今回はバージョン 2020.3 で確認した。<br />\n最新版は <a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html</a> を参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf l_openvino_toolkit_p_<version>.tgz\n<span class=\"nb\">cd </span>l_openvino_toolkit_p_<version>/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n<p>GUIで次へを押していく。</p>\n\n<p>完了したらこれが表示されるので、したがって進める。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<h3 id=\"install-external-software-dependencies\">Install External Software Dependencies</h3>\n<p>依存パッケージのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh \n</code></pre></div></div>\n\n<h3 id=\"set-the-environment-variables\">Set the Environment Variables</h3>\n<p>環境変数の設定<br />\n~/.bashrc に以下の一文を追加。これでこの後開くコンソールでは環境変数が設定される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>source /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<p>現在のターミナルでも使えるように以下のコマンドを実行しておく。コンソール開きなおしてもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<h3 id=\"configure-the-model-optimizer\">Configure the Model Optimizer</h3>\n<p>モデルオプティマイザのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh \n</code></pre></div></div>\n\n<p>上記スクリプトではsystemのpython3にpipモジュールがインストールされてしまうので、<br />\npyenv環境にも必要なpipモジュールをインストールしておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell openVINO                       <span class=\"c\"># python環境を固定したいので</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\npyenv shell <span class=\"nt\">--unset</span>                        <span class=\"c\"># python環境を戻しておく</span>\n</code></pre></div></div>\n\n<h3 id=\"run-the-verification-scripts-to-verify-installation\">Run the Verification Scripts to Verify Installation</h3>\n<p>デモ実行<br />\n「Verify Installation」って書いてあるけど、実行必須。</p>\n\n<ul>\n  <li>デモ用ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo/\n</code></pre></div>    </div>\n  </li>\n  <li>sudoでpyenvが使えないので、代わりに <code class=\"language-plaintext highlighter-rouge\">/work1</code>  で作成した <code class=\"language-plaintext highlighter-rouge\">.python-version</code>をコピーしておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /work1/.python-version <span class=\"nb\">.</span>\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境にデモ環境で必要なpipモジュールをインストールしておく 。Systemのpython使うときは↓のスクリプト実行時にインストールされる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その1\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/demo1.log\n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その2\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/dem2.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"steps-for-intel-processor-graphics-gpu\">Steps for Intel® Processor Graphics (GPU)</h3>\n<p>今回はGPUを使わないのでスキップ</p>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>NCS2の準備<br />\n色々書いてあるけど、これ一発でOK。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n中ではこんなことをやってます。<br />\nグループusersに自分を追加<br />\n(ログアウト & 再ログインするまで追加は反映されません)<br />\nudevルールの作成と再ロード</p>\n</blockquote>\n\n<p>NCS2をUSBポートにブッ挿すして認識したか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下があったら認識できてる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ID 03e7:2485\n</code></pre></div></div>\n\n<h3 id=\"steps-for-intel-vision-accelerator-design-with-intel-movidius-vpus\">Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPUs</h3>\n<p>今回はVPUを使わないのでスキップ</p>\n\n<p>デモプログラムの実行で動作確認</p>\n\n<p>で、Run a Sample Application に行く前に、ログアウト&再ログインでいいはずだけど、念のためリブート。</p>\n\n<h3 id=\"run-a-sample-application\">Run a Sample Application</h3>\n<p>リブートして開いてたページが分からなくなるといけないので、念のためURL貼っとく。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample</a></p>\n\n<ul>\n  <li>デモ実行ディレクトリに移動。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~/inference_engine_samples_build/intel64/Release\n</code></pre></div>    </div>\n  </li>\n  <li>CPUでデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> CPU\n</code></pre></div>    </div>\n  </li>\n  <li>NCS2でデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> MYRIAD\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>このページの手順はここでおしまい。</p>\n\n<h1 id=\"他のサンプルも試してみよう\">他のサンプルも試してみよう。</h1>\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n<h3 id=\"前準備\">前準備</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work1/NCS/sample <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work1/NCS/sample/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release /opt/intel/openvino_2020.3.194/deployment_tools/inference_engine/samples/cpp/\n</code></pre></div></div>\n\n<h3 id=\"ssdを試してみよう\">SSDを試してみよう</h3>\n<h4 id=\"build\">build</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">-j2</span> object_detection_sample_ssd\n</code></pre></div></div>\n<h4 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R4/20200117_150000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n</code></pre></div></div>\n\n<h4 id=\"実行\">実行</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./intel64/Release/object_detection_sample_ssd <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> /work/data/data2/z_20141013051441.jpg \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nコマンド実行時の<code class=\"language-plaintext highlighter-rouge\">-i</code>オプションは入力画像ファイル。<br />\n人の顔が写っているjpegファイルを指定しましょう。 \n顔が写ってなければ顔検出できません(^^ゞ</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[ INFO ] Execution successful</code>と表示されたら実行成功だと思う。</p>\n\n<h4 id=\"結果画像を表示してみる\">結果画像を表示してみる。</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>eog out_0.bmp \n</code></pre></div></div>\n\n<h4 id=\"おーーーー\"><strong><em>おーーーー</em></strong></h4>\n\n<h1 id=\"ここまでの作業でインストールしたpipパッケージ一覧\">ここまでの作業でインストールしたpipパッケージ一覧</h1>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.9.0\nastor==0.8.1\ncertifi==2020.4.5.2\nchardet==3.0.4\ndecorator==4.4.2\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.2.0\ngraphviz==0.8.4\ngrpcio==1.29.0\nh5py==2.10.0\nidna==2.9\nimportlib-metadata==1.6.1\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.2\nMarkdown==3.2.2\nmxnet==1.5.1\nnetworkx==2.4\nnumpy==1.18.5\nonnx==1.7.0\nopt-einsum==3.2.1\nprotobuf==3.6.1\nPyYAML==5.3.1\nrequests==2.23.0\nsix==1.15.0\ntensorboard==1.15.0\ntensorflow==1.15.3\ntensorflow-estimator==1.15.1\ntermcolor==1.1.0\ntyping-extensions==3.7.4.2\nurllib3==1.25.9\nWerkzeug==1.0.1\nwrapt==1.12.1\nzipp==3.1.0\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その6</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その6</h1>\n      <p>tensorflow lite で色々なSSDモデルを使う手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はソースが大半なので、githubにリポジトリ作った。<br />\n内容は各ディレクトリのREADME.mdを見てチョ。<br />\n<a href=\"https://github.com/ippei8jp/tflite_trial\">https://github.com/ippei8jp/tflite_trial</a></p>\n\n<p>順序は <code class=\"language-plaintext highlighter-rouge\">download_models</code> → <code class=\"language-plaintext highlighter-rouge\">mk_tflite_ssd</code> → <code class=\"language-plaintext highlighter-rouge\">images</code> → <code class=\"language-plaintext highlighter-rouge\">ssd</code> が良いと思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>csvファイルをエクセルファイルに変換する</title>\n  </head>\n  <body>\n    <header>\n      <h1>csvファイルをエクセルファイルに変換する</h1>\n      <p>pythonでcsvファイルをエクセルファイルに変換する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonでcsvファイルをエクセルファイルに変換する方法。<br />\nぐぐったらすぐ出てくるけど、自分のとこにもメモしとく。<br />\nついでに、おまけとしてcsvファイルを読んで、各列の平均値を出力する処理も載せとく。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p>必要なモジュールをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>pandas openpyxl\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pandas</span> <span class=\"k\">as</span> <span class=\"n\">pd</span>\n\n<span class=\"c1\"># コマンドラインパラメータ\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span>\n\n<span class=\"c1\"># エラーチェックは省略\n# 入力ファイル(csv形式、拡張子は任意)の拡張子をxlsxに変更したファイルとして出力する\n</span>\n<span class=\"n\">input_file</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>                                        <span class=\"c1\"># 入力ファイル名\n</span><span class=\"n\">output_file</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">input_file</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".xlsx\"</span>     <span class=\"c1\"># 出力ファイル名\n</span> \n<span class=\"c1\"># CSVファイルの読み込み\n</span><span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">pd</span><span class=\"p\">.</span><span class=\"n\">read_csv</span><span class=\"p\">(</span><span class=\"n\">input_file</span><span class=\"p\">,</span> <span class=\"n\">index_col</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>     <span class=\"c1\"># 1行目がヘッダ、1列目がインデックスとする\n</span>\n<span class=\"c1\"># Excel形式で出力\n</span><span class=\"n\">data</span><span class=\"p\">.</span><span class=\"n\">to_excel</span><span class=\"p\">(</span><span class=\"n\">output_file</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s\">'utf-8'</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<p>csvファイルを読んで、各列の平均値を出力する処理をワンライナーで。<br />\n(前提:1行目がヘッダ、1列目がインデックス)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import sys; import pandas as pd; data = pd.read_csv(sys.argv[1], index_col=0); ave=data.mean(); print(ave)\"</span> «csvファイル»\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git の差分比較ツールにWinMergeを使用する</title>\n  </head>\n  <body>\n    <header>\n      <h1>git の差分比較ツールにWinMergeを使用する</h1>\n      <p>git の差分比較ツールに WinMerge を使用する方法</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows上のgit-の差分比較ツールに-winmerge-を使用する方法\">Windows上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows限定だが、git の差分比較ツールに WinMerge を使用する方法のメモ<br />\n参考: <a href=\"https://qiita.com/kobake@github/items/fb317b4fdacad718a4b2?fbclid=IwAR1eO6ENMKDeeY3PmGJWrKLf_n1rgC8NVPBF60xKMiG02yAFgCFS6ceC7IE\">git の差分比較・マージを WinMerge で行う</a><br />\n↑参考というよりパクリだが(^^ゞ</p>\n\n<p>git の差分比較の <code class=\"language-plaintext highlighter-rouge\">git diff</code> で見ると見難いので、WinmMergeを使えるようにしてみた。<br />\n普段はVS Code 使ってるけど…</p>\n\n<p>手順は、 <code class=\"language-plaintext highlighter-rouge\">C:\\Users\\〇〇\\.gitconfig</code> に以下を追記するだけ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n[difftool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -f \\\"*.*\\\" -e -u -r \\\"$LOCAL\\\" \\\"$REMOTE\\\"\n[merge]\n    tool = WinMerge\n[mergetool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -e -u \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$MERGED\\\"\n[alias]\n    windiff = difftool -y -d -t WinMerge\n    winmerge = mergetool -y -t WinMerge\n</code></pre></div></div>\n\n<p>差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力すれば良い。</p>\n\n<p>差分はファイル書き換えても自動的にアップデートされなので、都度<code class=\"language-plaintext highlighter-rouge\">git windiff</code> する必要がある。<br />\n(あくまでスナップショットでの比較を表示してるだけ)</p>\n\n<p>比較対象の指定とか、マージとかもできるみたいだけど、使ってないので、詳しくは↑の参考先を見てね。(^^ゞ</p>\n\n<h1 id=\"wsl上のgit-の差分比較ツールに-winmerge-を使用する方法\">WSL上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows上の場合とほぼ同じ。<code class=\"language-plaintext highlighter-rouge\">~/.gitconfig</code>に以下を追加しておき、差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力する。<br />\nマージは使わないので、diffだけ設定。<br />\n(上の方法をwslpathでLinux上のpath→Windows上のpath 変換してるだけ、かな?)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n\n[difftool]\n    prompt = false\n\n[difftool \"WinMerge\"]\n    cmd = '/mnt/c/Program Files/WinMerge/WinMergeU.exe' -e -r -u -wl -dl Local -wr -dr Remote \\\"`wslpath -wa $LOCAL`\\\" \\\"`wslpath -wa $REMOTE`\\\"\n    trustExitCode = false\n\n[alias]\n    windiff = difftool -y -d --no-symlinks -t WinMerge\n</code></pre></div></div>\n<p>参考:<a href=\"https://qiita.com/forest1/items/334b5d756b5696c63331\">WSL(Ubuntu 18.04)環境のgitでWinMergeを使う方法</a></p>\n\n<p>参考先ではUbuntu18.04となっているが、20.04でも問題なし。<br />\nまた、<code class=\"language-plaintext highlighter-rouge\">/mnt/c/Users/username</code>以下で作業と書いてあるが、どこで作業しても大丈夫。テンポラリパスの変更も不要。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ガラクタ置き場</title>\n  </head>\n  <body>\n    <header>\n      <h1>ガラクタ置き場</h1>\n      <p>COCO データセットから適当にファイルを取得する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ガラクタ\">ガラクタ</h1>\n<p>SSDなどの動作確認に使えるかなぁ~?と思ってCOCO データセットから適当にいくつかの画像ファイルを取得するスクリプトを作ってみた。<br />\n結局使わなかったけど、せっかくなのでガラクタ置き場に置いておく。(^^ゞ</p>\n\n<p>今回はリポジトリ作るほどではないので、ここにソース貼っとく。<br />\n解説するほどでもないので、使い方はソース見てチョ!←   テヌキ…</p>\n\n<h2 id=\"ソース\">ソース</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"s\">'''\nCOCOデータセットから適当にファイルを取得する\n'''</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">glob</span>\n<span class=\"kn\">import</span> <span class=\"nn\">shutil</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">RawTextHelpFormatter</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">urllib.request</span>\n<span class=\"kn\">import</span> <span class=\"nn\">zipfile</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n\n<span class=\"n\">COCO_2014</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>       <span class=\"c1\"># COCO 2014のminivalデータセット を使用する場合はTrueにする\n</span>\n<span class=\"c1\"># パラメータ\n</span><span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n    <span class=\"n\">DOWNLOAD_URL</span> <span class=\"o\">=</span> <span class=\"s\">'https://dl.dropboxusercontent.com/s/o43o90bna78omob/instances_minival2014.json.zip?dl=0'</span>\n    <span class=\"n\">JSON_FILE</span>    <span class=\"o\">=</span> <span class=\"s\">'instances_minival2014.json'</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">DOWNLOAD_URL</span> <span class=\"o\">=</span> <span class=\"s\">'http://images.cocodataset.org/annotations/image_info_test2017.zip'</span>\n    <span class=\"n\">JSON_FILE</span>    <span class=\"o\">=</span> <span class=\"s\">'annotations/image_info_test2017.json'</span>\n\n<span class=\"c1\"># zipファイル展開のための一時ファイル\n</span><span class=\"n\">TEMP_ZIP</span>     <span class=\"o\">=</span> <span class=\"s\">'temp.zip'</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">formatter_class</span><span class=\"o\">=</span><span class=\"n\">RawTextHelpFormatter</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--num'</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロードするファイル数\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--margin'</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">30</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロードエラーのためのマージン数\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--clean'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロード済みのファイルを削除して終了します</span><span class=\"se\">\\n</span><span class=\"s\">(ダウンロードは行いません)\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n\n<span class=\"c1\"># コマンドラインパーサの生成&解析\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">clean</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"==== CLEAN!! ====\"</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">):</span>\n        <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n            <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">shutil</span><span class=\"p\">.</span><span class=\"n\">rmtree</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">dirname</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">),</span> <span class=\"n\">ignore_errors</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">for</span> <span class=\"nb\">file</span> <span class=\"ow\">in</span> <span class=\"n\">glob</span><span class=\"p\">.</span><span class=\"n\">glob</span><span class=\"p\">(</span><span class=\"s\">'*.jpg'</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">):</span>\n            <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ファイル数設定\n</span><span class=\"n\">num_files</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num</span>\n<span class=\"n\">num_margin</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">margin</span>\n\n<span class=\"c1\"># JSONファイルがなければダウンロードする\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ダウンロードを実行\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">DOWNLOAD_URL</span><span class=\"si\">}</span><span class=\"s\"> をダウンロード中...'</span><span class=\"p\">)</span>\n    <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">urlretrieve</span><span class=\"p\">(</span><span class=\"n\">DOWNLOAD_URL</span><span class=\"p\">,</span> <span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 展開\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">TEMP_ZIP</span><span class=\"si\">}</span><span class=\"s\"> を展開中...'</span><span class=\"p\">)</span>\n    <span class=\"k\">with</span> <span class=\"n\">zipfile</span><span class=\"p\">.</span><span class=\"n\">ZipFile</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">zf</span><span class=\"p\">:</span>\n        <span class=\"n\">zf</span><span class=\"p\">.</span><span class=\"n\">extractall</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># テンポラリファイルの削除\n</span>    <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># JSONファイルの読み込み\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">JSON_FILE</span><span class=\"si\">}</span><span class=\"s\">の読み込み中...'</span><span class=\"p\">)</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_json</span> <span class=\"p\">:</span>\n    <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f_json</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ個数(5000のハズ)\n</span><span class=\"n\">data_len</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">])</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'DATA_LENGTH = </span><span class=\"si\">{</span><span class=\"n\">data_len</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 内容をダンプ\n# print(json.dumps(data[\"images\"], indent=2))\n</span>\n<span class=\"c1\"># ダウンロード数のチェック\n</span><span class=\"k\">if</span> <span class=\"n\">num_files</span> <span class=\"o\">+</span> <span class=\"n\">num_margin</span> <span class=\"o\">></span> <span class=\"n\">data_len</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'ERROR : ファイル数とマージンの合計がデータ個数を超えています'</span><span class=\"p\">)</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ダウンロードするインデックスを乱数で決定(エラー発生時のためにマージンを積んどく)\n</span><span class=\"n\">download_indexs</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">(</span><span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">data_len</span><span class=\"p\">),</span> <span class=\"n\">num_files</span> <span class=\"o\">+</span> <span class=\"n\">num_margin</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># ダウンロード完了個数\n</span><span class=\"n\">num_downloaded</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n<span class=\"n\">num_error</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># ダウンロードループ\n</span><span class=\"k\">for</span> <span class=\"nb\">id</span> <span class=\"ow\">in</span> <span class=\"n\">download_indexs</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ファイル名\n</span>    <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"file_name\"</span><span class=\"p\">]</span>\n    <span class=\"c1\"># URL\n</span>    <span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n        <span class=\"n\">url</span>      <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"url\"</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">url</span>      <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"coco_url\"</span><span class=\"p\">]</span>\n    <span class=\"c1\"># ダウンロード\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">filename</span><span class=\"si\">}</span><span class=\"s\">をダウンロード中...'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'ID : </span><span class=\"si\">{</span><span class=\"nb\">id</span><span class=\"si\">:</span><span class=\"mi\">3</span><span class=\"si\">}</span><span class=\"se\">\\t</span><span class=\"s\">NAME : </span><span class=\"si\">{</span><span class=\"n\">filename</span><span class=\"si\">}</span><span class=\"se\">\\t</span><span class=\"s\">URL : </span><span class=\"si\">{</span><span class=\"n\">url</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">try</span> <span class=\"p\">:</span> \n        <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">urlretrieve</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">)</span>\n    <span class=\"k\">except</span> <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">.</span><span class=\"n\">HTTPError</span> <span class=\"k\">as</span> <span class=\"n\">e</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># エラー発生\n</span>        <span class=\"n\">num_error</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'**** skip!! ****  </span><span class=\"si\">{</span><span class=\"n\">e</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ダウンロード完了\n</span>        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'---- DONE!! ----'</span><span class=\"p\">)</span>\n        <span class=\"n\">num_downloaded</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"c1\"># 所望の数に達したら終了\n</span>        <span class=\"k\">if</span> <span class=\"n\">num_downloaded</span> <span class=\"o\">>=</span> <span class=\"n\">num_files</span> <span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'ダウンロード数 : </span><span class=\"si\">{</span><span class=\"n\">num_downloaded</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'エラー数       : </span><span class=\"si\">{</span><span class=\"n\">num_error</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">num_error</span> <span class=\"o\">></span> <span class=\"n\">num_margin</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'warning : エラー数がマージンを越えました'</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<p>今後、なんかに使えると良いなぁ~(笑)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのバグ??</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのバグ??</h1>\n      <p>pyenvのバグ??</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>バグかどうかわからんけど、思った通りの動作をしなかったので、メモ。</p>\n\n<h1 id=\"現象\">現象</h1>\n\n<p>pyenv を使う環境で、</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    python script.py <span class=\"nt\">--option</span> /path/to/file\n</code></pre></div></div>\n\n<p>と実行した場合、カレントディレクトリと<code class=\"language-plaintext highlighter-rouge\">/path/to/file</code>の存在するディレクトリで使用するpythonのバージョンが異なる場合、<br />\n(どちらか片方 or 両方で <code class=\"language-plaintext highlighter-rouge\">pyenv local</code>が指定されている)<br />\nカレントディレクトリではなく、/path/to/fileの存在するディレクトリで使用するpythonのバージョンが指定されてしまうらしい。</p>\n\n<p>問題が発生するシチュエーションは そんなに多くないと思うけど、 双方のバージョンでインストールしてるモジュールが違ったりすると困ったことになる。</p>\n\n<h1 id=\"原因\">原因</h1>\n\n<p>色々試行錯誤してみてわかったことを結論だけ。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> を見ると、<br />\nコマンドラインをサーチして最初に見つかったファイルの属する<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読むらしい。<br />\n(以下の部分)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    ・・・\n    <span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"k\">in</span>\n        <span class=\"nt\">-c</span><span class=\"k\">*</span> <span class=\"p\">|</span> <span class=\"nt\">--</span> <span class=\"p\">)</span> <span class=\"nb\">break</span> <span class=\"p\">;;</span>\n        <span class=\"k\">*</span>/<span class=\"k\">*</span> <span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-f</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n                </span><span class=\"nb\">export </span><span class=\"nv\">PYENV_FILE_ARG</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span>\n                <span class=\"nb\">break\n            </span><span class=\"k\">fi</span>\n            <span class=\"p\">;;</span>\n    <span class=\"k\">esac</span>\n    ・・・\n</code></pre></div></div>\n<p>本来ならスクリプトファイルのあるディレクトリの<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読んでほしいはずなのに…<br />\n<code class=\"language-plaintext highlighter-rouge\">*/* )</code> でなく、<code class=\"language-plaintext highlighter-rouge\">*)</code> じゃないのかな? なんか深い訳があるのかもしれんけど…</p>\n\n<h1 id=\"対処方法\">対処方法</h1>\n\n<p>で、以下のいずれかの方法で対処できる。</p>\n\n<ul>\n  <li>オプションの場合は、オプションとオプションパラメータの間をスペースでなく、<code class=\"language-plaintext highlighter-rouge\">=</code>にする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  python script.py <span class=\"nt\">--option</span><span class=\"o\">=</span>/path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>ただし、パーサが<code class=\"language-plaintext highlighter-rouge\">argparse.ArgumentParser</code>など、オプションとオプションパラメータの区切りに<code class=\"language-plaintext highlighter-rouge\">=</code>が使えるものでなければダメ。</li>\n      <li>しかも、そもそもオプションパラメータでなくコマンドパラメータだったらどうしようもない…orz…</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pyenv shell</code>で使用するバージョンを指定する\n    <ul>\n      <li>メンドクサイ…</li>\n    </ul>\n  </li>\n  <li>スクリプトファイルの前に<code class=\"language-plaintext highlighter-rouge\">--</code>を追加してやる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">--</span> script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> では<code class=\"language-plaintext highlighter-rouge\">-c</code>か<code class=\"language-plaintext highlighter-rouge\">--</code>が見つかったら<code class=\"language-plaintext highlighter-rouge\">PYENV_FILE_ARG</code>を探すループを抜けてくれるので。</li>\n      <li>ちょっとめんどくさい…</li>\n    </ul>\n  </li>\n  <li>スクリプト名の前に./を追加する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ./script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>これが一番シンプルかな?</li>\n      <li>てか、コレしかないっしょ。 常に<code class=\"language-plaintext highlighter-rouge\">./</code>付けるクセ付ければいいし。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"免責のツモリ\">免責(のツモリ)</h1>\n\n<p>あくまで自分のメモなんで、、、  ゴニョゴニョ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>githubによるセキュリティチェック</title>\n  </head>\n  <body>\n    <header>\n      <h1>githubによるセキュリティチェック</h1>\n      <p>githubによるセキュリティチェックによるpullリクエストが来た場合の対処方法</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>githubによるセキュリティチェックによるpullリクエストが来た場合の対処方法</p>\n\n<p>例えば、tensorflow 1.15 を使用するような設定が書かれていた場合、2.1.0に変更しろと言ってくる。<br />\nでも、変更したら動かなくなるし…</p>\n\n<h1 id=\"対処方法\">対処方法</h1>\n\n<p>こんな場合は しかたないので、アラート無視するよう言い訳する。<br />\nやり方:<a href=\"https://blog.tmd45.jp/entry/2019/11/26/162157\">GitHub Security Alert の Dismiss 言い訳</a></p>\n\n<p>でもって、自動で作成されたpullリクエストをcloseすると勝手に作成されたブランチも消えるらしい。<br />\nやり方: <a href=\"https://help.github.com/ja/github/collaborating-with-issues-and-pull-requests/closing-a-pull-request\">プルリクエストをクローズする</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットをキャプチャするときの注意事項</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットをキャプチャするときの注意事項</h1>\n      <p>WiresharkでUSBパケットをキャプチャしようとしてちょっとハマったのでメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>WiresharkでUSBパケットをキャプチャするための準備(Linux版)<br />\nWindows版はちょっと異なると思うけど試してないので、ググってね😅。</p>\n\n<h1 id=\"wiresharkのインストール実行\">Wiresharkのインストール&実行</h1>\n\n<p>ふつーに<code class=\"language-plaintext highlighter-rouge\">apt install</code>するだけ。<br />\nWindows版と異なり、USBパケットキャプチャのために別途USBキャプチャプログラムをインストールする必要はない。<br />\nついでに<code class=\"language-plaintext highlighter-rouge\">sudo</code>しなくても実行できるように自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>グループを追加しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>wireshark\n<span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> wireshark \n</code></pre></div></div>\n\n<p>ここで一旦ログアウト&再ログイン or 再起動。</p>\n\n<p>このままだとUSBパケットキャプチャのためのプログラム(<code class=\"language-plaintext highlighter-rouge\">usbmon</code>)が動いてないので、動かす必要がある。<br />\n<strong>起動の度に</strong>ターミナルから以下のコマンドを実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbmon\n</code></pre></div></div>\n\n<p>Wiresharkの実行は、ターミナルから<code class=\"language-plaintext highlighter-rouge\">wireshark</code>を実行するか、メニューの「インターネット」→「Wireshark」を選択します。<br />\n(自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>`グループを追加してあるので、メニューからでも実行できます)</p>\n\n<p>起動の度に<code class=\"language-plaintext highlighter-rouge\">usbmon</code>を起動するのは面倒な場合は、以下の手順で自動化できます。</p>\n\n<ol>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/udev/rules.d/99-usbmon.rules</code>を以下の内容で作成\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>SUBSYSTEM==\"usbmon\", GROUP=\"wireshark\", MODE=\"640\"\n</code></pre></div>    </div>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/modules</code> に以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbmon\n</code></pre></div>    </div>\n  </li>\n  <li>リブート</li>\n</ol>\n\n<h1 id=\"wiresharkの使い方\">Wiresharkの使い方</h1>\n\n<p>あちこちのホームページに詳しく解説されているので、ぐぐってちょ(←なんて他力本願…😅)。<br />\nRaspberryPi4の場合、USBのインタフェースはusbmon1とusbmon2があるが、どっちをキャプチャするかは、接続した機器がUSB2.0かUSB3.0による。<br />\nたぶん、usbmon1がUSB2.0(外側/内側)、usbmon2がUSB3.0(内側のみ)だと思う。<br />\n<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)がusbmonYのYにあたるとだと推測。</p>\n\n<h1 id=\"wiresharkでパケット解析\">Wiresharkでパケット解析</h1>\n\n<p>USBのパケットの表示フィルタの書き方がネット上でもなかなか見つからなかったので、簡単なものだけメモ。</p>\n\n<h2 id=\"特定のusb機器のパケットだけ表示\">特定のUSB機器のパケットだけ表示</h2>\n\n<p>実際にはエンドポイントまで指定しているので、複数のエンドポイントを同時に表示したければ、OR(<code class=\"language-plaintext highlighter-rouge\">||</code>)で条件つなげてください。\n(<code class=\"language-plaintext highlighter-rouge\">1.5.*</code>みたいな書き方が出来るのかは不明 )</p>\n\n<p>この例の<code class=\"language-plaintext highlighter-rouge\">1.5.1</code>の<br />\n左の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)、 <br />\n中央の<code class=\"language-plaintext highlighter-rouge\">5</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のデバイス番号(<code class=\"language-plaintext highlighter-rouge\">Device YYY</code>の部分の数字)(<strong>挿抜の度に変わる</strong>)、 <br />\n右の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb -D /dev/bus/usb/XXX/YYY</code>(XXX、YYYは上記のバス番号、デバイス番号。0は省略不可) で表示される情報の <br />\n<code class=\"language-plaintext highlighter-rouge\">bEndpointAddress</code>で確認できるけど、これは機器内部で固定されてるはず。<br />\nと、難しく調べんでも、一度全部キャプチャしたものを表示して欲しいパケットを探してみてそこのアドレスを見れば分かる。</p>\n\n<p>USBホストの吐合は<code class=\"language-plaintext highlighter-rouge\">\"host\"</code>になる。</p>\n\n<h3 id=\"特定の機器の送信パケットだけ表示\">特定の機器の送信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\"\n</code></pre></div></div>\n<h3 id=\"特定の機器の受信パケットだけ表示\">特定の機器の受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n<h3 id=\"特定の機器の送受信パケットだけ表示\">特定の機器の送受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\" || usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要--背景\">概要 & 背景</h1>\n\n<p>WiresharkでUSBパケットをキャプチャしたとき、実際に転送されてるデータの中身が見たいというニッチな要求があった。<br />\n(送ったデータがちゃんとUSBバスに出てるよね~、という確認がしたいなどの用途)</p>\n\n<p>Wiresharkのセーブデータ渡して「Wiresharkで見てね~」と言ったら「見方が分からん!」と…<br />\nで、Excelで一覧表にしてあげようと思い、エクスポートできんかな~と探してみるも、適当な機能が見つからず…<br />\nしかたなく、変換スクリプトかましてCSVに出力してExcelで読み込んでみよう、と試した時のメモ。</p>\n\n<p>今回はisochronous転送のデータの中身をダンプしている。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<ol>\n  <li>最初に解析したいパケットをキャプチャしておく(これをやらなきゃ始まらん…)。</li>\n  <li>必要なら表示フィルタで解析したいパケットだけ選び出す。</li>\n  <li>それらのパケットの一部だけ(最初の1秒だけ など)解析したい場合はそのパケット群を選択する。<br />\n   RaspberryPiでのやり方が分からん…Windows版なら他のアプリ同様、先頭で左クリック→最後でshift押しながら左クリックでOK。<br />\n   どうしても出来なかったら、RaspberryPiでキャプチャしたのを保存して、そのファイル(pcapngファイル)をWindowsにコピーして、\n   Windows上のWiresharkで読み込んでくだされ…😅</li>\n  <li>メニューの「ファイル」→「パケット解析をエクスポート」→「JSONとして」を選択</li>\n  <li>ファイル操作ダイアログが表示される\n    <ul>\n      <li>真ん中の「ファイル名」を入力</li>\n      <li>左下の「パケットの範囲」で\n        <ul>\n          <li>「表示されたパケット」を選択</li>\n          <li>「すべてのパケット」または「選択されたパケットのみ」を選択<br />\n (ここで「範囲」を選んで入力すれば選択しなくてもいいのかな?試してないので不明)</li>\n        </ul>\n      </li>\n      <li>「保存」をクリック</li>\n    </ul>\n  </li>\n</ol>\n\n<p>これでJSONファイルが保存される。</p>\n\n<h1 id=\"csvファイルに変換\">CSVファイルに変換</h1>\n\n<p>さぁ、このJSONファイルを読み込んで必要な部分を取り出すスクリプトを書けばOKじゃん?と思ったが、<br />\nそうは問屋がおろしてくれない😢<br />\nじつはWiresharkがエクスポートするJSONファイルはJSONファイルの文法からはずれた部分があるのだ…<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">/_source/layers/usb</code> の配下に複数のキー<code class=\"language-plaintext highlighter-rouge\">usb</code>があって、すべてのUSBデータを読み込めない。<br />\n(JSONの仕様では同一階層に複数の同じキーの存在を許さない。pythonのJSONモジュールでは複数あるデータのうち、一つだけが読み込まれる)<br />\nここが配列になってればOKだと気が付いて、チカラワザで変換する処理を追加してみた。</p>\n\n<p>で、pyshonで書いたスクリプトがこちら。<br />\nWindows/RaspberryPi どっちでも大丈夫と思うけど、Windowsでしか試してない。<br />\npythonは3.6以降が必要。3.7.7で動作確認。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  json_read.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"c1\"># テンポラリファイル名\n</span><span class=\"n\">tmp_file</span> <span class=\"o\">=</span> <span class=\"s\">'tmp.json'</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'==== USAGE ========================='</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'    </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> <JSON file> <CSV file>'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'===================================='</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">json_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">csv_file</span>  <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'Error: JSON file not exist!!'</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># \"usb\" キーが複数あるので、これをリストに変換したJSONファイルを作成する\n# かなり力技...\n</span><span class=\"k\">def</span> <span class=\"nf\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_json</span><span class=\"p\">,</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_tmp</span><span class=\"p\">:</span>\n        <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        \n        <span class=\"k\">while</span> <span class=\"n\">line</span><span class=\"p\">:</span>\n            <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"n\">line_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>           <span class=\"c1\"># 行番号\n</span>            <span class=\"c1\"># line = line.rstrip('\\r\\n')              # CRLFを削除\n</span>            <span class=\"k\">if</span> <span class=\"n\">find_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">'\"usb\": '</span><span class=\"p\">,</span> <span class=\"s\">''</span><span class=\"p\">)</span>      <span class=\"c1\"># key名称 \"usb\"を削除\n</span>                <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'START: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          \"usb_data\": [</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">+</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'{'</span><span class=\"p\">)</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">-</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'}'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">brackets</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'END: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          ]</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb.iso.numdesc\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">f_pos</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">tell</span><span class=\"p\">()</span>\n                    <span class=\"n\">next_line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>        <span class=\"c1\"># 次の行を読み込んで\n</span>                    <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"n\">f_pos</span><span class=\"p\">)</span>                   <span class=\"c1\"># ファイル位置を戻す\n</span>                    <span class=\"k\">if</span> <span class=\"n\">next_line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                    <span class=\"c1\"># 括弧の数\n</span>            <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">line</span><span class=\"p\">)</span>\n            <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># JSONファイルの修正\n</span><span class=\"n\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># パケット解析用変数\n</span><span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n<span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># JSONファイルの読み込み\n</span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n    <span class=\"n\">json_load</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(json_load)\n</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">csv_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_csv</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ヘッダの出力\n</span>    <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">'PacketNo,Date,Relative_time,Delta_time,Packet Size,Video Stream Size,Video Stream offset,Frame No,Stream No,Stream Data</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">json_data</span> <span class=\"ow\">in</span> <span class=\"n\">json_load</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フレームデータ\n</span>        <span class=\"n\">frame_data</span>          <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"frame\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_index</span>         <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.number\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_epoc</span>     <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_epoch\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_delta</span>    <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_delta_displayed\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_relative</span> <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_relative\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_dt</span>       <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">fromtimestamp</span><span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">frame_time_epoc</span><span class=\"p\">))</span>\n        <span class=\"n\">frame_time</span>          <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_time_dt</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_len</span>           <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.len\"</span><span class=\"p\">]</span>\n        <span class=\"c1\"># print(f'{frame_index},\"\\'{frame_time}\",{frame_len},', end='')\n</span>        <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_index</span><span class=\"si\">}</span><span class=\"s\">,\"</span><span class=\"se\">\\'</span><span class=\"si\">{</span><span class=\"n\">frame_time</span><span class=\"si\">}</span><span class=\"s\">\",</span><span class=\"si\">{</span><span class=\"n\">frame_time_relative</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_time_delta</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_len</span><span class=\"si\">}</span><span class=\"s\">,'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># USBデータ\n</span>        <span class=\"n\">usb_datas</span>  <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"usb\"</span><span class=\"p\">][</span><span class=\"s\">\"usb_data\"</span><span class=\"p\">]</span>\n        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"k\">for</span> <span class=\"n\">usb_data</span> <span class=\"ow\">in</span> <span class=\"n\">usb_datas</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f',,,,,', end='')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">',,,,,'</span><span class=\"p\">)</span>\n            <span class=\"n\">iso_len</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_len'</span><span class=\"p\">])</span>\n            <span class=\"n\">iso_off</span>  <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_off'</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">iso_len</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">\"usb.iso.data\"</span><span class=\"p\">]</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"s\">'0x'</span><span class=\"o\">+</span><span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">':'</span><span class=\"p\">,</span> <span class=\"s\">',0x'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">stream_number</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_number</span><span class=\"p\">)</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"s\">''</span>\n                \n                <span class=\"c1\"># print(f'{iso_len},{iso_off},{stream_number},{iso_data}')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_number_str</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">stream_number</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_data</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x02'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x03'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"n\">stream_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f'{iso_len},{iso_off},,')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,,</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># テンポラリファイルの削除\n</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。(RaspberryPiだと<code class=\"language-plaintext highlighter-rouge\">python3</code>にしてちょ)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python json_read.py «入力JSONファイル» «出力CSVファイル»\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>やっつけスクリプトなので、エラーチェックはかなりいい加減…</p>\n\n<p>関数<code class=\"language-plaintext highlighter-rouge\">modify_json()</code> が 前述のJSONファイルの不具合をチカラワザで修正する処理。</p>\n\n<p>テンポラリファイルとしてカレントディレクトリに<code class=\"language-plaintext highlighter-rouge\">tmp.json</code>を作成するので、注意。\nファイル名を変更したければ、8行目の<code class=\"language-plaintext highlighter-rouge\">tmp_file</code>を変更。<br />\nこのファイルはスクリプトの最後で削除している。<br />\n作成したテンポラリファイルを残しておきたければ最後の<code class=\"language-plaintext highlighter-rouge\">os.remove(tmp_file)</code>をコメントアウト。</p>\n\n<p>71~72行目で修正したJSONファイルを読み込み。</p>\n\n<p>75行目で書き出すCSVファイルをオープン。</p>\n\n<p>78行目~のforループで各JSONレコードを読み込みながら処理。</p>\n\n<p>82,85~86行目でframe.time_epochから時刻文字列を作成。<br />\n時刻は<code class=\"language-plaintext highlighter-rouge\">frame.time</code>を使用する手もあるが、ここはプラットフォームによって変化するらしいので同じ表示にするためにエポックタイムから生成している。<br />\nその他時刻関連データでは、<code class=\"language-plaintext highlighter-rouge\">frame.time_delta_displayed</code>で「前のパケットからの相対時間」、\n<code class=\"language-plaintext highlighter-rouge\">frame.time_relative</code>で「最初のパケットからの相対時間」を取得している。</p>\n\n<p>94行目~のforループがデータを取り出す部分。<br />\nisochronous転送のデータではないデータを取り出したい場合は、所望のデータのキーに置き換えて取り出せば良い。<br />\n<code class=\"language-plaintext highlighter-rouge\">frame_number</code>と<code class=\"language-plaintext highlighter-rouge\">stream_number</code>は私の解析用の補助データなので気にしないでネ。</p>\n\n<p>あとは、エクスポートされたJSONファイルとスクリプトを見比べてちゃぶだい。(^^ゞ</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>あとは、csvファイルをExcelで読み込むなり、pandasとかを使った別のスクリプトで加工するなりしてちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順はWiresharkで色々操作しないといけないのがめんどっちいので、スクリプトで自動化してみた。</p>\n\n<p>WiresharkのCUI版である、tsharkを使うと出来るらしいとの情報があったので、試してみたときのメモ。<br />\n今回はRaspberryPiだけ。Windowsは対応してません。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_1.html\">WiresharkでUSBパケットをキャプチャするときの注意事項</a> \nの準備は出来ているものとする。(Wiresharkは入ってなくても大丈夫。もちろん 入ってても良いよ。)</p>\n\n<p>tsharkは以下のコマンドイッパツでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tshark \n</code></pre></div></div>\n\n<p>で、あとは以下のスクリプトを\n<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの<code class=\"language-plaintext highlighter-rouge\">json_read.py</code>と同じディレクトリに作成し、実行するだけ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cap.sh\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/usr/bin/env bash</span>\n\n<span class=\"c\"># 第一引数でキャプチャ期間(sec)</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-z</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n  <span class=\"c\"># 引数なしだと2secに設定</span>\n  <span class=\"nv\">period</span><span class=\"o\">=</span>2\n<span class=\"k\">else</span>\n  <span class=\"c\"># 引数のチェック</span>\n  <span class=\"k\">if </span><span class=\"nb\">expr</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> : <span class=\"s1\">'[0-9]*'</span> <span class=\"o\">></span> /dev/null <span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># 数値</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nv\">$1</span> <span class=\"nt\">-lt</span> 1 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n      <span class=\"c\"># 1未満の数値</span>\n      <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n      <span class=\"nb\">exit\n    </span><span class=\"k\">else</span>\n      <span class=\"c\"># 1以上の数値(OK)</span>\n      <span class=\"nv\">period</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span>\n    <span class=\"k\">fi\n  else</span>\n    <span class=\"c\"># 数値でない</span>\n    <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n    <span class=\"nb\">exit\n  </span><span class=\"k\">fi\nfi</span>\n\n<span class=\"c\"># 現在時刻</span>\n<span class=\"nv\">cur_time</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">date</span> <span class=\"s2\">\"+%y%m%d_%H%M%S\"</span><span class=\"sb\">`</span>\n<span class=\"c\"># ファイル名生成</span>\n<span class=\"nv\">fname_base</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span>_<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># USBパケットキャプチャ</span>\n<span class=\"nb\">echo</span> <span class=\"s2\">\"Capture USB packets for </span><span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span><span class=\"s2\"> second from </span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\ntshark <span class=\"nt\">-i</span> usbmon1 <span class=\"nt\">-w</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-a</span> duration:<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># バス番号、デバイス番号の抽出</span>\n<span class=\"nv\">tmp_str</span><span class=\"o\">=</span><span class=\"sb\">`</span>lsusb | <span class=\"nb\">grep </span>WebCam<span class=\"sb\">`</span>\n<span class=\"nv\">bus_and_dev</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">tmp_str</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/Bus </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">Device </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">: ID.*/</span><span class=\"se\">\\1</span><span class=\"s2\"> </span><span class=\"se\">\\2</span><span class=\"s2\">/g\"</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">bus</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[0]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">dev</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[1]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">endpoint</span><span class=\"o\">=</span>1\n<span class=\"nv\">addr</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">bus</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">dev</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">endpoint</span><span class=\"k\">}</span>\n<span class=\"c\"># echo ${addr}</span>\n\n<span class=\"c\"># JSONファイルをエクスポート</span>\n<span class=\"nb\">echo </span>JSON data save to <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json...\ntshark <span class=\"nt\">-r</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-Y</span> <span class=\"s2\">\"usb.src==</span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">addr</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span> <span class=\"nt\">-T</span> json <span class=\"o\">></span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json\n\n<span class=\"c\"># JSON->CSV 変換</span>\npython json_read.py <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.csv\n\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。キャプチャ時間を秒で設定する。省略時は2秒。<br />\n出力されるファイル名は実行時の時刻で作成された文字列に各拡張子を付加したもの。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash cap.sh <span class=\"o\">[</span>キャプチャ時間<span class=\"o\">(</span>sec<span class=\"o\">)]</span>\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>なんかパラメータチェックが一番長いなぁ…😅</p>\n\n<p>33行目でパケットキャプチャ実行。</p>\n\n<p>35~41行目で対象USB機器のアドレス(バス番号、デバイス番号)を取得している。<br />\n36行目の<code class=\"language-plaintext highlighter-rouge\">grep</code>のパラメータは対象となるUSB機器に合わせて変更してちょ。<br />\nエンドポイント番号は対象機器によって固定なので、調べてね。\n分からなかったら、キャプチャしたデータをWiresharkで読み込んで確認してちょ。</p>\n\n<p>46行目でキャプチャしたファイルをJSONファイルにエクスポート。</p>\n\n<p>49行目でJSON→CSV変換。</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>これで<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順をスクリプトイッパツで完了できる。<br />\nま、特定環境でしか試してないから、どんな環境でも使えるとは限らないけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージ(2021.1)をインストール(追加)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージ(2021.1)をインストール(追加)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2021.1対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a>で\nubuntuへopenVINO 2020.3のインストールしたが、今回は 2021.1 を追加インストールしたのでメモ。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>前に登録したときに通知されたURLから「Choose Version」でバージョン選んでダウンロードできる。<br />\n新しく登録しなても大丈夫(登録方法は<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>参照)。</p>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>これは前回と同じ。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫だが、<br />\ncmakeは<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたバージョンだと古くてNGといわれてしまうので、<br />\n別途本家からダウンロードしてインストールする(ubuntu 18.04の場合。20.04だとたぶん<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたので大丈夫)。</p>\n\n<ul>\n  <li>既に<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストール済みの場合は、アンインストールする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt purge <span class=\"nt\">--auto-remove</span> cmake\n</code></pre></div>    </div>\n  </li>\n  <li>本家からダウンロードして展開\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/Kitware/CMake/releases/download/v3.18.4/cmake-3.18.4-Linux-x86_64.tar.gz  \n<span class=\"nb\">tar </span>xzvf cmake-3.18.4-Linux-x86_64.tar.gz \n</code></pre></div>    </div>\n  </li>\n  <li>/opt ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv </span>cmake-3.18.4-Linux-x86_64 /opt/\n</code></pre></div>    </div>\n  </li>\n  <li>/usr/bin ディレクトリにシンボリックリンク作成\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /opt/cmake-3.18.4-Linux-x86_64/bin/<span class=\"k\">*</span> /usr/bin/\n</code></pre></div>    </div>\n  </li>\n  <li>バージョン確認\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">--version</span> \n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>インストール手順も<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫。</p>\n\n<p>完了したらこれが表示されるページのURLは以下に変更されている。<br />\n<a href=\"https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<p>2020.3インストール済みだと端折っても大丈夫かと思ったけど、微妙にパッケージ増えてたりするので、再度やった方が良い。<br />\n環境変数の設定のために、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に記述する処理は以下に変更(<code class=\"language-plaintext highlighter-rouge\">openvino</code>→<code class=\"language-plaintext highlighter-rouge\">openvino_2021</code>)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\n<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を実行すると、再度<code class=\"language-plaintext highlighter-rouge\">apt</code>で<code class=\"language-plaintext highlighter-rouge\">cmake</code>がインストールされてしまいます。<br />\nopenVINOのインストール完了後であれば<code class=\"language-plaintext highlighter-rouge\">cmake</code>のバージョンが古くても大丈夫ですが、<br />\n気になるなら、再度アンインストールとシンボリックリンクの作成を行います。<br />\n(実行前に<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を編集してcmake消しておいても良いけど)</p>\n</blockquote>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>これは2020.3インストール済みだと端折ってもOK。<br />\n初めてインストールなら<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>を参照。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をセットアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をセットアップする</h1>\n      <p>Jetson nano をセットアップする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>本稿はJetoack4.4での手順です。<br />\nJetpack4.6のときのメモは<a href=\"/memoBlog/2021/09/13/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする(Jetpack4.6)</a> にあります。</p>\n\n<p>Nvidiaの<a href=\"https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/\">Jetson nano</a>をセットアップしたときのメモ</p>\n\n<h1 id=\"参照先\">参照先</h1>\n<ul>\n  <li><a href=\"https://monoist.atmarkit.co.jp/mn/articles/1905/30/news029.html\">「Jetson Nano」の電源を入れて立ち上げる</a>\n    <ul>\n      <li>わりと詳しく書いてある</li>\n    </ul>\n  </li>\n  <li><a href=\"https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit\">Getting Started With Jetson Nano Developer Kit </a>\n    <ul>\n      <li>本家</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"sdカードの作成\">SDカードの作成</h1>\n<p>参照先の通り。</p>\n\n<p>ただし、参照先のSDカードイメージへのリンクは古いので、は以下から最新版をダウンロードする(古いのも下の方を探せば出てくる)</p>\n<ul>\n  <li><a href=\"https://developer.nvidia.com/embedded/downloads\">Jetson Download Center</a></li>\n</ul>\n\n<p>SDカード書き込みは記事に書かれた balenaEtcher でなく WIN32DiskImager でも大丈夫だが、<br />\nbalenaEtcher は zipファイルを解凍せずにSDカードに書き込めるので便利。<br />\nちなみに、<em>balena</em> はイタリア語で <em>鯨</em> の意味らしい…全然関係ないけど…</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストール先のSDカードは32GB必須みたい。<br />\n16GBだとインストールしただけで「残り少ない」と言われてしまう。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSDカードスロットが分かりにくいところにある(開発ボード側ではなく、モジュール側の裏側)。<br />\nシリアルコンソール繋いでるとケーブルが邪魔で特に挿抜しにくい…</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\n一度このイメージを書き込んだSDカードは、以後Windowsから認識されなくなる。<br />\nよって、SDフォーマッタやディスクイメージ書き込みツールから新たに書き込みできなくなってしまう。\nこれは書き込んだSDカードにFATのパーティションが存在しないためのよう。<br />\n(RaspberryPiはbootパーティションとしてFATパーティションを持っているので認識されるようだ)</p>\n\n  <p>コントロールパネル→管理ツール→コンピュータの管理を起動して、<br />\n記憶域の下のディスクの管理からSDカード上の不明なパーティションを解放し、<br />\nそこに新たにFATパーティションを作成すればWindowsから認識されるようになる。<br />\nもちろん、他のUbuntuマシンで書き換えちゃうのもアリだけど。。。</p>\n</blockquote>\n\n<h1 id=\"シリアルコンソールの使用\">シリアルコンソールの使用</h1>\n<p>シリアルコンソールが必要なら接続できる。<br />\n特に設定等は必要ない。  <br />\n接続端子は以下を参照</p>\n<ul>\n  <li><a href=\"https://www.jetsonhacks.com/2019/04/19/jetson-nano-serial-console/\">Jetson Nano – Serial Console</a>\nの 「Wiring」の下の「Jetson Nano B01」を参照。</li>\n</ul>\n\n<p>シリアルポートの設定は115200bps/8bit/none/1bit/none</p>\n\n<blockquote>\n  <p>[!WARNING]\nJ41(RaspberryPi互換の40pinヘッダ)のUART端子はコンソールとして動作していないみたい。<br />\ngettyが動いてないみたいなので。  <br />\nたぶん、<code class=\"language-plaintext highlighter-rouge\">/etc/systemd/nvgetty.sh</code> に<code class=\"language-plaintext highlighter-rouge\">ttyTHS2</code>の設定を追加すればできるようになる感じだけど、試してないので詳細不明。<br />\nJ41のUARTを汎用UARTとして使用するには、以下を参照。</p>\n  <ul>\n    <li><a href=\"https://www.jetsonhacks.com/2019/10/10/jetson-nano-uart/\">Jetson Nano – UART</a></li>\n  </ul>\n</blockquote>\n\n<p>その他、コネクタ類の配置が分かりにくい場合は、\n<a href=\"https://developer.download.nvidia.com/assets/embedded/secure/jetson/Nano/docs/NV_Jetson_Nano_Developer_Kit_User_Guide.pdf?yIbsUqvBKxI1G6r3WW7cOdheZGv2-eSfaFW_kMt3dSgi0NJ7h77OwFHr5b-rquc3IX7Tyrt8FV6IKD4DHqvP4_LzhWt55tb071gqXlNGwBPYCOC5pnEKAla8D-B82bPjhQMykANFyn-EhxZRHC8AIBYWuVwwwXVPWtCOjs34Tg50oBdN0vBNoyUlZMRFXLNJ2to\">JETSON NANO DEVELOPER KIT</a>\nのP22 に<strong>Developer kit module and carrier board: rev B01 top view</strong>として配置図が掲載されているので参照のこと。</p>\n\n<h1 id=\"firstboot\">FirstBoot</h1>\n<p>最初のブートでUbuntuのセットアップを行う。<br />\nこれも参照先の通り。<br />\n終わったら、何はともあれ最新版にアップデート。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ここで一旦リブートしておく。</p>\n\n<p>その他こまごました設定はこちらが参考になるかも。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/05/08/ubuntu_native.html\">UbuntuをNative環境にインストールする(18.04)</a></li>\n</ul>\n\n<p>インストールしたパッケージ\ngnome-tweaks\ndconf-editor\nsamba</p>\n<blockquote>\n  <p>[!NOTE]\nmin/max/closeボタンがウィンドウ右側に移動できない…\nちょっとストレス…</p>\n</blockquote>\n\n<h1 id=\"その他設定\">その他設定</h1>\n<h2 id=\"ウィンドウマネージャをunityからubuntuに変更する\">ウィンドウマネージャをUnityからubuntuに変更する</h2>\n<p>Unityは使いにくくて嫌(個人の見解デス)なので、Ubuntuに変更する(変更しなくても良い)。\n自動ログインしている場合は、一旦ログアウトして、<br />\n再ログインする際に、「サインイン」ボタンの左にある歯車アイコンをクリック→Ubuntuを選択してから<br />\nログインすると、ウィンドウマネージャがUbuntuに変更されている。<br />\n次回ログイン(自動ログインでも)は何もしなくても前回のウィンドウマネージャが選択される。</p>\n<blockquote>\n  <p>[!NOTE]\nUbuntuに変えると min/max/closeボタンがウィンドウ右側に移動できてる。<br />\n結果オーライ😅</p>\n</blockquote>\n\n<h2 id=\"sshでの接続\">SSHでの接続</h2>\n<p>特に設定などは必要ない。<br />\nTeraTermなどで接続すれば良い。\nUbuntuではmDNSが動いているので、«マシン名».localでアクセスできる。</p>\n\n<p>コマンドは以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\"C:\\Program Files (x86)\\teraterm\\ttermpro.exe\" /auth=password /user=«ユーザ名» /passwd=«パスワード» «JetsonのIPアドレス or マシン名.local»\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nSSHやmDNSは立ち上がるまで少し時間がかかるみたいなので、<br />\n起動後数十秒程度待ってから接続した方が良い。</p>\n</blockquote>\n\n<h3 id=\"ssh接続がタイムアウトする対策\">SSH接続がタイムアウトする対策</h3>\n<p>SSH接続したターミナルを触らずにしばらく置いておくと、タイムアウトしてクローズされてしまう。\nこれを防ぐにはクライアント側からkeep-aliveパケットを定期的に送信してやれば良いらしい。</p>\n\n<p>Teratermの場合、「設定」→「SSH」→「ハートビート(keep-alive)」を「8」とかに設定し、保存。\n次回接続時はこの保存した設定ファイルを読み込む</p>\n\n<h3 id=\"シリアルコンソールssh接続でguiウィンドウを表示できるようにする\">シリアルコンソール/SSH接続でGUIウィンドウを表示できるようにする</h3>\n<p>シリアルコンソール/SSH接続でGUIウィンドウを表示できるようにするには、\nWindowsPCなどでX-Serverを動作させておき、<br />\nそこに出力するようにすればよい。<br />\nJetson側は<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加しておく。<br />\nここのIPアドレスはX-Serverが動作しているマシンのIPアドレスに変更すること。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XX.XX:0.0\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"リモートデスクトップの設定\">リモートデスクトップの設定</h1>\n<p>TigerVNC はちょっと動作があやしいので、やめておいて、Desktop Sharing(Vino)を使うことにする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f#%E6%96%B9%E6%B3%952-desktop-sharingvino%E3%82%92%E4%BD%BF%E3%81%86\">Jetson Nanoにリモートデスクトップ(VNC)環境を用意する</a></li>\n  <li><a href=\"https://www.hackster.io/news/getting-started-with-the-nvidia-jetson-nano-developer-kit-43aa7c298797\">Getting Started with the NVIDIA Jetson Nano Developer Kit</a> の 「Enabling Desktop Sharing」</li>\n</ul>\n\n<p>この手順はウィンドウマネージャがUnityで実行しています。 ウィンドウマネージャをUbuntuに変更していると少し手順が違うかもしれませんので、\nウィンドウマネージャをUbuntuに変更している場合はUnityに戻してから設定してください。<br />\n設定完了後はUbuntuに再変更しても問題ありません。</p>\n\n<p>以下手順の再掲。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml</code>に以下のパッチを当てる</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- org.gnome.Vino.gschema.xml.org      2020-10-19 06:21:32.034728957 +0900\n</span><span class=\"gi\">+++ org.gnome.Vino.gschema.xml  2020-10-19 06:22:30.887994965 +0900\n</span><span class=\"p\">@@ -154,5 +154,14 @@</span>\n       </description>\n       <default>true</default>\n     </key>\n<span class=\"gi\">+    <key name='enabled' type='b'>\n+      <summary>Enable remote access to the desktop</summary>\n+        <description>\n+          If true, allows remote access to the desktop via the RFB\n+          protocol. Users on remote machines may then connect to the\n+          desktop using a VNC viewer.\n+        </description>\n+      <default>false</default>\n+    </key>\n</span>   </schema>\n </schemalist>\n</code></pre></div></div>\n<ul>\n  <li>以下のコマンドを実行(これで「システム設定」に「デスクトップの共有」アイコンが表示されるようになる)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>glib-compile-schemas /usr/share/glib-2.0/schemas\n</code></pre></div>    </div>\n  </li>\n  <li>GUI画面から「システム設定」→「デスクトップの共有」(ユーザ向けカテゴリの中にある)\n    <ul>\n      <li>「Sharing」カテゴリ\n        <ul>\n          <li>「Allow other users to view your desktop」にチェックを<em>入れる</em></li>\n          <li>「Allow other users to control your desktop」にチェックを<em>入れる</em></li>\n        </ul>\n      </li>\n      <li>「セキュリティ」カテゴリ\n        <ul>\n          <li>「You must confirm each access to this machine」のチェックを<em>はずす</em></li>\n          <li>「Requwire the user to enter this password」にチェックを<em>入れて</em>パスワード設定</li>\n          <li>「Automatically configure UPnP router to open and forward ports」のチェックを<em>はずす</em></li>\n        </ul>\n      </li>\n      <li>「Show Notification Area Icon」カテゴリ\n        <ul>\n          <li>「Only when someone is connected」を選択\n            <blockquote>\n              <p>[!NOTE]\nウィンドウマネージャがUbuntuの時は「設定」で設定する。\n左側の「共有」カテゴリを選択、「画面共有」をクリック</p>\n              <ul>\n                <li>「このスクリーンの操作する接続を許可する」をチェック</li>\n                <li>「アクセスオプション」で「パスワードを要求する」を選択し、パスワード設定</li>\n                <li>「ネットワーク」で「有線接続1」のスライドスイッチで「オン」を選択\n左上のスライドスイッチで「オン」を選択\nで出来ると思うけど、出来なかったらUnityで上の方法で設定した後、再度Ubuntuに切り替えてちょ。</li>\n              </ul>\n            </blockquote>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>「自動起動するアプリケーション」を起動\n    <blockquote>\n      <p>[!NOTE]\n「コンピュータを検索」で「自動」または「session」と入力すると出てくる\n日本語環境だと「startup」で出てこないみたい…</p>\n    </blockquote>\n    <ul>\n      <li>「追加」ボタンをクリック\n        <ul>\n          <li>名前に「Vino」</li>\n          <li>コマンドに「/usr/lib/vino/vino-server」</li>\n          <li>説明に「VNC server」\nー と入力して「追加」をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>以下のコマンドを実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.Vino prompt-enabled <span class=\"nb\">false</span>\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\nこれはVinoの暗号化方式がWindowsと互換性がないための措置で、<br />\n暗号化を無効化しているらしい。<br />\ndconf-editorでも設定できる。</p>\n    </blockquote>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nVNC使う場合は自動ログインをONしておかないといけない<br />\n設定箇所はぐぐってちゃぶだい…😅</p>\n</blockquote>\n\n<ul>\n  <li>リブートする</li>\n  <li>ホストPCからRealVNCのVNC ViewerやUltraVNC viewerなどで接続する</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nVNCは反応速度が鈍いので、ちょっと使いにくい。<br />\n普段はSSHとsambaとホスト側のX-Serverで動かすのが良いかも…</p>\n</blockquote>\n\n<h1 id=\"追加情報\">追加情報</h1>\n<p>ipv6を無効にしたい(ネットワーク環境によっては無効にした方が良い)場合は、<br />\n<a href=\"/memoBlog/2020/05/26/ubuntu_koneta.html\">ubuntu 小ネタ集</a>の\n「ubuntu 18.04 で IPv6を無効にする方法」 にしたがって設定する。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano のSDカードをバックアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano のSDカードをバックアップする</h1>\n      <p>Jetson nano のSDカードをバックアップする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2020/10/23/Jetson_nano_install.html\">Jetson nano をセットアップする</a> \nでセットアップしたSDカードをバックアップしておけば逐一セットアップ作業を行わなくても環境を復元できます。</p>\n\n<p>ただ、そのままSDカードをイメージファイル化しただけでは復元するSDカードのサイズが微妙に小さい場合などは、復元できなくなってしまいます。<br />\nそこで、バックアップしtイメージファイル内のパーティションサイズを縮小し、イメージファイルを小さくするスクリプトを用意しました。</p>\n\n<p>この作業はubuntu PC上で行います。</p>\n\n<p>この方法、およびスクリプトはRaspberryPi用SDカードでも使用できます。</p>\n\n<h1 id=\"sdカードのバックアップ\">SDカードのバックアップ</h1>\n<blockquote>\n  <p>[!WARNING]\nJetson用SDカードはFATパーティションが存在しないため、<br />\nWindowsPCではバックアップツールがSDカードを認識できず、バックアップできません。</p>\n</blockquote>\n\n<ul>\n  <li>ubuntu PCにバックアップしたいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>SDカードイメージをファイルにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">of</span><span class=\"o\">=</span>«出力ファイル» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n  <li>ubuntu PCからSDカードを抜去</li>\n</ul>\n\n<h1 id=\"ディスクイメージファイルの縮小\">ディスクイメージファイルの縮小</h1>\n\n<p>バックアップしたイメージファイルはSDカード容量と同じサイズになっています。<br />\nディスクイメージを縮小するために <a href=\"/memoBlog/misc/stock/diskimage_shrink.sh\">このスクリプト</a> をダウンロードして実行します。</p>\n\n<p>まず、必要なツールをインストールしておきます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install </span>kpartx\n</code></pre></div></div>\n\n<p>ダウンロードしたスクリプトを実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash diskimage_shrink.sh «入力イメージファイル» «出力イメージファイル» \n</code></pre></div></div>\n<p>出力イメージファイルが既に存在する場合は、上書きするか聞かれますので、yまたはnで指定してください。</p>\n\n<p>最初に入力イメージファイルから出力イメージファイルへコピーを行います。<br />\nコピーが終了すると、<code class=\"language-plaintext highlighter-rouge\">sudo</code>実行するためのパスワードを聞かれますので、入力してください。<br />\n縮小するパーティションサイズを計算した後、\n現在のパーティションサイズと縮小後のパーティションサイズが表示されます。<br />\n各サイズが正しければ、yを入力してパーティションサイズの修正を行いますが、\n一般的に危険な処理なので、「警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?」と再度確認されます。<br />\nyを入力して実行してください。</p>\n\n<p>その後、さらに ファイルサイズを切り詰めます。</p>\n\n<p>処理が終了すると、以下のメッセージが表示されますので、これにしたがって後の処理を行ってください。<br />\nRaspberryPi用SDカードはMBRパーティションなので<code class=\"language-plaintext highlighter-rouge\">gdisk</code>の処理は不要です。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n<p>実行例を以下に示します。<br />\n入力コマンドは<code class=\"language-plaintext highlighter-rouge\"># =========</code>で囲んであります。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># =========================================================================\n/work2$ bash diskimage_shrink.sh jetson_sd_20201022_2.img XXXX.img\n# =========================================================================\nCopy image file...\n>f+++++++++ jetson_sd_20201022_2.img\n 30,953,963,520 100%   26.97MB/s    0:18:14 (xfr#1, to-chk=0/1)\nGet partition info...\n対象パーティション番号 : 1\nImage file mapping...\n[sudo] <<ユーザ>> のパスワード: «パスワードを入力»\nadd map loop18p1 (253:0): 0 60313600 linear 7:18 28672\nadd map loop18p2 (253:1): 0 256 linear 7:18 2048\nadd map loop18p3 (253:2): 0 896 linear 7:18 4096\nadd map loop18p4 (253:3): 0 1152 linear 7:18 6144\nadd map loop18p5 (253:4): 0 128 linear 7:18 8192\nadd map loop18p6 (253:5): 0 384 linear 7:18 10240\nadd map loop18p7 (253:6): 0 768 linear 7:18 12288\nadd map loop18p8 (253:7): 0 128 linear 7:18 14336\nadd map loop18p9 (253:8): 0 896 linear 7:18 16384\nadd map loop18p10 (253:9): 0 896 linear 7:18 18432\nadd map loop18p11 (253:10): 0 1536 linear 7:18 20480\nadd map loop18p12 (253:11): 0 128 linear 7:18 22528\nadd map loop18p13 (253:12): 0 160 linear 7:18 24576\nadd map loop18p14 (253:13): 0 256 linear 7:18 26624\nLOOP device : /dev/mapper/loop18p1\n現在のパーティションサイズ   : 29450MiB\n縮小後のパーティションサイズ : 15637MiB\nパーティションを縮小しますか? [y/N]: y\nPartition shrinking...\ne2fsck 1.44.1 (24-Mar-2018)\nPass 1: Checking iノードs, blocks, and sizes\nPass 2: Checking ディレクトリ structure\nPass 3: Checking ディレクトリ connectivity\nPass 4: Checking reference counts\nPass 5: Checking グループ summary information\n/dev/mapper/loop18p1: 199065/1881264 files (0.2% non-contiguous), 3701166/7539200 blocks\nresize2fs 1.44.1 (24-Mar-2018)\nResizing the filesystem on /dev/mapper/loop18p1 to 4003167 (4k) blocks.\nBegin pass 2 (max = 55)\nRelocating blocks             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nBegin pass 3 (max = 231)\nScanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nThe filesystem on /dev/mapper/loop18p1 is now 4003167 (4k) blocks long.\n\n警告: 管理者権限がありません。パーミッションに注意してください。\n警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?\nはい(Y)/Yes/いいえ(N)/No? y                                               \nTruncate image file size...\nReleas image file mapping...\nloop deleted : /dev/loop18\n******** Done!! ********\n\n\n\n対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\n\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n\n\n\n# =========================================================================\n/work2$ gdisk XXXX.img \n# =========================================================================\nGPT fdisk (gdisk) version 1.0.3\n\nWarning! Disk size is smaller than the main header indicates! Loading\nsecondary header from the last sector of the disk! You should use 'v' to\nverify disk integrity, and perhaps options on the experts' menu to repair\nthe disk.\nCaution: invalid backup GPT header, but valid main header; regenerating\nbackup header from main header.\n\nWarning! Error 25 reading partition table for CRC check!\nWarning! One or more CRCs don't match. You should repair the disk!\n\nPartition table scan:\n  MBR: protective\n  BSD: not present\n  APM: not present\n  GPT: damaged\n\n****************************************************************************\nCaution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\nverification and recovery are STRONGLY recommended.\n****************************************************************************\n\nCommand (? for help): b\nEnter backup filename to save: backup.gpt\nThe operation has completed successfully.\n\nCommand (? for help): r\n\nRecovery/transformation command (? for help): d\n\nRecovery/transformation command (? for help): w\nCaution! Secondary header was placed beyond the disk's limits! Moving the\nheader, but other problems may occur!\n\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\nPARTITIONS!!\n\nDo you want to proceed? (Y/N): y\nOK; writing new GUID partition table (GPT) to XXXX.img.\nWarning: The kernel is still using the old partition table.\nThe new table will be used at the next reboot or after you\nrun partprobe(8) or kpartx(8)\nThe operation has completed successfully.\n\n\n\n# =========================================================================\n/work2$ sudo parted -m XXXX.img unit GiB print\n# =========================================================================\nBYT;\n/work2/XXXX.img:15.3GiB:file:512:512:gpt::;\n2:0.00GiB:0.00GiB:0.00GiB::TBC:;\n3:0.00GiB:0.00GiB:0.00GiB::RP1:;\n4:0.00GiB:0.00GiB:0.00GiB::EBT:;\n5:0.00GiB:0.00GiB:0.00GiB::WB0:;\n6:0.00GiB:0.01GiB:0.00GiB::BPF:;\n7:0.01GiB:0.01GiB:0.00GiB::BPF-DTB:;\n8:0.01GiB:0.01GiB:0.00GiB::FX:;\n9:0.01GiB:0.01GiB:0.00GiB::TOS:;\n10:0.01GiB:0.01GiB:0.00GiB::DTB:;\n11:0.01GiB:0.01GiB:0.00GiB::LNX:;\n12:0.01GiB:0.01GiB:0.00GiB::EKS:;\n13:0.01GiB:0.01GiB:0.00GiB::BMP:;\n14:0.01GiB:0.01GiB:0.00GiB::RP4:;\n1:0.01GiB:15.3GiB:15.3GiB:ext4:APP:;\n\n\n\n# =========================================================================\n/work2$ ls -la jetson_sd_20201022_2.img y.img \n# =========================================================================\n-rw-r--r-- 1 user  user 30953963520 10月 22 15:42 jetson_sd_20201022_2.img\n-rw-r--r-- 1 user  user 16422139904 10月 25 07:00 y.img\n</code></pre></div></div>\n\n<h1 id=\"新しいsdカードにバックアップを復元\">新しいSDカードにバックアップを復元</h1>\n\n<p>イメージファイルからSDカードへのコピーはWindowsマシンで行っても良いですが、ここではubuntu PCで行う方法について記載します。</p>\n\n<ul>\n  <li>ubuntu PCに新しいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>バックアップしたイメージファイルをSDカードにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«入力ファイル» <span class=\"nv\">of</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h1 id=\"新しいsdカードのパーティションを拡張\">新しいSDカードのパーティションを拡張</h1>\n\n<p>バックアップした際にパーティションサイズを縮小してあるため、そのままのSDカードではディスクの残り容量がわずかしかありません。<br />\nそこで、パーティションサイズを拡張して容量を増加させます。</p>\n\n<p>この作業はubuntu PCであらかじめ行うか、またはターゲットマシンでブートした後に行います。</p>\n\n<p>パーティション操作プログラム<code class=\"language-plaintext highlighter-rouge\">gparted</code>を使用します。<br />\nインストールされていない場合は、<code class=\"language-plaintext highlighter-rouge\">sudo apt install gparted</code>でインストールしておいてください。</p>\n\n<ul>\n  <li>gpartedを起動\n    <ul>\n      <li>Libparted Warning ダイアログで”Not all of the space available to ~”と出たらFixをクリック</li>\n      <li>Libparted Warning ダイアログで”The backup GPT table is corrupt, but the primary appears OK, so that will be used.”と出たらOKをクリック<br />\n以降も何度か出るが、以下の操作がすべて終わればbackup GPTが新たに作成されるので問題なし。<br />\n(これは、ディスクイメージを縮小したときにgdiskコマンドを実行しなかった場合に出ます)</li>\n      <li>Gparted→デバイスで<code class=\"language-plaintext highlighter-rouge\">«SDカードデバイス»</code>`を選択</li>\n      <li>図の<code class=\"language-plaintext highlighter-rouge\">«SDカードのパーティション»</code> を右クリック→「リサイズ/移動」をクリック\n        <ul>\n          <li>「新しいサイズ」の欄に上にある「最大サイズ」以下の値を入力</li>\n          <li>「リサイズ」をクリック</li>\n        </ul>\n      </li>\n      <li>「編集(E)」→「保留中の全ての操作を適用する(A)」をクリック\n        <ul>\n          <li>「本当に保留中の操作を適用してもよろしいですか?」と聞かれるので、「適用」をクリック</li>\n        </ul>\n      </li>\n      <li>処理が完了したら「閉じる」をクリック</li>\n    </ul>\n  </li>\n  <li>gpartedを終了</li>\n</ul>\n\n<p>ターゲットマシンで実行している場合は、そのまま使用できます。<br />\nubuntuマシンで実行した場合は、SDカードを取り外してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をUSBドライブからブートできるようにする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をUSBドライブからブートできるようにする</h1>\n      <p>Jetson nano をUSBドライブからブートできるようにする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>本稿はJetoack4.4での手順です。<br />\nJetpack4.6のときのメモは<a href=\"/memoBlog/2021/09/14/Jetson_usb_boot.html\" target=\"_blank\">Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</a> にあります。</p>\n\n<h1 id=\"概要\">概要</h1>\n<p>SDカードからブートすると、かなりディスクアクセスが遅いのと、ディスク容量を結構喰うので、<br />\nUSBドライブ(HDD/SSD)からブートできるようにする手順。<br />\n例によって、先人の知恵を借りるだけだけど(パクりとも言う)…(^^ゞ</p>\n\n<p>めんどくさそうだったけど、ほとんどスクリプト化されているので、意外と簡単。</p>\n\n<h1 id=\"参考\">参考</h1>\n<ul>\n  <li><a href=\"https://www.miki-ie.com/nvidiajetsonnano/nvidia-jetson-nano-usb-root/\">NVIDIA Jetson Nano USB ディスクをルート構成</a></li>\n  <li><a href=\"https://qiita.com/sgrowd/items/87d65383c0b74306ea7d\">Jetson Nanoの/をUSBドライブにしてSDカードを長生きさせる</a></li>\n  <li><a href=\"https://www.jetsonhacks.com/2019/09/17/jetson-nano-run-from-usb-drive/\">Jetson Nano – Run From USB Drive</a></li>\n</ul>\n\n<h1 id=\"手順を再掲しとく\">手順を再掲しとく</h1>\n\n<ul>\n  <li>SDカードからブート</li>\n  <li>USBドライブを接続&フォーマット</li>\n  <li>USBドライブをマウント</li>\n  <li>ツールのダウンロード\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/JetsonHacksNano/rootOnUSB.git\n<span class=\"nb\">cd </span>rootOnUSB/\n</code></pre></div>    </div>\n  </li>\n  <li>USBドライブからbootするためのinitrdを作成する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./addUSBToInitramfs.sh\n</code></pre></div>    </div>\n  </li>\n  <li>SDカードからUSBドライブへファイルをコピーする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./copyRootToUSB.sh <span class=\"nt\">-p</span> «コピー先パーティション»\n  <span class=\"c\"># 例: ./copyRootToUSB.sh -p /dev/sda1</span>\n</code></pre></div>    </div>\n  </li>\n  <li>実際にUSBドライブからブートするための設定\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/boot/extlinux/extlinux.conf</code>のバックアップをとっておく\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv</span> /boot/extlinux/extlinux.conf /boot/extlinux/extlinux.conf.org\n</code></pre></div>        </div>\n      </li>\n      <li>USBドライブのUUIDを調べる\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./diskUUID.sh\n</code></pre></div>        </div>\n        <p>→ <code class=\"language-plaintext highlighter-rouge\">XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</code>として得られる。</p>\n      </li>\n      <li><code class=\"language-plaintext highlighter-rouge\">sample-extlinux.conf</code> の <code class=\"language-plaintext highlighter-rouge\">APPEND</code>の行のUUID部分を以下のように変更する\n        <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    APPEND ${cbootargs} root=UUID=dc21871e-9db4-434c-98b4-713f55f807eb rootwait rootfstype=ext4\n                                     ↓↓↓↓↓\n    APPEND ${cbootargs} root=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rootwait rootfstype=ext4\n</code></pre></div>        </div>\n      </li>\n      <li>変更した<code class=\"language-plaintext highlighter-rouge\">sample-extlinux.conf</code>を<code class=\"language-plaintext highlighter-rouge\">/boot/extlinux/extlinux.conf</code>をコピー\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp </span>sample-extlinux.conf /boot/extlinux/extlinux.conf\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>リーブート</li>\n</ul>\n\n<p>リブート完了したらUSBドライブがrootにマウントされていることを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">mount</code>で確認しても良いけど、いっぱい出てきて鬱陶しいので<code class=\"language-plaintext highlighter-rouge\">df</code>で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">df</span> <span class=\"nt\">-h</span> /\n</code></pre></div></div>\n<p>こんな感じで行頭にマウント元が表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Filesystem      Size  Used Avail Use% Mounted on\n/dev/sda1       110G   14G   91G  13% /\n</code></pre></div></div>\n\n<h1 id=\"注意\">注意</h1>\n<p>USBドライブからブートできるようになっても、SDカードは取り外してはいけない。<br />\nu-bootからinitrdをロードするのはSDカードなので。</p>\n\n<p>ということは、<code class=\"language-plaintext highlighter-rouge\">apt update</code>でカーネルアップデートされても古いカーネルが使われちゃうなぁ…<br />\nそれはそのとき考えよう…<br />\nそんなに変わるもんでもないだろう。</p>\n\n<h1 id=\"独り言\">独り言</h1>\n<p>u-bootの環境変数見ると、そのままUSBブート出来そうな感じだったけど、<br />\n実際に<code class=\"language-plaintext highlighter-rouge\">usb start</code>してみたらエラーになる。<br />\nどうやらu-bootにはUSBドライバが入ってないらしい…<br />\nそんな環境変数残しとくな!!</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano に pyenv をインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano に pyenv をインストールする</h1>\n      <p>Jetson nano に pyenvをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>systemのpythonを使うのはちょっと嫌なので、仮想環境を使えるようにしておく。<br />\n<code class=\"language-plaintext highlighter-rouge\">venv</code>でもいいけど、やっぱり使い慣れた<code class=\"language-plaintext highlighter-rouge\">pyenv</code>+<code class=\"language-plaintext highlighter-rouge\">vertualenv</code>で。<br />\n基本的に<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a>と同じだけど、<br />\nJetpackでインストール済みで、<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできないパッケージがあるなど、<br />\nJetson nano 固有の設定等があるので、メモ。</p>\n\n<h1 id=\"手順再掲を含む\">手順(再掲を含む)</h1>\n\n<h2 id=\"pyenvをインストールする\">pyenvをインストールする</h2>\n<ul>\n  <li>必要なパッケージのインストール\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>pyenvとプラグインをダウンロード\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git            <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone git://github.com/pyenv/pyenv-update.git      <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境からJetpackでインストール済みのパッケージを参照できるようにしておく。<br />\n(pipでインストールできないみたいなので、お手軽な方法で解決)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/cv2          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/graphsurgeon <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/tensorrt     <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/uff          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>\n、とやりたいけど、ARM版は非対応らしいので…</p>\n    </blockquote>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>の修正<br />\n以下を追加しておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n<span class=\"c\">#jetson専用のインストール済みパッケージをコピっておく</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHONPATH</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span><span class=\"s2\">/jetson_pythonlib:</span><span class=\"nv\">$PYTHONPATH</span><span class=\"s2\">\"</span>\n</code></pre></div>    </div>\n  </li>\n  <li>ターミナル開きなおし or <code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を再読み込み</li>\n</ul>\n\n<h2 id=\"ベースとなるpythonのインストール\">ベースとなるpythonのインストール</h2>\n<p>バージョンは3.6.xでないとダメっぽい</p>\n\n<h2 id=\"python-のインストール\">python のインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.12\npyenv global 3.6.12\n</code></pre></div></div>\n<p>pip と setuptools のアップデート</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n<h2 id=\"その他\">その他</h2>\n<p>wheelが入ってると仮想環境を変えて同じモジュールをインストールするときに早いので、<br />\nインストールしておきたいが、各仮想環境に逐一インストールするのも面倒なので<br />\n共通に参照できるディレクトリにインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>wheel <span class=\"nt\">-t</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google spreadsheet にREST APIを追加(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google spreadsheet にREST APIを追加(その1)</h1>\n      <p>HTTP GETリクエストでGoogle spreadsheetに追記する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2019/10/01/spreadsheet.html\" target=\"_blank\">Node.jsでGoogle spreadsheet にデータを書き込む</a> で\nGoogle Drive APIでGoogle spreadsheet にデータを書き込む方法を紹介しましたが、\nクライアント側の処理をもっと簡単にするためにREST APIを追加してHTTP GETリクエストでデータを書き込めるようにしてみました。</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは操作されるspreadsheetを作成します。</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> を開く</li>\n  <li>左側「新規」→ 「Googleスプレッドシート」で新しいスプレッドシートが開く</li>\n  <li>無題のスプレッドシート」をクリックして名前を入力</li>\n</ul>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n<ul>\n  <li>メニューの「ツール」→「スクリプトエディタ」をクリック</li>\n</ul>\n\n<p>新しいウィンドウでスクリプトエディタが開きます。</p>\n<ul>\n  <li>コード.gs に以下のコードを入力</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストで渡されたデータをスプレッドシートの最終行に追加する\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">AddDataToSeet start</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n\n  <span class=\"c1\">// 記録するシート(現在のスプレッドシートのアクティブなシート)</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">sheet</span> <span class=\"o\">=</span> <span class=\"nx\">SpreadsheetApp</span><span class=\"p\">.</span><span class=\"nx\">getActiveSheet</span><span class=\"p\">();</span>\n\n  <span class=\"kd\">var</span> <span class=\"nx\">dt</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>    <span class=\"c1\">// 日付</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>            <span class=\"c1\">// デフォルト値</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv0が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv1が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv2が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n\n  <span class=\"c1\">// スプレッドシートの最終行に追加</span>\n  <span class=\"nx\">sheet</span><span class=\"p\">.</span><span class=\"nx\">appendRow</span><span class=\"p\">([</span><span class=\"nx\">dt</span><span class=\"p\">,</span> <span class=\"nx\">v0</span><span class=\"p\">,</span> <span class=\"nx\">v1</span><span class=\"p\">,</span> <span class=\"nx\">v2</span><span class=\"p\">]);</span>\n\n  <span class=\"c1\">// HTML表示データを生成</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">createTextOutput</span><span class=\"p\">();</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setMimeType</span><span class=\"p\">(</span><span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">MimeType</span><span class=\"p\">.</span><span class=\"nx\">TEXT</span><span class=\"p\">);</span>\n  <span class=\"c1\">// メッセージボディ</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setContent</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">set data:</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">date=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">dt</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v0=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v0</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v1=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v1</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v2=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v2</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"cm\">/**\n * GETリクエストの処理\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">doGet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 処理本体</span>\n  <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ndoGet関数のパラメータ<code class=\"language-plaintext highlighter-rouge\">e</code>については、<a href=\"https://developers.google.com/apps-script/guides/web\" target=\"_blank\">このへん</a>を参照してください。</p>\n</blockquote>\n\n<ul>\n  <li>右上の青いボタン「デプロイ」→「新しいデプロイ」をクリック\n    <ul>\n      <li>「デプロイタイプを選択してください」と言われるので、「種類の選択」横の歯車アイコンをクリック → 「ウェブアプリ」をクリック\n        <ul>\n          <li>「説明」に説明文を入力(省略可)</li>\n          <li>「ウェブアプリ」の「次のユーザとして実行」で「自分」を選択</li>\n          <li>「アクセスできるユーザ」を適切な範囲に設定  (「全員」にすればパスワードなしでアクセスできる)\n            <blockquote>\n              <p>[!NOTE]\ncurlなどでアクセスしたい場合は、「全員」にしておかないと、認証画面に飛んでしまい、アクセスが完了しません。</p>\n            </blockquote>\n          </li>\n          <li>「デプロイ」をクリック</li>\n        </ul>\n      </li>\n      <li>「このウェブ アプリケーションを使用するには、データへのアクセスを許可する必要があります。」と言われるので「アクセスを承認」をクリック</li>\n      <li>「アカウントの選択」が表示されるので、使用するアカウントを選択</li>\n      <li>「このアプリは Google で確認されていません」と言われるので、左下「詳細」をクリック\n        <ul>\n          <li>「無題のプロジェクト(安全ではないページ)に移動」をクリック</li>\n          <li>「無題のプロジェクトがGoogle アカウントへのアクセスをリクエストしています」と言われるので、「許可」をクリック</li>\n          <li>「新しいデプロイ」が表示される</li>\n          <li>一番下の「ウェブアプリ」のUARLをコピーして使用</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<p>例えば以下のコマンドでアクセスする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>curl <span class=\"nt\">-L</span> <span class=\"s2\">\"«上でコピーしたURL»?v0=1&v1=2&v2=3\"</span>\n</code></pre></div></div>\n\n<p>実行すると、対象のスプレッドシートの最終行に以下のデータが追加されます。</p>\n<ul>\n  <li>A列: 日付と時刻</li>\n  <li>B列: v0で指定した値</li>\n  <li>C列: v1で指定した値</li>\n  <li>D列: v2で指定した値</li>\n</ul>\n\n<p>スクリプトを修正した場合、再度「新しいデプロイ」を実行する必要がある。</p>\n\n<p>または、「デプロイ」→「デプロイをテスト」で表示されるURLを使用すると、デプロイせずに現在の最新ソースで実行できる。<br />\nただし、この場合、ユーザ認証が必須になってしまうので、ブラウザ等でアクセスする必要がある。<br />\nどうしてもcurlでアクセスしたい場合は、ヘッダに<code class=\"language-plaintext highlighter-rouge\">Authorization: Bearer «アクセストークン»</code>を追加してやれば良い。(あまりおススメはしないけど)<br />\nやり方は<a href=\"https://www.ka-net.org/blog/?p=12258\" target=\"_blank\">ここらへん</a>を参考にしてください。</p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>時刻の文字列を取得した場合、知らないタイムゾーンになっていて困ったときはタイムゾーンを変更すれば良い。</p>\n\n<p>タイムゾーンを変更するにはこちら。</p>\n<ul>\n  <li>画面左の歯車アイコン「プロジェクトの設定」をクリック\n    <ul>\n      <li>「「appsscript.json」マニフェスト ファイルをエディタで表示する」にチェックを入れる</li>\n    </ul>\n  </li>\n  <li>画面左の<>アイコン「エディタ」をクリックしてエディタに戻る\n    <ul>\n      <li>ファイル一覧に「appsscript.json」が追加されているのでクリック</li>\n      <li>タイムゾーンを指定している部分を   <code class=\"language-plaintext highlighter-rouge\">\"timeZone\": \"Asia/Tokyo\",</code> に変更</li>\n      <li>保存して再度デプロイ</li>\n    </ul>\n  </li>\n</ul>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google spreadsheet にREST APIを追加(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google spreadsheet にREST APIを追加(その2)</h1>\n      <p>Google Apps Scriptのライブラリ化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">Google spreadsheet にREST APIを追加 その1</a>   では\nSpreadsheetに埋め込んだスクリプトにすべて記述しましたが、 新しいSpreadsheetを作成する度にコードをコピーするのは大変ですし、\n何らかの不具合が見つかったときに複数のファイルをメンテナンスしなければならないのは現実的ではありません。<br />\nそこで、スプレッドシートにデータを登録する部分をライブラリ化し、Spreadsheetに埋め込んだスクリプトには最低限のコードだけ記載するようにしてみます。</p>\n\n<h1 id=\"手順\">手順</h1>\n<p>まずはスクリプトライブラリを作成します</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a>   を開く</li>\n  <li>左側「新規」→ 「その他」→「Google Apps Script」で新しいスクリプトエディタが開く\n    <ul>\n      <li>「無題のプロジェクト」をクリックして名前を入力</li>\n      <li>コード.gsに以下を入力(<a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">その1</a>  の<code class=\"language-plaintext highlighter-rouge\">AddDataToSeet()</code>と同一)</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストで渡されたデータをスプレッドシートの最終行に追加する\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">AddDataToSeet start</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n\n  <span class=\"c1\">// 記録するシート(現在のスプレッドシートのアクティブなシート)</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">sheet</span> <span class=\"o\">=</span> <span class=\"nx\">SpreadsheetApp</span><span class=\"p\">.</span><span class=\"nx\">getActiveSheet</span><span class=\"p\">();</span>\n\n  <span class=\"kd\">var</span> <span class=\"nx\">dt</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>    <span class=\"c1\">// 日付</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>            <span class=\"c1\">// デフォルト値</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv0が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv1が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv2が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n\n  <span class=\"c1\">// スプレッドシートの最終行に追加</span>\n  <span class=\"nx\">sheet</span><span class=\"p\">.</span><span class=\"nx\">appendRow</span><span class=\"p\">([</span><span class=\"nx\">dt</span><span class=\"p\">,</span> <span class=\"nx\">v0</span><span class=\"p\">,</span> <span class=\"nx\">v1</span><span class=\"p\">,</span> <span class=\"nx\">v2</span><span class=\"p\">]);</span>\n\n  <span class=\"c1\">// HTML表示データを生成</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">createTextOutput</span><span class=\"p\">();</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setMimeType</span><span class=\"p\">(</span><span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">MimeType</span><span class=\"p\">.</span><span class=\"nx\">TEXT</span><span class=\"p\">);</span>\n  <span class=\"c1\">// メッセージボディ</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setContent</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">set data:</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">date=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">dt</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v0=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v0</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v1=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v1</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v2=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v2</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<ul>\n  <li>右上の青いボタン「デプロイ」→「新しいデプロイ」をクリック\n    <ul>\n      <li>「デプロイタイプを選択してください」と言われるので、\n        <ul>\n          <li>「種類の選択」横の歯車アイコンをクリック → 「ライブラリ」をクリック</li>\n          <li>「説明」に説明文を入力(省略可)</li>\n          <li>「デプロイ」をクリック</li>\n        </ul>\n      </li>\n      <li>新しいデプロイウィンドウが表示されるので、「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>画面左の歯車アイコン「プロジェクトの設定」をクリック\n    <ul>\n      <li>「プロジェクトの設定」の真ん中あたりの「スクリプトID」をメモしておく</li>\n    </ul>\n  </li>\n</ul>\n\n<p>次に操作されるspreadsheetを作成します。</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a>   を開く</li>\n  <li>左側「新規」→ 「Googleスプレッドシート」で新しいスプレッドシートが開く</li>\n  <li>無題のスプレッドシート」をクリックして名前を入力</li>\n  <li>SpreadsheetにGoogle Apps Script(GAS)を追加します。\n    <ul>\n      <li>メニューの「ツール」→「スクリプトエディタ」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<p>新しいウィンドウでスクリプトエディタが開きます。</p>\n<ul>\n  <li>「ライブラリ」の横の+マーク(ライブラリを追加)をクリック</li>\n  <li>「ライブラリの追加」ウィンドウが開くので、「スクリプトID」の欄に上でメモしたスクリプトIDを入力し、「検索」をクリック</li>\n  <li>バージョンで使用するバージョンを選択(HAEAD(開発モード)を選択すると、デプロイするまえの最新ソースが使用される)</li>\n  <li>ID を設定します。\n    <blockquote>\n      <p>[!NOTE]\nID は node.jsで言うところの、以下の部分の「変数名」に相当する</p>\n      <div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">var</span> <span class=\"nx\">変数名</span> <span class=\"o\">=</span> <span class=\"nx\">require</span><span class=\"p\">(</span><span class=\"dl\">'</span><span class=\"s1\">モジュール名</span><span class=\"dl\">'</span><span class=\"p\">)</span>\n</code></pre></div>      </div>\n    </blockquote>\n  </li>\n  <li>コード.gs に以下のコードを入力</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストの処理\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">doGet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 処理本体</span>\n  <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">MySpreadsheetLib</span><span class=\"p\">.</span><span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>以降、(<a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">その1</a> のデプロイ作業と同一です。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Apps Script で LINE Notify</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Apps Script で LINE Notify</h1>\n      <p>Google Apps Script から LINE に通知を送る</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Google Apps Script(GAS)からリアルタイムな通知を送る方法としてLINEにメッセージを送ってみる。</p>\n\n<p>LINE Notify を使うとアクセストークンを取得すれば、REST APIで簡単にメッセージを送れるので、これを使うことにした。</p>\n\n<h1 id=\"前準備\">前準備</h1>\n\n<p><a href=\"https://qiita.com/iitenkida7/items/576a8226ba6584864d95\" target=\"_blank\">[超簡単]LINE notify を使ってみる</a>  を参考に、\nLINEの設定 および LINE Notifyのアクセストークンの取得を行っておいてください。</p>\n<blockquote>\n  <p>[!NOTE]\nトークルームでなく、『1:1でLINE Notifyから通知を受け取る』を選択した場合は、ID検索で「@linenotify」を検索して友だちに追加してください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://notify-bot.line.me/ja/\" target=\"_blank\">LINE Notifyホーム</a> <br />\n<a href=\"https://notify-bot.line.me/doc/ja/\" target=\"_blank\">ドキュメント</a></p>\n</blockquote>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは<a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> で新しいGoogle Apps Scriptのプロジェクトを作成します。</p>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n\n<ul>\n  <li>新しいウィンドウでスクリプトエディタが開きます。</li>\n  <li>コード.gs に以下のコードを入力してください。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">// アクセストークン </span>\n<span class=\"kd\">const</span> <span class=\"nx\">ACCESS_TOKEN</span> <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">«取得したアクセストークン»</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n\n<span class=\"cm\">/**\n * テスト用関数\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">myFunction</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 時刻文字列取得</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">date_str</span> <span class=\"o\">=</span> <span class=\"nx\">Utilities</span><span class=\"p\">.</span><span class=\"nx\">formatDate</span><span class=\"p\">(</span><span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">(),</span><span class=\"dl\">\"</span><span class=\"s2\">JST</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">yyyy/MM/dd hh:mm:ss</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">token</span> <span class=\"o\">=</span> <span class=\"nx\">ACCESS_TOKEN</span><span class=\"p\">;</span>\n  <span class=\"nx\">LINE_notify</span><span class=\"p\">(</span><span class=\"nx\">token</span><span class=\"p\">,</span> <span class=\"nx\">date_str</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">    てすとぉぉぉ</span><span class=\"dl\">\"</span> <span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n<span class=\"cm\">/**\n * メッセージ送信処理\n *\n * @param {string} token    - アクセストークン\n * @param {string} message  - 送信するメッセージ\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">LINE_notify</span><span class=\"p\">(</span><span class=\"nx\">token</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">){</span>\n    <span class=\"kd\">const</span> <span class=\"nx\">url</span> <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">https://notify-api.line.me/api/notify</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n    <span class=\"kd\">var</span> <span class=\"nx\">headers</span> <span class=\"o\">=</span> <span class=\"p\">{</span> \n      <span class=\"dl\">'</span><span class=\"s1\">Authorization</span><span class=\"dl\">'</span><span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">Bearer </span><span class=\"dl\">'</span> <span class=\"o\">+</span> <span class=\"nx\">token</span> \n    <span class=\"p\">};</span>\n    <span class=\"kd\">var</span> <span class=\"nx\">options</span> <span class=\"o\">=</span> <span class=\"p\">{</span> \n      <span class=\"dl\">'</span><span class=\"s1\">headers</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"nx\">headers</span> <span class=\"p\">,</span>\n      <span class=\"dl\">'</span><span class=\"s1\">method</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">post</span><span class=\"dl\">'</span> <span class=\"p\">,</span>\n      <span class=\"c1\">// encodeURIComponent()はなくても大丈夫っぽい...</span>\n      <span class=\"c1\">// 'payload' : 'message=' + encodeURIComponent(message)</span>\n      <span class=\"dl\">'</span><span class=\"s1\">payload</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">message=</span><span class=\"dl\">'</span> <span class=\"o\">+</span> <span class=\"nx\">message</span><span class=\"p\">,</span> \n      <span class=\"dl\">'</span><span class=\"s1\">muteHttpExceptions</span><span class=\"dl\">'</span><span class=\"p\">:</span> <span class=\"kc\">true</span>        <span class=\"c1\">// エラーが返ってきても例外発生させない</span>\n     <span class=\"p\">};</span> \n    <span class=\"kd\">var</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n\n    <span class=\"k\">try</span> <span class=\"p\">{</span>\n      <span class=\"c1\">// メッセージを送信 </span>\n      <span class=\"kd\">var</span> <span class=\"nx\">res</span> <span class=\"o\">=</span> <span class=\"nx\">UrlFetchApp</span><span class=\"p\">.</span><span class=\"nx\">fetch</span><span class=\"p\">(</span><span class=\"nx\">url</span> <span class=\"p\">,</span><span class=\"nx\">options</span><span class=\"p\">);</span>\n\n      <span class=\"kd\">var</span> <span class=\"nx\">resCode</span> <span class=\"o\">=</span> <span class=\"nx\">res</span><span class=\"p\">.</span><span class=\"nx\">getResponseCode</span><span class=\"p\">();</span>              <span class=\"c1\">// HTTP レスポンスステータスコード</span>\n      <span class=\"kd\">var</span> <span class=\"nx\">resBody</span> <span class=\"o\">=</span> <span class=\"nx\">JSON</span><span class=\"p\">.</span><span class=\"nx\">parse</span><span class=\"p\">(</span><span class=\"nx\">res</span><span class=\"p\">.</span><span class=\"nx\">getContentText</span><span class=\"p\">());</span>   <span class=\"c1\">// レスポンス本体はJSONなのでパースする</span>\n\n      <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nx\">resCode</span> <span class=\"o\">===</span> <span class=\"mi\">200</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// レスポンスが200 → 正常終了</span>\n        <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">SUCCESS: %s</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"nx\">resBody</span><span class=\"p\">.</span><span class=\"nx\">message</span><span class=\"p\">);</span>\n      <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// それ以外→エラーレスポンス</span>\n        <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"nx\">Utilities</span><span class=\"p\">.</span><span class=\"nx\">formatString</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">ERROR: status:%d  body:%s</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"nx\">resCode</span><span class=\"p\">,</span> <span class=\"nx\">resBody</span><span class=\"p\">.</span><span class=\"nx\">message</span><span class=\"p\">));</span>\n      <span class=\"p\">}</span>\n    <span class=\"p\">}</span> <span class=\"k\">catch</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n      <span class=\"c1\">// その他のエラー(DNSエラー、タイムアウトなど)は例外が発生する</span>\n      <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">ERROR: </span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">e</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<ul>\n  <li>「実行する関数」に<code class=\"language-plaintext highlighter-rouge\">myFunction</code>を選択(エディタの上、「実行ログ」の左の▼をクリックして選ぶ)\nー 「実行」をクリック</li>\n  <li>LINEに通知が届きます</li>\n</ul>\n\n<h1 id=\"最後に\">最後に</h1>\n\n<p>これだけだと大したことできないけど、ライブラリ化して他のサービスと組み合わせて使えばなんかのPUSH通知っぽく使えるかな?</p>\n\n<blockquote>\n  <p>[!NOTE]\nSpreadsheetの時のように、ウェブアプリにしようかと思ったら、もともとREST APIだから全然意味ないので関数作るだけにしておいた。<br />\n(POST使えない場合にGETで受け付けるラッパみたいなのは考えられなくはないけど)</p>\n</blockquote>\n\n<h1 id=\"参考\">参考</h1>\n\n<p>通知回数の上限は1000回/1時間/アクセストークンです。(そんなに送ったら鬱陶しいでしょうから問題ないかな?)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Apps Script で メール送信</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Apps Script で メール送信</h1>\n      <p>Google Apps Script から メールを送信する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Google Apps Script(GAS)からメールを送信してみます。</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは<a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> で新しいGoogle Apps Scriptのプロジェクトを作成します。</p>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n\n<ul>\n  <li>新しいウィンドウでスクリプトエディタが開きます。</li>\n  <li>コード.gs に以下のコードを入力してください。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * テスト用関数\n */</span>\n <span class=\"kd\">function</span> <span class=\"nx\">myFunction</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">sendGmail</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">XXXX@gmail.com</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">TEST</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">テストだよ~ん</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n\n<span class=\"cm\">/**\n * Gmail送信処理\n *\n * @param {string|string[]} address    - 送信先アドレス\n * @param {string} subject  - サブジェクト(最大250文字)\n * @param {string} message  - 送信するメッセージ\n * \n * @note 送信先アドレスが間違っていてもここではエラーにならず、送信元アドレスにエラーメールが返る\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">sendGmail</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">,</span> <span class=\"nx\">subject</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n\n  <span class=\"c1\">// アドレスが配列だったらカンマ区切りの文字列に変換する</span>\n  <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nb\">Array</span><span class=\"p\">.</span><span class=\"nx\">isArray</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n    <span class=\"nx\">address</span> <span class=\"o\">=</span> <span class=\"nx\">address</span><span class=\"p\">.</span><span class=\"nx\">join</span><span class=\"p\">(</span><span class=\"dl\">'</span><span class=\"s1\">,</span><span class=\"dl\">'</span><span class=\"p\">);</span>\n  <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// そのまま</span>\n  <span class=\"p\">}</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">options</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"na\">name</span><span class=\"p\">:</span> <span class=\"dl\">\"</span><span class=\"s2\">てすと</span><span class=\"dl\">\"</span>        <span class=\"c1\">// 送信者名を指定したい場合は入れる</span>\n    <span class=\"c1\">// , replyTo: \"ZZZZ@gmail.com\"     // Reply-To を指定したい場合は入れる</span>\n  <span class=\"p\">};</span>\n\n  <span class=\"c1\">// メール送信</span>\n  <span class=\"nx\">GmailApp</span><span class=\"p\">.</span><span class=\"nx\">sendEmail</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">,</span> <span class=\"nx\">subject</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">,</span> <span class=\"nx\">options</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n</code></pre></div></div>\n\n<ul>\n  <li>「実行する関数」に<code class=\"language-plaintext highlighter-rouge\">myFunction</code>を選択(エディタの上、「実行ログ」の左の▼をクリックして選ぶ)</li>\n  <li>「実行」をクリック</li>\n  <li>送信先アドレスへメールが送信されます</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n送信元アドレスにはこのスクリプトを実行しているGoogleユーザ(デプロイ設定によってはそのとき実行しているGoogleユーザ)が使用されます。<br />\noptionsで「from」フィールドを指定する事が出来ますが、このアドレスは送信元アドレスのaliasである必要があります。<br />\nそうでない場合は例外 Invalid argument がthrowされます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n送信先アドレスが間違っていてもここではエラーになりません。<br />\n送信元アドレスにエラーメール(subject:「Delivery Status Notification (Failure)」)が送られてきます。</p>\n</blockquote>\n\n<h1 id=\"最後に\">最後に</h1>\n\n<p>関数化する必要もないくらい簡単ですが😅</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 20.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 20.04のインストール</h1>\n      <p>Ubuntu 20.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>VirtualBox へのインストール前提で書いてます。<br />\nでも、仮想マシンの作成以外は同じかな。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2004-インストール媒体の入手\">Ubuntu 20.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら:\n<a href=\"https://www.ubuntulinux.jp/products/JA-Localized/download\" target=\"_blank\">Ubuntu Desktop 日本語 Remixのダウンロード</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを2048MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<p>以下の説明が図付きで分かりやすい:\n<a href=\"https://qiita.com/HirMtsd/items/225c20b77a7cd5194834\" target=\"_blank\">Windows10上のVirtualBoxにUbuntu20.04をインストール</a></p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面ロック を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから「デバイス」→「クリップボードの共有」→「双方向」<br />\nを選択。\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h3 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h2>\n<blockquote>\n  <p>[!NOTE]\n前のバージョンまでは、WMをGnome Flashbackに変更してたけど、<br />\n日本語入力とかと相性悪いみたいなので、やめといた方が無難<br />\nインストールする場合はここを参考に: <a href=\"https://goto-linux.com/ja/2020/3/13/ubuntu-20.04-gnome-flashback%E3%83%86%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%95%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB/\" target=\"_blank\">Ubuntu 20.04 Gnome Flashbackデスクトップのインストール</a></p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-session-flashback\n</code></pre></div>  </div>\n  <p>「GNOME Flashback(Compiz)」はなくなったらしい</p>\n</blockquote>\n\n<h2 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h2>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nUbuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h2>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"bashの設定変更\">bashの設定変更</h2>\n\n<p>~/.bashrcに以下を追記</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h2 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h2 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h2 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nFlashbackの場合は以下らしい。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.gnome-flashback.desktop.icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.gnome-flashback.desktop.icons show-trash <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h2>\n<p>なんとなく使いにくいので好みのデザインに変更。<br />\ndconf-editorでも良いよ(しつこい…)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h2 id=\"日本語入力\">日本語入力</h2>\n<p>前は設定必要だったけど、なんか大丈夫になったみたい</p>\n<blockquote>\n  <p>[!NOTE]\n以前の設定手順<br />\n右上の「A」または「あ」と書かれたアイコンをクリック→「テキスト入力設定」を選択\n一番下の「インストールされている言語の管理」をクリック\n「言語サポートが完全にはインストールされていません」と出るので「インストール」をクリック\n一旦log offして再log in\n右上のJaまたはMoと書かれたアイコンをクリック\n    Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)\nキーボードの全角/半角キーで切り替えられるようになる</p>\n</blockquote>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h2 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h2>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h2 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h2>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a></p>\n\n<p>リブート必要だが、以下のIPv6無効化とまとめてリブートでも可。</p>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>grubメニューの更新</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hosts は書き換えられないので、手動で書き換える</p>\n</blockquote>\n\n<p>IPアドレスの変更(固定アドレスにしたい場合)</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<p>まとめて実行するならこちら。<br />\n接続名があってるかは確認しておくこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># マシン番号の設定とホスト名の設定</span>\n<span class=\"nv\">number</span><span class=\"o\">=</span>30\n<span class=\"nv\">new_hostname</span><span class=\"o\">=</span>skull<span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span>\n\n<span class=\"c\"># HOSTNAMEの変更</span>\n<span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/ubuntu-20.*</span><span class=\"nv\">$/</span><span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span><span class=\"s2\">/\"</span> /etc/hosts\n\n<span class=\"c\"># HOST ONLY ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n\n<span class=\"c\"># BRIDGE ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2 メモ</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2 メモ</h1>\n      <p>WSL2に関するメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <blockquote>\n  <p>[!NOTE]\n<strong><a href=\"https:///memoBlog/2024/07/24/WSL_memo2.html\" target=\"_blank\">改訂版</a>があります。</strong></p>\n</blockquote>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"wsl2のインストール\">WSL2のインストール</h2>\n<p>参考: <a href=\"https://itengine.seesaa.net/article/479688577.html\" target=\"_blank\">WSL2をインストールしてみた</a></p>\n\n<h2 id=\"virtualboxとの共存\">Virtualboxとの共存</h2>\n<p>参考: <a href=\"https://qiita.com/hibohiboo/items/c17459e0af84d2059d21\" target=\"_blank\">Vagrant + Virtualbox 6.1.16 と WSL2 を同時に動かしたメモ</a></p>\n\n<h1 id=\"セットアップ\">セットアップ</h1>\n\n<h2 id=\"アップデート\">アップデート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n</code></pre></div></div>\n\n<h2 id=\"日本語化\">日本語化</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 日本語ランゲージパック</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>language-pack-ja\n<span class=\"c\"># ロケールの設定</span>\n<span class=\"nb\">sudo </span>update-locale <span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF8\n<span class=\"c\"># 日本語manページのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>manpages-ja manpages-ja-dev\n</code></pre></div></div>\n\n<h2 id=\"beepを消す\">BEEPを消す</h2>\n<p>鬱陶しいのでBEEPを消しておく。<br />\n参考: <a href=\"https://linuxfan.info/bow-stop-beep\" target=\"_blank\">Bash on Windowsでビープ音を消す方法</a></p>\n\n<ul>\n  <li>ターミナルのbeepを消して画面フラッシュにする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"set bell-style visible\"</span> <span class=\"o\">>></span> ~/.inputrc\n</code></pre></div>    </div>\n  </li>\n  <li>vimのbeepを消す\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"set visualbell t_vb=\"</span> <span class=\"o\">>></span> ~/.vimrc\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalの場合、<code class=\"language-plaintext highlighter-rouge\">settings.json</code>に各プロファイルの設定に\n以下の設定を追加すればbash、vim、その他一括して変更できる。</p>\n  <div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\"> </span><span class=\"nl\">\"bellStyle\"</span><span class=\"w\"> </span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visual\"</span><span class=\"err\">,</span><span class=\"w\">\n</span></code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"デフォルトshをbashに変更\">デフォルトshをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"ツール類インストール\">ツール類インストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> /proj /work\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n<p>参考:<a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a></p>\n\n<h2 id=\"nodenvのインストール\">nodenvのインストール</h2>\n<p>参考:<a href=\"/memoBlog/2019/06/28/nodenv.html\" target=\"_blank\">nodenvのインストール</a></p>\n\n<h2 id=\"bashrcの設定\">.bashrcの設定</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\[\\e</span><span class=\"s2\">[36m</span><span class=\"se\">\\]</span><span class=\"nv\">$WSL_DISTRO_NAME</span><span class=\"se\">\\[\\e</span><span class=\"s2\">[0m</span><span class=\"se\">\\]</span><span class=\"s2\">:</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n        <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n        <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"nb\">export </span><span class=\"nv\">VIRTUAL_ENV_DISABLE_PROMPT</span><span class=\"o\">=</span>1\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h1 id=\"起動時の初期ディレクトリをホームディレクトリにするための設定\">起動時の初期ディレクトリをホームディレクトリにするための設定</h1>\n\n<p>起動時の初期ディレクトリがホームディレクトリにならないので(SSHの場合は大丈夫なはず)、以下の方法で指定する。</p>\n\n<h3 id=\"windows-terminalのsettingjsonでの設定\">Windows TerminalのSetting.jsonでの設定</h3>\n<p><a href=\"https://ryotatake.hatenablog.com/entry/2019/08/15/windows_terminal_wsl\" target=\"_blank\">Windows Terminal + WSLでターミナル起動時のディレクトリをホームディレクトリにする</a></p>\n\n<h3 id=\"wtexeのコマンドラインで指定する場合\">wt.exeのコマンドラインで指定する場合</h3>\n\n<p>settings.jsonで設定してない場合や設定とは別のディレクトリを指定する場合は-dオプションで指定する。<br />\nホームディレクトリを指定する場合は以下。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">C:\\Users\\</span><span class=\"err\"><<ユーザ名>></span><span class=\"nx\">\\AppData\\Local\\Microsoft\\WindowsApps\\wt.exe</span><span class=\"w\"> </span><span class=\"nt\">-p</span><span class=\"w\"> </span><span class=\"s2\">\"«環境登録名»\"</span><span class=\"w\"> </span><span class=\"nt\">-d</span><span class=\"w\"> </span><span class=\"s2\">\"\\\\wsl</span><span class=\"err\">$</span><span class=\"s2\">\\«仮想環境名»\\home\\<<ユーザ名>>\"</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ -p で指定するのは仮想環境名ではなく、WindowsTerminal に登録した環境名(ドロップダウンリストに表示される名前)。 -d で指定するのは仮想環境名。同一でない場合は間違えないように注意。</p>\n\n<h3 id=\"wsl-コマンドで起動する場合\">wsl コマンドで起動する場合</h3>\n\n<p>使用中のターミナルを使って起動する場合はwslコマンドで起動する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">c:\\WINDOWS\\system32\\wsl.exe</span><span class=\"w\"> </span><span class=\"nx\">~</span><span class=\"w\"> </span><span class=\"nt\">-d</span><span class=\"w\"> </span><span class=\"s2\">\"仮想環境名\"</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ wsl コマンドのパラメータに <code class=\"language-plaintext highlighter-rouge\">~</code> を追加</p>\n\n<h1 id=\"pathにwindowsのpathを引き継がせない設定\">PATHにWindowsのPATHを引き継がせない設定</h1>\n<p>仮想マシン起動語、PATHにWindows環境のPATHが引き継がれる。<br />\n便利な半面、コマンド名補完でサーチに行くと かなりの時間をくってしまい 不便。<br />\nWindowsのコマンドを仮想マシン上から起動することはあまりない(私の場合)ので、、<br />\nWindows環境のPATHを引き継がせないようにする。</p>\n\n<p>設定方法は <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に 以下の設定を追加する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>interop]\nappendWindowsPath <span class=\"o\">=</span> <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>参考: <a href=\"https://zenn.dev/o2z/articles/zenn-20210524-01\" target=\"_blank\">WSL2でWindowsのPATH設定が引き継がれるのを解除する</a></p>\n\n<h1 id=\"guiアプリを使用する\">GUIアプリを使用する</h1>\n<p>参考: <a href=\"https://qiita.com/vega77/items/f00323e8ce64bfa1fdd6\" target=\"_blank\">WSL2でGUIアプリを起動</a></p>\n\n<h1 id=\"wsl2上のサーバプログラムへのアクセス\">WSL2上のサーバプログラムへのアクセス</h1>\n<p>参考:<a href=\"https://www.atmarkit.co.jp/ait/articles/1909/09/news020.html\" target=\"_blank\">Linuxがほぼそのまま動くようになった「WSL2」のネットワーク機能</a></p>\n\n<table>\n  <thead>\n    <tr>\n      <th>向き</th>\n      <th>可否</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>HOST → WSL2</td>\n      <td>localhost でアクセスできる</td>\n    </tr>\n    <tr>\n      <td>WSL2 → HOST</td>\n      <td>localhost でアクセスできない。<br /> IPアドレス指定ならアクセスできる。</td>\n    </tr>\n  </tbody>\n</table>\n\n<h1 id=\"仮想マシンの複製\">仮想マシンの複製</h1>\n\n<h2 id=\"手順\">手順</h2>\n<p>仮想マシンは元になる仮想マシンをエクスポートして、別のディレクトリにインポートすれば複製できる。</p>\n\n<h3 id=\"仮想マシン一覧の確認\">仮想マシン一覧の確認</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>対象の仮想マシンが停止していることを確認。<br />\n停止してない場合はそれぞれのターミナルを終了するか、以下のコマンドで。<br />\nターミナルを終了してから実際に仮想マシンが停止するまで少し時間がかかる(数十秒くらい?)。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"err\">«対象の仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"エクスポート\">エクスポート</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--export</span><span class=\"w\"> </span><span class=\"err\">«エクスポート元仮想環境名»</span><span class=\"w\"> </span><span class=\"err\">«エクスポートファイル名»</span><span class=\"o\">.</span><span class=\"nf\">tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>例</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--export</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04</span><span class=\"w\"> </span><span class=\"nx\">F:\\WSL_VMs\\_Backup\\Ubuntu-20.04.tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"インポート\">インポート</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"err\">«新しい仮想環境名»</span><span class=\"w\"> </span><span class=\"err\">«インストール先ディレクトリ»</span><span class=\"w\"> </span><span class=\"err\">«エクスポートファイル名»</span><span class=\"o\">.</span><span class=\"nf\">tar</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ インストール先ディレクトリは自動で作成される</p>\n\n<p>例:</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04-1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">/Ubuntu-20.04-1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">\\_Backup\\Ubuntu-20.04.tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"削除\">削除</h3>\n<p>不要になった仮想環境は削除する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"err\">«削除する仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04-2</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"参考\">参考</h2>\n<ul>\n  <li>同一ディストリビューションの複製<br />\n<a href=\"https://qiita.com/souyakuchan/items/9f95043cf9c4eda2e1cc\" target=\"_blank\">WSL 上で同一ディストリビューションの環境を複数インストール・管理する</a></li>\n  <li>仮想環境をCドライブ以外に変更する<br />\n<a href=\"https://nosubject.io/windowsdocker-desktop-move-disk-image/\" target=\"_blank\">[Windows] Docker Desktop の ディスク領域 を Cドライブから別のドライブへ移動する方法</a></li>\n</ul>\n\n<h2 id=\"インポートした環境のデフォルトユーザを変更する\">インポートした環境のデフォルトユーザを変更する</h2>\n<p>インポートした環境では、デフォルトユーザがrootになっているため、自分に変更しておく。<br />\n方法は2つ。  <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>のほうがお手軽かな? エクスポート元で書いておけば逐一書かなくてもいいし。<br />\n両方設定した場合は<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>の設定が優先される(らしい)。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>で指定する方法。<br />\nインポートした環境を起動して、 <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>を以下の内容で作成\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>user]\n<span class=\"nv\">default</span><span class=\"o\">=</span>«デフォルトユーザ名» \n</code></pre></div>    </div>\n    <p>参考:<a href=\"https://github.com/Microsoft/WSL/issues/3974#issuecomment-576782860\" target=\"_blank\">github Microsoft/WSL/issues/3974</a>\n参考:<a href=\"https://roy-n-roy.github.io/Windows/WSL%EF%BC%86%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A/wslconfig/\" target=\"_blank\">wsl.conf と .wslconfig - roy-n-roy メモ</a></p>\n  </li>\n  <li>レジストリで設定する方法\n    <ul>\n      <li>Windowsでレジストリエディタを起動</li>\n      <li><strong><em>コンピューター\\HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Lxss</em></strong> 下の<br />\n各エントリで <strong><em>DistributionName</em></strong> が対象の名前になっているエントリを探す</li>\n      <li>そのエントリの<strong><em>DefaultUid</em></strong> を 対象のユーザIDに変更する。<br />\n対象のユーザIDはコピー元の<strong><em>DefaultUid</em></strong> に合わせれば良い。 あるいは、一旦ログインして/etc/passwd で調べる。 (大抵、1000( = 0x3e8 )のはず)</li>\n    </ul>\n  </li>\n</ul>\n\n<p>参考:<a href=\"https://roy-n-roy.github.io/Windows/WSL%EF%BC%86%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A/centos/#wsl\" target=\"_blank\">WSLでCentOS/Fedoraを利用する - roy-n-roy メモ</a></p>\n\n<h1 id=\"なんかのときに使うかも\">なんかのときに使うかも</h1>\n\n<p>試してないけど、メモっておく。</p>\n<ul>\n  <li>仮想ディスクが肥大化した場合の対処方法<br />\n<del><a href=\"https://qiita.com/386jp/items/e469333c5a74789db46d\" target=\"_blank\">WSL2を使っているパソコンのディスク容量が枯渇したときにやってみるべきこと</a></del><br />\nこっちの方が分かりやすかった。<br />\n<a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1271vhdexpcmd/vhdexpcmd.html\">仮想ディスクをコマンドラインから拡大/縮小する</a></li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>PS: XXXX> diskpart                                                 ← コマンド起動\n\nMicrosoft DiskPart バージョン 10.0.19041.964\n\nCopyright (C) Microsoft Corporation.\nコンピューター: XXXXXX\n\nDISKPART> select vdisk file=\"f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\" ← 圧縮したいvhdxファイル\n\nDiskPart により、仮想ディスク ファイルが選択されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   20 GB\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART> compact vdisk                                            ← 縮小の実行\n\n  100% 完了しました                       ← ちょっと時間がかかる\n\nDiskPart により、仮想ディスク ファイルは正常に圧縮されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   12 GB                      ← 小さくなった\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART>exit                                                      ← 終了\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu20.04 on WSL2 で openVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu20.04 on WSL2 で openVINO</h1>\n      <p>WSL2上のUbuntu20.04でopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"環境構築\">環境構築</h1>\n\n<p>WSL環境ではNCS2は使えないが、CPU演算での実行は可能。<br />\n以下インストール~デモ実行までのメモ。</p>\n\n<p>基本は以下を参考に。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></li>\n  <li><a href=\"/memoBlog/2020/10/18/openVINO_ubuntu_3.html\">openVINO フルパッケージ(2021.1)をインストール(追加)</a></li>\n</ul>\n\n<p>WSLのインストールメモはこちら:<a href=\"/memoBlog/2021/03/03/WSL_memo.html\">WSL2 メモ</a><br />\nUbuntuは20.04。<br />\n今回はopenVINO 2021.2を使用した。</p>\n\n<h2 id=\"pyenvの仮想環境を作成\">pyenvの仮想環境を作成</h2>\n<p>まずは、pythonの環境を準備。<br />\n以下ではpythonは3.7.10を使用。(3.8を使えばTensorflow2を使えるらしい(?))</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.10 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n\n<p>ubuntuのライブラリ類をインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev \n<span class=\"c\"># 他にもあるかもしれんけど、とりあえずこれだけ。</span>\n</code></pre></div></div>\n\n<p>WSLでは以下も必要(グラフィック系処理が入ってないので)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgtk-3-0\n</code></pre></div></div>\n<h2 id=\"ダウンロードしたopenvinoアーカイブの展開とインストール\">ダウンロードしたopenVINOアーカイブの展開とインストール</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/mnt/f/Download/</code>にダウンロードしたファイルがあるとして。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\n<span class=\"nb\">tar </span>xzvf /mnt/f/Download/l_openvino_toolkit_p_2021.2.185.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2021.2.185/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n<span class=\"c\"># なぜかXwindow設定しててもテキストベースになる...</span>\n<span class=\"c\"># てきとーに答えていく。</span>\n</code></pre></div></div>\n\n<p>スクリプト終了したら、以下に従い進めていく。<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html</a></p>\n\n<h2 id=\"後半のコマンド一覧と注意事項\">後半のコマンド一覧と注意事項</h2>\n\n<ul>\n  <li>環境変数の設定とpythonモジュールのインストール</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># このコマンド、~/.bashrcにも書いておくこと</span>\n<span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n\n<span class=\"c\"># このコマンド実行すると、pyenvでなくsystemのpipでモジュールがインストールされるので実行しない</span>\n<span class=\"c\"># しかも、systemのpip3が壊れる...すごい罠😡</span>\n<span class=\"c\"># cd /opt/intel/openvino_2021/deployment_tools/model_optimizer/install_prerequisites/</span>\n<span class=\"c\"># sudo -E ./install_prerequisites.sh </span>\n\n<span class=\"c\"># 代わりに以下を実行(上記スクリプトは結局これを実行しているだけなので)</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npython 3.7で実行すると、</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version >= \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われるけど、無視して良い。<br />\nこれはPython3.8未満か以上で異なるバージョンのTensorflowがインストールされるように設定されているため。<br />\nちなみに、python 3.8でやると</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version < \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nもし、<code class=\"language-plaintext highlighter-rouge\">install_prerequisites.sh</code>を実行してしまい、pip3が壊れてしまった場合は\n以下で復旧する(一旦アンインストールしてから再インストール)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove python3-pip \n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip \n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"デモ実行\">デモ実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino_2021/deployment_tools/demo\n<span class=\"nb\">sudo cp</span> /work/.python-version <span class=\"nb\">.</span>\n\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/demo1.log\n\n<span class=\"c\"># このデモはグラフィック表示可能環境で実行する必要がある。  </span>\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/dem2.log\n</code></pre></div></div>\n\n<h1 id=\"別の仮想環境を用意する場合\">別の仮想環境を用意する場合</h1>\n\n<p>別の仮想環境を用意するときは以下で新しい仮想環境下にモジュールをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2でX-serverへの表示</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2でX-serverへの表示</h1>\n      <p>WindowsTerminal上のWSL2コンソールからGUIプログラムを起動する場合の設定メモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>MobaXtermを使えば何もしなくてもGUIプログラムを表示できるけど、\nWindowsTerminalなどから表示したい場合に対応してみた。</p>\n\n<h1 id=\"windows側の設定\">Windows側の設定</h1>\n<p>VcXsrvをインストールして起動しておく。<br />\n参考:<a href=\"/memoBlog/2019/11/26/VcXsrv.html\" target=\"_blank\">WindowsでX-serve</a></p>\n\n<h1 id=\"linux側の設定\">Linux側の設定</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">.bashrc</code>に以下を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># HOSTのIPアドレス取得</span>\n<span class=\"c\"># export HOST_IP_ADDR=$(host `hostname`.mshome.net | sed -r 's/.*address (.*)$/\\1/')</span>\n<span class=\"c\"># HOSTのIPアドレス取得(アドレスが2つ以上返ってきたときは1個目だけ取り出す)</span>\n<span class=\"nb\">export </span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"o\">=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-n</span> 1p<span class=\"si\">)</span>\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"k\">}</span>:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n他の用途でホストのIPアドレス(名前でなく)を使いたいときのために別に変数作っておいた。<br />\n以下のように名前で書いて指定しても良い。<br />\nマシン名は<code class=\"language-plaintext highlighter-rouge\">hostname</code>コマンドで得られるので、別のマシンに移動しても変更の必要はない。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net:0.0\n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">.mshome.net</code>ドメインを指定するとホスト側のIPアドレスが得られるらしい。<br />\nドメインなしだと<code class=\"language-plaintext highlighter-rouge\">localhost</code>になっちゃうから注意。<br />\nぐぐると<code class=\"language-plaintext highlighter-rouge\">/etc/resolv.conf</code>を<code class=\"language-plaintext highlighter-rouge\">awk</code>でごちょごちょやるのが流行っているが<br />\n本来の設定値ではない(結果的に同じだけど)のでちゃんと設定しておくことにする。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nドメイン<code class=\"language-plaintext highlighter-rouge\">mshome.net</code>はHyper-Vのネットワークのドメインらしい。<br />\n要はWSL-Windows間の仮想ネットワークのドメイン名みたい。<br />\nちなみに、WSL2上から<code class=\"language-plaintext highlighter-rouge\">nslookup <<ホストのIPアドレス>></code>とやったら出てきた。</p>\n</blockquote>\n\n<h1 id=\"x-windowを使用するプログラムを起動\">X-Windowを使用するプログラムを起動</h1>\n<p>なんか起動してちょ。\nとりあえず<code class=\"language-plaintext highlighter-rouge\">xeyes</code>とか。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">xeyes</code> は <code class=\"language-plaintext highlighter-rouge\">sudo apt install x11-apps</code>でインストールできる。</p>\n\n<h1 id=\"wslからのgui表示が行えない場合の対処\">WSLからのGUI表示が行えない場合の対処</h1>\n\n<h2 id=\"原因\">原因</h2>\n<p>WSLのネットワークがパブリックネットワークになっており、<br />\nWSLネットワークからの接続要求がファイアウォールで はじかれている。</p>\n\n<h2 id=\"ファイアウォールの設定変更による回避\">ファイアウォールの設定変更による回避</h2>\n\n<p>VcXsrvをパブリックネットワークからの接続も受け付けるようにする \n以下手順。</p>\n\n<ul>\n  <li>コントロール パネル  →  Windows Defender ファイアウォール</li>\n  <li>左側上から2番目「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック</li>\n  <li>名前の欄から「VcXsrv windows xserver」を探す</li>\n  <li>その横のチェックボックスの「パブリック」側(右側)にもチェックを入れる(プライベート側は既にチェックが入っているはず。そっちはそのまま)。</li>\n  <li>OKボタンをクリックして終了</li>\n  <li>コントロールパネルは閉じてOK</li>\n</ul>\n\n<h2 id=\"ちなみに\">ちなみに</h2>\n\n<p>以下のような回避方法もある。</p>\n\n<h3 id=\"display変数を変更して回避\">DISPLAY変数を変更して回避</h3>\n<p>一旦WSLネットワークから外に出て接続すれば接続できる。<br />\n具体的には、DISPLAY変数をWSL側のIPアドレス(172.xxx.xxx.xxx)ではなく、<br />\nWi-Fiやイーサネットに割り当てられたアドレス(一般に 192.168.xxx.xxx)を指定する。<br />\n → WSL側から自動的にアドレスを取得できないのであまりおススメできない。<br />\n    VcXsrvがちゃんと動いているかを確認するには有効な手段かも。</p>\n\n<h3 id=\"根本的回避\">根本的回避</h3>\n<p><a href=\"https://daizo3.tumblr.com/post/150523393217/%E5%82%99%E5%BF%98%E9%8C%B2-%E5%85%88%E6%97%A5%E3%81%AE%E7%B6%9A%E3%81%8D-%E8%AD%98%E5%88%A5%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF-%E3%82%92%E3%83%97%E3%83%A9%E3%82%A4%E3%83%99%E3%83%BC%E3%83%88%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AB%E3%81%99%E3%82%8B\">備忘録 - (先日の続き) 識別されていないネットワーク をプライベートネットワークにする</a><br />\nによると、<br />\n<a href=\"https://www.atmarkit.co.jp/ait/articles/1012/24/news127.html\">Windowsで、「識別されていないネットワーク」の種類を「パブリック ネットワーク」から「プライベート ネットワーク」に変更する</a><br />\nの「レジストリによる設定」に記載された方法でも出来るらしいけど(こっちの方が根本的解決な気がする)、<br />\nレジストリ弄るのは気が引けるので、小手先対処にて。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PyPiからopenVINOをインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>PyPiからopenVINOをインストール</h1>\n      <p>PyPiで配布されているopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>openVINOを使いたいが、SDKをインストールするのは面倒というズボラさんのためのTips😅<br />\nNCS2を使うためのドライバをインストールするにはSDK必要だが(WSLだとそもそもNCS2は使えないけど)、CPUだけでさくっと使いたいときなんかは有効かな?<br />\nあと、SDKインストール済みだけど、別のバージョン試したいときとか。</p>\n\n<p>対象はWindwos(試してないけど)、Ubuntu(x86_64 の 18.04、20.04)。(macOSも対象らしいけど使ったことないのでよーわからん😅)<br />\nPython は3.6、3.7、3.8<br />\nRasoberryPiは現在のところ対象外。</p>\n\n<h1 id=\"pypiのページ\">PyPiのページ</h1>\n\n<p>PyPiは以下にページがある。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino/\" target=\"_blank\">openvino · PyPI</a></li>\n</ul>\n\n<p>ただし、現状はUbuntuでPython3.8を使用する場合は以下を使用(Ubuntu Python3.7は両方用意されているらしい)。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino-ubuntu20/\" target=\"_blank\">openvino-ubuntu20 · PyPI</a></li>\n</ul>\n\n<h1 id=\"pythonモジュールのインストール\">pythonモジュールのインストール</h1>\n<p>上記ページに記載された通りだが、大抵openCVも必要になるので、インストールしておく。 <br />\n最近はopenCVも<code class=\"language-plaintext highlighter-rouge\">pip</code>コマンドイッパツでインストールできるのでラクチン😊</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOのインストール</span>\npip <span class=\"nb\">install </span>openvino\n<span class=\"c\"># またはこちら</span>\n<span class=\"c\"># pip install openvino-ubuntu20</span>\n\n<span class=\"c\"># openCVのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<p>インストールすると、現状、以下のモジュールがインストールされる(ubuntuでpython3.7/3.8の場合)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>numpy==1.20.1\nopencv-python==4.5.1.48\nopenvino==2021.2\ntbb==2020.3.254\n</code></pre></div></div>\n\n<h1 id=\"実行前の準備\">実行前の準備</h1>\n\n<p>openVINOモジュールは<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>の設定が必要なので、\nシステムのpythonを使用するときは上記ページに記載された通りに<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>を設定する。<br />\nただし、pyenvを使用している場合は、以下のように設定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"k\">}</span>:<span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/versions/<span class=\"sb\">`</span>pyenv version-name<span class=\"sb\">`</span>/lib\n</code></pre></div></div>\n\n<p>pyenvで環境を切り替えることを考えると、<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>で設定するより、スクリプト実行ラッパで設定した方が無難かも。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Keras on tensorflow2 で SSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>Keras on tensorflow2 で SSD</h1>\n      <p>Tensorflow2上のKerasでSSDを実行を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>※ 2021.05.21 kerasをtensorflow.kerasに変更</p>\n\n<h1 id=\"概要\">概要</h1>\n\n<p>Kerasを使ってSSDを実行してみようと思ったら、Tensorflow1.x上の情報ばかり出てきて、Tensorflow2で実行するのに手間取ったのでメモ。<br />\n(最終的にopenVINOに持っていきたいなぁ、と思って試し始めたんだけど、openVINOにサクッと変換できるのはcaffeだった😅)<br />\nということで、やったけど 続きはないかも。実行遅いし…😩💨</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p><a href=\"https://smilerobo.com/papero/tips_keras_tf_ssd/\" target=\"_blank\">【実験】学習済のSSDを使ってPaPeRo i に複数種類の物体を数えさせる</a>\nを参考に、KerasをTensorflow2で動かしてみる。</p>\n\n<p>Pythonは3.8を使用した(念のため明記しておく)。</p>\n\n<p>Anaconda使ってないし、Paperoじゃないので、そのまんまじゃないけど、<br />\nとりあえずSSDを動かしてみよう。</p>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n\n<p>まずは、python仮想環境の準備をする。<br />\npyenv環境前提。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースディレクトリとpython仮想環境の準備</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/keras2/\n<span class=\"nb\">cd</span> /work/keras2/\npyenv virtualenv 3.8.8 keras2\npyenv <span class=\"nb\">local </span>keras2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># pythonモジュールのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n<span class=\"c\"># kerasはtensorflow内を直接参照にしたので不要  </span>\n<span class=\"c\"># pip install keras</span>\npip <span class=\"nb\">install </span>matplotlib\npip <span class=\"nb\">install </span>imageio\n</code></pre></div></div>\n\n<p>インストールされているpythonモジュールは以下の通り</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.2\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.4.0\ngoogle-auth==1.30.0\ngoogle-auth-oauthlib==0.4.4\ngoogle-pasta==0.2.0\ngrpcio==1.34.1\nh5py==3.1.0\nidna==2.10\nimageio==2.9.0\nkeras-nightly==2.5.0.dev2021032900\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.4.2\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.2.52\nopt-einsum==3.3.0\nPillow==8.2.0\nprotobuf==3.17.0\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nsix==1.15.0\ntensorboard==2.5.0\ntensorboard-data-server==0.6.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.5.0\ntensorflow-estimator==2.5.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==2.0.1\nwrapt==1.12.1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nKeras修正以前の状態は以下</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.1\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.3.3\ngoogle-auth==1.28.0\ngoogle-auth-oauthlib==0.4.3\ngoogle-pasta==0.2.0\ngrpcio==1.32.0\nh5py==2.10.0\nidna==2.10\nimageio==2.9.0\nKeras==2.4.3\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.3.4\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.1.48\nopt-einsum==3.3.0\nPillow==8.1.2\nprotobuf==3.15.6\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nPyYAML==5.4.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nscipy==1.6.1\nsix==1.15.0\ntensorboard==2.4.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.4.1\ntensorflow-estimator==2.4.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==1.0.1\nwrapt==1.12.1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"patchファイルの準備\">patchファイルの準備</h2>\n\n<p>参照先には色々手順が書いてあるが、めんどくさいので パッチファイル用意した(足りない修正もあるし)。<br />\n以下の内容を<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code> <code class=\"language-plaintext highlighter-rouge\">ssd_keras_2.patch</code>のファイル名で保存しておく。</p>\n\n<h3 id=\"ssd_keraspatch\">ssd_keras.patch</h3>\n\n<p>参照先の情報によるpatch</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/ssd.py b/ssd.py\nindex c0049d8..656cd83 100644\n</span><span class=\"gd\">--- a/ssd.py\n</span><span class=\"gi\">+++ b/ssd.py\n</span><span class=\"p\">@@ -2,14 +2,15 @@</span>\n \n import keras.backend as K\n from keras.layers import Activation\n<span class=\"gd\">-from keras.layers import AtrousConvolution2D\n</span><span class=\"gi\">+#from keras.layers import AtrousConvolution2D\n</span> from keras.layers import Convolution2D\n from keras.layers import Dense\n from keras.layers import Flatten\n from keras.layers import GlobalAveragePooling2D\n from keras.layers import Input\n from keras.layers import MaxPooling2D\n<span class=\"gd\">-from keras.layers import merge\n</span><span class=\"gi\">+#from keras.layers import merge\n+from keras.layers.merge import concatenate\n</span> from keras.layers import Reshape\n from keras.layers import ZeroPadding2D\n from keras.models import Model\n<span class=\"p\">@@ -34,109 +35,115 @@</span> def SSD300(input_shape, num_classes=21):\n     input_tensor = input_tensor = Input(shape=input_shape)\n     img_size = (input_shape[1], input_shape[0])\n     net['input'] = input_tensor\n<span class=\"gd\">-    net['conv1_1'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    net['conv1_1'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_1')(net['input'])\n<span class=\"gd\">-    net['conv1_2'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    \n+    net['conv1_2'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_2')(net['conv1_1'])\n<span class=\"gd\">-    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+\n+    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool1')(net['conv1_2'])\n     # Block 2\n<span class=\"gd\">-    net['conv2_1'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+    net['conv2_1'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_1')(net['pool1'])\n<span class=\"gd\">-    net['conv2_2'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+\n+    net['conv2_2'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_2')(net['conv2_1'])\n<span class=\"gd\">-    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool2')(net['conv2_2'])\n<span class=\"gi\">+\n</span>     # Block 3\n<span class=\"gd\">-    net['conv3_1'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_1'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_1')(net['pool2'])\n<span class=\"gd\">-    net['conv3_2'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_2'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_2')(net['conv3_1'])\n<span class=\"gd\">-    net['conv3_3'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_3'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_3')(net['conv3_2'])\n<span class=\"gd\">-    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool3')(net['conv3_3'])\n     # Block 4\n<span class=\"gd\">-    net['conv4_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_1')(net['pool3'])\n<span class=\"gd\">-    net['conv4_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_2')(net['conv4_1'])\n<span class=\"gd\">-    net['conv4_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_3')(net['conv4_2'])\n<span class=\"gd\">-    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool4')(net['conv4_3'])\n<span class=\"gd\">-    # Block 5\n-    net['conv5_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+# Block 5\n+    net['conv5_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_1')(net['pool4'])\n<span class=\"gd\">-    net['conv5_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_2')(net['conv5_1'])\n<span class=\"gd\">-    net['conv5_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_3')(net['conv5_2'])\n<span class=\"gd\">-    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), border_mode='same',\n</span><span class=\"gi\">+    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), padding='same',\n</span>                                 name='pool5')(net['conv5_3'])\n     # FC6\n<span class=\"gd\">-    net['fc6'] = AtrousConvolution2D(1024, 3, 3, atrous_rate=(6, 6),\n-                                     activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['fc6'] = Convolution2D(1024, (3, 3), dilation_rate=(6, 6),\n+                                     activation='relu', padding='same',\n</span>                                      name='fc6')(net['pool5'])\n     # x = Dropout(0.5, name='drop6')(x)\n     # FC7\n<span class=\"gd\">-    net['fc7'] = Convolution2D(1024, 1, 1, activation='relu',\n-                               border_mode='same', name='fc7')(net['fc6'])\n</span><span class=\"gi\">+    net['fc7'] = Convolution2D(1024, (1, 1), activation='relu',\n+                               padding='same', name='fc7')(net['fc6'])\n</span>     # x = Dropout(0.5, name='drop7')(x)\n     # Block 6\n<span class=\"gd\">-    net['conv6_1'] = Convolution2D(256, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv6_1'] = Convolution2D(256, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv6_1')(net['fc7'])\n<span class=\"gd\">-    net['conv6_2'] = Convolution2D(512, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+\n+\n+    net['conv6_2'] = Convolution2D(512, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv6_2')(net['conv6_1'])\n<span class=\"gd\">-    # Block 7\n-    net['conv7_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+        # Block 7\n+    net['conv7_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv7_1')(net['conv6_2'])\n     net['conv7_2'] = ZeroPadding2D()(net['conv7_1'])\n<span class=\"gd\">-    net['conv7_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='valid',\n</span><span class=\"gi\">+    net['conv7_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='valid',\n</span>                                    name='conv7_2')(net['conv7_2'])\n     # Block 8\n<span class=\"gd\">-    net['conv8_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv8_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv8_1')(net['conv7_2'])\n<span class=\"gd\">-    net['conv8_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['conv8_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv8_2')(net['conv8_1'])\n     # Last Pool\n     net['pool6'] = GlobalAveragePooling2D(name='pool6')(net['conv8_2'])\n     # Prediction from conv4_3\n     net['conv4_3_norm'] = Normalize(20, name='conv4_3_norm')(net['conv4_3'])\n     num_priors = 3\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv4_3_norm_mbox_loc')(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_loc'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_loc_flat')\n<span class=\"p\">@@ -144,7 +151,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv4_3_norm_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_conf'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_conf_flat')\n<span class=\"p\">@@ -155,16 +162,16 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv4_3_norm_mbox_priorbox'] = priorbox(net['conv4_3_norm'])\n     # Prediction from fc7\n     num_priors = 6\n<span class=\"gd\">-    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, 3, 3,\n-                                        border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, (3, 3),\n+                                        padding='same',\n</span>                                         name='fc7_mbox_loc')(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_loc_flat')\n     net['fc7_mbox_loc_flat'] = flatten(net['fc7_mbox_loc'])\n     name = 'fc7_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, 3, 3,\n-                                         border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, (3, 3),\n+                                         padding='same',\n</span>                                          name=name)(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_conf_flat')\n     net['fc7_mbox_conf_flat'] = flatten(net['fc7_mbox_conf'])\n<span class=\"p\">@@ -174,7 +181,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['fc7_mbox_priorbox'] = priorbox(net['fc7'])\n     # Prediction from conv6_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv6_2_mbox_loc')(net['conv6_2'])\n     net['conv6_2_mbox_loc'] = x\n     flatten = Flatten(name='conv6_2_mbox_loc_flat')\n<span class=\"p\">@@ -182,7 +189,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv6_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv6_2'])\n     net['conv6_2_mbox_conf'] = x\n     flatten = Flatten(name='conv6_2_mbox_conf_flat')\n<span class=\"p\">@@ -193,7 +200,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv6_2_mbox_priorbox'] = priorbox(net['conv6_2'])\n     # Prediction from conv7_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv7_2_mbox_loc')(net['conv7_2'])\n     net['conv7_2_mbox_loc'] = x\n     flatten = Flatten(name='conv7_2_mbox_loc_flat')\n<span class=\"p\">@@ -201,7 +208,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv7_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv7_2'])\n     net['conv7_2_mbox_conf'] = x\n     flatten = Flatten(name='conv7_2_mbox_conf_flat')\n<span class=\"p\">@@ -212,7 +219,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv7_2_mbox_priorbox'] = priorbox(net['conv7_2'])\n     # Prediction from conv8_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv8_2_mbox_loc')(net['conv8_2'])\n     net['conv8_2_mbox_loc'] = x\n     flatten = Flatten(name='conv8_2_mbox_loc_flat')\n<span class=\"p\">@@ -220,7 +227,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv8_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv8_2'])\n     net['conv8_2_mbox_conf'] = x\n     flatten = Flatten(name='conv8_2_mbox_conf_flat')\n<span class=\"p\">@@ -241,7 +248,7 @@</span> def SSD300(input_shape, num_classes=21):\n     priorbox = PriorBox(img_size, 276.0, max_size=330.0, aspect_ratios=[2, 3],\n                         variances=[0.1, 0.1, 0.2, 0.2],\n                         name='pool6_mbox_priorbox')\n<span class=\"gd\">-    if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+    if K.image_data_format() == 'channels_last':\n</span>         target_shape = (1, 1, 256)\n     else:\n         target_shape = (256, 1, 1)\n<span class=\"p\">@@ -249,42 +256,47 @@</span> def SSD300(input_shape, num_classes=21):\n                                     name='pool6_reshaped')(net['pool6'])\n     net['pool6_mbox_priorbox'] = priorbox(net['pool6_reshaped'])\n     # Gather all predictions\n<span class=\"gd\">-    net['mbox_loc'] = merge([net['conv4_3_norm_mbox_loc_flat'],\n</span><span class=\"gi\">+    net['mbox_loc'] = concatenate([net['conv4_3_norm_mbox_loc_flat'],\n</span>                              net['fc7_mbox_loc_flat'],\n                              net['conv6_2_mbox_loc_flat'],\n                              net['conv7_2_mbox_loc_flat'],\n                              net['conv8_2_mbox_loc_flat'],\n                              net['pool6_mbox_loc_flat']],\n<span class=\"gd\">-                            mode='concat', concat_axis=1, name='mbox_loc')\n-    net['mbox_conf'] = merge([net['conv4_3_norm_mbox_conf_flat'],\n</span><span class=\"gi\">+                            axis=1,\n+                                  name='mbox_loc')\n+    net['mbox_conf'] = concatenate([net['conv4_3_norm_mbox_conf_flat'],\n</span>                               net['fc7_mbox_conf_flat'],\n                               net['conv6_2_mbox_conf_flat'],\n                               net['conv7_2_mbox_conf_flat'],\n                               net['conv8_2_mbox_conf_flat'],\n                               net['pool6_mbox_conf_flat']],\n<span class=\"gd\">-                             mode='concat', concat_axis=1, name='mbox_conf')\n-    net['mbox_priorbox'] = merge([net['conv4_3_norm_mbox_priorbox'],\n</span><span class=\"gi\">+                              axis=1,\n+                              name='mbox_conf')\n+    net['mbox_priorbox'] = concatenate([net['conv4_3_norm_mbox_priorbox'],\n</span>                                   net['fc7_mbox_priorbox'],\n                                   net['conv6_2_mbox_priorbox'],\n                                   net['conv7_2_mbox_priorbox'],\n                                   net['conv8_2_mbox_priorbox'],\n                                   net['pool6_mbox_priorbox']],\n<span class=\"gd\">-                                 mode='concat', concat_axis=1,\n</span><span class=\"gi\">+                                 axis=1,\n</span>                                  name='mbox_priorbox')\n     if hasattr(net['mbox_loc'], '_keras_shape'):\n         num_boxes = net['mbox_loc']._keras_shape[-1] // 4\n     elif hasattr(net['mbox_loc'], 'int_shape'):\n<span class=\"gd\">-        num_boxes = K.int_shape(net['mbox_loc'])[-1] // 4\n</span><span class=\"gi\">+        num_boxes = net['mbox_loc'].int_shape()[-1] // 4\n+    elif hasattr(net['mbox_loc'], 'get_shape'):\n+        num_boxes = net['mbox_loc'].get_shape()[-1] // 4\n</span>     net['mbox_loc'] = Reshape((num_boxes, 4),\n                               name='mbox_loc_final')(net['mbox_loc'])\n     net['mbox_conf'] = Reshape((num_boxes, num_classes),\n                                name='mbox_conf_logits')(net['mbox_conf'])\n     net['mbox_conf'] = Activation('softmax',\n                                   name='mbox_conf_final')(net['mbox_conf'])\n<span class=\"gd\">-    net['predictions'] = merge([net['mbox_loc'],\n</span><span class=\"gi\">+    net['predictions'] = concatenate([net['mbox_loc'],\n</span>                                net['mbox_conf'],\n                                net['mbox_priorbox']],\n<span class=\"gd\">-                               mode='concat', concat_axis=2,\n</span><span class=\"gi\">+                               axis=2,\n+                               #axis = 0,\n</span>                                name='predictions')\n     model = Model(net['input'], net['predictions'])\n     return model\n<span class=\"gh\">diff --git a/ssd_layers.py b/ssd_layers.py\nindex 5e10478..41ee510 100644\n</span><span class=\"gd\">--- a/ssd_layers.py\n</span><span class=\"gi\">+++ b/ssd_layers.py\n</span><span class=\"p\">@@ -29,7 +29,8 @@</span> class Normalize(Layer):\n         Add possibility to have one scale for all features.\n     \"\"\"\n     def __init__(self, scale, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n+\n</span>             self.axis = 3\n         else:\n             self.axis = 1\n<span class=\"p\">@@ -41,7 +42,7 @@</span> class Normalize(Layer):\n         shape = (input_shape[self.axis],)\n         init_gamma = self.scale * np.ones(shape)\n         self.gamma = K.variable(init_gamma, name='{}_gamma'.format(self.name))\n<span class=\"gd\">-        self.trainable_weights = [self.gamma]\n</span><span class=\"gi\">+        self._trainable_weights = [self.gamma]\n</span> \n     def call(self, x, mask=None):\n         output = K.l2_normalize(x, self.axis)\n<span class=\"p\">@@ -81,7 +82,7 @@</span> class PriorBox(Layer):\n     \"\"\"\n     def __init__(self, img_size, min_size, max_size=None, aspect_ratios=None,\n                  flip=True, variances=[0.1], clip=True, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n</span>             self.waxis = 2\n             self.haxis = 1\n         else:\n<span class=\"p\">@@ -108,7 +109,7 @@</span> class PriorBox(Layer):\n         self.clip = True\n         super(PriorBox, self).__init__(**kwargs)\n \n<span class=\"gd\">-    def get_output_shape_for(self, input_shape):\n</span><span class=\"gi\">+    def compute_output_shape(self, input_shape):\n</span>         num_priors_ = len(self.aspect_ratios)\n         layer_width = input_shape[self.waxis]\n         layer_height = input_shape[self.haxis]\n<span class=\"gh\">diff --git a/ssd_utils.py b/ssd_utils.py\nindex 0a9ffb1..4fc7a49 100644\n</span><span class=\"gd\">--- a/ssd_utils.py\n</span><span class=\"gi\">+++ b/ssd_utils.py\n</span><span class=\"p\">@@ -1,7 +1,8 @@</span>\n \"\"\"Some utils for SSD.\"\"\"\n \n import numpy as np\n<span class=\"gd\">-import tensorflow as tf\n</span><span class=\"gi\">+import tensorflow.compat.v1 as tf\n+tf.disable_v2_behavior()\n</span> \n \n class BBoxUtility(object):\n<span class=\"gh\">diff --git a/testing_utils/videotest.py b/testing_utils/videotest.py\nindex 0cbae3c..7b2ff4f 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest.py\n</span><span class=\"p\">@@ -3,13 +3,14 @@</span>\n import cv2\n import keras\n from keras.applications.imagenet_utils import preprocess_input\n<span class=\"gd\">-from keras.backend.tensorflow_backend import set_session\n</span><span class=\"gi\">+# from keras.backend.tensorflow_backend import set_session\n</span> from keras.models import Model\n from keras.preprocessing import image \n import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-from scipy.misc import imread, imresize\n</span><span class=\"gi\">+# from scipy.misc import imread, imresize\n+from imageio import imread\n</span> from timeit import default_timer as timer\n \n import sys\n<span class=\"p\">@@ -84,8 +85,8 @@</span> class VideoTest(object):\n             \"trying to open a webcam, make sure you video_path is an integer!\"))\n         \n         # Compute aspect ratio of video     \n<span class=\"gd\">-        vidw = vid.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)\n-        vidh = vid.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)\n</span><span class=\"gi\">+        vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)\n+        vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)\n</span>         vidar = vidw/vidh\n         \n         # Skip frames until reaching start_frame\n<span class=\"gh\">diff --git a/testing_utils/videotest_example.py b/testing_utils/videotest_example.py\nindex fb4d873..27ec148 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest_example.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest_example.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import os\n+# GPU不使用を設定\n+os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n+\n</span> import keras\n import pickle\n from videotest import VideoTest\n<span class=\"p\">@@ -9,16 +13,38 @@</span> from ssd import SSD300 as SSD\n input_shape = (300,300,3)\n \n # Change this if you run with other classes than VOC\n<span class=\"gd\">-class_names = [\"background\", \"aeroplane\", \"bicycle\", \"bird\", \"boat\", \"bottle\", \"bus\", \"car\", \"cat\", \"chair\", \"cow\", \"diningtable\", \"dog\", \"horse\", \"motorbike\", \"person\", \"pottedplant\", \"sheep\", \"sofa\", \"train\", \"tvmonitor\"];\n</span><span class=\"gi\">+class_names = [ \n+                \"background\", \n+                \"aeroplane\", \n+                \"bicycle\", \n+                \"bird\", \n+                \"boat\", \n+                \"bottle\", \n+                \"bus\", \n+                \"car\", \n+                \"cat\", \n+                \"chair\", \n+                \"cow\", \n+                \"diningtable\", \n+                \"dog\", \n+                \"horse\", \n+                \"motorbike\", \n+                \"person\", \n+                \"pottedplant\", \n+                \"sheep\", \n+                \"sofa\", \n+                \"train\", \n+                \"tvmonitor\"\n+            ];\n</span> NUM_CLASSES = len(class_names)\n \n model = SSD(input_shape, num_classes=NUM_CLASSES)\n \n # Change this path if you want to use your own trained weights\n<span class=\"gd\">-model.load_weights('../weights_SSD300.hdf5') \n</span><span class=\"gi\">+model.load_weights('../../weights_SSD300.hdf5') \n</span>         \n vid_test = VideoTest(class_names, model, input_shape)\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('path/to/your/video.mkv')\n</span><span class=\"gi\">+vid_test.run('../../testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h3 id=\"ssd_keras_2patch\">ssd_keras_2.patch</h3>\n\n<p>keras修正対応</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras_2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd.py ssd_keras.tmp/ssd.py\n</span><span class=\"gd\">--- ssd_keras/ssd.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd.py\t2021-05-21 07:06:44.970000000 +0900\n</span><span class=\"p\">@@ -1,19 +1,17 @@</span>\n \"\"\"Keras implementation of SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.layers import Activation\n-#from keras.layers import AtrousConvolution2D\n-from keras.layers import Convolution2D\n-from keras.layers import Dense\n-from keras.layers import Flatten\n-from keras.layers import GlobalAveragePooling2D\n-from keras.layers import Input\n-from keras.layers import MaxPooling2D\n-#from keras.layers import merge\n-from keras.layers.merge import concatenate\n-from keras.layers import Reshape\n-from keras.layers import ZeroPadding2D\n-from keras.models import Model\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.keras.layers import Activation\n+from tensorflow.keras.layers import Convolution2D\n+from tensorflow.keras.layers import Dense\n+from tensorflow.keras.layers import Flatten\n+from tensorflow.keras.layers import GlobalAveragePooling2D\n+from tensorflow.keras.layers import Input\n+from tensorflow.keras.layers import MaxPooling2D\n+from tensorflow.keras.layers import concatenate\n+from tensorflow.keras.layers import Reshape\n+from tensorflow.keras.layers import ZeroPadding2D\n+from tensorflow.keras.models import Model\n</span> \n from ssd_layers import Normalize\n from ssd_layers import PriorBox\n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd_layers.py ssd_keras.tmp/ssd_layers.py\n</span><span class=\"gd\">--- ssd_keras/ssd_layers.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd_layers.py\t2021-05-21 06:31:11.780000000 +0900\n</span><span class=\"p\">@@ -1,8 +1,8 @@</span>\n \"\"\"Some special pupropse layers for SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.engine.topology import InputSpec\n-from keras.engine.topology import Layer\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.python.keras.engine.input_spec import InputSpec\n+from tensorflow.python.keras.engine.base_layer import Layer\n</span> import numpy as np\n import tensorflow as tf\n \n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest.py ssd_keras.tmp/testing_utils/videotest.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest.py\t2021-05-21 07:08:24.680000000 +0900\n</span><span class=\"p\">@@ -1,15 +1,13 @@</span>\n \"\"\" A class for testing a SSD model on a video file or webcam \"\"\"\n \n import cv2\n<span class=\"gd\">-import keras\n-from keras.applications.imagenet_utils import preprocess_input\n-# from keras.backend.tensorflow_backend import set_session\n-from keras.models import Model\n-from keras.preprocessing import image \n</span><span class=\"gi\">+import tensorflow.keras as keras\n+from tensorflow.keras.applications.imagenet_utils import preprocess_input\n+from tensorflow.keras.models import Model\n+from tensorflow.keras.preprocessing import image \n</span> import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-# from scipy.misc import imread, imresize\n</span> from imageio import imread\n from timeit import default_timer as timer\n \n<span class=\"p\">@@ -179,6 +177,7 @@</span>\n             cv2.putText(to_draw, fps, (3,10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0,0,0), 1)\n             \n             cv2.imshow(\"SSD result\", to_draw)\n<span class=\"gd\">-            cv2.waitKey(10)\n-            \n-        \n</span><span class=\"gi\">+            key = cv2.waitKey(1)\n+            if key == 27:\n+                # ESCキー\n+                break\n</span><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest_example.py ssd_keras.tmp/testing_utils/videotest_example.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest_example.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest_example.py\t2021-05-21 07:04:24.320000000 +0900\n</span><span class=\"p\">@@ -2,7 +2,7 @@</span>\n # GPU不使用を設定\n os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n \n<span class=\"gd\">-import keras\n</span><span class=\"gi\">+import tensorflow.keras as keras\n</span> import pickle\n from videotest import VideoTest\n \n<span class=\"p\">@@ -47,4 +47,4 @@</span>\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('../../testvideo3.mp4')\n</span><span class=\"gi\">+vid_test.run('../../images/testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h2 id=\"学習済み重みファイルのダウンロード\">学習済み重みファイルのダウンロード</h2>\n\n<p>参照先の記載にしたがって、重み学習済み重みファイルをダウンロードする。</p>\n\n<p>wgetでは取得できなかったので、ブラウザで↓ここ から weights_SSD300.hdf5 をダウンロード。<br />\n<a href=\"https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA\" target=\"_blank\">https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA</a><br />\nで、ZIPファイルをカレントディレクトリに解凍しておく。</p>\n\n<h2 id=\"ソースのダウンロードパッチをあてる\">ソースのダウンロード&パッチをあてる</h2>\n\n<p>githubからソースをダウンロードする。<br />\nこのままではエラーになるので、先ほど作成したパッチファイル<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code>でパッチをあてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/rykov8/ssd_keras.git\n<span class=\"nb\">cd </span>ssd_keras\npatch <span class=\"nt\">-p1</span> < ../ssd_keras.patch \n<span class=\"c\"># Keras修正対応パッチ</span>\npatch <span class=\"nt\">-p1</span> < ../ssd_keras_2.patch \n</code></pre></div></div>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>testing_utils/\npython videotest_example.py\n</code></pre></div></div>\n\n<p>おー。<br />\nしかし遅い…. <br />\nKerasは遅いみたい。。。orz…</p>\n\n<h1 id=\"こんなんもある\">こんなんもある</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50\" target=\"_blank\">「Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Visual Studio Code で Jupyter Notebook</title>\n  </head>\n  <body>\n    <header>\n      <h1>Visual Studio Code で Jupyter Notebook</h1>\n      <p>Visual Studio Code で Jupyter Notebookを実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Visual Studio CodeでJupyter Notebookを実行する。</p>\n\n<p>サンプルプログラムがJupyter Notebookだったりするとブラウザで動かすのめんどいので、Visual Studio Codeで動かしてみた。<br />\n参考:このあたりかな? <a href=\"https://codeaid.jp/vscode-jupyter/\" target=\"_blank\">Visual Studio CodeでJupyter Notebookを使う方法</a></p>\n\n<p>以下では、<a href=\"https://www.koi.mashykom.com/tensorflow.html\" target=\"_blank\">SSD と YOLO を用いた物体検出</a> の「Object Detection APIを用いた物体検出」を参考に進めてみる。</p>\n\n<h1 id=\"前準備\">前準備</h1>\n<p>作業ディレクトリとツール類のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Tensorflow\n<span class=\"nb\">cd</span> /work/Tensorflow\n\n<span class=\"c\"># pyenvの仮想環境作成と切り替え</span>\npyenv virtualenv 3.7.10 tensorflow\npyenv <span class=\"nb\">local </span>tensorflow\n<span class=\"c\"># お約束</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># Protocol buffers コンパイラのインストール(Jupyter Notebookの実行には関係ない)</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n\n<span class=\"c\"># Jupyter Notebook のモジュールインストール</span>\npip <span class=\"nb\">install </span>notebook\n</code></pre></div></div>\n\n<h1 id=\"modelsリポジトリのクローン\">modelsリポジトリのクローン</h1>\n<p>実行するプログラムの準備</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git\n</code></pre></div></div>\n\n<h1 id=\"visual-studio-codeの起動\">Visual Studio Codeの起動</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models/\ncode <span class=\"nb\">.</span>\n</code></pre></div></div>\n<p><strong>*** Visual Studio Code起動 ***</strong></p>\n\n<h1 id=\"visual-studio-codeでの作業\">Visual Studio Codeでの作業</h1>\n<p>以下、Visual Studio Codeで作業する</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>拡張機能から「Jupyter」と「Python」を選択し、対象マシンにインストール</p>\n\n<h2 id=\"使用するpythonを選択その1\">使用するpythonを選択その1</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n<ul>\n  <li>Python: インタプリター選択\n    <ul>\n      <li>これはどこで有効なんだろうか?念のため設定しておこう。</li>\n    </ul>\n  </li>\n  <li>Jupyter: Select interpreter to start jupyter server\n    <ul>\n      <li>たぶん、Jupyter Notebookそのものを実行するためのPython<br />\njupyter-notebookモジュールがインストールされている必要がある</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"対象ファイルをオープン\">対象ファイルをオープン</h2>\n<p>エクスプローラから<br />\n<code class=\"language-plaintext highlighter-rouge\">research/object_detection/colab_tutorials/object_detection_tutorial.ipynb</code>\nを開く<br />\n<code class=\"language-plaintext highlighter-rouge\">a notebook could execute harmful code when opened. ~</code>\nと言われるので、<code class=\"language-plaintext highlighter-rouge\">Trust</code> をクリック</p>\n\n<h2 id=\"使用するpythonを選択その2\">使用するpythonを選択その2</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する<br />\n(ipynbファイルを開かないと選べない)</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n\n<ul>\n  <li>Jupyter: Select a Kernel\n    <ul>\n      <li>たぶん、Notebook内のpythonスクリプトを実行するためのPython<br />\nシステムコマンド(!を行頭につけて指定)として実行したり、<code class=\"language-plaintext highlighter-rouge\">%%bash</code> で指定したCode cell で実行した<br />\npython スクリプト(pipコマンドなども含む)を実行した場合もこのバージョンが使用される</li>\n      <li>ipykernelモジュールをインストールしておく必要があるが、入ってなければVSCodeからインストールできるので気にしなくても大丈夫。<br />\n(Jupyter Notebook のモジュールがインストールされていれば同時にインストールされている)</li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nその1、その2で選択するバージョンはそれぞれ異なるバージョンを設定できるが、<br />\n上でpyenvで選択したバージョンで統一しておくのが混乱しなくて良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSelect a Kernel の設定内容は以下のファイルに保存されるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.vscode-server/data/User/globalStorage/ms-toolsai.jupyter/kernelSpecPaths.json</code><br />\nこの設定はシステム(ターゲットマシン)で1つのようなので、他のプロジェクトで設定を変更した場合は再度確認しておくのが良いと思う。</p>\n</blockquote>\n\n<h2 id=\"エラーになる部分の対策\">エラーになる部分の対策</h2>\n\n<h3 id=\"その1\">その1</h3>\n<p>「Get tensorflow/models or cd to parent directory of the repository.」\nの下のCode cellの最後に以下を追加</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n<span class=\"n\">cwd</span><span class=\"o\">=</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getcwd</span><span class=\"p\">()</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research/slim\"</span><span class=\"p\">)</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research\"</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"その2\">その2</h3>\n<p>以下のcellを削除(エラーになる)<br />\n(おそらく、その1で追加している処理に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>%%bash \ncd models/research\npip install .\n</code></pre></div></div>\n\n<h3 id=\"その3\">その3</h3>\n<p>「Instance Segmentation」以下はエラーになる(RCNNのモデル形状が変更された?)ので削除しておく。<br />\n(手順の本筋に関係ないので)</p>\n\n<h2 id=\"実行\">実行</h2>\n<p>最初のCode cell(Installの下)で▶(Run)をクリック<br />\nあとは、続くcellで▶(Run)をクリックしていく。</p>\n\n<p>または、ツールバーの⏩(Run all cells)をクリックする</p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<h2 id=\"ipynbファイルをpythonファイルにエクスポートする\">ipynbファイルをpythonファイルにエクスポートする。</h2>\n\n<p>Visual Studio Codeのエクスプローラペインで対象のipynbファイルを右クリックして<br />\n<code class=\"language-plaintext highlighter-rouge\">Convert a Notebook to Python Script</code>を選択すると、変換結果が新しいファイルとしてエディタに開かれる。<br />\nこれを名前を付けて保存する。</p>\n\n<p>または、コマンドラインから以下のコマンドを実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>jupyter nbconvert «対象ファイル».ipynb <span class=\"nt\">--to</span> python\n</code></pre></div></div>\n<p>デフォルトの出力ファイル名は«対象ファイル名».py(拡張子をipynb→pyに変えたもの)になる。</p>\n\n<p>ただし、単独で動かす場合は <code class=\"language-plaintext highlighter-rouge\">get_ipython()</code> で始まる行(システムコマンドを実行する部分)はエラーになるので、コメントアウトしておくこと。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tensorflowの転移学習に関するメモ</title>\n  </head>\n  <body>\n    <header>\n      <h1>tensorflowの転移学習に関するメモ</h1>\n      <p>tensorflowの転移学習を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"tensorflow-1xでのssdの転移学習の例\">tensorflow 1.XでのSSDの転移学習の例</h1>\n\n<p><a href=\"https://github.com/ippei8jp/tf1_TransferLearning\" target=\"_blank\">https://github.com/ippei8jp/tf1_TransferLearning</a></p>\n\n<h1 id=\"tensorflow-2xでのssdの転移学習の例\">tensorflow 2.XでのSSDの転移学習の例</h1>\n\n<p><a href=\"https://github.com/ippei8jp/tf2_TransferLearning\" target=\"_blank\">https://github.com/ippei8jp/tf2_TransferLearning</a></p>\n\n<h1 id=\"pascal-voc-で転移学習\">Pascal VOC で転移学習</h1>\n\n<p>ローカルマシン(Core-i7/Win10/WSL2/Ubuntu20.04/Tensorflow2.4)で試してみた手順が以下。<br />\nかなり時間がかかるけど、GPUなくても24時間もあればそれなりの回数がこなせる(5000回くらい?)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA  To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.</code> と言われているので、これらを有効にしてTensorflowを再構築すればもうちっと速くなるはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nずいぶん前にtensorflow 1.1.0でAVXを有効にしたら、MNISTの学習で実行時間が半分になった記憶もあるが、<br />\ntensorflow 1.6以降でAVXは有効になってて、AVX2,FMAの有無では10%くらいしか違わないらしい。<br />\n参考:<a href=\"https://www.acceluniverse.com/blog/developers/2019/05/tensorflowavx2-fma.html\" target=\"_blank\">TensorFlowのAVX2, FMAの有無で性能の比較をする</a><br />\ntensorflowのbuildに十何時間もかかることを考えたら 「ま、いっか」となっちゃうな…</p>\n</blockquote>\n\n<h2 id=\"実行手順\">実行手順</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">BASE_DIR</span><span class=\"o\">=</span>/work/test\n<span class=\"nv\">MODELS_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>/models\n<span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>/voc\n\n<span class=\"c\"># modelsリポジトリのclone</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>\ngit clone <span class=\"nt\">--depth</span> 1 https://github.com/tensorflow/models.git\n<span class=\"c\"># object_detectionモジュール未インストールならインストールすること</span>\n\n<span class=\"c\"># Pascal VOC データ取得</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>\nwget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar <span class=\"nt\">-O</span> - | <span class=\"nb\">tar </span>xvf -\n\n<span class=\"c\"># 学習データ(tf-record)の作成</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython create_pascal_tf_record.py <span class=\"nt\">--label_map_path</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"nt\">--data_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/VOCdevkit <span class=\"nt\">--year</span> VOC2007 <span class=\"nt\">--set</span> train <span class=\"nt\">--output_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pascal_train.record\npython create_pascal_tf_record.py <span class=\"nt\">--label_map_path</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"nt\">--data_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/VOCdevkit <span class=\"nt\">--year</span> VOC2007 <span class=\"nt\">--set</span> val <span class=\"nt\">--output_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pascal_val.record\n\n<span class=\"c\"># 元となるモデルのダウンロード</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/\nwget http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8.tar.gz <span class=\"nt\">-O</span> - | <span class=\"nb\">tar </span>xzvf -\n<span class=\"nb\">cp </span>ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/pipeline.config <span class=\"nb\">.</span>\n\n<span class=\"c\"># pipeline.config を編集(下記参照)</span>\n\n<span class=\"c\"># 学習実行</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython model_main_tf2.py <span class=\"nt\">--pipeline_config_path</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--model_dir</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--alsologtostderr</span>\n</code></pre></div></div>\n\n<h3 id=\"object_detectionモジュールのインストール方法\">object_detectionモジュールのインストール方法</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models/research\nprotoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n<span class=\"nb\">cp </span>object_detection/packages/tf2/setup.py <span class=\"nb\">.</span> \n<span class=\"c\"># ↑ tf1の場合はtf1ディレクトリを指定する</span>\n\npip <span class=\"nb\">install</span> <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"pipelineconfig-の修正例\">pipeline.config\tの修正例</h3>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/pipeline.config\t2020-07-11 09:16:11.000000000 +0900\n</span><span class=\"gi\">+++ pipeline.config\t2021-05-11 05:22:30.943865000 +0900\n</span><span class=\"p\">@@ -1,6 +1,6 @@</span>\n model {\n   ssd {\n<span class=\"gd\">-    num_classes: 90\n</span><span class=\"gi\">+    num_classes: 20\n</span>     image_resizer {\n       fixed_shape_resizer {\n         height: 320\n<span class=\"p\">@@ -132,7 +132,7 @@</span>\n   }\n }\n train_config {\n<span class=\"gd\">-  batch_size: 128\n</span><span class=\"gi\">+  batch_size: 64\n</span>   data_augmentation_options {\n     random_horizontal_flip {\n     }\n<span class=\"p\">@@ -162,19 +162,19 @@</span>\n     }\n     use_moving_average: false\n   }\n<span class=\"gd\">-  fine_tune_checkpoint: \"PATH_TO_BE_CONFIGURED\"\n-  num_steps: 50000\n</span><span class=\"gi\">+  fine_tune_checkpoint: \"/work/test/voc/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/checkpoint/ckpt-0\"\n+  num_steps: 2000\n</span>   startup_delay_steps: 0.0\n   replicas_to_aggregate: 8\n   max_number_of_boxes: 100\n   unpad_groundtruth_tensors: false\n<span class=\"gd\">-  fine_tune_checkpoint_type: \"classification\"\n</span><span class=\"gi\">+  fine_tune_checkpoint_type: \"detection\"\n</span>   fine_tune_checkpoint_version: V2\n }\n train_input_reader {\n<span class=\"gd\">-  label_map_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+  label_map_path: \"/work/test/models/research/object_detection/data/pascal_label_map.pbtxt\"\n</span>   tf_record_input_reader {\n<span class=\"gd\">-    input_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+    input_path: \"/work/test/voc/pascal_train.record\"\n</span>   }\n }\n eval_config {\n<span class=\"p\">@@ -182,10 +182,10 @@</span>\n   use_moving_averages: false\n }\n eval_input_reader {\n<span class=\"gd\">-  label_map_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+  label_map_path: \"/work/test/models/research/object_detection/data/pascal_label_map.pbtxt\"\n</span>   shuffle: false\n   num_epochs: 1\n   tf_record_input_reader {\n<span class=\"gd\">-    input_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+    input_path: \"/work/test/voc/pascal_val.record\"\n</span>   }\n }\n</code></pre></div></div>\n\n<h2 id=\"学習の中断\">学習の中断</h2>\n\n<p>学習処理を中断したい場合は、CTRL+cを入力する。<br />\nただし、中断した時点でのチェックポイントの保存は行われないので、それまでに保存されたチェックポイントが有効。<br />\nデフォルトではチェックポイントの保存は1000回毎なので、1000回未満で中断すると学習してないのと同じ(たぶん)。</p>\n\n<h2 id=\"追加学習学習の再開\">追加学習/学習の再開</h2>\n\n<p>中断した学習を再開したい場合や設定した学習回数では十分ではなかった場合の追加学習を行うには<br />\n<code class=\"language-plaintext highlighter-rouge\">model_main_tf2.py</code>を再度実行すればOK。<br />\nそれまで実行した学習結果の続きを実行してくれます。<br />\n(特に設定ファイル類を変更する必要はないみたい)</p>\n\n<p>追加学習の場合や学習回数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--num_train_steps</code>オプションで新しい学習回数を指定するか、\n<code class=\"language-plaintext highlighter-rouge\">pipeline.config</code>ファイル内の<code class=\"language-plaintext highlighter-rouge\">num_steps</code>の項目を変更します。</p>\n\n<p>また、デフォルトでは学習結果は1000回毎にセーブされるので、学習回数が1000回未満の場合や端数が出る場合、結果がセーブされません。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">--checkpoint_every_n</code>オプションで何回毎にセーブするかを指定する必要があります。</p>\n\n<p>以下に例を示します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python model_main_tf2.py <span class=\"nt\">--pipeline_config_path</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--model_dir</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--alsologtostderr</span> <span class=\"nt\">--checkpoint_every_n</span><span class=\"o\">=</span>100 <span class=\"nt\">--num_train_steps</span><span class=\"o\">=</span>2300\n</code></pre></div></div>\n<h2 id=\"モデルのエクスポート\">モデルのエクスポート</h2>\n\n<p>学習を行った結果をエクスポートしてsaved_modelを作成します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython exporter_main_v2.py <span class=\"nt\">--trained_checkpoint_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--pipeline_config_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--output_directory</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/inference_voc\n<span class=\"c\"># ラベルファイルもコピーしておく</span>\n<span class=\"nb\">cp</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/inference_voc/\n</code></pre></div></div>\n\n<h1 id=\"学習データtf-recordの確認方法\">学習データ(tf-record)の確認方法</h1>\n<h2 id=\"セットアップ\">セットアップ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tfrecord\n<span class=\"nb\">cd</span>  /work/tfrecord\n<span class=\"c\"># 仮想環境の準備</span>\npyenv virtualenv 3.8.9 tfrecord\npyenv <span class=\"nb\">local </span>tfrecord \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n<span class=\"c\"># 必要なモジュールのインストール</span>\npip <span class=\"nb\">install </span><span class=\"nv\">tensorflow</span><span class=\"o\">==</span>2.<span class=\"k\">*</span>\npip <span class=\"nb\">install </span>flask\npip <span class=\"nb\">install </span>pillow\npip <span class=\"nb\">install </span>tqdm\n</code></pre></div></div>\n\n<h2 id=\"リポジトリのclone\">リポジトリのclone</h2>\n\n<p>以下のリポジトリから</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/sulc/tfrecord-viewer.git\n<span class=\"nb\">cd </span>tfrecord-viewer/\n</code></pre></div></div>\n<h2 id=\"viewerの実行\">Viewerの実行</h2>\n\n<p>webサーバを起動する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfviewer.py «tf-recordファイル» \n</code></pre></div></div>\n\n<p>例:</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfviewer.py /work/test/train.record \n</code></pre></div></div>\n\n<p>ブラウザで以下に接続する(ポート番号は実行環境によって変わるかも)<br />\n<code class=\"language-plaintext highlighter-rouge\">http://localhost:5000/</code></p>\n\n<p>表示下部にサムネイルが表示されるので、クリックすると中央に拡大表示される。</p>\n\n<h2 id=\"元画像データの抽出\">元画像データの抽出</h2>\n\n<p>以下のパッチを当てる<br />\n(元のファイル名がディレクトリ名を含んでいるとファイル作成エラーになるので)</p>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tfrecord_to_imfolder.py b/tfrecord_to_imfolder.py\nindex 81bb764..7a0e269 100644\n</span><span class=\"gd\">--- a/tfrecord_to_imfolder.py\n</span><span class=\"gi\">+++ b/tfrecord_to_imfolder.py\n</span><span class=\"p\">@@ -41,6 +41,7 @@</span> def parse_tfrecord(record):\n     feat = example.features.feature\n\n     filename = feat[args.filename_key].bytes_list.value[0].decode(\"utf-8\")\n<span class=\"gi\">+    filename = os.path.basename(filename)\n</span>     img =  feat[args.image_key].bytes_list.value[0]\n     label = feat[args.class_label_key].bytes_list.value[0].decode(\"utf-8\")\n</code></pre></div></div>\n\n<p>以下のコマンドを実行<br />\n<code class=\"language-plaintext highlighter-rouge\">--class-label-key</code> には他にも指定できるものがあるけど、これくらいしか使わないと思う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfrecord_to_imfolder.py <span class=\"se\">\\</span>\n  <span class=\"nt\">--output_path</span> «ファイル出力ディレクトリ» <span class=\"se\">\\</span>\n  <span class=\"nt\">--class-label-key</span> image/object/class/text <span class=\"se\">\\</span>\n  <span class=\"nt\">-v</span> <span class=\"se\">\\</span>\n   «tf-recordファイル»\n</code></pre></div></div>\n\n<p>実行すると、«ファイル出力ディレクトリ»/«クラス名»/の下に画像ファイルが生成される。<br />\n(画像中に複数のクラスが含まれる場合は、一番最初のクラスが使用される)</p>\n\n<p>例:</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfrecord_to_imfolder.py <span class=\"se\">\\</span>\n  <span class=\"nt\">--output_path</span> ./hogehoge <span class=\"se\">\\</span>\n  <span class=\"nt\">--class-label-key</span> image/object/class/text <span class=\"se\">\\</span>\n  <span class=\"nt\">-v</span> <span class=\"se\">\\</span>\n  /work/test/train.record\n</code></pre></div></div>\n\n<h1 id=\"参考になるかもしれないページ\">参考になるかもしれないページ</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8c3197d11f61812546a9?fbclid=IwAR35TFl3mOK9XxXcZChP8wNkxp8cF6HZwnrWiTborZqETz7LJBZ88Dehvvs\">TensorFlowでの物体検出が超手軽にできる「Object Detection Tools」をTensorFlow 2.xに対応しました</a></p>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50?fbclid=IwAR35TFl3mOK9XxXcZChP8wNkxp8cF6HZwnrWiTborZqETz7LJBZ88Dehvvs\">Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>UbuntuをNative環境にインストールする(20.04)</title>\n  </head>\n  <body>\n    <header>\n      <h1>UbuntuをNative環境にインストールする(20.04)</h1>\n      <p>Ubunt(20.04)をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"インストール\">インストール</h1>\n<p>最初の起動まではこちらに詳しく書かれています。<br />\n<a href=\"https://qiita.com/koba-jon/items/019a3b4eac4f60ca89c9\" target=\"_blank\">Ubuntu 20.04 LTS インストール方法(外付けドライブ用)</a></p>\n\n<blockquote>\n  <p>[!WARNING]\nEFIシステムパーティションを作成するのを忘れがち。<br />\n外付けだと作成忘れると内蔵HDDのEFIシステムパーティションに追記されちゃうので注意。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\nユーザ名に英数字以外を含むとChrome remote desktop の インストール&設定でエラーになることがあるので、<br />\n英数字以外を含まないユーザ名を設定することをおススメします。</p>\n</blockquote>\n\n<h1 id=\"その後の設定手順\">その後の設定手順</h1>\n\n<h2 id=\"最新版にアップデート\">最新版にアップデート</h2>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h2 id=\"ipアドレス確認したいとき\">IPアドレス確認したいとき</h2>\n<p>SSHのクライアントからの接続先が分からないと困るので、\nIPアドレスを確認するためにnet-toolsをインストールして\nifconfigで確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\nifconfig\n</code></pre></div></div>\n\n<h2 id=\"sshのインストール\">sshのインストール</h2>\n<p>WindowsPCにあるデータをubuntuPCにキーボードで打ち込むのは効率が悪いので、最も簡単なsshでリモートログインできるようにしてみる。</p>\n\n<p>以下のコマンドでsshサーバをインストールし、サーバを開始する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n\n<p>クライアントからTeraTermなどでsshで対象マシンのポート22に接続する</p>\n\n<h2 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面ロック を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h2 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h2>\n\n<p>とりあえず入れとこう</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\n</code></pre></div></div>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが…</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h3 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>NFSサーバの再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.XX.XX:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"bashの設定変更\">bashの設定変更</h2>\n\n<p>~/.bashrcに以下を追記</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h2 id=\"guiの動作の設定変更をお好みで\">GUIの動作の設定変更をお好みで</h2>\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.mutter auto-maximize\ngsettings get org.gnome.mutter edge-tiling\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.desktop.wm.preferences auto-raise \ngsettings get org.gnome.desktop.wm.preferences focus-mode \ngsettings get org.gnome.desktop.wm.preferences raise-on-click\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.shell.extensions.desktop-icons show-home\ngsettings get org.gnome.shell.extensions.desktop-icons show-trash\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。<br />\ndconf-editorでも良いよ(しつこい…)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 ==================================</span>\n<span class=\"c\"># Dockバー上のゴミ箱表示有無</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock show-trash\n\n<span class=\"c\"># アプリケーションのDockバー上の表示位置</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock show-apps-at-top\n\n<span class=\"c\"># Dockバー表示位置</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock dock-position\n\n<span class=\"c\"># Dockバー上のアイコンサイズ</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock dash-max-icon-size\n\n<span class=\"c\"># 設定 ==================================</span>\n<span class=\"c\"># Dockバー上のゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># Dockバー上のアイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.interface cursor-size\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"capsキーをctrlキーに変更\">CAPSキーをCtrlキーに変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.input-sources xkb-options\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.input-sources xkb-options <span class=\"se\">\\[\\'</span>ctrl:nocaps<span class=\"se\">\\'\\]</span>\n\n<span class=\"c\"># 設定を有効にするにはGUIでのlogout&再loginが必要</span>\n\n</code></pre></div></div>\n\n<h2 id=\"日本語入力\">日本語入力</h2>\n<p>前は設定必要だったけど、なんか大丈夫になったみたい</p>\n<blockquote>\n  <p>[!NOTE]\n以前の設定手順<br />\n右上の「A」または「あ」と書かれたアイコンをクリック→「テキスト入力設定」を選択\n一番下の「インストールされている言語の管理」をクリック\n「言語サポートが完全にはインストールされていません」と出るので「インストール」をクリック\n一旦log offして再log in\n右上のJaまたはMoと書かれたアイコンをクリック\n    Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)\nキーボードの全角/半角キーで切り替えられるようになる</p>\n</blockquote>\n\n<h2 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h2>\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nUbuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>IPv6が動いてるとうまく行かない環境のときは無効化しておく。<br />\n参考:<a href=\"https://www.server-memo.net/ubuntu/ubuntu_disable_ipv6.html#IPv6-4\" target=\"_blank\">UbuntuでIPv6を無効化する方法</a></p>\n\n<p>sysctlで設定するのがお手軽かな?</p>\n\n<h2 id=\"システムバックアップ\">システムバックアップ</h2>\n<p>Nativeならバックアップしといた方がいいかな。<br />\n参考:<a href=\"https://gihyo.jp/admin/serial/01/ubuntu-recipe/0588\">第588回 TimeShiftでUbuntuをホットバックアップする 2019年版</a> <br />\n<code class=\"language-plaintext highlighter-rouge\">add-apt-repository</code> でリポジトリを追加しなくても大丈夫。標準リポジトリにも入ってるから。</p>\n\n<h2 id=\"chrome-remote-desktopインストール\">chrome remote desktopインストール</h2>\n\n<p>remote desktop使いたいので、インストールする。</p>\n\n<h3 id=\"chromeのインストール\">chromeのインストール</h3>\n<p><a href=\"https://www.google.com/chrome/\">Google Chrome - Google の高速で安全なブラウザをダウンロード</a>からダウンロードしてインストール。</p>\n\n<h3 id=\"おまじない\">おまじない</h3>\n<p>remote desktopのインストール時にエラーが発生するので、以下のディレクトリを作成しておく。<br />\n(インストーラのバグらしい)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/.config/chrome-remote-desktop\n</code></pre></div></div>\n\n<h3 id=\"remote-desktopのインストール\">remote desktopのインストール</h3>\n<p>以下参考ページ</p>\n<ul>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>パソコンでリモート アクセスを設定する</li>\n      <li>パソコンにリモート アクセスする</li>\n    </ul>\n  </li>\n</ul>\n\n<p>接続すると、開始するセッションの選択画面になるので、「Ubuntu」を選択。</p>\n\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。<br />\nこのダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></li>\n</ul>\n\n<p>要約すると\n<code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下の内容で作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(May 7th 2021)のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(May 7th 2021)のインストール</h1>\n      <p>Raspberry Pi OS(May 7th 2021)のインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>前にやった <a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\" target=\"_blank\">Raspbian Busterのインストール</a>\nからあまり違わないけど、微妙に違いもあるので、もう一度メモしておく。</p>\n\n<h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspberry Pi OS with desktop」 の 「Download」でダウンロードしてSDカードに書き込む。<br />\n(「・・・ and recommended software」 の方ではない)<br />\n以下の手順は、RaspberryPi4 model B で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の <code class=\"language-plaintext highlighter-rouge\">[pi4]</code>の行の前に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\nシリアルコンソールの送信改行コードは<code class=\"language-plaintext highlighter-rouge\">CR</code>にしておくこと。<br />\nそうしないと、ビミョーに悲しいことが起こる場合がある。</p>\n</blockquote>\n\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>の <code class=\"language-plaintext highlighter-rouge\">[pi4]</code>の行の前に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group</code>と<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>については使用するモニタに合わせる。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group=2</code>はモニタ種別でDMT(一般的にモニタディスプレイ)、<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_mode=82</code>が 1920x1080 60Hz(1080p)を示している。<br />\n設定値の内容については、<a href=\"https://www.raspberrypi.org/documentation/configuration/config-txt/video.md\" target=\"_blank\">Video options in config.txt</a>\nを参照。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>はテキストモードで表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nhdmi_group=2\nhdmi_mode=82\nframebuffer_width=1920\nframebuffer_height=1080\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nHDMIディスプレイを常に接続しているなら設定しなくても問題ないが、<br />\nHDMIディスプレイをはずしてVNCでリモート接続だけする場合は設定しておかないと<br />\n解像度が1024x768までしか設定できなくなるので注意。</p>\n</blockquote>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S7 Splash Screen\n            Would you like to show the splash screen at boot? \n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nこの操作で<code class=\"language-plaintext highlighter-rouge\">/boot/cmdline.txt</code>が書き換えられるらしい。</p>\n</blockquote>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\" target=\"_blank\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n            B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    3 Interfacing Options        \n        P3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>    \n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n<p>Windows側のクライアントは、<br />\n<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a> \nから VNC Viewerをダウンロード。<br />\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。<br />\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。<br />\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。<br />\n日本語化の手順はこちらを参考に。 <a href=\"http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。<br />\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"--enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マウスフォーカスの変更\">マウスフォーカスの変更</h1>\n\n<p>ウィンドウをクリックしないとフォーカスが移動しないのはイライラするので x-mouse相当の設定をする。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/xdg/openbox/lxde-pi-rc.xml</code>の以下の部分をnoからyesに変更。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><followMouse>yes</followMouse>\n</code></pre></div></div>\n\n<h1 id=\"ipv6の無効化\">IPv6の無効化</h1>\n<p>IPv6を無効化したい場合は以下を設定。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/sysctl.conf</code>に以下を追加する\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Disable IPv6\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\n</code></pre></div>    </div>\n  </li>\n  <li>以下を実行する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sysctl <span class=\"nt\">-p</span>\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian SDカードイメージファイルの作成(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian SDカードイメージファイルの作成(改訂版)</h1>\n      <p>Raspbian SDカードイメージファイルの縮小</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/07/17/raspios_20210507.html\" target=\"_blank\">Raspberry Pi OS(May 7th 2021)のインストール</a> \nでセットアップしたSDカードをバックアップしておけば逐一セットアップ作業を行わなくても環境を復元できます。</p>\n\n<p>ただ、そのままSDカードをイメージファイル化しただけでは復元するSDカードのサイズが微妙に小さい場合などは、復元できなくなってしまいます。<br />\nそこで、バックアップしtイメージファイル内のパーティションサイズを縮小し、イメージファイルを小さくして保存します。</p>\n\n<p>以前、<a href=\"/memoBlog/2019/09/15/sd_image.html\" target=\"_blank\">Raspbian SDカードイメージファイルの縮小</a>、\n<a href=\"/memoBlog/2020/10/25/Jetson_nano_backup.html\" target=\"_blank\">Jetson nano のSDカードをバックアップする</a>\nでも書いていますが、今回はSDカード上でパーティションを縮小する方法にしてみました。<br />\nこれだと、不要な部分のバックアップを行わなくて済むので、ディスク領域/時間敵に有利かと思います。</p>\n\n<p>Windowsでは出来ない操作があるので、Ubuntu PCが必要です。<br />\nWSLではたぶん出来ません。<br />\nVirtualboxだと出来そうな気がしますが、試していません。</p>\n\n<h1 id=\"事前準備\">事前準備</h1>\n<h2 id=\"raspberrypiの準備\">RaspberryPiの準備</h2>\n<p>コピーしたSDカードで初回Boot時にパーティションを拡張するためのスクリプト<code class=\"language-plaintext highlighter-rouge\">expand_partition.sh</code>を\n<a href=\"/memoBlog/misc/stock/diskimage_shrink.sh\" target=\"_blank\">ここ</a> \nから適当なディレクトリにダウンロードしておきます。<br />\n(SDカードのコピーからブートしたあとに実行するので、コピーからブートした環境でダウンロードしても良いですが、\nマスタにダウンロードしておけばコピーの度にダウンロードしなくて済むので。)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/first_boot_settings\n<span class=\"nb\">cd</span>  ~/first_boot_settings\nwget https://ippei8jp.github.io/memoBlog/misc/stock/expand_partition.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPiの場合は<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>でパーティション拡張できるので、このスクリプトはなくても良い。</p>\n</blockquote>\n\n<p>RaspberryPiの電源をOFFし、SDカードを取り外してubuntu PCに挿入しておきます。</p>\n\n<h1 id=\"ubuntu-pcでの操作\">Ubuntu PCでの操作</h1>\n\n<p>以下、SDカードは<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0</code>に割り当てられているものとします。</p>\n\n<blockquote>\n  <p>[!NOTE]\nSDカードが自動マウントされている場合はアンマウントしておいてください。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount /dev/mmcblk0p1\n<span class=\"nb\">sudo </span>umount /dev/mmcblk0p2\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"gpartedのインストール\">gpartedのインストール</h2>\n<p>パーティション操作を行うため、gpartedがインストールされていなければインストールしておきます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gparted\n</code></pre></div></div>\n\n<h2 id=\"gpartedによりパーティションを縮小\">gpartedによりパーティションを縮小</h2>\n<ul>\n  <li>goartedを起動</li>\n  <li>対象デバイスとして<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0</code>を選択。</li>\n  <li>配置図またはパーティション一覧で<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0p2</code>を右クリックし、「リサイズ/移動」を選択</li>\n  <li>ダイアログで「新しいサイズ」に縮小したサイズを設定。 ダイアログ左上に表示されている「最小サイズ」よりも少し多めに。<br />\n(後方の空き領域は自動計算されます)</li>\n  <li>メニューの「編集」→「保留中の全ての操作を適用する」を選択し、パーティションを縮小する</li>\n  <li>gpartedを終了</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\ngpartedによるパーティションの縮小はマウントしたままではできません。<br />\nしたがって、RaspberryPiでは作業できず、Ubuntu PCで行う必要があります。</p>\n</blockquote>\n\n<h2 id=\"データサイズを確認\">データサイズを確認</h2>\n<p>以下のコマンドを実行し、コピーすべきデータサイズを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>parted /dev/mmcblk0 unit MiB print\n</code></pre></div></div>\n<p>以下が実行結果例。<br />\nここで、パーティション2の終了位置をメモ(ここでは<code class=\"language-plaintext highlighter-rouge\">3760</code>)しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>モデル: SD SA16G <span class=\"o\">(</span>sd/mmc<span class=\"o\">)</span>\nディスク /dev/mmcblk0: 14772MiB\nセクタサイズ <span class=\"o\">(</span>論理/物理<span class=\"o\">)</span>: 512B/512B\nパーティションテーブル: msdos\nディスクフラグ: \n\n番号  開始     終了     サイズ   タイプ   ファイルシステム  フラグ\n 1    4.00MiB  260MiB   256MiB   primary  fat32             lba\n 2    260MiB   3760MiB  3500MiB  primary  ext4\n</code></pre></div></div>\n\n<h2 id=\"イメージファイルの作成\">イメージファイルの作成</h2>\n<p>以下のコマンドでSDカードのデータをイメージファイルに保存します。<br />\nここで、<code class=\"language-plaintext highlighter-rouge\">of=</code>で指定しているのが作成するイメージファイル名、<br />\n<code class=\"language-plaintext highlighter-rouge\">count=</code>は上で調べたパーティションの終了位置をしていします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>/dev/mmcblk0 <span class=\"nv\">of</span><span class=\"o\">=</span>hoge1.img <span class=\"nv\">bs</span><span class=\"o\">=</span>1M <span class=\"nv\">count</span><span class=\"o\">=</span>3760 <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div></div>\n\n<p>必要ならzip圧縮しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>zip hoge1.zip hoge1.img \n</code></pre></div></div>\n\n<h1 id=\"新しい環境での起動\">新しい環境での起動</h1>\n\n<h2 id=\"新しいsdカードにバックアップを復元\">新しいSDカードにバックアップを復元</h2>\n\n<p>上で作成したイメージファイルをSDカードに書き込み(WindowsでもUbuntuでもお好きにどうぞ)、</p>\n\n<h2 id=\"最初のブート\">最初のブート</h2>\n<p>RaspberryPiに挿入しBootします(特別な手順は特にありません)。</p>\n\n<h2 id=\"新しいsdカードのパーティションを拡張\">新しいSDカードのパーティションを拡張</h2>\n\n<p>Boot完了したらlog inしてパーティションサイズを変更するために\n以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash first_boot_settings/expand_partition.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nまたは、RaspberryPiにgpartedをインストールして、<br />\nパーティションを縮小したときと同様に最大サイズまでパーティションサイズを拡大しても良いです。<br />\nパーティションの拡大はマウントしたままでも可能。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPiの場合は<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>でパーティション拡張できる</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config --expand-rootfs  \n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">Please reboot</code>と言われたらrebootする。</p>\n</blockquote>\n\n<h2 id=\"その他\">その他</h2>\n<p>必要であれば、ホスト名など必要な変更を行います。</p>\n\n<h2 id=\"リブート\">リブート</h2>\n<p>リブートします。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をセットアップする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をセットアップする(Jetpack4.6)</h1>\n      <p>Jetson nano をセットアップする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Nvidiaの<a href=\"https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/\">Jetson nano</a>をセットアップしたときのメモ<br />\nJetpack4.4のときのメモは<a href=\"/memoBlog/2020/10/23/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする</a> にあります。</p>\n\n<h1 id=\"参照先\">参照先</h1>\n<ul>\n  <li><a href=\"https://monoist.atmarkit.co.jp/mn/articles/1905/30/news029.html\">「Jetson Nano」の電源を入れて立ち上げる</a>\n    <ul>\n      <li>わりと詳しく書いてある</li>\n    </ul>\n  </li>\n  <li><a href=\"https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit\">Getting Started With Jetson Nano Developer Kit </a>\n    <ul>\n      <li>本家</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"シリアルコンソールの使用\">シリアルコンソールの使用</h1>\n<p>シリアルコンソールが必要なら接続できる。<br />\n特に設定等は必要ない。  <br />\n接続端子は以下を参照</p>\n<ul>\n  <li><a href=\"https://www.jetsonhacks.com/2019/04/19/jetson-nano-serial-console/\">Jetson Nano – Serial Console</a>\nの 「Wiring」の下の「Jetson Nano B01」を参照。</li>\n</ul>\n\n<p>シリアルポートの設定は115200bps/8bit/none/1bit/none</p>\n\n<p>その他、コネクタ類の配置が分かりにくい場合は、\n<a href=\"https://developer.download.nvidia.com/assets/embedded/secure/jetson/Nano/docs/NV_Jetson_Nano_Developer_Kit_User_Guide.pdf?yIbsUqvBKxI1G6r3WW7cOdheZGv2-eSfaFW_kMt3dSgi0NJ7h77OwFHr5b-rquc3IX7Tyrt8FV6IKD4DHqvP4_LzhWt55tb071gqXlNGwBPYCOC5pnEKAla8D-B82bPjhQMykANFyn-EhxZRHC8AIBYWuVwwwXVPWtCOjs34Tg50oBdN0vBNoyUlZMRFXLNJ2to\">JETSON NANO DEVELOPER KIT</a>\nのP22 に<strong>Developer kit module and carrier board: rev B01 top view</strong>として配置図が掲載されているので参照のこと。</p>\n\n<h1 id=\"sdカードの作成firstboot\">SDカードの作成~FirstBoot</h1>\n<p>基本的に参照先の通り。<br />\n<a href=\"https://developer.nvidia.com/embedded/downloads\">https://developer.nvidia.com/embedded/downloads</a>\nから「Jetson Nano Developer Kit SD Card Image」  の Version 「4.6」 をダウンロード<br />\n(他のバージョンが必要ならそのバージョンで)</p>\n\n<p>ファーストブートで設定が終わったら、何はともあれ最新版にアップデート。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ここで一旦リブートしておく。</p>\n\n<h1 id=\"sshでの接続\">SSHでの接続</h1>\n<p>特に設定などは必要ない。<br />\nTeraTermなどで接続すれば良い。\nUbuntuではmDNSが動いているので、«マシン名».localでアクセスできる。</p>\n\n<p>TeraTerm使用時のコマンドは以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\"C:\\Program Files (x86)\\teraterm\\ttermpro.exe\" /auth=password /user=«ユーザ名» /passwd=«パスワード» «JetsonのIPアドレス or マシン名.local»\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nSSHやmDNSは立ち上がるまで少し時間がかかるみたいなので、<br />\n起動後数十秒程度待ってから接続した方が良い。</p>\n</blockquote>\n\n<h2 id=\"ssh接続がタイムアウトする対策\">SSH接続がタイムアウトする対策</h2>\n<p>SSH接続したターミナルを触らずにしばらく置いておくと、タイムアウトしてクローズされてしまう。\nこれを防ぐにはクライアント側からkeep-aliveパケットを定期的に送信してやれば良いらしい。</p>\n\n<p>Teratermの場合、「設定」→「SSH」→「ハートビート(keep-alive)」を「8」とかに設定し、保存。\n次回接続時はこの保存した設定ファイルを読み込む</p>\n\n<h1 id=\"初期設定\">初期設定</h1>\n<h2 id=\"bashrcの修正\">.bashrcの修正</h2>\n<p>.bashrcの修正をお好みで。<br />\n以下は設定例</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> resize <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># numpy 1.19.5 のimportでcore dumpする対策</span>\n<span class=\"nb\">export </span><span class=\"nv\">OPENBLAS_CORETYPE</span><span class=\"o\">=</span>ARMV8\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"c\"># export PYTHON_CONFIGURE_OPTS=\"--enable-ipv6\\</span>\n    <span class=\"c\">#     --enable-unicode=ucs4\\</span>\n    <span class=\"c\">#     --enable-shared\\</span>\n    <span class=\"c\">#     --with-dbmliborder=bdb:gdbm\\</span>\n    <span class=\"c\">#     --with-system-expat\\</span>\n    <span class=\"c\">#     --with-system-ffi\\</span>\n    <span class=\"c\">#     --with-fpectl\"</span>\n    <span class=\"c\"># Ubuntu向け対策</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vim\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># venvの仮想環境名を表示するための設定</span>\n    show_virtual_env<span class=\"o\">()</span> <span class=\"o\">{</span>\n      <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"s2\">)\"</span>\n      <span class=\"k\">fi</span>\n    <span class=\"o\">}</span>\n    <span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s1\">'$(show_virtual_env)'</span><span class=\"nv\">$PS1</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># DISPLAYが未定義なら設定する</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-z</span> <span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n    <span class=\"k\">fi\nfi</span>\n</code></pre></div></div>\n\n<h2 id=\"不要なソフトのアンインストール\">不要なソフトのアンインストール</h2>\n<p>使わないのでアンインストールしておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\n</code></pre></div></div>\n\n<h2 id=\"guiの動作の設定変更をお好みで\">GUIの動作の設定変更をお好みで</h2>\n<!--\n「ウィンドウが勝手に最大化するのをやめる」はOK\n「ウィンドウにマウスを乗せるとフォーカスされるようにする」で \"focus-mode\" は 'mouse' ではなく 'sloppy'\n「デスクトップからゴミ箱とホームを消す」は項目としてないらしい\n「Dockのカスタマイズ」は設定できるけど有効でない?\n「マウスカーソルを大きくする」は設定できるけど有効でない?リブートすると元に戻る?\nwindowの閉じるボタンなどを右に移動するにはgnome-tweaskでWindowsのTitlebar Buttons を設定する → 反映されず\n「CAPSキーをCtrlキーに変更」はOK\n-->\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.mutter auto-maximize\ngsettings get org.gnome.mutter edge-tiling\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.desktop.wm.preferences auto-raise \ngsettings get org.gnome.desktop.wm.preferences focus-mode \ngsettings get org.gnome.desktop.wm.preferences raise-on-click\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode sloppy\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"capsキーをctrlキーに変更\">CAPSキーをCtrlキーに変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.input-sources xkb-options\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.input-sources xkb-options <span class=\"se\">\\[\\'</span>ctrl:nocaps<span class=\"se\">\\'\\]</span>\n\n<span class=\"c\"># 設定を有効にするにはGUIでのlogout&再loginが必要</span>\n\n</code></pre></div></div>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>IPv6を無効化したい場合は、\n/<code class=\"language-plaintext highlighter-rouge\">boot/extlinux/extlinux.conf</code>の<code class=\"language-plaintext highlighter-rouge\">APPEND</code>の行の最後に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加してリブートする<br />\n参考: <a href=\"https://www.rough-and-cheap.jp/ubuntu/ubuntu18_04_howto_diseable_ipv6/\" target=\"_blank\">Ubuntu 18.04 で ipv6 を無効にする</a></p>\n<blockquote>\n  <p>[!NOTE]\ngrubではなく、U-Bootなので設定するところが違う</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSysctl の設定ではうまくいかなかった。</p>\n</blockquote>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work\n</code></pre></div></div>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<h3 id=\"インストール\">インストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<h3 id=\"設定ファイル\">設定ファイル</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<h3 id=\"ユーザの追加と再起動\">ユーザの追加と再起動</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"vncサーバvinoの設定\">VNCサーバ(vino)の設定</h2>\n<p>参考: <a href=\"https://zenn.dev/tunefs/articles/9774eb8f229e1bf97a8c\">https://zenn.dev/tunefs/articles/9774eb8f229e1bf97a8c</a>\n以下、参考先をベースに説明</p>\n\n<h3 id=\"vinoのインストール\">Vinoのインストール</h3>\n<p>インストール済みなので不要</p>\n\n<h3 id=\"vinoの自動起動の設定\">Vinoの自動起動の設定</h3>\n<p>コピー先ディレクトリは作成済み</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> /usr/share/applications/vino-server.desktop ~/.config/autostart/\n</code></pre></div></div>\n\n<h3 id=\"vinoのコンフィグレーション\">Vinoのコンフィグレーション</h3>\n<p>実行は以下のみでOK</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.Vino prompt-enabled <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false</span>\n</code></pre></div></div>\n<p>以下は不要</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>set org.gnome.Vino authentication-methods は \"['vnc']\" でなく \"['none']\"   デフォルトと同じなので不要\ngsettings set org.gnome.Vino vnc-password $(echo -n 'thepassword'|base64) は不要\n</code></pre></div></div>\n\n<h3 id=\"自動loginの設定\">自動loginの設定</h3>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定する</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h3 id=\"解像度の設定\">解像度の設定</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n\n<h3 id=\"リブートする\">リブートする</h3>\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続する。</p>\n\n<h3 id=\"設定メニューを表示できるようにする\">設定メニューを表示できるようにする</h3>\n<p>上記だけで設定は完了するが、設定メニュー(Settings)から設定しようとするとエラーになるので、\nそれを修正しておく(やらなくても設定メニュー使わなければ問題ない)。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml</code>に以下のパッチを当てる</li>\n</ul>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  /tmp/a.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- org.gnome.Vino.gschema.xml.org      2020-10-19 06:21:32.034728957 +0900\n</span><span class=\"gi\">+++ org.gnome.Vino.gschema.xml  2020-10-19 06:22:30.887994965 +0900\n</span><span class=\"p\">@@ -154,5 +154,14 @@</span>\n       </description>\n       <default>true</default>\n     </key>\n<span class=\"gi\">+    <key name='enabled' type='b'>\n+      <summary>Enable remote access to the desktop</summary>\n+        <description>\n+          If true, allows remote access to the desktop via the RFB\n+          protocol. Users on remote machines may then connect to the\n+          desktop using a VNC viewer.\n+        </description>\n+      <default>false</default>\n+    </key>\n</span>   </schema>\n </schemalist>\n</code></pre></div></div>\n\n<ul>\n  <li>パッチを当てるコマンド\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>patch /usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml /tmp/a.patch\n</code></pre></div>    </div>\n  </li>\n  <li>さらにコンパイルが必要\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>glib-compile-schemas /usr/share/glib-2.0/schemas\n</code></pre></div>    </div>\n  </li>\n  <li>これで「settings」から「Desktop Sharing」が実行できるようになる</li>\n</ul>\n\n<h2 id=\"使用率等の確認ツールのインストールと起動\">使用率等の確認ツールのインストールと起動</h2>\n\n<p>pyenvインストール済みのときは念のため<code class=\"language-plaintext highlighter-rouge\">pyenv shell system</code>しておく。<br />\nvenv環境使用時はデアクティベートしておく。<br />\n(sudo付きで実行してるのでsystemのpython3が使用されるハズだけど)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip\n<span class=\"nb\">sudo </span>pip3 <span class=\"nb\">install </span>jetson-stats\n<span class=\"nb\">sudo </span>jtop \n</code></pre></div></div>\n<p>一度再起動したあとは、<code class=\"language-plaintext highlighter-rouge\">sudo</code>なしの<code class=\"language-plaintext highlighter-rouge\">jtop</code>のみで実行可能。</p>\n<blockquote>\n  <p>[!NOTE]\njtopは結構CPUパワーを喰うので、性能評価等の間は止めておくのが無難と思われる。</p>\n</blockquote>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"sdカードのイメージファイル化\">SDカードのイメージファイル化</h1>\n<p><a href=\"/memoBlog/2021/07/18/sd_image_2.html\" target=\"_blank\">Raspbian SDカードイメージファイルの作成(改訂版)</a>を参照。</p>\n\n<h1 id=\"イメージのコピーからの起動\">イメージのコピーからの起動</h1>\n<h2 id=\"縮小されたパーティションを拡張する\">縮小されたパーティションを拡張する</h2>\n<p>バックアップはパーティションが縮小されているので、拡張する。<br />\n上記参照先の拡張方法ではうまくいかない(JetsonはパーティションがGPTだから?)。<br />\nなので、GUIツールのgpartedを使用して拡張する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gparted\n<span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0       <span class=\"c\"># sshから実行するときはXserverが起動しているマシンをDISPLAY変数に設定</span>\n<span class=\"nb\">sudo </span>gparted /dev/mmcblk0\n</code></pre></div></div>\n\n<ul>\n  <li>Libparted Warning ダイアログで”Not all of the space available to ~”と出たらFixをクリック</li>\n  <li>Libparted Warning ダイアログで”The backup GPT table is corrupt, but the primary appears OK, so that will be used.”と出たらOKをクリック</li>\n  <li>以降も何度か出るが、以下の操作がすべて終わればbackup GPTが新たに作成されるので問題なし。\n    <ul>\n      <li>(これは、ディスクイメージを縮小したときにgdiskコマンドを実行しなかった場合に出ます)</li>\n    </ul>\n  </li>\n  <li>図の«SDカードのパーティション» を右クリック→「Resize/Move」をクリック\n    <ul>\n      <li>「New size」の欄に上にある「Maximum size」以下の値を入力(「Free space following」 に残したいサイズを入れても可)</li>\n      <li>他の入力欄をクリックして自動計算を反映</li>\n      <li>「Resize」をクリック\n-「Edit」→「Apply All Operations」をクリック</li>\n      <li>「Are you sure you want to apply the pending operations?」と聞かれるので、「Apply」をクリック</li>\n    </ul>\n  </li>\n  <li>処理が完了したら閉じるボタンでプログラム終了</li>\n</ul>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"venvによるpython-仮想環境の構築\">venvによるpython 仮想環境の構築</h1>\n<p>いつもはpyenv + virtualenv で環境構築しているが、この環境ではプリインストールされた opencv を使用できないらしい(core dumpする)。<br />\nなので、system上のpythonを使用してvenvで仮想環境を構築して使用するようにしてみた。<br />\n(これ、↓のnumpyの問題かも。でもtensorflowはpython3.6でないとダメだから、pyenv引っ張ってこなくてもいいか。)</p>\n\n<h2 id=\"venvのインストール\">venvのインストール</h2>\n<p>venv使用のためのプログラムをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-venv\n</code></pre></div></div>\n\n<h2 id=\"仮想環境の構築\">仮想環境の構築</h2>\n<p>仮想環境を構築する。<br />\nここで実行したpythonが仮想環境で実行されるpythonになる。<br />\n<code class=\"language-plaintext highlighter-rouge\">--system-site-packages</code> を付加しておくと元のパッケージも参照される。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> «venv_dir»\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">pip list/freeze</code> でも参照される。pipのバージョンが新しければ、<code class=\"language-plaintext highlighter-rouge\">pip -v list</code>と オプション<code class=\"language-plaintext highlighter-rouge\">-v</code>を付けることで インストール先を見分けることでどちらにインストールされているかが判別できる。</p>\n\n<p>例えばこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/TF2.5\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート\">仮想環境のアクティベート</h2>\n<p>pyenvではlocalで指定してあればディレクトリ移動で自動的に仮想環境を切り替えられたが、<br />\nvenvでは逐一仮想環境をアクティベートしなければならない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> «venv_dir»/bin/bin/activate\n</code></pre></div></div>\n\n<h2 id=\"お約束\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"仮想環境の終了\">仮想環境の終了</h2>\n<p>仮想環境を終了するときは以下のコマンドでデアクティベートする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>deactivate\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">deactivate</code>はアクティベート時に関数として登録されている<br />\n下記のようにdirenvで設定した場合は<code class=\"language-plaintext highlighter-rouge\">deactivate</code>は使えないが、ディレクトリから移動すれば元にもどるので問題ない</p>\n</blockquote>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"direnvのインストールと設定\">direnvのインストールと設定</h1>\n<p>仮想環境管理をvenvで行うようにしたが、venvだと逐一activateしないといけないので、pyenvに慣れたカラダでは なかなか 使いにくい。<br />\nそこで、direnvを使ってpyenvに近い使い勝手を実現してみる。</p>\n\n<p>参考:<a href=\"https://yoshitaku-jp.hatenablog.com/entry/2018/07/29/070000\">direnvを使って、source bin/activateを自動化する</a></p>\n\n<h2 id=\"インストール-1\">インストール</h2>\n<p>インストールは<code class=\"language-plaintext highlighter-rouge\">apt</code>でイッパツ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>direnv\n</code></pre></div></div>\n\n<h2 id=\"初期設定-1\">初期設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code> に以下の内容を追記。(上記<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>例では記載済み)<br />\nエディタはvimに設定してあるが、別のものを使いたければ設定変更のこと。<br />\n(direnv 未インストール時は設定はスキップされる)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vim\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># venvの仮想環境名を表示するための設定</span>\n    show_virtual_env<span class=\"o\">()</span> <span class=\"o\">{</span>\n      <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"s2\">)\"</span>\n      <span class=\"k\">fi</span>\n    <span class=\"o\">}</span>\n    <span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s1\">'$(show_virtual_env)'</span><span class=\"nv\">$PS1</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">source ~/.bashrc</code> するか、terminalを開きなおす。</p>\n\n<h2 id=\"対象ディレクトリに処理を登録する\">対象ディレクトリに処理を登録する</h2>\n<p>対象ディレクトリに移動して<code class=\"language-plaintext highlighter-rouge\">direnv edit .</code> を実行して中身を作成するか、 <code class=\"language-plaintext highlighter-rouge\">.envrc</code>を直接生成する。</p>\n\n<p>中身は以下の通り<br />\n他にも設定したい環境変数があれば設定しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> «venv_dir»/bin/activate\n</code></pre></div></div>\n<p>例えばこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/TF2.5/bin/activate\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">direnv: error .envrc is blocked. Run `direnv allow` to approve its content.</code>と言われたら、以下のように実行する。<br />\n(直接編集した時に言われるらしい)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>direnv allow\n</code></pre></div></div>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"tensorflow2-のインストール\">tensorflow2 のインストール</h1>\n<h2 id=\"仮想環境の構築-1\">仮想環境の構築</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/TF2.5\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート-1\">仮想環境のアクティベート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/TF2.5/bin/activate\n</code></pre></div></div>\n<p>またはdirenvで上記が実行されるように設定しておく</p>\n\n<h2 id=\"お約束-1\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<p>tensorflowをimportしたとき(具体的にはその中でnumpyをimportしたとき)に\n<code class=\"language-plaintext highlighter-rouge\">Illegal instruction (core dumped)</code>が発生する。<br />\nこれを回避するため、以下を<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に設定しておく(上記<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>例では記載済み) 。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">OPENBLAS_CORETYPE</span><span class=\"o\">=</span>ARMV8\n</code></pre></div></div>\n\n<p>tensoorflowはpypiではなく、nvidiaのサイトからダウンロードしてインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>https://developer.download.nvidia.com/compute/redist/jp/v46/tensorflow/tensorflow-2.5.0+nv21.7-cp36-cp36m-linux_aarch64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nn5pyインストールでエラーになった時は以下の手順で回避する。  <br />\nミソはh5pyのインストール時点でnumpy 1.19.5がインストールされているとエラーになるので、<br />\n一時的にnumpyのそれ以前のバージョンをインストールしてh5pyをインストールし、その後numpyを本来のバージョンに戻す。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libhdf5-serial-dev hdf5-tools libhdf5-dev\npip <span class=\"nb\">install </span>cython\n<span class=\"c\"># numpyのバージョン下げる  </span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">numpy</span><span class=\"o\">==</span>1.19.3\npip <span class=\"nb\">install </span><span class=\"nv\">h5py</span><span class=\"o\">==</span>2.10.0\n<span class=\"c\"># h5pyのインストールのためにインストールしたnumpyを本来のバージョンに更新  </span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">numpy</span><span class=\"o\">==</span>1.19.5\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"tensorflowなどのありか\">Tensorflowなどのありか</h2>\n<p>以下に色々まとめられている。<br />\n<a href=\"https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime\">https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime</a></p>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"onnx-runtimeのインストール\">onnx-runtimeのインストール</h1>\n<h2 id=\"仮想環境の構築-2\">仮想環境の構築</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/onnx\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート-2\">仮想環境のアクティベート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/onnx/bin/activate\n</code></pre></div></div>\n<p>またはdirenvで上記が実行されるように設定しておく</p>\n\n<h2 id=\"お約束-2\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"インストールファイルのダウンロード\">インストールファイルのダウンロード</h2>\n<p><a href=\"https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime\" target=\"_blank\">Jetson Zoo</a>\nから使用環境に対応するインストールファイルをダウンロードする。<br />\n表の下にあるコマンド例の<code class=\"language-plaintext highlighter-rouge\">wget</code>ではうまくダウンロードできないのでブラウザでダウンロードしてコピっておく。<br />\n以下、onnxruntime 1.8.0/Python 3.6 を選択したものとする。</p>\n\n<h2 id=\"インストール-2\">インストール</h2>\n\n<p>システムにインストールされたprotobufのバージョンが古くてエラーになるので、\nあらかじめ最新版にアップデートしておく。<br />\n(venv環境なので、システムのprotobufには影響ない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> protobuf\n</code></pre></div></div>\n\n<p>ダウンロードしたonnx-runtimeをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>onnxruntime_gpu-1.8.0-cp36-cp36m-linux_aarch64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</h1>\n      <p>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/09/13/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする(Jetpack4.6)</a>\nではVNCにvinoをインストールしましたが、vinoはキー入力/画面描画のレスポンスがかなり遅く、\n結構なストレスになります。<br />\nそこで、代わりに<a href=\"https://tigervnc.org/\">tigerVNC</a>をインストールしてみます。</p>\n\n<p>最初に結論を書いておきますが、レスポンスはvinoより良くなるのですが、クリップボードの共有\n(ホスト/ターゲット間でのコピペ)ができないので、普段使いにはあまり使い勝手が良くありません。<br />\ngithubのリポジトリもずいぶん前から更新されていないみたいなので、今後改善される可能性も低そうです。<br />\nなので、私は使っていません(^^ゞ</p>\n\n<h1 id=\"前準備\">前準備</h1>\n<p>vinoをセットアップしてある場合は停止しておいてください。<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.config/autostart/vino-server.desktop</code> を削除しておけば大丈夫でしょう。<br />\n以下、vinoのセットアップは行っていないものとして記載します。</p>\n\n<h1 id=\"tigervncの設定\">tigerVNCの設定</h1>\n\n<h2 id=\"tiger-vnc-のインストール\">tiger VNC のインストール</h2>\n<p>必要なプログラムをインストールします</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tigervnc-standalone-server tigervnc-scraping-server\n</code></pre></div></div>\n\n<h2 id=\"vncのパスワードの設定\">VNCのパスワードの設定</h2>\n<p>接続パスワードを設定します</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vncpasswd\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">Password:</code>と<code class=\"language-plaintext highlighter-rouge\">Verify:</code>で設定するパスワードを入力<br />\n<code class=\"language-plaintext highlighter-rouge\">Would you like to enter a view-only password (y/n)?</code>には <code class=\"language-plaintext highlighter-rouge\">n</code>を入力<br />\nVNCクライアントから接続する際にこのパスワードを入力します</p>\n\n<h2 id=\"自動loginの設定\">自動loginの設定</h2>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定します</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h2 id=\"解像度の設定\">解像度の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n<h2 id=\"ここで一旦リブートする\">ここで一旦リブートする</h2>\n<p>リブートしないと下の単体テストで「displayがopenできない」とエラーになる模様。</p>\n\n<h2 id=\"手動で動かしてみる画面のミラーリング\">手動で動かしてみる(画面のミラーリング)</h2>\n\n<p>動作確認として、サーバを手動で起動してみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>x0vncserver <span class=\"nt\">-display</span> :0 <span class=\"nt\">-passwordfile</span> ~/.vnc/passwd\n</code></pre></div></div>\n\n<p>サーバが起動したら、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続します。</p>\n\n<p>正常に設定できていればVNCクライアントにデスクトップが表示されます。</p>\n\n<h2 id=\"自動起動の設定\">自動起動の設定</h2>\n<p>逐一<code class=\"language-plaintext highlighter-rouge\">x0vncserver</code>を起動するのは面倒なので、自動で起動するように設定しておきます。</p>\n\n<p>参考: <a href=\"https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f\">https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/systemd/system/x0vncserver.service</code> を以下の内容で作成します。<br />\nただし、<code class=\"language-plaintext highlighter-rouge\">XXXXXXXX</code>の部分は 自分のユーザ名に置き換えてください。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Remote desktop service (VNC)\nAfter=syslog.target\nAfter=network.target remote-fs.target nss-lookup.target\nAfter=x11-common.service \n\n[Service]\nType=forking\nUser=XXXXXXXX\nGroup=XXXXXXXX\nWorkingDirectory=/home/XXXXXXXX\nExecStart=/bin/sh -c 'sleep 10 && /usr/bin/x0vncserver -display :0  -rfbport 5900 -passwordfile /home/XXXXXXXX/.vnc/passwd &'\n\n[Install]\nWantedBy=multi-user.target\n</code></pre></div></div>\n\n<h2 id=\"サービスの起動と確認\">サービスの起動と確認</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl start x0vncserver\n<span class=\"nb\">sudo </span>systemctl status x0vncserver\n</code></pre></div></div>\n\n<p>以下のように出力されることを確認します</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>● x0vncserver.service - Remote desktop service (VNC)\n   Loaded: loaded (/etc/systemd/system/x0vncserver.service; enabled; vendor pres\n   Active: active (running) since Fri 2021-09-03 11:08:07 JST; 8s ago\n  Process: 14646 ExecStart=/bin/sh -c sleep 10 && /usr/bin/x0vncserver -display ・・・・\n Main PID: 14659 (sh)\n    Tasks: 2 (limit: 4172)\n   CGroup: /system.slice/x0vncserver.service\n           ├─14659 /bin/sh -c sleep 10 && /usr/bin/x0vncserver -display :0  ・・・・\n           └─14666 sleep 10\n\n 9月 03 11:08:07 jetson systemd[1]: Starting Remote desktop service (VNC)...\n 9月 03 11:08:07 jetson systemd[1]: Started Remote desktop service (VNC).\n</code></pre></div></div>\n\n<h2 id=\"サービスの有効化\">サービスの有効化</h2>\n<p>起動時に自動実行されるように、サービスの有効化を行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl <span class=\"nb\">enable </span>x0vncserver\n</code></pre></div></div>\n\n<h2 id=\"リブート\">リブート</h2>\n\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続します。</p>\n\n<p>正常に起動できていればVNCクライアントにデスクトップが表示されます。</p>\n\n<h1 id=\"別のやり方参考\">別のやり方(参考)</h1>\n<p>ディスプレイとは別のデスクトップを表示する場合は以下の手順で。<br />\nここではwindow managerにlxdeを使用していますので、モニタ表示とは異なる見た目になりますし、\nウィンドウマネージャの設定も同じではありません。</p>\n\n<p>参考:<a href=\"https://forums.developer.nvidia.com/t/how-to-setup-tigervnc-on-jetson-nano/174244\">https://forums.developer.nvidia.com/t/how-to-setup-tigervnc-on-jetson-nano/174244</a></p>\n\n<p>一回試しただけ(ちゃんとメモってなかった)なので、抜けとかあるかも。</p>\n\n<h2 id=\"tiger-vnc-のインストール-1\">Tiger VNC のインストール</h2>\n<p>必要なプログラムをインストールします</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tigervnc-standalone-server\n</code></pre></div></div>\n\n<h2 id=\"vncのパスワードの設定-1\">VNCのパスワードの設定</h2>\n<p>接続パスワードを設定します</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vncpasswd\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">Password:</code>と<code class=\"language-plaintext highlighter-rouge\">Verify:</code>で設定するパスワードを入力<br />\n<code class=\"language-plaintext highlighter-rouge\">Would you like to enter a view-only password (y/n)?</code>には <code class=\"language-plaintext highlighter-rouge\">n</code>を入力<br />\nVNCクライアントから接続する際にこのパスワードを入力します</p>\n\n<h2 id=\"自動loginの設定-1\">自動loginの設定</h2>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定します</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h2 id=\"解像度の設定-1\">解像度の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n\n<h2 id=\"vncxstartup-の作成\">~/.vnc/xstartup の作成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.vnc/xstartup</code> を以下の内容で作成します<br />\nXXXXXXXX は 自分のユーザ名に置き換えてください</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">!</span>/bin/sh\n<span class=\"nb\">export </span><span class=\"nv\">XDG_RUNTIME_DIR</span><span class=\"o\">=</span>/run/user/1000\n<span class=\"nb\">export </span><span class=\"nv\">XKL_XMODMAP_DISABLE</span><span class=\"o\">=</span>1\n<span class=\"nb\">unset </span>SESSION_MANAGER\n<span class=\"nb\">unset </span>DBUS_SESSION_BUS_ADDRESS\nxrdb /home/XXXXXXXX/.Xresources\nxsetroot <span class=\"nt\">-solid</span> grey\ngnome-session &\nstartlxde &\n</code></pre></div></div>\n\n<p>実行属性を付けます</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod </span>755 ~/.vnc/xstartup\n</code></pre></div></div>\n\n<h2 id=\"xresources-ファイルの作成\">.Xresources ファイルの作成</h2>\n<p>.Xresources ファイルを作成します</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">touch</span> ~/.Xresources\n</code></pre></div></div>\n\n<h2 id=\"vncの自動起動の設定\">VNCの自動起動の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/systemd/system/vncserver@.service</code>を以下の内容で作成します<br />\nXXXXXXXX は 自分のユーザ名に置き換えてください</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Start TigerVNC Server at startup\nAfter=syslog.target network.target\n\n[Service]\nType=forking\nUser=XXXXXXXX\nGroup=XXXXXXXX\nWorkingDirectory=/home/XXXXXXXX\nPIDFile=/home/XXXXXXXX/.vnc/%H:%i.pid\nExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1\nExecStart=/usr/bin/vncserver :%i -depth 24 -geometry 1920x1080 -nolisten tcp\n\nExecStop=/usr/bin/vncserver -kill :%i\n\n[Install]\nWantedBy=multi-user.target\n</code></pre></div></div>\n\n<h2 id=\"リモートからのアクセス許可\">リモートからのアクセス許可</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/vnc.conf</code> に以下を追記してリモートアクセスを許可します</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$localhost = “no”;\n</code></pre></div></div>\n\n<h2 id=\"systemctl-enable-の代わりにシンボリックリンクの作成\">systemctl enable の代わりにシンボリックリンクの作成</h2>\n<p>参照元がこうなってたので。<br />\n<code class=\"language-plaintext highlighter-rouge\">sudo systemctl enable vncserver@</code>でも良い気がするけど。ここのファイル名でポート番号決めてる?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /etc/systemd/system/multi-user.target.wants/\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /etc/systemd/system/vncserver@.service vncserver@1.service\n</code></pre></div></div>\n\n<h2 id=\"リブートする\">リブートする</h2>\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5901に接続します。<br />\n(VNCクライアントの接続先に<code class=\"language-plaintext highlighter-rouge\">«JetsonのIPアドレス»:5901</code> を指定します)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</h1>\n      <p>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>SDカードのアクセスが遅いのと、USBドライブの方が大容量のメディアを入手しやすいので\nUSBドライブをブートデバイスに変更してみる。</p>\n\n<p>といっても、Jetpack4.5以降ではブートローダがUSBからのブートをサポートしたので、かなり簡単になった。</p>\n\n<p>Jetpack4.4のときのメモは<a href=\"/memoBlog/2020/10/30/Jetson_usb_boot.html\" target=\"_blank\">Jetson nano をUSBドライブからブートできるようにする</a> にあります。</p>\n\n<h1 id=\"ディスクイメージの書き込み\">ディスクイメージの書き込み</h1>\n<p>通常セットアップを行ったSDカードのディスクイメージをUSBドライブにコピーします。\nSDカード→USBドライブ直接でも構いませんし、バックアップとして作成したディスクイメージファイルからでも構いません。</p>\n\n<p>ubuntu PCでディスクイメージファイルからコピーする場合はこんな感じ。<br />\n<code class=\"language-plaintext highlighter-rouge\">/dev/sdc</code> の部分は環境により異なるので注意(間違って他のディスクに上書きしないように!!)。<br />\n<code class=\"language-plaintext highlighter-rouge\">jetpack46_XXXXXXXX.img</code>がディスクイメージファイルのファイル名です。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"nv\">of</span><span class=\"o\">=</span>/dev/sdc <span class=\"k\">if</span><span class=\"o\">=</span>jetpack46_XXXXXXXX.img <span class=\"nv\">bs</span><span class=\"o\">=</span>1M <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div></div>\n\n<h1 id=\"bootデバイス変更のための設定\">BOOTデバイス変更のための設定</h1>\n\n<p>ディスクイメージを書き込んたUSBドライブをSDカードブートした Jetson nano や ubuntu PCに接続し、\n設定ファイルを書き換えます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ディスクのマウント</span>\n<span class=\"nb\">sudo </span>mount /dev/sdc1 /mnt\n<span class=\"nb\">cd</span> /mnt/boot/extlinux/\n<span class=\"c\"># オリジナルファイルのバックアップ</span>\n<span class=\"nb\">sudo cp </span>extlinux.conf extlinux.conf.mmc\n<span class=\"c\"># 編集</span>\n<span class=\"nb\">sudo </span>vi extlinux.conf\n</code></pre></div></div>\n\n<p>以下のように変更します\n具体的には<code class=\"language-plaintext highlighter-rouge\">/mnt/boot/extlinux/extlinux.conf</code> 内の \n<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0p1</code>を<code class=\"language-plaintext highlighter-rouge\">/dev/sda1</code>に変更します。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- extlinux.conf.mmc\t2021-09-14 06:02:45.889520568 +0900\n</span><span class=\"gi\">+++ extlinux.conf\t2021-09-14 06:03:29.453873117 +0900\n</span><span class=\"p\">@@ -7,7 +7,7 @@</span>\n       MENU LABEL primary kernel\n       LINUX /boot/Image\n       INITRD /boot/initrd\n<span class=\"gd\">-      APPEND ${cbootargs} loglevel=6 root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 ipv6.disable=1\n</span><span class=\"gi\">+      APPEND ${cbootargs} loglevel=6 root=/dev/sda1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 ipv6.disable=1\n</span> \n # When testing a custom kernel, it is recommended that you create a backup of\n # the original kernel and add a new entry to this file so that the device can\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nrootパラメータはパーティションのUUIDを書いておくのが最近の作法らしいが\n大抵 マウント先は <code class=\"language-plaintext highlighter-rouge\">/dev/sda1</code> なので、お手軽にこっちで指定する。</p>\n</blockquote>\n\n<h1 id=\"ついでに設定\">ついでに設定</h1>\n<p>ついでにパーティションサイズも変更しておくと良いです。</p>\n\n<h1 id=\"boot\">BOOT</h1>\n<p>あとはJetson nano にUSBドライブを接続し、元々ブートに使用していた<strong>SDカードを取り外し</strong>て電源ON。</p>\n\n<p>起動後、USBドライブがrootにマウントされていることを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">mount</code>で確認しても良いけど、いっぱい出てきて鬱陶しいので<code class=\"language-plaintext highlighter-rouge\">df</code>で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">df</span> <span class=\"nt\">-h</span> /\n</code></pre></div></div>\n<p>こんな感じで行頭にマウント元が表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Filesystem      Size  Used Avail Use% Mounted on\n/dev/sda1       108G   13G   91G  13% /\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Dockerをインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Dockerをインストールする</h1>\n      <p>Windos/Ubuntu に Dockerをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows10-home-に-dockerをインストールする\">Windows10 Home に Dockerをインストールする</h1>\n<p>HomeだとWSL2必須なので、WSL2はあらかじめインストールして使用できるようにしておく。<br />\n<a href=\"/memoBlog/2021/03/03/WSL_memo.html\" target=\"_blank\">WSL2 メモ</a></p>\n\n<p><a href=\"https://docs.docker.jp/docker-for-windows/install-windows-home.html\" target=\"_blank\">https://docs.docker.jp/docker-for-windows/install-windows-home.html</a> を参考にインストールする。 <br />\nとはいっても、<a href=\"https://hub.docker.com/editions/community/docker-ce-desktop-windows/\" target=\"_blank\">https://hub.docker.com/editions/community/docker-ce-desktop-windows/</a>からダウンロードして実行するだけ。</p>\n\n<p>コンテナを一杯作るとデータ領域がどんどん肥大していくので、Cドライブから変更しておいた方が良いかも。<br />\n<a href=\"https://nosubject.io/windowsdocker-desktop-move-disk-image/\" target=\"_blank\">Docker Desktop の ディスク領域 を Cドライブから別のドライブへ移動する方法</a><br />\nを参考に作業すればOK。<br />\nVHDをエクスポート、元の仮想マシンのレジストリを削除、他の場所へ同名でインポート、とやってる。</p>\n\n<h1 id=\"ubuntu-に-dockerをインストールする\">Ubuntu に Dockerをインストールする</h1>\n<p><a href=\"https://docs.docker.jp/linux/step_one.html\" target=\"_blank\">https://docs.docker.jp/linux/step_one.html</a> を参考にインストールする。 <br />\n実際は以下を実行するだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>curl <span class=\"nt\">-fsSL</span> https://get.docker.com/ | sh\n</code></pre></div></div>\n\n<p>docker実行に逐一<code class=\"language-plaintext highlighter-rouge\">sudo</code>をつけるのは面倒なので、以下の設定をしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> docker\n</code></pre></div></div>\n<p>設定後は念のためリブートしておく(logoutだけで可らしいけど)。</p>\n\n<h1 id=\"インストール後のお試し実行\">インストール後のお試し実行</h1>\n<p>正常に動いていることを確認するためになんか動かしてみる。<br />\n以下はWindows版で書かれているが、基本的にUbuntuでも同じ。<br />\n<a href=\"https://qiita.com/nanaki11/items/97e5685ed84547526be2\" target=\"_blank\">https://qiita.com/nanaki11/items/97e5685ed84547526be2</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">docker pull</code>はしなくても<code class=\"language-plaintext highlighter-rouge\">docker run</code>したときにローカルにimegeがなければ自動でダウンロードしてくれるらしい。</p>\n\n<h1 id=\"コマンド例\">コマンド例</h1>\n<p>ちょろっと試したコマンド群</p>\n<h2 id=\"コンテナの生成\">コンテナの生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの起動\">コンテナの起動</h2>\n<p>終了したコンテナの再開も同じ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> py_test\n</code></pre></div></div>\n\n<h2 id=\"コンテナに新たなコンソール接続\">コンテナに新たなコンソール接続</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> py_test /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの生成と起動を同時に行う\">コンテナの生成と起動を同時に行う</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">create</code>を<code class=\"language-plaintext highlighter-rouge\">run</code>に変えるだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"nwork-を-work-にマウントする場合windows\">n:\\work を /work にマウントする場合(Windows)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /n/work:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"カレントディレクトリを-work-にマウントする場合ubuntu\">カレントディレクトリを /work にマウントする場合(ubuntu)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナ一覧起動中のもののみ\">コンテナ一覧(起動中のもののみ)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<h2 id=\"コンテナ一覧終了したものを含む\">コンテナ一覧(終了したものを含む)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n\n<h2 id=\"pull済みイメージ一覧\">pull済みイメージ一覧</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<h2 id=\"コンテナの情報を確認する\">コンテナの情報を確認する</h2>\n<p>下記コマンドでJSONデータが出力される。<br />\n直近で興味ありそうなのは<code class=\"language-plaintext highlighter-rouge\">HostConfig</code>、<code class=\"language-plaintext highlighter-rouge\">Mounts</code>、<code class=\"language-plaintext highlighter-rouge\">NetworkSettings</code>あたりかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker inspect py_test2\n</code></pre></div></div>\n\n<h1 id=\"どんなイメージがあるのか\">どんなイメージがあるのか?</h1>\n<p><a href=\"https://hub.docker.com/search?type=image\" target=\"_blank\">dockerhub</a>でサーチしてちょ。</p>\n\n<h1 id=\"dockerはwsl2でどんな感じで動いているのか\">DockerはWSL2でどんな感じで動いているのか?</h1>\n<p>あんまり意味ないけど。<br />\n<a href=\"https://www.docker.com/blog/new-docker-desktop-wsl2-backend/\" target=\"_blank\">https://www.docker.com/blog/new-docker-desktop-wsl2-backend/</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>VSCodeでDocker内のpythonプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>VSCodeでDocker内のpythonプログラムをデバッグする</h1>\n      <p>VSCodeでDocker内のpythonプログラムをデバッグする(Windos/Ubuntu)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからWindows上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nubuntu上のVSCodeからubuntu上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nどちらもほぼ同じ手順でデバッグできる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>VScodeに拡張機能Python、Docker、Remote Containers をインストールしておく</p>\n\n<h1 id=\"コンテナ起動\">コンテナ起動</h1>\n<p>ターミナルからコンテナ起動する<br />\nソースの編集をしやすいように、ホストのフォルダを<code class=\"language-plaintext highlighter-rouge\">/work</code>に割り当てている。<br />\nいや、VSCodeで編集すれば問題ないんだけどさ…<br />\nいつも編集は別のエディタ使ってたりするとコンテナ内のファイルいじるのが面倒なので…</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Windows\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> /m/work/zzz:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ubuntu\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> <span class=\"sb\">`</span><span class=\"nb\">realpath</span> .<span class=\"sb\">`</span>:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンテナを一度作成してあれば起動していなくても大丈夫らしい。</p>\n</blockquote>\n\n<h1 id=\"コンテナに接続\">コンテナに接続</h1>\n<p>VScodeのリモートエクスプローラにコンテナが見える</p>\n<blockquote>\n  <p>[!NOTE]\nRemote SSHやRemote WSLがインストールされている場合はリモートエクスプローラ上部のドロップダウンリストからContainersを選択</p>\n</blockquote>\n\n<p>対象のコンテナを右クリックして<code class=\"language-plaintext highlighter-rouge\">Attach to Container</code> または<code class=\"language-plaintext highlighter-rouge\">Attach in New Window</code>をクリック<br />\n<code class=\"language-plaintext highlighter-rouge\">Attaching to a container may execute arbitrary code</code><br />\nと言われるたら、変なコードが実行されないことが分かっていれば <code class=\"language-plaintext highlighter-rouge\">Got it</code> をクリック</p>\n<blockquote>\n  <p>[!NOTE]\n一度開いたフォルダはその下にショートカットが表示されているので、そこから開けば手っ取り早い。</p>\n</blockquote>\n\n<p>コンテナが開く</p>\n\n<p>コンテナ内には拡張機能が入ってないので、必要な拡張機能をインストールする</p>\n\n<h1 id=\"デバッグ\">デバッグ</h1>\n<p>エクスプローラでデバッグしたいフォルダを開いてソースを開く(VSCodeの設定によっては前回開いていたフォルダが開かれる)<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Python: Select Interpreter</code> で 使用するpythonを選択する。<br />\nこのとき、必ずしも使用するpythonのpathが表示されているとは限らないので、<br />\n(逆にコンテナ内にないホスト側のものが表示されたりする😢)<br />\n表示されていない場合は<code class=\"language-plaintext highlighter-rouge\">+ Enter Interpreter path...</code>から使用するpythonを選択する。<br />\n上記イメージの場合、<code class=\"language-plaintext highlighter-rouge\">/usr/local/bin/python3</code> なので、これを設定。</p>\n<blockquote>\n  <p>[!NOTE]\nあらかじめコンソールで which python3 して調べておく</p>\n</blockquote>\n\n<p>あとはローカルと同じようにデバッグできる。</p>\n\n<h1 id=\"コンテナとの接続終了\">コンテナとの接続終了</h1>\n\n<p>コンテナとの接続を終了するときは<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Remote: Close Remote Connection</code> で終了する。</p>\n\n<p>接続終了してもコンテナを停止しないので、別途停止処理を行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker stop py_test2\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>こういうのもある。<br />\n(参照しているのはmicrosoft純正のサンプルらしい)<br />\n普通にDocker使うのと異なるファイル<code class=\"language-plaintext highlighter-rouge\">devcontainer.json</code>を使うので、\n便利なんだか不便なんだか…<br />\nDocker拡張機能なくても動かせた気がする。<br />\n<a href=\"https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html\">https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerコンテナからGUIを起動する</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerコンテナからGUIを起動する</h1>\n      <p>Windos/Ubuntu の DockerコンテナからGUIを起動する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuでローカルのデスクトップに表示する場合\">Ubuntuでローカルのデスクトップに表示する場合</h1>\n<p>Docker(ubuntu)のみ。<br />\nコンテナ生成時に以下のように<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数の設定と<code class=\"language-plaintext highlighter-rouge\">/tmp/.X11-unix/</code>のマウントを行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test3 <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n<p>この場合、表示する前にホスト側で以下を実行しておく必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>xhost +local:\n</code></pre></div></div>\n<p>実行していない場合、GUI起動コマンド実行で以下のエラーが出る。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>No protocol specified\nError: Can't open display: XXX\n</code></pre></div></div>\n\n<p>Ubuntuを再起動したときに設定は忘れられてしまうので、起動の度に実行必要。</p>\n\n<blockquote>\n  <p>[!NOTE]\nxhostはセキュリティ上問題があるとのことだが、家の中だけだし、localだけなら許可してもいいかな…\nrc.localあたりに書いとこうかと思ったけど、使用するときだけ実行するのが無難かな。</p>\n</blockquote>\n\n<h1 id=\"windows上のvcxsrvに表示する場合\">Windows上のVcXsrvに表示する場合</h1>\n<p>Docker(windows)だとコレ一択。<br />\nDocker(ubuntu)でも大丈夫。<br />\nなので、Docker(ubuntu)にリモート接続で使用することがある場合はこっちを使っておくのが良いと思う。<br />\nWindowsマシンのIPアドレスが192.168.XXX.XXX(マシン名指定不可)だとして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test4 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XXX.XXX:0.0 <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ubuntuにSSHサーバをセットアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ubuntuにSSHサーバをセットアップする</h1>\n      <p>ubuntuにSSHサーバをセットアップするし、公開鍵認証を設定する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuにsshサーバをセットアップする\">UbuntuにSSHサーバをセットアップする</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n\n<p>この状態でWindowsなどから以下のコマンドで接続するとパスワード認証でlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«ユーザ名»@«IPアドレス»<span class=\"s1\">'s password: «パスワードを入力»  \n</span></code></pre></div></div>\n\n<p>リモート接続でshellを使うだけならこれでも良いが、\nVScodeでリモートデバッグをしたりするときなどはパスワード入力を何回も行う必要があったりして面倒。<br />\nそこで、公開鍵認証を設定してパスワード入力を不要にする。</p>\n\n<h1 id=\"秘密鍵と公開鍵の生成と公開鍵ファイルの設置\">秘密鍵と公開鍵の生成と公開鍵ファイルの設置</h1>\n<p>Windowsマシンで以下のコマンドを実行して秘密鍵ファイルと公開鍵ファイルを生成する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh-keygen.exe <span class=\"nt\">-t</span> rsa\n<span class=\"o\">(</span>リターン3回<span class=\"o\">)</span>\n※ 本当はpassphase入れないといけないけど、ローカルお試し環境なので省略\n</code></pre></div></div>\n<p>実行すると以下のファイルが出来る</p>\n<ul>\n  <li>%USERPROFILE%/.ssh/id_rsa</li>\n  <li>%USERPROFILE%/.ssh/id_rsa.pub</li>\n</ul>\n\n<p>このうち、<code class=\"language-plaintext highlighter-rouge\">id_rsa.pub</code>をUbuntuマシンの <code class=\"language-plaintext highlighter-rouge\">~/.ssh</code>へ<code class=\"language-plaintext highlighter-rouge\">authorized_keys</code>というファイル名でコピー(既に存在する場合は追記)する。</p>\n<blockquote>\n  <p>[!NOTE]\nやり方検索すると<code class=\"language-plaintext highlighter-rouge\">scp</code>コマンドでコピーする方法が紹介されているが、\n家の中だけなのでネットワークドライブ経由でのコピーや\nファイル自体はテキストファイルなので、SSH接続したshellからエディタを起動して\nコピペするのでも良い。</p>\n</blockquote>\n\n<p>コピーが完了したらファイルのパーミッションを変更する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod </span>600 ~/.ssh/authorized_keys\n</code></pre></div></div>\n\n<h1 id=\"接続テスト\">接続テスト</h1>\n<p>この状態でWindowsマシンから以下のコマンドで接続するとパスワード認証なしでlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«パスワード入力なしで接続»\n</code></pre></div></div>\n\n<p>Windows側のユーザディレクトリ/.ssh/config の設定もやっておくと便利<br />\n参考: <a href=\"https://qiita.com/passol78/items/2ad123e39efeb1a5286b\">https://qiita.com/passol78/items/2ad123e39efeb1a5286b</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</h1>\n      <p>ローカル(Windows)のVSCodeからリモートホスト(ubuntu)上のDockerコンテナ内のプログラムをデバッグする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからUbuntu上のDockerコンテナに接続してデバッグする方法。</p>\n\n<p>UbuntuへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>\nsudo なしで Docker動かせるようにしとく必要あり</p>\n\n<h1 id=\"リモートホストへの接続\">リモートホストへの接続</h1>\n<p>UbuntuへのSSH接続の準備については<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">こちら</a></p>\n\n<h2 id=\"手順\">手順</h2>\n<ul>\n  <li>WindowsマシンでVScode 起動する</li>\n  <li>拡張機能「Remote Development」をインストールしておく。</li>\n  <li>左下にある「><」ボタンをクリック</li>\n  <li>上にメニューが出るので、「Connect to host…」 または「Connect Current Window to Host…」を選択</li>\n  <li>続いて「Select configured SSH host~」で接続するホストを選択。\n    <ul>\n      <li>新規接続の場合は「Add New SSH Host…」を選択</li>\n      <li>「ssh «user»@«IPアドレス or マシン名»」</li>\n      <li>設定を保存するファイルを選択。特に理由がなければ c:\\Users\\«ユーザ».config でいいかな。</li>\n      <li>右下に「Host added!」ウィンドウが出るので「Connect」をクリック</li>\n      <li>初めて接続するホストの場合、上にSelect the platform of remote host “~” と聞かれるのでOS種別を選択</li>\n      <li>「あんた«OS»を選らんだでー。~に保存したから変えたかったら ここ変更しぃや~」みたいなことを言ってるウィンドウが出るので「Don’t Show Again」をクリック</li>\n    </ul>\n  </li>\n  <li>接続された。右下の「><」ボタンが「>< SSH:«マシン名»」に変わっている。</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n一度接続すればリモートエクスプローラ(SSH TARGETS)に表示されるのでそこから接続しても良い。</p>\n</blockquote>\n\n<p>リモートホスト上のプログラムをデバッグしたい場合はここでフォルダを開いてごちょごちょやればよい。</p>\n\n<h1 id=\"dockerコンテナへの接続\">Dockerコンテナへの接続</h1>\n<h2 id=\"準備\">準備</h2>\n<p>WindowsマシンにDocker desktop for windows が必要になるので、インストールしておく。<br />\nWindowsへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\">こちら</a><br />\nCLIだけでよさそうなんだけど、CLIだけってのがどこかにあるのか分からんかったのでとりあえず全部入れた。<br />\nDocker Desktopは動いてなくて良いので、Exitして可。<br />\n普段から使わないならDocker Dashboardの設定のGeneralから「Start Docker Desktop when you log in」のチェックを はずしておけばOK。</p>\n\n<h2 id=\"dockerexeで疎通確認\">docker.exeで疎通確認</h2>\n<p>コマンドプロンプト等で以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">set </span><span class=\"nv\">DOCKER_HOST</span><span class=\"o\">=</span>ssh://«ユーザ名»@«ホスト»\ndocker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<p>リモートホスト上のコンテナの状態が返ってくるか確認。</p>\n\n<h2 id=\"docker-hostの設定\">DOCKER HOSTの設定</h2>\n<p>VScodeの<code class=\"language-plaintext highlighter-rouge\">settings.json</code> に以下の一文を追加する。もちろん上で確認した内容で。</p>\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\">    </span><span class=\"nl\">\"docker.host\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"ssh://«ユーザ名»@«ホスト»\"</span><span class=\"err\">,</span><span class=\"w\">\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルにつなぎたいときはこの行をコメントアウト(<code class=\"language-plaintext highlighter-rouge\">//</code>をつける)すればOK。<br />\n<code class=\"language-plaintext highlighter-rouge\">setting.json</code>はJSONファイルだけど、 <code class=\"language-plaintext highlighter-rouge\">//</code>でコメントアウトできる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nVScode settings.json の開き方</p>\n  <ul>\n    <li>メニュー ファイル→ユーザ設定→ 設定</li>\n    <li>設定画面の右上のボタン「設定(JSON)を開く」をクリック</li>\n  </ul>\n\n  <p>または</p>\n  <ul>\n    <li>メニュー表示→コマンドパレット</li>\n    <li>Preference:  Open Settings(JSON) を選択</li>\n  </ul>\n</blockquote>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その1\">VScodeでリモート エクスプローラからリモートホストに接続(その1)</h2>\n<p>リモートホストに拡張機能 Docker と Docker Explorer をインストールしておき、\nDockerペインを開くとリモートホスト上のコンテナとかが見える</p>\n\n<p>ここでは既にリモートホスト上でコンテナ作成済みとする。<br />\n(イメージからコンテナ作ったりDockerfileからBuildしたりできると思うけど、今はおいとく)</p>\n\n<ul>\n  <li>接続するコンテナが起動していない場合はDockerペインで使用するコンテナを右クリック→Start でコンテナを起動</li>\n  <li>起動したら対象コンテナのアイコンが三角マークになる</li>\n  <li>同じくDockerペインで使用するコンテナを右クリック→Attach Visual Studio Code を選択</li>\n  <li>select the container to attach VS Code と聞かれるのでアタッチするコンテナを選択(コンテナ選択してAttachしたはずだけど、なぜかここで再度選択が必要)</li>\n  <li>初めて接続した場合は「Attaching to a container may execute arbitrary code」<br />\nと言われるので、変なコードが実行されないことが分かっていれば Got it をクリック</li>\n  <li>接続された。右下の「><」ボタンが「>< Conteiner «コンテナ名»」に変わっている。</li>\n</ul>\n\n<p>あとはリモート SSH や ローカルのDockerでのデバッグと同じ。</p>\n\n<h2 id=\"接続の終了\">接続の終了</h2>\n<p>接続を終了する場合は</p>\n<ul>\n  <li>メニュー表示→コマンドパレット</li>\n  <li>Remote:  Close Remote Connection を選択</li>\n</ul>\n\n<p>このとき、コンテナからだけでなく、リモートホストからも切断される。</p>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その2\">VScodeでリモート エクスプローラからリモートホストに接続(その2)</h2>\n<p>リモートエクスプローラ(Containers)で接続するコンテナを右クリックし、「Attach to Container」または「Attach in New Window」を選択<br />\n(コンテナが起動されていなければ起動して)コンテナに接続される。</p>\n\n<p>あんまりごちょごちょしなくて済むのでこっちの方がおススメかな。</p>\n\n<h1 id=\"ネットワークポート\">ネットワークポート</h1>\n<p>通常Cockerコンテナ内のネットワークポートをホストや外部コンピュータからアクセスするには、<br />\nコンテナ作成時に-p (–publish) オプションで接続を受け入れるポート番号を指定する必要があるが、<br />\nVScodeから接続している場合は、Docker内のネットワークポートにVScodeが実行されているマシンからlocalhost:«ポート番号»で接続できる。<br />\n(アクセス遅いけど、ちょっと別のポート開けて試したい なんて時には便利)</p>\n\n<p>ただし、これはDockerが動作しているホストコンピュータや他のコンピュータからはアクセスできない。<br />\nこれらからアクセスするには-pオプションを指定する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n<p><a href=\"https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0\">https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0</a><br />\n↑ここにある、「Remote-Containers: Open Folder in Container…」での手順はリモートホストに接続した状態では実行できないらしい。<br />\nどうしてもこのコンテナでデバッグしたい場合は、<br />\n一旦リモートホスト上でVSCodeを起動してコンテナを作成しておき、<br />\nその後ローカルPCからこのコンテナにアタッチするような手順をふめばデバッグできる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerでopenVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerでopenVINO</h1>\n      <p>DockerでopenVINOプログラムの開発</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>DockerコンテナでopenVINOのプログラム開発を行う手順。<br />\n↓ここを参考にUbuntu 20.04/openVINO 2021.3に変更してみる。ついでによく使う機能の準備もやっておく。<br />\n<a href=\"https://kuttsun.blogspot.com/2021/06/openvino-docker.html\">https://kuttsun.blogspot.com/2021/06/openvino-docker.html</a></p>\n\n<h1 id=\"dockerイメージの作成\">Dockerイメージの作成</h1>\n\n<p>上の参照先を参考に公式イメージに必要な処理を加えておく。<br />\nDockerfile は以下。<br />\n参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>ベースをopenVINO/ubuntu20に変更</li>\n  <li>sudoとvimとless入れとく。sudoはパスワードなしで動作するようにしとく。</li>\n  <li>開発マシンなのでbaskhの補完機能を有効にしておく</li>\n  <li>キーバインド変更 ( <code class=\"language-plaintext highlighter-rouge\">^p</code> / <code class=\"language-plaintext highlighter-rouge\">^n</code> )</li>\n  <li>日本語文字化け対策</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code> がキー入力待ちになってbuildエラーになるので<code class=\"language-plaintext highlighter-rouge\">-y</code>オプションを追加</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-docker highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースイメージ</span>\n<span class=\"k\">FROM</span><span class=\"s\"> openvino/ubuntu20_dev:2021.3</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">ENV</span><span class=\"s\"> DEBIAN_FRONTEND=noninteractive</span>\n\n<span class=\"c\"># sudo と vim と less のインストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install sudo </span>vim less <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo </span>openvino <span class=\"nv\">ALL</span><span class=\"o\">=</span><span class=\"se\">\\(</span>root<span class=\"se\">\\)</span> NOPASSWD:ALL <span class=\"o\">></span> /etc/sudoers.d/openvino <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">chmod </span>0440 /etc/sudoers.d/openvino\n\n<span class=\"c\"># bashの補完機能 & キーバインドの設定 & 日本語文字化け対策</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nb\">install </span>bash-completion <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"s2\">\". /usr/share/bash-completion/bash_completion\"</span> <span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-n</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-forward' </span><span class=\"se\">\\n\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-p</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-backward'</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">export LANG=C.UTF-8</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">export LANGUAGE=en_US:</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc\n\n<span class=\"c\"># 依存パッケージのインストール(-yオプションで Yes自動選択)</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies <span class=\"o\">&&</span> ./install_openvino_dependencies.sh <span class=\"nt\">-y</span>\n\n<span class=\"c\"># サンプル、デモアプリのビルド</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/samples/cpp <span class=\"o\">&&</span> ./build_samples.sh\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/demos <span class=\"o\">&&</span> ./build_demos.sh\n<span class=\"c\"># /opt/intel/openvino_2021/deployment_tools/demo にデモアプリがある</span>\n\n<span class=\"c\"># 他に必要なものを適宜インストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>wget git python3-pip\n<span class=\"k\">RUN </span>pip3 <span class=\"nb\">install </span>onnxruntime flask\n\n<span class=\"c\"># aptのクリア</span>\n<span class=\"k\">RUN </span>apt clean <span class=\"o\">&&</span> <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> /var/lib/apt/lists/<span class=\"k\">*</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> openvino</span>\n\n<span class=\"c\"># bash起動</span>\n<span class=\"k\">CMD</span><span class=\"s\"> [ \"/bin/bash\" ]</span>\n</code></pre></div></div>\n\n<h1 id=\"ビルド\">ビルド</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker build <span class=\"nt\">-t</span> myopenvino/ubuntu20_dev:2021.3 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h1 id=\"コンテナの生成\">コンテナの生成</h1>\n<p>参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>カレントディレクトリ下のworkを/workに割り当てるように追加</li>\n  <li>GPU関連の設定を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ./work\ndocker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"se\">\\</span>\n       <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"se\">\\</span>\n       myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nX-Windowの表示先(<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code> 変数) は ここで固定されるので、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を変更したい場合は<br />\nコンテナをスタートした後、コンテナ内で手打ちで設定するか、<br />\n変更後の<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を設定したターミナルから以下を実行。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> openvino_2021.3 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<p>Windows の場合は以下な感じ。<br />\nDISPLAY変数は環境に合わせて変更してちょ。<br />\nNCS周りの設定は削除してある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.204:0.0 <span class=\"nt\">-v</span> %CD%<span class=\"se\">\\w</span>ork:/work myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ndocker をWSL上のコマンドラインから起動しているときは<code class=\"language-plaintext highlighter-rouge\">%CD%</code>でなく<code class=\"language-plaintext highlighter-rouge\">$PWD</code><br />\nPowerShellでコマンドを複数行に分割する場合は、行末記号は<code class=\"language-plaintext highlighter-rouge\">\\</code> ではなく <code class=\"language-plaintext highlighter-rouge\">`</code><br />\nコマンドプロンプトでは<code class=\"language-plaintext highlighter-rouge\">^</code> NYAGOSは分からん😢<br />\nそれぞれ違ってびみょーにストレス…</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> openvino_2021.3\n</code></pre></div></div>\n\n<p>コンテナ内でデモを動かしてみる<br />\n(デモの実行で必要なライブラリ類がインストールされたりするので、実行しましょう)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ~/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/demo1.log\n\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/dem2.log\n</code></pre></div></div>\n\n<p>前に作ったプログラムを試してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\ngit clone https://github.com/ippei8jp/ov_trial.git\n<span class=\"c\"># 入力画像の準備</span>\n<span class=\"nb\">cd </span>ov_trial/images/\nbash download.sh\n<span class=\"c\"># モデルファイルの準備(mobilenet-ssdのダウンロードがエラーになるけど大勢に影響ない) </span>\n<span class=\"nb\">cd</span> ../convert_model_ssd/\nbash convert_model_ssd.sh \n\n<span class=\"c\"># 認識してみる</span>\n<span class=\"nb\">cd</span> ../ssd/\nbash test.sh list\nbash test.sh 6\n</code></pre></div></div>\n\n<h1 id=\"ncs2の使用ubuntuのみ\">NCS2の使用(ubuntuのみ)</h1>\n<p>ubuntuではホストに接続したNCS2を使用することもできる。<br />\nただし、DockerコンテナからNCS2を使用するにはDokerホスト側にドライバをインストールしておく必要がある。<br />\n(udevルールだけ?イマイチ自信ないのでフルパッケージでインストールしておいた)<br />\n以下の部分がNCS2を使用するために必要な設定。(上記コマンド例では設定済み)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi向け)のbuild</h1>\n      <p>Raspberry Pi向けopenVINOのbuild(特にCPU extension)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi用 openVINO は デフォルト状態ではCPUで実行できない(NCS2必須)。<br />\nそこで、オープンソース版openVINOを使用してCPU extensionを作成してみる。<br />\nとはいえ、CPU extension だけサクっと作成できなくて、openVINO全体を作成するハメに…</p>\n\n<p>Raspberry Pi 実機でbuildすると、ディスク容量がバカにならないし、<br />\nあまり実環境を弄りたくなかったので、<br />\nUbuntuマシン上のDockerコンテナで実行する方法を試してみる(Docker Desktop for Windowsでもできると思う)</p>\n\n<h1 id=\"arm版dockerコンテナを使用したセルフコンパイル\">ARM版Dockerコンテナを使用したセルフコンパイル</h1>\n\n<p>Dockerコンテナ全体をQEMU上でARMエミュレーションしてくれるので、特に難しいことを考えずに<br />\nネイティブ環境と変わりなくあつかえる。<br />\nでも、かなり遅い(実機よりちょっと速い?同じくらい?)。<br />\n試した環境では、x86_64な環境でクロスコンパイルした場合の15倍くらいかかった。  <br />\n(M1 Mac上でACVMを使うとかなり早いという噂も…M1 Mac持ってない😢  <a href=\"https://qiita.com/kose3/items/af9edc9c40c9ae8fc5c3\" target=\"_blank\">参考</a>  )</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h3 id=\"qemuのインストール\">qemuのインストール</h3>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_emu\n</code></pre></div></div>\n\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm32v7/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成\">patchファイルを作成</h3>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_emu_1 ov_pi_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n以下のオプションを追加すると少しは速くなるかと思ったが、あまり変わらない。</p>\n  <ul>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_OPENCV=OFF</code></li>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_SAMPLES=OFF</code></li>\n  </ul>\n</blockquote>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。</p>\n\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./inference_engine</code> がない\n    <ul>\n      <li>実体は <code class=\"language-plaintext highlighter-rouge\">deployment_tools/inference_engine</code> なので、シンボリックリンクを作れば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/opencv/</code>からコピーすれば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>opencvのpythonモジュールがない\n        <ul>\n          <li>どこから持ってくれば良いんだろう?</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h3 id=\"実機へのインストール\">実機へのインストール</h3>\n<p>CPU extensionだけなら<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l/</code><br />\nへコピーするだけで良い。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれはmake install してもこれはコピーされないらしい。</p>\n</blockquote>\n\n<p>openVINO全体のインストールなら<code class=\"language-plaintext highlighter-rouge\">work/opt/intel/openvino</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/</code>にコピーすれば良いのだけど、opencvのpythonインタフェースがないので注意。<br />\nということで、実際に試していない…</p>\n\n<blockquote>\n  <p>[!NOTE]\n※※※※ メモ ※※※※ <br />\nopenCVはここでbuildするのではなく、<br />\n<a href=\"https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/\" target=\"_blank\">https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/</a> \nからbuild済みモジュールをダウンロードして<br />\n<code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/</code><br />\nに展開している。</p>\n</blockquote>\n\n<h1 id=\"i386版32bit-x86dockerコンテナを使用したクロスコンパイル\">i386版(32bit x86)Dockerコンテナを使用したクロスコンパイル</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>セルフコンパイルは時間がかかりすぎるので、クロスコンパイルで試してみた。<br />\nかなり早くなったが、一部使えないモジュールが…<br />\n当初の目的のCPU extensionは使えるので、掲載しとく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n当初、64bit版debianをベースに作業しようとしたが、\npybind11のbuildで以下のように怒られる。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Make Error at build/_deps/pybind11-src/tools/FindPythonLibsNew.cmake:127 (message):\n  Python config failure: Python is 64-bit, chosen compiler is 32-bit\nCall Stack (most recent call first):\n  build/_deps/pybind11-src/tools/pybind11Tools.cmake:16 (find_package)\n  build/_deps/pybind11-src/CMakeLists.txt:33 (include)\n</code></pre></div>  </div>\n  <p>以下のような対策が考えられる。</p>\n  <ul>\n    <li>FindPythonLibsNew.cmakeにbit数チェックをしないようにパッチを当てる\n      <ul>\n        <li>やり方がよう分からん…</li>\n      </ul>\n    </li>\n    <li>amd64なdebianに32bitのpythonをインストールする\n      <ul>\n        <li>イマイチうまくインストールできなかった</li>\n      </ul>\n    </li>\n  </ul>\n\n  <p>しかたないので、32bit版debianで作ることにした</p>\n</blockquote>\n\n<h2 id=\"準備-1\">準備</h2>\n\n<h3 id=\"作業用ディレクトリの準備-1\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_buster_32 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_buster_32\n</code></pre></div></div>\n<h3 id=\"openvino-の-gitリポジトリを-clone-1\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> i386/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> armhf <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-armhf <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:armhf <span class=\"se\">\\\n</span>    libgtk-3-dev:armhf <span class=\"se\">\\\n</span>    libavcodec-dev:armhf <span class=\"se\">\\\n</span>    libavformat-dev:armhf <span class=\"se\">\\\n</span>    libswscale-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:armhf <span class=\"se\">\\\n</span>    libpython3-dev:armhf <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python-argparse <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"c\"># aptでインストールするので削除</span>\n<span class=\"c\"># RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.3/cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     tar xzvf cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     (cd cmake-3.21.3 && ./bootstrap --parallel=$(nproc --all) -- -DCMAKE_USE_OPENSSL=OFF && make --jobs=$(nproc --all) && make install) && \\</span>\n<span class=\"c\">#     rm -rf cmake-3.21.3 cmake-3.21.3.tar.gz</span>\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"patchファイルを作成-1\">patchファイルを作成</h3>\n\n<p>以下の2つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch1.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake\nindex 6cb15a0..66a1ef6 100644\n</span><span class=\"gd\">--- a/cmake/dependencies.cmake\n</span><span class=\"gi\">+++ b/cmake/dependencies.cmake\n</span><span class=\"p\">@@ -19,8 +19,9 @@</span> if(CMAKE_CROSSCOMPILING AND CMAKE_HOST_SYSTEM_NAME MATCHES Linux AND CMAKE_HOST_\n     find_program(\n         SYSTEM_PROTOC\n         NAMES protoc\n<span class=\"gd\">-        PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n-        NO_DEFAULT_PATH)\n</span><span class=\"gi\">+        # PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n+        # NO_DEFAULT_PATH)\n+        )\n</span>     if(NOT SYSTEM_PROTOC)\n         message(FATAL_ERROR \"[ONNX IMPORTER] Missing host protoc binary\")\n     endif()\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる-1\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../patch1.patch<span class=\"o\">)</span>\n<span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino apply ../../patch1.patch\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_buster_32 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32_1</code> を使用。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_buster_32_1 ov_pi_buster_32 /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/386) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_buster_32_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_buster_32_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make-1\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n\n<p>コンテナから出て、<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の \n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l</code>/<br />\nへコピーする</p>\n\n<blockquote>\n  <p>[!WARNING]\ncythonの出力がx86のコードを吐くので、pythonモジュールの一部に正常に動作しないものがある。<br />\npythonモジュールを使いたいときはセルフコンパイルするしかないかな?</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その1)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(DDQN編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"https://qiita.com/bathtimefish/items/a9b23681720527c0bd7e?fbclid=IwAR3sbaoBn09U7pFL4AKyEOXMi0wNXyAYi9jODUzO1muYr-N7q6hFG-hDfKs\" target=\"_blank\">DonkeyCar3シミュレーターで強化学習してみる</a>のマネをしてDonkeyCarシミュレータライブラリの中にあるサンプルのddqn.pyを実行してみる。<br />\n参考:<br />\nDQNについてはここが分かりやすかったかな。<br />\n<a href=\"https://www.tcom242242.net/entry/ai-2/%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/%E6%B7%B1%E5%B1%A4%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/%E3%80%90%E6%B7%B1%E5%B1%A4%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92%E3%80%91deep_q_network_%E3%82%92tensorflow%E3%81%A7%E5%AE%9F%E8%A3%85/\" target=\"_blank\">【深層強化学習,入門】Deep Q Network(DQN)の解説とPythonで実装 〜図を使って説明〜 </a><br />\n<a href=\"https://www.tcom242242.net/entry/ai-2/%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92/%e3%80%90%e6%b7%b1%e5%b1%a4%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92%e3%80%91double-q-network/\" target=\"_blank\">【深層強化学習】Double Deep Q Network(DDQN)</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim\n<span class=\"nb\">cd</span> /work2/donkey_sim\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 donkey_sim\npyenv <span class=\"nb\">local </span>donkey_sim \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n\n<span class=\"c\"># 現時点での最新リリース v21.7.24 をcheckoutしておく</span>\ngit clone https://github.com/tawnkramer/gym-donkeycar <span class=\"nt\">-b</span> v21.07.24\n\n<span class=\"c\"># gym-donkeycarライブラリのインストール</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-e</span> gym-donkeycar\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ngym-donkeycar は -e (–editable) オプション付きでインストールしているので、編集も可能。 \ngit cloneした先を参照しているので、インストール後もgym-donkeycarを削除しちゃダメ。</p>\n\n  <p>githubから直接インストールする場合は以下。<br />\nこの場合、パッケージは通常のディレクトリにインストールされる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n</code></pre></div>  </div>\n  <p>でも、以下でサンプルプログラム使うので、git cloneもしないとダメ。</p>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p>以下のページから実行するプラットフォームに合わせて<code class=\"language-plaintext highlighter-rouge\">DonkeySimXXXX.zip</code>(XXXXはプラットフォーム名)をダウンロードし、<br />\n適当なディレクトリに展開しておきます。<br />\n(Linux/Macの場合は実行属性付けるのを忘れずに)<br />\n<a href=\"https://github.com/tawnkramer/gym-donkeycar/releases\">https://github.com/tawnkramer/gym-donkeycar/releases</a></p>\n\n<p>マシンスペックがそれほど高くない場合は別マシンで実行してリモート接続するのがおススメ。<br />\nSSH接続で実行する場合はリモート必須。</p>\n\n<h2 id=\"patchをあてる\">patchをあてる</h2>\n\n<p>以下のパッチファイルを使用してサンプルプログラムにパッチをあてます。<br />\n内容は、</p>\n<ul>\n  <li>なぜか<code class=\"language-plaintext highlighter-rouge\">gym_donkeycar</code>がimportされてなかった</li>\n  <li>tensorflow 1.13以降2.0未満用の設定をバージョン情報からスキップできるようにした</li>\n  <li>シミュレータのリモート実行対応(hostオプション追加)</li>\n  <li>探索率(ε値)の初期値設定オプションの追加<br />\n探索率(ε値)については<a href=\"https://www.tcom242242.net/entry/ai-2/%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/epsilon-greedy/\" target=\"_blank\">ε-greedy行動選択 </a>を参照</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  rl_sample.patch\n</p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/examples/reinforcement_learning/ddqn.py b/examples/reinforcement_learning/ddqn.py\nindex 87c74f0..5c32f49 100755\n</span><span class=\"gd\">--- a/examples/reinforcement_learning/ddqn.py\n</span><span class=\"gi\">+++ b/examples/reinforcement_learning/ddqn.py\n</span><span class=\"p\">@@ -21,6 +21,8 @@</span> from tensorflow.keras.layers import Activation, Conv2D, Dense, Flatten\n from tensorflow.keras.models import Sequential\n from tensorflow.keras.optimizers import Adam\n \n<span class=\"gi\">+import gym_donkeycar\n+\n</span> EPISODES = 10000\n img_rows, img_cols = 80, 80\n # Convert image into Black and white\n<span class=\"p\">@@ -121,6 +123,9 @@</span> class DQNAgent:\n         if self.epsilon > self.epsilon_min:\n             self.epsilon -= (self.initial_epsilon - self.epsilon_min) / self.explore\n \n<span class=\"gi\">+    def set_epsilon(self, epsilon):\n+        self.epsilon = epsilon\n+\n</span>     def train_replay(self):\n         if len(self.memory) < self.train_start:\n             return\n<span class=\"p\">@@ -196,15 +201,17 @@</span> def run_ddqn(args):\n     run a DDQN training session, or test it's result, with the donkey simulator\n     \"\"\"\n \n<span class=\"gd\">-    # only needed if TF==1.13.1\n-    config = tf.ConfigProto()\n-    config.gpu_options.allow_growth = True\n-    sess = tf.Session(config=config)\n-    K.set_session(sess)\n</span><span class=\"gi\">+    tf_ver = tf.__version__.split('.')\n+    if (tf_ver[0] == 1 and tf_ver[1] >= 13) :\n+        # only needed if TF==1.13.1\n+        config = tf.ConfigProto()\n+        config.gpu_options.allow_growth = True\n+        sess = tf.Session(config=config)\n+        K.set_session(sess)\n</span> \n     conf = {\n         \"exe_path\": args.sim,\n<span class=\"gd\">-        \"host\": \"127.0.0.1\",\n</span><span class=\"gi\">+        \"host\": args.host,\n</span>         \"port\": args.port,\n         \"body_style\": \"donkey\",\n         \"body_rgb\": (128, 128, 128),\n<span class=\"p\">@@ -237,6 +244,9 @@</span> def run_ddqn(args):\n     try:\n         agent = DQNAgent(state_size, action_space, train=not args.test)\n \n<span class=\"gi\">+        if args.epsilon > 0 :\n+            agent.set_epsilon(args.epsilon)\n+\n</span>         throttle = args.throttle  # Set throttle as constant value\n \n         episodes = []\n<span class=\"p\">@@ -350,6 +360,7 @@</span> if __name__ == \"__main__\":\n         default=\"manual\",\n         help=\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\",\n     )\n<span class=\"gi\">+    parser.add_argument(\"--host\", type=str, default=\"127.0.0.1\", help=\"simulator address\")\n</span>     parser.add_argument(\"--model\", type=str, default=\"rl_driver.h5\", help=\"path to model\")\n     parser.add_argument(\"--test\", action=\"store_true\", help=\"agent uses learned model to navigate env\")\n     parser.add_argument(\"--port\", type=int, default=9091, help=\"port to use for websockets\")\n<span class=\"p\">@@ -357,6 +368,7 @@</span> if __name__ == \"__main__\":\n     parser.add_argument(\n         \"--env_name\", type=str, default=\"donkey-warehouse-v0\", help=\"name of donkey sim environment\", choices=env_list\n     )\n<span class=\"gi\">+    parser.add_argument(\"--epsilon\", type=float, default=0.0, help=\"initial epsilon value\")\n</span> \n     args = parser.parse_args()\n</code></pre></div></div>\n\n<p>以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>gym-donkeycar/\npatch <span class=\"nt\">-p1</span> < rl_sample.patch \n</code></pre></div></div>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習しないと話にならないので学習します。<br />\n強化学習は教師データが要らないので、準備がラクチン…  でも学習には時間がかかる…<br />\nDonkeyCar シミュレータをリモートマシンで実行する場合、<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションに<code class=\"language-plaintext highlighter-rouge\">remote</code>を、実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>examples/reinforcement_learning\npython ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルマシンでシミュレータを実行する場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションにDonkeyCar シミュレータ起動コマンドをフルパスで指定します。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションは不要です。<br />\nシミュレータをあらかじめ起動しておく必要はなく、自動的に起動されます。</p>\n</blockquote>\n\n<p>エピソード毎に学習結果が <code class=\"language-plaintext highlighter-rouge\">rl_driver.h5</code>に保存されるので、任意のタイミングでCTRL-Cで中断できます。<br />\n次回学習を再開する場合は、ログとして表示されている<code class=\"language-plaintext highlighter-rouge\">epsilon: 0.XXXXXXX</code>の部分の最後の値を覚えておいてください。<br />\nこのプログラムではε値は0.02を下回ると固定されるので、ある程度学習が進んだ状態では<code class=\"language-plaintext highlighter-rouge\">0.02</code>だと思っても問題ないでしょう。</p>\n\n<p>学習を再開する場合は以下のように上記コマンドに<code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプションを追加して実行します。<br />\n(<code class=\"language-plaintext highlighter-rouge\">0.XXXXXXX</code>の部分は上で覚えておいた値。ピッタリ同じでなくて大体で可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--epsilon</span><span class=\"o\">=</span>0.XXXXXXX\n</code></pre></div></div>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンドに<code class=\"language-plaintext highlighter-rouge\">--test</code>を指定するだけです。<br />\n<code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプションは指定しません。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--test</span>\n</code></pre></div></div>\n<p>うまく学習が進んでいれば、コースアウトすることなく周回してくれるハズ。<br />\n学習時と同様、コースアウトすると自動的にスタート位置に戻って再スタートします。<br />\n適当にCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>以下はソースを読んだ時のメモです。<br />\n書いてみたけど、自分で読んでも なにが何だか分からない…😢</p>\n\n<h2 id=\"冒頭部分\">冒頭部分</h2>\n<p>この辺はお約束なので。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"s\">\"\"\"\nfile: ddqn.py\nauthor: Felix Yu\ndate: 2018-09-12\noriginal: https://github.com/flyyufelix/donkey_rl/blob/master/donkey_rl/src/ddqn.py\n\"\"\"</span>\n<span class=\"kn\">import</span> <span class=\"nn\">argparse</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">signal</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">from</span> <span class=\"nn\">collections</span> <span class=\"kn\">import</span> <span class=\"n\">deque</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">gym</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">tensorflow</span> <span class=\"k\">as</span> <span class=\"n\">tf</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras</span> <span class=\"kn\">import</span> <span class=\"n\">backend</span> <span class=\"k\">as</span> <span class=\"n\">K</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.layers</span> <span class=\"kn\">import</span> <span class=\"n\">Activation</span><span class=\"p\">,</span> <span class=\"n\">Conv2D</span><span class=\"p\">,</span> <span class=\"n\">Dense</span><span class=\"p\">,</span> <span class=\"n\">Flatten</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.models</span> <span class=\"kn\">import</span> <span class=\"n\">Sequential</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.optimizers</span> <span class=\"kn\">import</span> <span class=\"n\">Adam</span>\n\n</code></pre></div></div>\n<h2 id=\"冒頭部分その2\">冒頭部分その2</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">gym_donkey</code>をimportしないとDonkeyCarシミュレータと接続できないので。<br />\nなぜかオリジナルでは入ってなかった。<br />\n<code class=\"language-plaintext highlighter-rouge\">if __name__ == \"__main__\":</code>付けといた方が良いかもしれんが、とりあえずそのままimportしておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">gym_donkeycar</span>\n\n</code></pre></div></div>\n\n<h2 id=\"パラメータの設定\">パラメータの設定</h2>\n<p>意味は以下の通り。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: center\">変数</th>\n      <th style=\"text-align: left\">意味</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: center\">EPISODES</td>\n      <td style=\"text-align: left\">学習回数</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_rows</td>\n      <td style=\"text-align: left\">入力に使用する画像サイズ(Y)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_cols</td>\n      <td style=\"text-align: left\">入力に使用する画像サイズ(X)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_channels</td>\n      <td style=\"text-align: left\">入力に過去何フレーム分のデータを使用するか</td>\n    </tr>\n  </tbody>\n</table>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">EPISODES</span> <span class=\"o\">=</span> <span class=\"mi\">10000</span>\n<span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span> <span class=\"o\">=</span> <span class=\"mi\">80</span><span class=\"p\">,</span> <span class=\"mi\">80</span>\n<span class=\"c1\"># Convert image into Black and white\n</span><span class=\"n\">img_channels</span> <span class=\"o\">=</span> <span class=\"mi\">4</span>  <span class=\"c1\"># We stack 4 frames\n</span></code></pre></div></div>\n\n<h2 id=\"強化学習エージェントクラス\">強化学習エージェントクラス</h2>\n\n<p>強化学習のエージェントを定義したクラスです。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">DQNAgent</span><span class=\"p\">:</span>\n</code></pre></div></div>\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>クラス変数</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: center\">変数</th>\n      <th style=\"text-align: left\">意味</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: center\">t</td>\n      <td style=\"text-align: left\">実行カウンタ(ステータス表示用のみ使用)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">max_Q</td>\n      <td style=\"text-align: left\">Q値の最大値(ステータス表示用のみ使用)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">train</td>\n      <td style=\"text-align: left\">学習モード/テストモード(<code class=\"language-plaintext highlighter-rouge\">--test</code>オプションで指定)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">state_size</td>\n      <td style=\"text-align: left\">モデルの入力層のサイズ。現状未使用</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">action_space</td>\n      <td style=\"text-align: left\">シミュレータの現在のステアリング/スロットル設定値取得用</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">action_size</td>\n      <td style=\"text-align: left\">未使用。たぶん、ステアリング角を何分割するかの定義(15)にすべきだと思う</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">discount_factor</td>\n      <td style=\"text-align: left\">割引率(γ値) (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">learning_rate</td>\n      <td style=\"text-align: left\">学習率 (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">epsilon</td>\n      <td style=\"text-align: left\">現在の探索率(ε値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">initial_epsilon</td>\n      <td style=\"text-align: left\">探索率の最大値  最小率と共に探索率の変更率を計算する(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">epsilon_min</td>\n      <td style=\"text-align: left\">探索率の最小値 学習時の探索率をこれより小さくしない(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">explore</td>\n      <td style=\"text-align: left\">探索率を最小値にするまでの回数(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">batch_size</td>\n      <td style=\"text-align: left\">バッチサイズ (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">train_start</td>\n      <td style=\"text-align: left\">学習開始タイミング(最初は学習を行わない)(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">memory</td>\n      <td style=\"text-align: left\">Experience Buffer</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">model</td>\n      <td style=\"text-align: left\">メインモデル</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">target_model</td>\n      <td style=\"text-align: left\">ターゲットモデル(double DQNなので)</td>\n    </tr>\n  </tbody>\n</table>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state_size</span><span class=\"p\">,</span> <span class=\"n\">action_space</span><span class=\"p\">,</span> <span class=\"n\">train</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">max_Q</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train</span> <span class=\"o\">=</span> <span class=\"n\">train</span>\n\n        <span class=\"c1\"># Get size of state and action\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">state_size</span> <span class=\"o\">=</span> <span class=\"n\">state_size</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_space</span> <span class=\"o\">=</span> <span class=\"n\">action_space</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_size</span> <span class=\"o\">=</span> <span class=\"n\">action_space</span>\n\n        <span class=\"c1\"># These are hyper parameters for the DQN\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">discount_factor</span> <span class=\"o\">=</span> <span class=\"mf\">0.99</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">learning_rate</span> <span class=\"o\">=</span> <span class=\"mf\">1e-4</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1e-6</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1e-6</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span> <span class=\"o\">=</span> <span class=\"mf\">0.02</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">64</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train_start</span> <span class=\"o\">=</span> <span class=\"mi\">100</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">explore</span> <span class=\"o\">=</span> <span class=\"mi\">10000</span>\n\n        <span class=\"c1\"># Create replay memory using deque\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span> <span class=\"o\">=</span> <span class=\"n\">deque</span><span class=\"p\">(</span><span class=\"n\">maxlen</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Create main model and target model\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">build_model</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">build_model</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># Copy the model to target model\n</span>        <span class=\"c1\"># --> initialize the target model so that the parameters of model & target model to be same\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_target_model</span><span class=\"p\">()</span>\n\n</code></pre></div></div>\n<h3 id=\"モデルの生成\">モデルの生成</h3>\n\n<p>そんなに複雑なモデルではないみたい。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">build_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Sequential</span><span class=\"p\">()</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span>\n            <span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">24</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">,</span> <span class=\"n\">input_shape</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">,</span> <span class=\"n\">img_channels</span><span class=\"p\">))</span>\n        <span class=\"p\">)</span>  <span class=\"c1\"># 80*80*4\n</span>        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">32</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Flatten</span><span class=\"p\">())</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Dense</span><span class=\"p\">(</span><span class=\"mi\">512</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n\n        <span class=\"c1\"># 15 categorical bins for Steering angles\n</span>        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Dense</span><span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">activation</span><span class=\"o\">=</span><span class=\"s\">\"linear\"</span><span class=\"p\">))</span>\n\n        <span class=\"n\">adam</span> <span class=\"o\">=</span> <span class=\"n\">Adam</span><span class=\"p\">(</span><span class=\"n\">lr</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">learning_rate</span><span class=\"p\">)</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"nb\">compile</span><span class=\"p\">(</span><span class=\"n\">loss</span><span class=\"o\">=</span><span class=\"s\">\"mse\"</span><span class=\"p\">,</span> <span class=\"n\">optimizer</span><span class=\"o\">=</span><span class=\"n\">adam</span><span class=\"p\">)</span>\n\n        <span class=\"k\">return</span> <span class=\"n\">model</span>\n\n</code></pre></div></div>\n<h3 id=\"rgbグレースケール変換処理\">RGB→グレースケール変換処理</h3>\n<p>シミュレータの出力はRGB画像、モデルの入力はグレースケール画像なので、その変換を行うための関数。<br />\n<code class=\"language-plaintext highlighter-rouge\">cv2.dst = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)</code> で良い気もするが…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">rgb2gray</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">rgb</span><span class=\"p\">):</span>\n        <span class=\"s\">\"\"\"\n        take a numpy rgb image return a new single channel image converted to greyscale\n        \"\"\"</span>\n        <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">dot</span><span class=\"p\">(</span><span class=\"n\">rgb</span><span class=\"p\">[...,</span> <span class=\"p\">:</span><span class=\"mi\">3</span><span class=\"p\">],</span> <span class=\"p\">[</span><span class=\"mf\">0.299</span><span class=\"p\">,</span> <span class=\"mf\">0.587</span><span class=\"p\">,</span> <span class=\"mf\">0.114</span><span class=\"p\">])</span>\n\n</code></pre></div></div>\n\n<h3 id=\"入力画像前処理\">入力画像前処理</h3>\n<p>シミュレータの出力画像をモデルの入力データに変換する処理。<br />\nRGBからグレースケールに変換し、リサイズを行う。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">process_image</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">obs</span><span class=\"p\">):</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rgb2gray</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">obs</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ターゲットモデルのパラメータ更新\">ターゲットモデルのパラメータ更新</h3>\n\n<p>メインモデルのパラメータをターゲットモデルにコピーする</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">update_target_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span><span class=\"p\">.</span><span class=\"n\">set_weights</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">get_weights</span><span class=\"p\">())</span>\n\n</code></pre></div></div>\n\n<h3 id=\"現在の環境での次の行動を取得する\">現在の環境での次の行動を取得する</h3>\n\n<p>乱数を発生し、ε値以下だったら環境が生成したランダム値(<code class=\"language-plaintext highlighter-rouge\">self.action_space.sample()[0]</code>)を返す。<br />\nそれ以外はメインモデルで予測した結果を返す。<br />\nその際、モデルの出力結果そのままではなく、どのステアリング位置に当たるかの量子化を行って返す。<br />\n(得られるのはステアリング情報だけで、スロットル情報は固定値)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Get action from model using epsilon-greedy policy\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_action</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">rand</span><span class=\"p\">()</span> <span class=\"o\"><=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_space</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"c1\"># print(\"Return Max Q Prediction\")\n</span>            <span class=\"n\">q_value</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">)</span>\n\n            <span class=\"c1\"># Convert q array to steering value\n</span>            <span class=\"k\">return</span> <span class=\"n\">linear_unbin</span><span class=\"p\">(</span><span class=\"n\">q_value</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<h3 id=\"状態等の保存\">状態等の保存</h3>\n<p>現在の状態(state)、行動(action)、報酬(reward)、行動後の状態(next_state)、\n終了フラグ(done)をExperience Bufferに保存する。<br />\n(Experience Buffer は Experience Replayに使用するためのデータを保存しておくところ)<br />\n<code class=\"language-plaintext highlighter-rouge\">memory</code> は <code class=\"language-plaintext highlighter-rouge\">collections.dque()</code>で作成しているので、指定サイズを超えたときは古いデータから順に削除される。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">replay_memory</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">next_state</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">((</span><span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">next_state</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">))</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ε値の更新\">ε値の更新</h3>\n\n<p>現在のε値が最小値より大きかったら一定比率で小さくしていく。<br />\n最小値以下になっていたらそのまま。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">update_epsilon</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">></span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">-=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">-</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">explore</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ε値の初期設定\">ε値の初期設定</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプション追加したので、指定値でε値を変更する処理を追加。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">set_epsilon</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">epsilon</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"n\">epsilon</span>\n</code></pre></div></div>\n\n<h3 id=\"学習\">学習</h3>\n\n<p>Experience Bufferから任意の経験を取り出し、Q Networkをミニバッチ学習(Experience Replay)</p>\n\n<p>記憶したデータ数が<code class=\"language-plaintext highlighter-rouge\">self.train_start</code>に達するまでは何もしない。<br />\nバッチ学習に使用するデータをExperience Bufferから取り出し、<br />\nそれぞれの配列にバラす(<code class=\"language-plaintext highlighter-rouge\">state_t</code>,<code class=\"language-plaintext highlighter-rouge\">action_t</code>, <code class=\"language-plaintext highlighter-rouge\">reward_t</code>, <code class=\"language-plaintext highlighter-rouge\">state_t1</code>, <code class=\"language-plaintext highlighter-rouge\">terminal</code>)。<br />\n<code class=\"language-plaintext highlighter-rouge\">state_t</code>と<code class=\"language-plaintext highlighter-rouge\">state_t1</code>は<code class=\"language-plaintext highlighter-rouge\">np.concatenate()</code>でndarrayにまとめておく。<br />\n11行目の<code class=\"language-plaintext highlighter-rouge\">self.model.predict(state_t)</code>は<code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>の取得にしか使用されておらず、</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>はステータス表示にしか使用されてなく、無駄な計算なので、削除するのが良いと思われる(無駄な計算なので)。<br />\nその場合、<code class=\"language-plaintext highlighter-rouge\">targets</code>の初期化は<code class=\"language-plaintext highlighter-rouge\">targets = np.zeros((batch_size, 15))</code>で行う。<br />\n(<code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>を参照しているところも削除。あるいは<code class=\"language-plaintext highlighter-rouge\">get_action()</code>で戻り値として返すのも手か。)</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">state_t1</code>を入力としてメインモデルをターゲットモデルを使用して得られた出力から出力期待値を取得し、<br />\n学習を行う<code class=\"language-plaintext highlighter-rouge\">self.model.train_on_batch(state_t, targets)</code>。<br />\nこの辺は\n<a href=\"https://www.tcom242242.net/entry/ai-2/%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92/%e3%80%90%e6%b7%b1%e5%b1%a4%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92%e3%80%91double-q-network/\" target=\"_blank\">【深層強化学習】Double Deep Q Network(DDQN)</a>\nのソースとかを見ると分かったような分からないような気になれるかも…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">train_replay</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train_start</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span>\n\n        <span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">batch_size</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">))</span>\n        <span class=\"n\">minibatch</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">,</span> <span class=\"n\">batch_size</span><span class=\"p\">)</span>\n\n        <span class=\"n\">state_t</span><span class=\"p\">,</span> <span class=\"n\">action_t</span><span class=\"p\">,</span> <span class=\"n\">reward_t</span><span class=\"p\">,</span> <span class=\"n\">state_t1</span><span class=\"p\">,</span> <span class=\"n\">terminal</span> <span class=\"o\">=</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">minibatch</span><span class=\"p\">)</span>\n        <span class=\"n\">state_t</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">concatenate</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">)</span>\n        <span class=\"n\">state_t1</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">concatenate</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"n\">targets</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">max_Q</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n        <span class=\"n\">target_val</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"n\">target_val_</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">batch_size</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">terminal</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]:</span>\n                <span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">action_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">reward_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">target_val</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">])</span>\n                <span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">action_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">reward_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">discount_factor</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">target_val_</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">a</span><span class=\"p\">])</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">train_on_batch</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">,</span> <span class=\"n\">targets</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"モデルのロード\">モデルのロード</h3>\n\n<p>モデルの読み込み先はメインモデル。<br />\nこのあと、ターゲットモデルへコピーするので、ここではターゲットモデルは触らない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">load_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">load_weights</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"モデルの保存\">モデルの保存</h3>\n\n<p>メインモデルをファイルに保存する。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Save the model which is under training\n</span>    <span class=\"k\">def</span> <span class=\"nf\">save_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save_weights</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"ステアリング角モデル出力形式変換\">ステアリング角→モデル出力形式変換</h2>\n\n<p>ステアリング角(-1~1)をモデル出力形式(要素数15の配列のどれか1つに1が入る)に変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">linear_bin</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    Convert a value to a categorical array.\n\n    Parameters\n    ----------\n    a : int or float\n        A value between -1 and 1\n\n    Returns\n    -------\n    list of int\n        A list of length 15 with one item set to 1, which represents the linear value, and all other items set to 0.\n    \"\"\"</span>\n    <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    <span class=\"n\">b</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">a</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"mi\">2</span> <span class=\"o\">/</span> <span class=\"mi\">14</span><span class=\"p\">))</span>\n    <span class=\"n\">arr</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">)</span>\n    <span class=\"n\">arr</span><span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">b</span><span class=\"p\">)]</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">return</span> <span class=\"n\">arr</span>\n</code></pre></div></div>\n\n<h2 id=\"モデル出力形式ステアリング角変換\">モデル出力形式→ステアリング角変換</h2>\n\n<p>モデル出力のうち、最大値を持つindexに相当するステアリング角を取得する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">linear_unbin</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    Convert a categorical array to value.\n\n    See Also\n    --------\n    linear_bin\n    \"\"\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">15</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"nb\">ValueError</span><span class=\"p\">(</span><span class=\"s\">\"Illegal array length, must be 15\"</span><span class=\"p\">)</span>\n    <span class=\"n\">b</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">)</span>\n    <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">b</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"mi\">2</span> <span class=\"o\">/</span> <span class=\"mi\">14</span><span class=\"p\">)</span> <span class=\"o\">-</span> <span class=\"mi\">1</span>\n    <span class=\"k\">return</span> <span class=\"n\">a</span>\n</code></pre></div></div>\n\n<h2 id=\"メインルーチン\">メインルーチン</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">run_ddqn</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    run a DDQN training session, or test it's result, with the donkey simulator\n    \"\"\"</span>\n</code></pre></div></div>\n\n<h3 id=\"tensorflow-1131でのおまじない\">Tensorflow 1.13.1でのおまじない</h3>\n\n<p>Tensorflow 2 を使用したかったので、処理不要。<br />\nコメントアウトすれば良いのだけれど、なんとなくバージョンで分けてみた。<br />\n1.14以降では要るのかな?要ると思って書いてみた。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tf_ver</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">__version__</span><span class=\"p\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">'.'</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">tf_ver</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">tf_ver</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"mi\">13</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># only needed if TF==1.13.1\n</span>        <span class=\"n\">config</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">ConfigProto</span><span class=\"p\">()</span>\n        <span class=\"n\">config</span><span class=\"p\">.</span><span class=\"n\">gpu_options</span><span class=\"p\">.</span><span class=\"n\">allow_growth</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"n\">sess</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">Session</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">=</span><span class=\"n\">config</span><span class=\"p\">)</span>\n        <span class=\"n\">K</span><span class=\"p\">.</span><span class=\"n\">set_session</span><span class=\"p\">(</span><span class=\"n\">sess</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"シミュレータ環境の構築\">シミュレータ環境の構築</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">body_style</code> には <code class=\"language-plaintext highlighter-rouge\">donkey</code>、 <code class=\"language-plaintext highlighter-rouge\">bare</code>、<code class=\"language-plaintext highlighter-rouge\">car01</code>、<code class=\"language-plaintext highlighter-rouge\">cybertruck</code>、<code class=\"language-plaintext highlighter-rouge\">f1</code>が使用できるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">body_rgb</code> で 色を指定できるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">car_name</code> でシミュレータに表示される名前を指定。複数の車を走らせるときに見分けられるみたい。<br />\n<code class=\"language-plaintext highlighter-rouge\">font_size</code>で名前のフォントサイズを指定。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s\">\"exe_path\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sim</span><span class=\"p\">,</span>\n        <span class=\"s\">\"host\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">host</span><span class=\"p\">,</span>\n        <span class=\"s\">\"port\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">port</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_style\"</span><span class=\"p\">:</span> <span class=\"s\">\"donkey\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_rgb\"</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span>\n        <span class=\"s\">\"car_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"me\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"font_size\"</span><span class=\"p\">:</span> <span class=\"mi\">100</span><span class=\"p\">,</span>\n        <span class=\"s\">\"racer_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"DDQN\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"country\"</span><span class=\"p\">:</span> <span class=\"s\">\"USA\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"bio\"</span><span class=\"p\">:</span> <span class=\"s\">\"Learning to drive w DDQN RL\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"guid\"</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"p\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()),</span>\n        <span class=\"s\">\"max_cte\"</span><span class=\"p\">:</span> <span class=\"mi\">10</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\"># Construct gym environment. Starts the simulator if path is given.\n</span>    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">make</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">env_name</span><span class=\"p\">,</span> <span class=\"n\">conf</span><span class=\"o\">=</span><span class=\"n\">conf</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"プログラム終了時のフックルーチンの定義と登録\">プログラム終了時のフックルーチンの定義と登録</h3>\n\n<p>プログラム終了時にシミュレータの終了処理を行うようにフックルーチンを登録する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># not working on windows...\n</span>    <span class=\"k\">def</span> <span class=\"nf\">signal_handler</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"catching ctrl+c\"</span><span class=\"p\">)</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">unwrapped</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGINT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGTERM</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGABRT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"パラメータ用変数の定義\">パラメータ用変数の定義</h3>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Get size of state and action from environment\n</span>    <span class=\"n\">state_size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">,</span> <span class=\"n\">img_channels</span><span class=\"p\">)</span>\n    <span class=\"n\">action_space</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">action_space</span>  <span class=\"c1\"># Steering and Throttle\n</span></code></pre></div></div>\n\n<h3 id=\"エージェントの生成\">エージェントの生成</h3>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">agent</span> <span class=\"o\">=</span> <span class=\"n\">DQNAgent</span><span class=\"p\">(</span><span class=\"n\">state_size</span><span class=\"p\">,</span> <span class=\"n\">action_space</span><span class=\"p\">,</span> <span class=\"n\">train</span><span class=\"o\">=</span><span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ε値の設定\">ε値の設定</h3>\n\n<p>オプションでε値が指定されていたら設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">></span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">set_epsilon</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スロットル値の設定\">スロットル値の設定</h3>\n\n<p>スロットルの設定は固定値(コマンドラインオプションで設定)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">throttle</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">throttle</span>  <span class=\"c1\"># Set throttle as constant value\n</span>\n        <span class=\"n\">episodes</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n</code></pre></div></div>\n\n<h3 id=\"モデルのロード-1\">モデルのロード</h3>\n\n<p>モデルファイルがあれば読み込む。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">):</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"load the saved model\"</span><span class=\"p\">)</span>\n            <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">load_model</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"学習ループ\">学習ループ</h3>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">for</span> <span class=\"n\">e</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">EPISODES</span><span class=\"p\">):</span>\n\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Episode: \"</span><span class=\"p\">,</span> <span class=\"n\">e</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h4 id=\"スタート位置へ移動\">スタート位置へ移動</h4>\n\n<p><code class=\"language-plaintext highlighter-rouge\">obs</code> ← スタート時のカメラ画像<br />\n<code class=\"language-plaintext highlighter-rouge\">x_t</code> ← <code class=\"language-plaintext highlighter-rouge\">obs</code> をモデルの入力形式に合わせて変換(グレースケール化&リサイズ) <br />\n<code class=\"language-plaintext highlighter-rouge\">s_t</code> ← <code class=\"language-plaintext highlighter-rouge\">x_t</code>を4枚分コピー(入力画像は過去4枚分を使用するので)(ちゃんと<code class=\"language-plaintext highlighter-rouge\">img_channels</code>参照して欲しいけど)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"n\">done</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">reset</span><span class=\"p\">()</span>\n\n            <span class=\"n\">episode_len</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n            <span class=\"n\">x_t</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">process_image</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n\n            <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">stack</span><span class=\"p\">((</span><span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">),</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"c1\"># In Keras, need to reshape\n</span>            <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>  <span class=\"c1\"># 1*80*80*4\n</span></code></pre></div></div>\n\n<h4 id=\"エピソードループ\">エピソードループ</h4>\n\n<p>終了フラグがセットされるまでループ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">done</span><span class=\"p\">:</span>\n</code></pre></div></div>\n\n<h5 id=\"現在の状態から行動を予測しシミュレータで実行\">現在の状態から行動を予測し、シミュレータで実行</h5>\n\n<p><code class=\"language-plaintext highlighter-rouge\">steering</code> ← 予測結果<br />\n<code class=\"language-plaintext highlighter-rouge\">env.step()</code>でシミュレータステップ実行<br />\n<code class=\"language-plaintext highlighter-rouge\">x_t1</code> ←ステップ実行後のカメラ画像<br />\n<code class=\"language-plaintext highlighter-rouge\">s_t1</code> ← 現在の入力データの一番古いものを削除し、今回の画像を追加</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"c1\"># Get action for the current state and go one step in environment\n</span>                <span class=\"n\">steering</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">get_action</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">)</span>\n                <span class=\"n\">action</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">steering</span><span class=\"p\">,</span> <span class=\"n\">throttle</span><span class=\"p\">]</span>\n                <span class=\"n\">next_obs</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">,</span> <span class=\"n\">info</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">(</span><span class=\"n\">action</span><span class=\"p\">)</span>\n\n                <span class=\"n\">x_t1</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">process_image</span><span class=\"p\">(</span><span class=\"n\">next_obs</span><span class=\"p\">)</span>\n\n                <span class=\"n\">x_t1</span> <span class=\"o\">=</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"mi\">1</span><span class=\"p\">)</span>  <span class=\"c1\"># 1x80x80x1\n</span>                <span class=\"n\">s_t1</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">x_t1</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">:,</span> <span class=\"p\">:</span><span class=\"mi\">3</span><span class=\"p\">],</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>  <span class=\"c1\"># 1x80x80x4\n</span></code></pre></div></div>\n\n<h5 id=\"experience-bufferに現在の状態を保存\">Experience Bufferに現在の状態を保存</h5>\n\n<p>ε値の更新も</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"c1\"># Save the sample <s, a, r, s'> to the replay memory\n</span>                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">replay_memory</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">linear_bin</span><span class=\"p\">(</span><span class=\"n\">steering</span><span class=\"p\">)),</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">s_t1</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">)</span>\n                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">update_epsilon</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h5 id=\"学習実行\">学習実行</h5>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n                    <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train_replay</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h5 id=\"ループ更新処理とステータス表示\">ループ更新処理とステータス表示</h5>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">s_t1</span>\n                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"n\">episode_len</span> <span class=\"o\">=</span> <span class=\"n\">episode_len</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">%</span> <span class=\"mi\">30</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span>\n                        <span class=\"s\">\"EPISODE\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">e</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"TIMESTEP\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ ACTION\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">action</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ REWARD\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">reward</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ EPISODE LENGTH\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">episode_len</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ Q_MAX \"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">max_Q</span><span class=\"p\">,</span>\n                    <span class=\"p\">)</span>\n</code></pre></div></div>\n<h5 id=\"ループ更新処理とステータス表示-1\">ループ更新処理とステータス表示</h5>\n\n<p><code class=\"language-plaintext highlighter-rouge\">agent.update_target_model()</code>でターゲットモデルの更新\n<code class=\"language-plaintext highlighter-rouge\">episodes.append(e)</code>はデバッグ用?</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"k\">if</span> <span class=\"n\">done</span><span class=\"p\">:</span>\n\n                    <span class=\"c1\"># Every episode update the target model to be same with model\n</span>                    <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">update_target_model</span><span class=\"p\">()</span>\n\n                    <span class=\"n\">episodes</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n\n                    <span class=\"c1\"># Save model for each episode\n</span>                    <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">save_model</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n\n                    <span class=\"k\">print</span><span class=\"p\">(</span>\n                        <span class=\"s\">\"episode:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">e</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"  memory length:\"</span><span class=\"p\">,</span>\n                        <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">),</span>\n                        <span class=\"s\">\"  epsilon:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">,</span>\n                        <span class=\"s\">\" episode length:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">episode_len</span><span class=\"p\">,</span>\n                    <span class=\"p\">)</span>\n</code></pre></div></div>\n<h4 id=\"エピソードループと学習ループの終わり\">エピソードループと学習ループの終わり</h4>\n<p>キーボード割り込み例外と終了処理</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">except</span> <span class=\"nb\">KeyboardInterrupt</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stopping run...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">finally</span><span class=\"p\">:</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">unwrapped</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"コマンドライン解析処理まわり\">コマンドライン解析処理まわり</h2>\n\n<p>コマンドライン解析処理とメインルーチンへのジャンプ</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n\n    <span class=\"c1\"># Initialize the donkey environment\n</span>    <span class=\"c1\"># where env_name one of:\n</span>    <span class=\"n\">env_list</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-roads-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-avc-sparkfun-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-roboracingleague-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-waveshare-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-minimonaco-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-warren-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-thunderhill-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-circuit-launch-track-v0\"</span><span class=\"p\">,</span>\n    <span class=\"p\">]</span>\n\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s\">\"ddqn\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--sim\"</span><span class=\"p\">,</span>\n        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span>\n        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"manual\"</span><span class=\"p\">,</span>\n        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\"</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--host\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"127.0.0.1\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"simulator address\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"rl_driver.h5\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"agent uses learned model to navigate env\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--port\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">9091</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for websockets\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--throttle\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.3</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"constant throttle for driving\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--env_name\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"name of donkey sim environment\"</span><span class=\"p\">,</span> <span class=\"n\">choices</span><span class=\"o\">=</span><span class=\"n\">env_list</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--epsilon\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"initial epsilon value\"</span><span class=\"p\">)</span>\n\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n    <span class=\"n\">run_ddqn</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"でもってこんな改造をするとちょびっと計算量が減る\">でもって、こんな改造をするとちょびっと計算量が減る</h2>\n<p>シミュレータに表示される車を変更してるのはご愛敬😅</p>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ddqn.py.old\t2021-12-02 06:25:02.149997073 +0900\n</span><span class=\"gi\">+++ ddqn.py\t2021-12-03 07:14:49.346378878 +0900\n</span><span class=\"p\">@@ -98,9 +98,10 @@</span>\n         return np.dot(rgb[..., :3], [0.299, 0.587, 0.114])\n \n     def process_image(self, obs):\n<span class=\"gd\">-        obs = self.rgb2gray(obs)\n-        obs = cv2.resize(obs, (img_rows, img_cols))\n-        return obs\n</span><span class=\"gi\">+        # obs1 = self.rgb2gray(obs)\n+        obs1 = cv2.dst = cv2.cvtColor(obs, cv2.COLOR_RGB2GRAY)\n+        obs2 = cv2.resize(obs1, (img_rows, img_cols))\n+        return obs2\n</span> \n     def update_target_model(self):\n         self.target_model.set_weights(self.model.get_weights())\n<span class=\"p\">@@ -108,13 +109,17 @@</span>\n     # Get action from model using epsilon-greedy policy\n     def get_action(self, s_t):\n         if np.random.rand() <= self.epsilon:\n<span class=\"gd\">-            return self.action_space.sample()[0]\n</span><span class=\"gi\">+            return self.action_space.sample()[0], 0\n</span>         else:\n             # print(\"Return Max Q Prediction\")\n             q_value = self.model.predict(s_t)\n \n<span class=\"gi\">+            max_q = np.amax(q_value[0])\n+            if self.max_Q < max_q :\n+                self.max_Q = max_q\n+\n</span>             # Convert q array to steering value\n<span class=\"gd\">-            return linear_unbin(q_value[0])\n</span><span class=\"gi\">+            return linear_unbin(q_value[0]), max_q\n</span> \n     def replay_memory(self, state, action, reward, next_state, done):\n         self.memory.append((state, action, reward, next_state, done))\n<span class=\"p\">@@ -136,16 +141,16 @@</span>\n         state_t, action_t, reward_t, state_t1, terminal = zip(*minibatch)\n         state_t = np.concatenate(state_t)\n         state_t1 = np.concatenate(state_t1)\n<span class=\"gd\">-        targets = self.model.predict(state_t)\n-        self.max_Q = np.max(targets[0])\n-        target_val = self.model.predict(state_t1)\n-        target_val_ = self.target_model.predict(state_t1)\n</span><span class=\"gi\">+\n+        targets = np.zeros((batch_size, 15))\n+        q_val = self.model.predict(state_t1)\n+        target_q_val = self.target_model.predict(state_t1)\n</span>         for i in range(batch_size):\n             if terminal[i]:\n                 targets[i][action_t[i]] = reward_t[i]\n             else:\n<span class=\"gd\">-                a = np.argmax(target_val[i])\n-                targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_val_[i][a])\n</span><span class=\"gi\">+                a = np.argmax(q_val[i])\n+                targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_q_val[i][a])\n</span> \n         self.model.train_on_batch(state_t, targets)\n \n<span class=\"p\">@@ -213,8 +218,8 @@</span>\n         \"exe_path\": args.sim,\n         \"host\": args.host,\n         \"port\": args.port,\n<span class=\"gd\">-        \"body_style\": \"donkey\",\n-        \"body_rgb\": (128, 128, 128),\n</span><span class=\"gi\">+        \"body_style\": \"f1\",\n+        \"body_rgb\": (255, 128, 128),\n</span>         \"car_name\": \"me\",\n         \"font_size\": 100,\n         \"racer_name\": \"DDQN\",\n<span class=\"p\">@@ -273,7 +278,7 @@</span>\n             while not done:\n \n                 # Get action for the current state and go one step in environment\n<span class=\"gd\">-                steering = agent.get_action(s_t)\n</span><span class=\"gi\">+                steering, max_Q = agent.get_action(s_t)\n</span>                 action = [steering, throttle]\n                 next_obs, reward, done, info = env.step(action)\n \n<span class=\"p\">@@ -305,7 +310,7 @@</span>\n                         \"/ EPISODE LENGTH\",\n                         episode_len,\n                         \"/ Q_MAX \",\n<span class=\"gd\">-                        agent.max_Q,\n</span><span class=\"gi\">+                        max_Q,\n</span>                     )\n \n                 if done:\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その2)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(PPO2編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_1.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a>\nではポリシーにDDQNを使用したサンプルを実行してみたが、今回はもう一つのサンプル(PPO2を使用)を試してみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim2\n<span class=\"nb\">cd</span> /work2/donkey_sim2\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv <span class=\"nb\">install </span>3.7.12 \npyenv virtualenv 3.7.12 donkey_sim2\npyenv <span class=\"nb\">local </span>donkey_sim2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>stable-baselines\npip <span class=\"nb\">install </span><span class=\"nv\">tensorflow</span><span class=\"o\">==</span>1.14.0\n\n<span class=\"c\"># 現時点での最新リリース v21.7.24 をcheckoutしておく</span>\ngit clone https://github.com/tawnkramer/gym-donkeycar <span class=\"nt\">-b</span> v21.07.24\n\n<span class=\"c\"># gym-donkeycarライブラリのインストール</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-e</span> gym-donkeycar\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nstable-baselines は tensorflow ~1.14.0 しかサポートしていないので、バージョン指定してインストールする。<br />\ntensorflow 1.14.0 は python ~3.7 しかサポートしていないので、3.7系の最新版を使用している。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ngym-donkeycar は -e (–editable) オプション付きでインストールしているので、編集も可能。 \ngit cloneした先を参照しているので、インストール後もgym-donkeycarを削除しちゃダメ。</p>\n\n  <p>githubから直接インストールする場合は以下。<br />\nこの場合、パッケージは通常のディレクトリにインストールされる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n</code></pre></div>  </div>\n  <p>でも、以下でサンプルプログラム使うので、git cloneもしないとダメ。</p>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a> と同じ</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<p>用意されているサンプルプログラムにパッチをあてようと思ったのだけど、<br />\n<code class=\"language-plaintext highlighter-rouge\">ppo_train.py</code> はやっつけ感満載のイマイチソースなので いっそ全書き換えで。</p>\n\n<p>主な対応内容は、</p>\n<ul>\n  <li>一定間隔でモデルの保存を行うようcallbackクラスの追加</li>\n  <li>シミュレータのリモート実行対応(<code class=\"language-plaintext highlighter-rouge\">--host</code>)</li>\n  <li>学習回数指定オプション(<code class=\"language-plaintext highlighter-rouge\">--step</code>)</li>\n  <li>テスト回数指定オプション(<code class=\"language-plaintext highlighter-rouge\">--test_step</code>)</li>\n  <li>保存したモデルファイルをロードしてからの学習に対応</li>\n  <li></li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ppo.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">signal</span>\n<span class=\"kn\">import</span> <span class=\"nn\">argparse</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">typing</span>\n<span class=\"kn\">from</span> <span class=\"nn\">typing</span> <span class=\"kn\">import</span> <span class=\"n\">Union</span><span class=\"p\">,</span> <span class=\"n\">List</span><span class=\"p\">,</span> <span class=\"n\">Dict</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">,</span> <span class=\"n\">Optional</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">gym</span>\n<span class=\"kn\">import</span> <span class=\"nn\">gym_donkeycar</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines</span> <span class=\"kn\">import</span> <span class=\"n\">PPO2</span>\n<span class=\"c1\"># from stable_baselines.common import set_global_seeds\n</span><span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.policies</span> <span class=\"kn\">import</span> <span class=\"n\">CnnPolicy</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.vec_env</span> <span class=\"kn\">import</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.callbacks</span> <span class=\"kn\">import</span> <span class=\"n\">EventCallback</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.base_class</span> <span class=\"kn\">import</span> <span class=\"n\">BaseRLModel</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MyCallback</span><span class=\"p\">(</span><span class=\"n\">EventCallback</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> \n                 <span class=\"n\">eval_env</span><span class=\"p\">:</span> <span class=\"n\">Union</span><span class=\"p\">[</span><span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">Env</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span><span class=\"p\">],</span>\n                 <span class=\"n\">save_freq</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">1000</span><span class=\"p\">,</span>\n                 <span class=\"n\">save_file</span><span class=\"p\">:</span> <span class=\"n\">Optional</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"bp\">None</span><span class=\"p\">,</span>\n                 <span class=\"n\">verbose</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">MyCallback</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"n\">verbose</span><span class=\"o\">=</span><span class=\"n\">verbose</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span> <span class=\"o\">=</span> <span class=\"n\">save_file</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">=</span> <span class=\"n\">save_freq</span>\n        \n        <span class=\"c1\"># Convert to VecEnv for consistency\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">eval_env</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span><span class=\"p\">):</span>\n            <span class=\"n\">eval_env</span> <span class=\"o\">=</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">([</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"n\">eval_env</span><span class=\"p\">])</span>\n            \n        <span class=\"k\">assert</span> <span class=\"n\">eval_env</span><span class=\"p\">.</span><span class=\"n\">num_envs</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"You must pass only one environment for evaluation\"</span>\n        \n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">eval_env</span> <span class=\"o\">=</span> <span class=\"n\">eval_env</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">init_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">model</span><span class=\"p\">:</span> <span class=\"s\">'BaseRLModel'</span><span class=\"p\">)</span> <span class=\"o\">-></span> <span class=\"bp\">None</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#### INIT ####\"</span><span class=\"p\">)</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">EventCallback</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">init_callback</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">_init_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#### _INIT ####\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">_on_step</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"o\">-></span> <span class=\"nb\">bool</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">></span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">n_calls</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">now</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">now</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">verbose</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">now</span><span class=\"si\">}</span><span class=\"s\"> saving...'</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span> <span class=\"p\">:</span>\n                <span class=\"n\">now_str</span>  <span class=\"o\">=</span> <span class=\"n\">now</span><span class=\"p\">.</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s\">'%y%m%d_%H%M%S'</span><span class=\"p\">)</span>\n                <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span>\n                <span class=\"c1\"># filename = os.path.join(os.path.dirname(self.save_file), f'{now_str}_{os.path.basename(self.save_file)}')\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">True</span>\n    \n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Initialize the donkey environment\n</span>    <span class=\"c1\"># where env_name one of:\n</span>    <span class=\"n\">env_list</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-roads-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-avc-sparkfun-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-roboracingleague-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-waveshare-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-minimonaco-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-warren-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-thunderhill-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-circuit-launch-track-v0\"</span><span class=\"p\">,</span>\n    <span class=\"p\">]</span>\n    \n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s\">\"ppo_train\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--sim\"</span><span class=\"p\">,</span>\n        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span>\n        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"sim_path\"</span><span class=\"p\">,</span>\n        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\"</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--model\"</span><span class=\"p\">,</span>     <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"ppo_donkey\"</span><span class=\"p\">,</span>  <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--host\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"127.0.0.1\"</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"simulator address\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--port\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">9091</span><span class=\"p\">,</span>          <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--step\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">,</span>         <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test_step\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">,</span>             <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test\"</span><span class=\"p\">,</span>      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">,</span>             <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"load the trained model and play\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--env_name\"</span><span class=\"p\">,</span>  <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"name of donkey sim environment\"</span><span class=\"p\">,</span> <span class=\"n\">choices</span><span class=\"o\">=</span><span class=\"n\">env_list</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">test_step</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test_step</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span> <span class=\"ow\">and</span> <span class=\"n\">test_step</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"n\">test_step</span> <span class=\"o\">=</span> <span class=\"mi\">1000</span>\n        \n    <span class=\"c1\"># Complement the file extension\n</span>    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s\">\".zip\"</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span> <span class=\"o\">+</span> <span class=\"s\">\".zip\"</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    \n    <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s\">\"exe_path\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sim</span><span class=\"p\">,</span>\n        <span class=\"s\">\"host\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">host</span><span class=\"p\">,</span>\n        <span class=\"s\">\"port\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">port</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_style\"</span><span class=\"p\">:</span> <span class=\"s\">\"car01\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_rgb\"</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span>\n        <span class=\"s\">\"car_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"me\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"font_size\"</span><span class=\"p\">:</span> <span class=\"mi\">100</span><span class=\"p\">,</span>\n        <span class=\"s\">\"racer_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"PPO\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"country\"</span><span class=\"p\">:</span> <span class=\"s\">\"USA\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"bio\"</span><span class=\"p\">:</span> <span class=\"s\">\"Learning to drive w PPO RL\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"guid\"</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"p\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()),</span>\n        <span class=\"s\">\"max_cte\"</span><span class=\"p\">:</span> <span class=\"mi\">10</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\"># Make an environment test our trained policy\n</span>    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">make</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">env_name</span><span class=\"p\">,</span> <span class=\"n\">conf</span><span class=\"o\">=</span><span class=\"n\">conf</span><span class=\"p\">)</span>\n    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">([</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"n\">env</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># hook terninate signal\n</span>    <span class=\"k\">def</span> <span class=\"nf\">signal_handler</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"catching ctrl+c\"</span><span class=\"p\">)</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGINT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGTERM</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGABRT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">try</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># check model path\n</span>        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">):</span>\n            <span class=\"c1\"># load model\n</span>            <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">PPO2</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">,</span> <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span> \n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">:</span>\n                <span class=\"c1\"># create model\n</span>                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"create new model\"</span><span class=\"p\">)</span>\n                <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">PPO2</span><span class=\"p\">(</span><span class=\"n\">CnnPolicy</span><span class=\"p\">,</span> <span class=\"n\">env</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">raise</span> <span class=\"nb\">ValueError</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Error: the file </span><span class=\"si\">{</span><span class=\"n\">model_path</span><span class=\"si\">}</span><span class=\"s\"> could not be found\"</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># change throttle lower limit\n</span>        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">action_space</span><span class=\"p\">.</span><span class=\"n\">low</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.1</span>\n        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">:</span>\n            <span class=\"c1\"># in training mode\n</span>            \n            <span class=\"n\">callback</span> <span class=\"o\">=</span> <span class=\"n\">MyCallback</span><span class=\"p\">(</span><span class=\"n\">env</span><span class=\"p\">,</span> <span class=\"n\">save_freq</span> <span class=\"o\">=</span> <span class=\"mi\">5000</span><span class=\"p\">,</span> <span class=\"n\">save_file</span> <span class=\"o\">=</span> <span class=\"n\">model_path</span><span class=\"p\">,</span> <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"c1\"># callback = MyCallback(env, save_freq = 10, verbose = 1)\n</span>            \n            <span class=\"c1\"># set up model in learning mode with goal number of timesteps to complete\n</span>            <span class=\"c1\"># model.learn(total_timesteps=10000)\n</span>            <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">learn</span><span class=\"p\">(</span><span class=\"n\">total_timesteps</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">,</span> <span class=\"n\">callback</span><span class=\"o\">=</span><span class=\"n\">callback</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># save model\n</span>            <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stert testing...\"</span><span class=\"p\">)</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">reset</span><span class=\"p\">()</span>\n        <span class=\"n\">prev_done_count</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">test_step</span><span class=\"p\">):</span>\n            <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">_states</span> <span class=\"o\">=</span> <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n            <span class=\"n\">obs</span><span class=\"p\">,</span> <span class=\"n\">rewards</span><span class=\"p\">,</span> <span class=\"n\">dones</span><span class=\"p\">,</span> <span class=\"n\">info</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">(</span><span class=\"n\">action</span><span class=\"p\">)</span>\n            <span class=\"c1\"># print(f\"cnt : {i}    rewards : {rewards[0]}    dones : {dones[0]}    pos : {info[0]['pos']}, CrossTrackError : {info[0]['cte']}, speed : {info[0]['speed']}\")\n</span>            <span class=\"c1\"># print(f\"+++ info: {info} +++\")\n</span>            <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">render</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">dones</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'dones flag detected : </span><span class=\"si\">{</span><span class=\"n\">i</span> <span class=\"o\">-</span> <span class=\"n\">prev_done_count</span><span class=\"si\">}</span><span class=\"s\">  (</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n                <span class=\"n\">prev_done_count</span> <span class=\"o\">=</span> <span class=\"n\">i</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done testing\"</span><span class=\"p\">)</span>\n        \n    <span class=\"k\">except</span> <span class=\"nb\">KeyboardInterrupt</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stopping run...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n</code></pre></div></div>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習。<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションに<code class=\"language-plaintext highlighter-rouge\">remote</code>を、実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>examples/reinforcement_learning\npython ppo.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n学習回数を指定するには<code class=\"language-plaintext highlighter-rouge\">--step</code>オプションで指定します。<br />\n指定する回数はエピソード数ではなく、アクション数。<br />\n例えば、<code class=\"language-plaintext highlighter-rouge\">--step=100000</code></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nローカルマシンでシミュレータを実行する場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションにDonkeyCar シミュレータ起動コマンドをフルパスで指定します。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションは不要です。<br />\nシミュレータをあらかじめ起動しておく必要はなく、自動的に起動されます。</p>\n</blockquote>\n\n<p>モデルの保存間隔は<code class=\"language-plaintext highlighter-rouge\">MyCallback</code>のインスタンス生成時に<code class=\"language-plaintext highlighter-rouge\">save_freq = 5000</code>で指定していますので、必要なら変更してください。</p>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンドに<code class=\"language-plaintext highlighter-rouge\">--test</code>を指定するだけです。<br />\nテストを実行するステップ数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--test_step</code>オプションで指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ppo.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--test</span> \n</code></pre></div></div>\n<p>途中で止めたい場合はCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>ほど複雑じゃないので省略。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その3)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(VAE+SAC編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_1.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a>、\n<a href=\"/memoBlog/2021/12/09/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その2)</a>\nではDonkeyCar simulatorに添付のサンプルプログラムを実行してみたが、結果がイマイチだったので別のプログラムを試してみる。<br />\n<del>パクった</del> 参考にしたのは、<a href=\"https://masato-ka.hatenablog.com/entry/2020/04/29/153505?fbclid=IwAR1sjfiN1dAGRn6vIKU9vOSnfoCCsmgvVXRV_MWaLdUr3FeIUvUAr1Ef_yo\" target=\"_blank\">Jetson Nanoで動く深層強化学習を使ったラジコン向け自動運転ソフトウェアの紹介</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim3\n<span class=\"nb\">cd</span> /work2/donkey_sim3/\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 donkey_sim3\npyenv <span class=\"nb\">local </span>donkey_sim3 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>torch\npip <span class=\"nb\">install </span>torchvision\npip <span class=\"nb\">install </span>pyyaml\npip <span class=\"nb\">install </span>stable_baselines3\npip <span class=\"nb\">install </span>gym\npip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n\n<span class=\"c\"># tensorboard も必要</span>\npip <span class=\"nb\">install </span>tensorboard\n<span class=\"c\"># たぶん要らないけど、念のため入れとく(tensorboard 実行時になんか言われるので)</span>\npip <span class=\"nb\">install </span>tensorflow\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n今回は stable-baselines3 を使用するので、 tensorflow ではなく、pytorch。<br />\nしかし、tensorboardは必要(学習ログ記録のため)。<br />\ntensorboardで可視化機能を使用する際はtensorflowが入ってないと実行時になんか言われるので\n念のためtensorflowも入れとく(たぶん入れなくても大丈夫)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n試したときのモジュール類のバージョンは以下の通り</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>opencv-python                4.5.4.60\ntorch                        1.10.0\ntorchvision                  0.11.1\nPyYAML                       6.0\nstable-baselines3            1.3.0\ngym                          0.19.0\ngym-donkeycar                1.1.1      ← Githubのtagはv21.07.24\ntensorboard                  2.7.0\ntensorflow                   2.7.0\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a> と同じ</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n<h3 id=\"プログラム拾ってくる\">プログラム拾ってくる。</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/masato-ka/airc-rl-agent.git\n<span class=\"nb\">cd </span>airc-rl-agent/\ngit checkout <span class=\"nt\">-b</span> release-v1.5.2 refs/tags/release-v1.5.2\n</code></pre></div></div>\n\n<h3 id=\"パッチをあてる\">パッチをあてる。</h3>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/config.yml b/config.yml\nindex bda2308..3bf2ad4 100644\n</span><span class=\"gd\">--- a/config.yml\n</span><span class=\"gi\">+++ b/config.yml\n</span><span class=\"p\">@@ -48,8 +48,8 @@</span> AGENT_SETTING:\n   N_COMMAND_HISTORY: 20\n   MIN_STEERING: -1.0\n   MAX_STEERING: 1.0\n<span class=\"gd\">-  MIN_THROTTLE: 0.7 # 0.4\n-  MAX_THROTTLE: 0.95 # 0.9\n</span><span class=\"gi\">+  MIN_THROTTLE: 0.3  # 0.7  # 0.4\n+  MAX_THROTTLE: 0.95 # 0.95 # 0.9\n</span>   MAX_STEERING_DIFF: 0.9 #0.35\n \n JETRACER_SETTING:\n<span class=\"gh\">diff --git a/learning_racer/commands/subcommand.py b/learning_racer/commands/subcommand.py\nindex 0cf6eac..e4474e7 100644\n</span><span class=\"gd\">--- a/learning_racer/commands/subcommand.py\n</span><span class=\"gi\">+++ b/learning_racer/commands/subcommand.py\n</span><span class=\"p\">@@ -56,6 +56,7 @@</span> def command_train(args, config):\n     model = CustomSAC(agent, args, config)\n     model.lean(callback=callback)\n     model.save(args.save)\n<span class=\"gi\">+    agent.close()\n</span> \n \n def command_demo(args, config):\n<span class=\"p\">@@ -65,4 +66,14 @@</span> def command_demo(args, config):\n     for step in range(args.time_steps):\n         if step % 100 == 0: print(\"step: \", step)\n         action, _states = model.predict(obs)\n<span class=\"gi\">+        steer = action[0]\n+        throttle = action[1]\n</span>         obs, rewards, dones, info = agent.step(action)\n<span class=\"gi\">+        steer2 = agent.action_history[-2]\n+        throttle2 = agent.action_history[-1]\n+        speed = info[\"speed\"]\n+        cte = info[\"cte\"]\n+        print(f'steer:{steer:9.5f}    steer2:{steer2:9.5f}    throttle:{throttle:9.5f}    throttle2:{throttle2:9.5f}    speed:{speed:9.5f}    cte:{cte:9.5f}')\n+        if dones :\n+            obs = agent.reset()\n+    agent.close()\n</span><span class=\"gh\">diff --git a/learning_racer/racer.py b/learning_racer/racer.py\nindex 3e67ca2..dee0905 100644\n</span><span class=\"gd\">--- a/learning_racer/racer.py\n</span><span class=\"gi\">+++ b/learning_racer/racer.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import sys\n+import os\n+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))\n+\n</span> import argparse\n from learning_racer.commands.subcommand import command_demo, command_train\n from learning_racer.config import ConfigReader\n<span class=\"p\">@@ -8,6 +12,20 @@</span> logger = getLogger(__name__)\n \n __version__ = '1.5.1'\n \n<span class=\"gi\">+track_list = [\n+    \"donkey-generated-roads-v0\",\n+    \"donkey-warehouse-v0\",\n+    \"donkey-avc-sparkfun-v0\",\n+    \"donkey-generated-track-v0\",\n+    \"donkey-mountain-track-v0\",\n+    \"donkey-roboracingleague-track-v0\",\n+    \"donkey-waveshare-v0\",\n+    \"donkey-minimonaco-track-v0\",\n+    \"donkey-warren-track-v0\",\n+    \"donkey-thunderhill-track-v0\",\n+    \"donkey-circuit-launch-track-v0\",\n+]\n+\n</span> parser = argparse.ArgumentParser(description='Learning Racer command.')\n parser.add_argument('--version', action='version', version='learning_racer version {} .'.format(__version__))\n subparser = parser.add_subparsers()\n<span class=\"p\">@@ -39,7 +57,7 @@</span> parser_train.add_argument('-host', '--sim-host', help='Define host IP of DonkeyS\n parser_train.add_argument('-port', '--sim-port', help='Define port number of DonkeySim host.',\n                           default='9091', type=int)\n parser_train.add_argument('-track', '--sim-track', help='Define track name for DonkeySim',\n<span class=\"gd\">-                          default='donkey-generated-track-v0', type=str)\n</span><span class=\"gi\">+                          default='donkey-generated-track-v0', type=str, choices=track_list)\n</span> parser_train.set_defaults(handler=command_train)\n \n # demo subcommand.\n<span class=\"p\">@@ -63,7 +81,7 @@</span> parser_demo.add_argument('-host', '--sim-host', help='Define host IP of DonkeySi\n parser_demo.add_argument('-port', '--sim-port', help='Define port number of DonkeySim host.',\n                          default='9091', type=int)\n parser_demo.add_argument('-track', '--sim-track', help='Define track name for DonkeySim',\n<span class=\"gd\">-                         default='donkey-generated-track-v0', type=str)\n</span><span class=\"gi\">+                         default='donkey-generated-track-v0', type=str, choices=track_list)\n</span> parser_demo.add_argument('-user', '--sim-user', help='Define user name for own car that showed DonkeySim',\n                          default='anonymous', type=str)\n parser_demo.add_argument('-car', '--sim-car', help='Define car model type for own car that showed DonkeySim',\n<span class=\"gh\">diff --git a/learning_racer/sac/custom_sac.py b/learning_racer/sac/custom_sac.py\nindex 734fd95..3642ca8 100644\n</span><span class=\"gd\">--- a/learning_racer/sac/custom_sac.py\n</span><span class=\"gi\">+++ b/learning_racer/sac/custom_sac.py\n</span><span class=\"p\">@@ -21,6 +21,7 @@</span> def _load_sac(agent, args, config, policy):\n                     sde_sample_freq=config.sac_sde_sample_freq()\n                     )\n     else:\n<span class=\"gi\">+        print(f\"**** load model{args.load_model} ****\")\n</span>         model = SAC.load(args.load_model, env=agent,\n                          policy_kwargs=policy,\n                          verbose=config.sac_verbose(),\n<span class=\"p\">@@ -31,7 +32,7 @@</span> def _load_sac(agent, args, config, policy):\n                          ent_coef=config.sac_ent_coef(), learning_rate=config.sac_learning_rate(),\n                          tensorboard_log=\"tblog\", gamma=config.sac_gamma(), tau=config.sac_tau(),\n                          use_sde_at_warmup=config.sac_use_sde_at_warmup(), use_sde=config.sac_use_sde(),\n<span class=\"gd\">-                         sde_sample_freq=config.sac_sample_freq(), n_episodes_rollout=1)\n</span><span class=\"gi\">+                         sde_sample_freq=config.sac_sde_sample_freq(), n_episodes_rollout=1)\n</span>     return model\n \n \n<span class=\"gh\">diff --git a/learning_racer/sac/hyperparam.py b/learning_racer/sac/hyperparam.py\nindex e58b3fa..5b4b3f0 100644\n</span><span class=\"gd\">--- a/learning_racer/sac/hyperparam.py\n</span><span class=\"gi\">+++ b/learning_racer/sac/hyperparam.py\n</span><span class=\"p\">@@ -2,7 +2,6 @@</span> import math\n \n from learning_racer.config.config import ConfigReader\n \n<span class=\"gd\">-hit_counter = 0\n</span> speed_counter = 0\n config = ConfigReader()\n \n<span class=\"p\">@@ -27,29 +26,32 @@</span> def reward_sim(self, done):\n \n \n # For gym_donkey\n<span class=\"gd\">-hit_counter = 0\n</span> speed_counter = 0\n initial = False\n \n \n def episode_over_sim(self):\n<span class=\"gd\">-    global hit_counter, speed_counter, initial\n</span><span class=\"gi\">+    global speed_counter, initial\n</span>     #    print(self.speed)\n \n     if not initial and self.speed > 3.0:\n         initial = True\n \n     if self.hit != \"none\":\n<span class=\"gd\">-        hit_counter += 1\n-        if hit_counter > 5:\n-            self.over = True\n-            hit_counter = 0\n</span><span class=\"gi\">+        self.over = True\n+        initial = False\n+    elif math.fabs(self.cte) > self.max_cte * 1.5:\n+        self.over = True\n+        initial = False\n</span>     elif self.speed < 0.03 and initial:\n         speed_counter += 1\n         if speed_counter > 10:\n             self.over = True\n             speed_counter = 0\n<span class=\"gi\">+            initial = False\n</span>     elif self.missed_checkpoint:\n         self.over = True\n<span class=\"gi\">+        initial = False\n</span>     elif self.dq:\n         self.over = True\n<span class=\"gi\">+        initial = False\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n主な変更内容は、</p>\n  <ul>\n    <li>config.yml\n      <ul>\n        <li>MIN_THROTTLE の値修正(ちょっと速すぎな感じだったので)</li>\n      </ul>\n    </li>\n    <li>learning_racer/commands/subcommand.py\n      <ul>\n        <li>simulatorのクローズ処理を追加</li>\n        <li>demo時の状態表示を追加</li>\n        <li>demo時のdonesステータスでsimulator初期化を追加</li>\n      </ul>\n    </li>\n    <li>learning_racer/racer.py\n      <ul>\n        <li>pip installせずに実行できるよう、sys.pathを修正する部分の追加</li>\n      </ul>\n    </li>\n    <li>learning_racer/sac/custom_sac.py\n      <ul>\n        <li>typo修正</li>\n      </ul>\n    </li>\n    <li>learning_racer/sac/hyperparam.py\n      <ul>\n        <li>エピソード終了判定<code class=\"language-plaintext highlighter-rouge\">episode_over_sim()</code>の変更</li>\n      </ul>\n    </li>\n  </ul>\n\n</blockquote>\n\n<h3 id=\"vaeの学習済みモデルを拾ってくる\">VAEの学習済みモデルを拾ってくる</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>learning_racer/\nwget <span class=\"s2\">\"https://drive.google.com/uc?export=download&id=19r1yuwiRGGV-BjzjoCzwX8zmA8ZKFNcC\"</span> <span class=\"nt\">-O</span> vae.torch\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこのVAEの学習済みモデルは<code class=\"language-plaintext highlighter-rouge\">donkey-generated-track-v0</code>用なので、\n以下の実行ではこのコースを使用する(<code class=\"language-plaintext highlighter-rouge\">-track</code>オプションのデフォルト)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">donkey-waveshare-v0</code>は簡単なコースなので流用できるっぽい。</p>\n</blockquote>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習。<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\nシミュレータ実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python racer.py train <span class=\"nt\">-robot</span><span class=\"o\">=</span>sim <span class=\"nt\">-vae</span><span class=\"o\">=</span>./vae.torch <span class=\"nt\">-config</span><span class=\"o\">=</span>../config.yml <span class=\"nt\">-device</span><span class=\"o\">=</span>cpu <span class=\"nt\">-host</span><span class=\"o\">=</span>192.168.78.200 \n</code></pre></div></div>\n\n<p>追加学習する場合は元のモデルファイルを<code class=\"language-plaintext highlighter-rouge\">-l</code>オプションで指定します。<br />\n学習に使用するステップ数を変更する場合は<code class=\"language-plaintext highlighter-rouge\">-steps</code>オプションで指定します(デフォルトは5000)。<br />\nその他詳細はソースを見てちょ。</p>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンド<code class=\"language-plaintext highlighter-rouge\">train</code>を<code class=\"language-plaintext highlighter-rouge\">demo</code>に変更するだけです。<br />\nテストを実行するステップ数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--steps</code>オプションで指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python racer.py demo <span class=\"nt\">-robot</span><span class=\"o\">=</span>sim <span class=\"nt\">-vae</span><span class=\"o\">=</span>./vae.torch <span class=\"nt\">-config</span><span class=\"o\">=</span>../config.yml <span class=\"nt\">-device</span><span class=\"o\">=</span>cpu <span class=\"nt\">-host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<p>途中で止めたい場合はCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>のはやめとく。</p>\n\n<p>おおざっぱに言うと、コースの画像を入力してその特徴を抽出するVAE(Variational Auto Encoder)と\nVAEの出力と過去の操作(steering/throttle)の履歴を入力に次の操作を決定するSAC(Soft-Actor-Critic)で構成されている。</p>\n\n<p>VAEはあらかじめ大量のコース画像を撮影したデータで学習しておく(<code class=\"language-plaintext highlighter-rouge\">airc-rl-agent/notebooks/colabo/VAE_CNN.ipyn</code>)。<br />\nこの学習はカメラ画像さえ用意できていれば実機(or シミュレータ)は不要なので、Google Colaboratoryなど高性能のマシンで一気に学習できる。<br />\n上記では参照元ページで用意されていた学習済みモデルを使用している。</p>\n\n<p>VAEは車載カメラ画像(RGBのカラー画像)で160x120pixelにリサイズしたものの下部160x80pixelを入力としている。<br />\n出力は32個のデータ。</p>\n\n<p>VAEは160x80x3(38400)の画素データを32の出力に圧縮するので、そのまま画素データを入力するより学習効率が上がるのかな??<br />\nちゃんと検証してないけど、「右カーブ」とか「左カーブ」とか「直進」みたいな情報に集約されるのかな?</p>\n\n<p>SACの入力はVAEの出力(32個)と過去の操作履歴(過去何回分かは<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.N_COMMAND_HISTOR</code>で指定。\n上記手順で使用した設定値は20なので、steeringとthrottleの2個 × 20 で40個)を使用。<br />\n出力はsteeringとthrottleの2個のデータ。</p>\n\n<p>SACの出力はそのまま車の操作に使用するのではなく、<br />\nthrottleは<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.MIN_THROTTLE</code>と<code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.MAX_THROTTLE</code>で指定した範囲に変換。<br />\nsteeringは前回の設定値との差が<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">MAX_STEERING_DIFF</code>で指定した値を超えないように制限処理、<br />\nを行って使用する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でJTAGデバッグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でJTAGデバッグ</h1>\n      <p>ESP32にFT232Hを接続してJTAGデバッグしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>ESP32のデフォルトの開発環境だと、シリアル通信でFlash書き込んで、<br />\nせいぜいprintfデバッグするしかないが、<br />\nJTAG接続でオンチップデバッグ機能を使えば、もっと使いやすくなるはず。</p>\n\n<p>ESP32のボードは<a href=\"https://www.espressif.com/en/products/devkits/esp32-devkitc\" target=\"_blank\">ESP32-DevKitC-VE</a>\n(<a href=\"https://www.espressif.com/sites/default/files/documentation/esp32-wrover-e_esp32-wrover-ie_datasheet_en.pdf\" target=\"_blank\">ESP32-WROVER-E</a>搭載)\nを使用。</p>\n\n<p>JTAGコントローラは<a href=\"https://ftdichip.com/products/ft232hl/\" target=\"_blank\">FTDIのFT232HL</a>を使用した\n<a href=\"https://akizukidenshi.com/catalog/g/gK-06503/\" target=\"_blank\">秋月電子のAE-FT232HL</a>を使用する(安価なので)。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://www.sunhayato.co.jp/material2/ett09/item_759\" target=\"_blank\">サンハヤトのMM-FT232H</a>\nが拡張コネクタが付いてて使いやすそうなんだけど、お値段かなりお高め…orz…</p>\n</blockquote>\n\n<p>IDEは以前はEclipse一択だったけど、最近はVisual Studio Code に拡張機能<a href=\"https://platformio.org/\" target=\"_blank\">PlatformIO</a>を使うのが\n流行ってるみたいなので、こっちを選択。<br />\nもう Visual Studio Code 最強だな…</p>\n\n<h1 id=\"まずはチュートリアルに沿って試してみる\">まずはチュートリアルに沿って試してみる</h1>\n\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html\" target=\"_blank\">PlatformIOの公式チュートリアル</a>に沿ってツールのインストール~JTAGを使用しないプログラムの書き込み、実行を試す。</p>\n\n<p>まずはツールとボードの動作確認ということで、まだJTAGモジュールは接続しない。</p>\n\n<h2 id=\"ツールのインストール\">ツールのインストール</h2>\n<p>これは上記ページには書いてないので、こっちを参照(Visual Studio Codeインストール済みなら参照するまでもないけど。)<br />\n<a href=\"https://kunsen.net/2018/07/28/post-618/\" target=\"_blank\">薫染庵 途上日誌 PlatformIO IDE for VSCode でESP32のプログラム開発</a><br />\n「3 ESP32プロジェクト作成」の手前まで(以降の説明はarduinoプロジェクトなので)。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPlatformIOのインストールには結構時間がかかる(数分くらい)。 \n右下に出るinstalling~のウィンドウが見難いので「ハングアップした~」と焦って強制終了しないように注意。</p>\n</blockquote>\n\n<h2 id=\"プロジェクトの作成\">プロジェクトの作成</h2>\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#setting-up-the-project\" target=\"_blank\">公式チュートリアルのSetting Up the Project</a>\nに従ってプロジェクトを作成。</p>\n<ul>\n  <li>Nameにプロジェクト名を設定</li>\n  <li>Boardで<code class=\"language-plaintext highlighter-rouge\">Espressif ESP32 Dev Module</code>を選択</li>\n  <li>Frameworkで<code class=\"language-plaintext highlighter-rouge\">Espressif IoT Development Framework</code>を選択(ESP-IDF)</li>\n  <li>Project Wizardの一番下、Locationのチェックをはずすとフォルダを選択できる<br />\nここで指定したフォルダの下にNameで設定した名前のフォルダが作られる<br />\nチェックしたままだと<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%\\Documents\\PlatformIO\\Projects\\</code>に作成されるらしい</li>\n  <li>「このフォルダーないのファイルの作成者を信頼しますか?」と聞かれたら、「はい」を選択</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n初回のみ、プロジェクトを作成すると、自動でESP-IDFがインストールされる。<br />\n環境にもよるけど、15分とかのオーダで覚悟してちょ。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nESP-IDFのインストールにはpythonが必要だが、platformioが自前で持っているのでインストールしなくても大丈夫っぽい。<br />\ngitはインストールしとかないとダメなのかな?なくても大丈夫な気もするけどわからん。</p>\n</blockquote>\n\n<h2 id=\"iniファイルの修正\">iniファイルの修正</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">platformio.ini</code>に<code class=\"language-plaintext highlighter-rouge\">monitor_speed = 115200</code>の1行を追加<br />\n最終的なの内容は以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = espidf\nmonitor_speed = 115200\n</code></pre></div></div>\n\n<h2 id=\"ソースコードの追加\">ソースコードの追加</h2>\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#adding-code-to-the-generated-project\" target=\"_blank\">公式チュートリアルのAdding Code to the Generated Project</a>\nにあるソースを<code class=\"language-plaintext highlighter-rouge\">src\\main.c</code>にコピペする</p>\n\n<blockquote>\n  <p>[!NOTE]\nCMakeLists.txtがどーたらこーたらとwarningが書いてあるけど、無視して良い。<br />\nバージョン変わってちょっと書き方変わったらしい。</p>\n</blockquote>\n\n<p>そのままでも無問題だけど、以下のパッチをあてておくと LEDがチカチカして かつ コンソールにカウント値が表示されるので、\nプログラムが動いてることが一目瞭然。<br />\n(もちろん、IO26端子にLEDを接続しておかないと見えないよ。端子変えるなら<code class=\"language-plaintext highlighter-rouge\">GPIO_NUM_26</code>の部分(2か所)を適当に変更してちょ。)</p>\n\n<p>あと、<code class=\"language-plaintext highlighter-rouge\">tcpip_adapter_init()</code>が非推奨だとワーニングがでるので、<code class=\"language-plaintext highlighter-rouge\">esp_netif_init()</code>に変更してある。<br />\n参考:<a href=\"https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/tcpip_adapter_migration.html\">https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/tcpip_adapter_migration.html</a></p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.c.org  2021-12-26 11:13:05.474815000 +0900\n</span><span class=\"gi\">+++ main.c      2021-12-26 11:12:42.842345600 +0900\n</span><span class=\"p\">@@ -18,6 +18,9 @@</span>\n #include \"lwip/err.h\"\n #include \"lwip/sys.h\"\n\n+#include       <stdio.h>\n<span class=\"gi\">+#include \"driver/gpio.h\"\n+\n</span> #define EXAMPLE_ESP_WIFI_SSID      \"mywifissid\"\n #define EXAMPLE_ESP_WIFI_PASS      \"mywifipass\"\n #define EXAMPLE_MAX_STA_CONN       (3)\n<span class=\"p\">@@ -40,7 +43,7 @@</span>\n\n void wifi_init_softap()\n {\n<span class=\"gd\">-    tcpip_adapter_init();\n</span><span class=\"gi\">+    esp_netif_init();\n</span>     ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();\n<span class=\"p\">@@ -81,4 +84,14 @@</span>\n\n     ESP_LOGI(TAG, \"ESP_WIFI_MODE_AP\");\n     wifi_init_softap();\n<span class=\"gi\">+\n+    gpio_set_direction(GPIO_NUM_26, GPIO_MODE_OUTPUT);\n+    int level = 0;\n+    int count = 0;\n+    while (true) {\n+        gpio_set_level(GPIO_NUM_26, level);\n+        level = !level;\n+        printf(\"count=%d\\n\", count++);\n+        vTaskDelay(300 / portTICK_PERIOD_MS);\n+    }\n</span> }\n</code></pre></div></div>\n\n<h2 id=\"ビルド\">ビルド</h2>\n<p>ビルド実行方法色々書いてあるけど、お好きな方法でどうぞ。<br />\n初回はライブラリもビルドするので時間がかかる。<br />\n(<code class=\"language-plaintext highlighter-rouge\">platform.ini</code>修正時も?)</p>\n\n<p>ターミナルに<code class=\"language-plaintext highlighter-rouge\">SUCCESS</code>と出てるのを確認して次へ。</p>\n\n<p>ターミナルの内容確認して不要になったら何かキーを押すと閉じられる。</p>\n\n<h2 id=\"ターゲットプログラムのダウンロード\">ターゲットプログラムのダウンロード</h2>\n<p>チュートリアルページにはuploadって書いてあるけど、普通はdownloadだと思うんだけど…<br />\nこれもお好きな方法でどうぞ。</p>\n\n<h2 id=\"実行状況の確認\">実行状況の確認</h2>\n<p>シリアルモニタでコンソール入出力を確認できる。<br />\nこれも起動方法はお好きな方法でどうぞ。</p>\n\n<p>うまく動いてたら、スマホやタブレットでWi-Fiスキャンすると「mywifissid」というSSIDが見つかるはず。<br />\n接続してもつながらないけど、なんか接続要求を受けたのがコンソールに表示されるみたい。</p>\n\n<h1 id=\"jtagデバッガを使用したデバッグ\">JTAGデバッガを使用したデバッグ</h1>\n<p>PlatformIOとESP32の動作が確認できたので、次はJTAGデバッガ。<br />\n念のため、cleanしてbuildファイルを一度消しておくのが良いかもしれない。</p>\n\n<p>でも、公式チュートリアルの<a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#debugging-the-firmware\" target=\"_blank\">Debugging the Firmware</a> \n以降は <a href=\"https://www.olimex.com/Products/ARM/JTAG/ARM-USB-OCD-H/\" target=\"_blank\">OLIMEXのARM-USB-OCD-H</a>\nを使用することが前提なので、今回は参照しない。</p>\n\n<p>代わりに<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h\" target=\"_blank\">Long-ship ESP32をPlatformIO上でJTAG(FT232H)デバッグする</a>を参照。<br />\n(でも、微妙に異なるのでちょっと補足書いとく)<br />\n<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc7\" target=\"_blank\">事前準備(自動書き込み)</a>までは上記で済んでいるのでスキップ。</p>\n\n<h2 id=\"ドライバの更新\">ドライバの更新</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc8\" target=\"_blank\">ドライバ更新</a>\nにあるように、ドライバの更新をする。</p>\n\n<p>ドライバ更新の詳しい手順は<a href=\"https://www.m-kobayashi.org/working_log/2018/06/10_01.html\" target=\"_blank\">ESP32で遊ぶ 開発環境を作る (4)</a>の「FT232HL のドライバをインストール」あたりを参照すると分かりやすい。</p>\n\n<p>最初に PCにFT232Hを接続しておくことを忘れないように。<br />\nツールは、<a href=\"https://zadig.akeo.ie/\" target=\"_blank\">Zadigのページ </a>のダウンロードからダウンロード。2021/12/23現在の最新は2.7。<br />\nメニューのoptions→ListAllDevices をやるのを忘れずに(忘れると表示されなくて「あれ?」となります(^^ゞ ) <br />\n対象のデバイスを見つけやすいように、不要なUSBデバイス(特に他のFTDIデバイス)は取り外しておいた方がいいかも。</p>\n\n<p>これは最初に1回やればOK</p>\n\n<h2 id=\"esp32とft232hの結線\">ESP32とFT232Hの結線</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc9\" target=\"_blank\">結線</a>の記載とは\nボードが異なるので、ボードのコネクタ名を含めて結線情報を掲載しておく。<br />\n以下の端子を結線する。</p>\n\n<table style=\"width:400px;\" border=\"3\">\n  <tbody>\n    <tr bgcolor=\"#ff7f7f\">\n      <th colspan=\"2\" width=\"50%\"><strong>FT232H</strong></th>\n      <th colspan=\"2\"><strong>ESP32</strong></th>\n    </tr>\n    <tr>\n      <td width=\"25%\">AD0(TxD)</td><td>J2-7</td>\n      <td width=\"25%\">IO13</td><td>J1-15</td>\n    </tr>\n    <tr>\n      <td>AD1(RxD)</td><td>J2-8</td>\n      <td>IO12</td><td>J1-13</td>\n    </tr>\n    <tr>\n      <td>AD2(RTS#)</td><td>J2-9</td>\n      <td>IO15</td><td>J2-17</td>\n    </tr>\n    <tr>\n      <td>AD3(CTS#)</td><td>J2-10</td>\n      <td>GPIO14</td><td>J3-12</td>\n    </tr>\n    <tr>\n      <td>AD5</td><td>J2-12</td>\n      <td>EN</td><td>J1-2</td>\n    </tr>\n    <tr>\n      <td>GND</td><td>J1-1</td>\n      <td>GND</td><td>J3-1</td>\n    </tr>\n  </tbody>\n</table>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc9\" target=\"_blank\">結線</a>には<br />\nAC1-EN結線と書いてあるけど、<br />\n設定値から判断してAD5-EN結線と思われる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://www.m-kobayashi.org/working_log/2018/06/10_01.html\" target=\"_blank\">ESP32で遊ぶ 開発環境を作る (4)</a>には<br />\nENの結線書いてないけど、結線なくても動くらしい。<br />\nRESET信号がJTAG側から入るのかな?</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nespressifのページによると、sRSTはオプションで繋いでも対応してるコンフィギュレーションが少ないと書いてある。<br />\nでも、CH_PDってどこやねん?<br />\n<a href=\"https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html#jtag-debugging-selecting-jtag-adapter\">https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html#jtag-debugging-selecting-jtag-adapter</a></p>\n</blockquote>\n\n<h2 id=\"iniファイルの修正-1\">iniファイルの修正</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">platformio.ini</code>に<code class=\"language-plaintext highlighter-rouge\">debug_tool = minimodule</code>の1行を追加<br />\n最終的なの内容は以下の通り。<br />\nこれはプロジェクト毎に必要。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = espidf\nmonitor_speed = 115200\ndebug_tool = minimodule\n</code></pre></div></div>\n<h2 id=\"minimoduleの設定変更\">minimoduleの設定変更</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc11\" target=\"_blank\">minimoduleの設定変更</a> のように以下のパッチでファイル修正<br />\n(コメントは変えなくても良いけど、あとで参照して分からなくなるので変更しておく)</p>\n\n<blockquote>\n  <p>[!WARNING]\nこの段階では<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%.platformio\\packages\\tool-openocd-esp32\\</code>ディレクトリがまだない(ダウウンロードされていない)ので、<br />\n一度、Visual Studio Codeのデバッグサイドバーを開き、デバッグターゲットに「PIO Debug」を選択し、実行ボタン(三角アイコン)をクリック<br />\nコンパイルが行われたあと、デバッガプログラムをダウンロードし、起動される。<br />\nデバッガの起動でエラー(<code class=\"language-plaintext highlighter-rouge\">no device found</code>)になるので、一旦キャンセルし、以下の修正を行う。</p>\n</blockquote>\n\n<p>修正するファイル:<br />\n<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%.platformio\\packages\\tool-openocd-esp32\\share\\openocd\\scripts\\interface\\ftdi\\minimodule.cfg</code></p>\n\n<p>変更内容は、ディスクリプタとPID(FT2232H→FT232H)。<br />\n変更後、Visual Studio Codeの再起動必要。<br />\nこれは最初に1回やればOK</p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- minimodule.cfg.org  2021-07-21 22:38:02.000000000 +0900\n</span><span class=\"gi\">+++ minimodule.cfg      2021-12-26 13:09:51.740579600 +0900\n</span><span class=\"p\">@@ -1,16 +1,16 @@</span>\n #\n<span class=\"gd\">-# FTDI MiniModule\n</span><span class=\"gi\">+# Akizuki AE-FT232HL(FTDI FT232HL)\n</span> #\n<span class=\"gd\">-# http://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT2232H_Mini_Module.pdf\n</span><span class=\"gi\">+# https://akizukidenshi.com/catalog/g/gK-06503/\n</span> #\n\n interface ftdi\n<span class=\"gd\">-ftdi_device_desc \"FT2232H MiniModule\"\n-ftdi_vid_pid 0x0403 0x6010\n</span><span class=\"gi\">+ftdi_device_desc \"Single RS232-HS\"\n+ftdi_vid_pid 0x0403 0x6014\n</span>\n # Every pin set as high impedance except TCK, TDI, TDO and TMS\n ftdi_layout_init 0x0008 0x000b\n\n-# nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip)\n<span class=\"gi\">+# nSRST defined on pin J2-12 of AE-FT232HL(pin ADBUS5 [AD5] on the FT232HL chip)\n</span> # This choice is arbitrary. Use other GPIO pin if desired.\n ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n好きなツール名を付けれれば良いんだけど、できないみたいなので一番近いものを修正して使用するということらしい。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">ftdi_layout_signal</code>の設定値を変えればESP32のEN端子に接続するFT232Hの端子を変更できるはずだけど試してない。<br />\nたぶん、値の意味はbit15から順に、 <code class=\"language-plaintext highlighter-rouge\">GPIOH7</code>、<code class=\"language-plaintext highlighter-rouge\">GPIOH6</code>、・・・、<code class=\"language-plaintext highlighter-rouge\">GPIOH0</code>、<code class=\"language-plaintext highlighter-rouge\">GPIOL3</code>、・・・、<code class=\"language-plaintext highlighter-rouge\">GPIOL0</code>、\n<code class=\"language-plaintext highlighter-rouge\">TMS/CS</code>、<code class=\"language-plaintext highlighter-rouge\">TDO/DI</code>、<code class=\"language-plaintext highlighter-rouge\">TDI/DO</code>、<code class=\"language-plaintext highlighter-rouge\">TCK/SK</code>に割り当てられていて、それらの端子は<code class=\"language-plaintext highlighter-rouge\">AC7</code>~<code class=\"language-plaintext highlighter-rouge\">AC0</code>、<code class=\"language-plaintext highlighter-rouge\">AD7</code>~<code class=\"language-plaintext highlighter-rouge\">AD0</code>にあたるものと思われる。<br />\n<a href=\"https://ftdichip.com/wp-content/uploads/2020/08/DS_FT232H.pdf\" target=\"_blank\">https://ftdichip.com/wp-content/uploads/2020/08/DS_FT232H.pdf</a> の「3.2 FT232H Pin Description」の表の\nMPSSEの桁を参照。<br />\nよって、<code class=\"language-plaintext highlighter-rouge\">ftdi_layout_signal</code>の設定値<code class=\"language-plaintext highlighter-rouge\">0x80</code>はAD5端子にあたると推測できる。<br />\nでも、つながなくても動いてるなぁ… 🤔</p>\n</blockquote>\n\n<h2 id=\"デバッグ\">デバッグ</h2>\n<p>Visual Studio Codeのデバッグサイドバーを開き、デバッグターゲットに「PIO Debug」を選択し、実行ボタン(三角アイコン)をクリックすると\nターゲットの依存関係にしたがってbuildを行い、ダウンロード、実行(<code class=\"language-plaintext highlighter-rouge\">app_main()</code>の先頭で一旦停止)を行う。<br />\nなお、デバッグターゲットに「PIO Debug (skip Pre-Debug)」だと、buildは行わず ダウンロード~のみ行う。\n「PIO Debug (without uploading)」ダウンロードも行わず、実行のみ。<br />\n通常は「PIO Debug」を選んでおけば問題ない。</p>\n\n<p>変数の確認やブレークポイントの設定、実行制御(go, step over, step in,…)などは他の環境と大差ない。 <br />\nレジスタダンプも動いてるっぽい。<br />\nコールスタックも動いてるっぽい。<br />\nメモリと逆アセンブルは動かし方分からんかった…</p>\n\n<blockquote>\n  <p>[!NOTE]\nコンソール入出力もVSCodeで上記のシリアルモニタ起動で送受信を行うことができるが、<br />\n外部ツール(TeraTermなど)でモニタすることが可能。<br />\nFlashの書き換えがJTAG経由なので、シリアルポートを他のツールがつかんだままでも大丈夫みたい。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\nプログラムを実行すると、コンソールに<code class=\"language-plaintext highlighter-rouge\">Brownout detector was triggered</code>と表示されてリセットを繰り返すことがある。<br />\nこれは、電圧低下を検出したことによるfail safeのリセット動作らしい。<br />\nWi-Fiを有効化したとき、モジュールに流れる電流が10mA程度→100~200mA程度(実測値)に上がる。<br />\nモジュールを接続しているUSB Hubにたくさんのデバイスを接続していると、電流を確保できなくなって 電圧が低下することがある模様。<br />\nこの場合、USB Hubに接続されている他のデバイスを取り外すか、セルフパワードHubに交換すると正常に動作するようになる。 <br />\nあと、使用するUSBケーブルのインピーダンスが大きいと電流増加で電圧が低下するので、大電流対応のUSBケーブルを使用しましょう。</p>\n\n</blockquote>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でBLEのデモを動かす</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でBLEのデモを動かす</h1>\n      <p>ESP32にBLEのデモを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>gistにupしたので、gistの埋め込みリンク貼っとく(コードをコピペするのめんどくさかったから)。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/3719faf64374d438fd879ce567becb4b\" target=\"_blank\">こちら</a> \nからどうぞ。</p>\n\n<script src=\"https://gist.github.com/ippei8jp/3719faf64374d438fd879ce567becb4b.js\"></script>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でBLEのデモを動かす 補足</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でBLEのデモを動かす 補足</h1>\n      <p>ESP32にBLEのデモの認証方法についての補足</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a>\nでは認証方法(IO capability なので入出能力と言うべきか? あまり直感的でないのでここでは認証方法と呼んでおこう)<br />\nを<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_NONE</code>(NoInputNoOutput; 入出力なし)に設定していたが、これを別の認証方法に変更する場合についてのメモ。</p>\n<blockquote>\n  <p>[!NOTE]\n自作の範囲だと<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_NONE</code>しか使わないと思うけど、使いたくなった時に備えて。</p>\n</blockquote>\n\n<h1 id=\"esp_io_cap_none-noinputnooutput\">ESP_IO_CAP_NONE (NoInputNoOutput)</h1>\n<p>入出力両方なし。<br />\npasskey(PINcode)入力などはなし。<br />\n接続すると自動的に鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (92315) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (92315) BLE_HEART_RATE:     connection start\nV (92975) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (92975) BLE_HEART_RATE:     event nor handled\nV (93245) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (93245) BLE_HEART_RATE:     event nor handled\nE (97855) BT_BTM: btm_ble_remove_resolving_list_entry_complete remove resolving list error 0x2\nV (98285) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (98285) BLE_HEART_RATE:     event nor handled\nW (98335) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (98375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98375) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (98375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98375) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (98385) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98385) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (98405) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98405) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (98405) nvs: nvs_open_from_partition bt_config.conf 1\nD (98415) nvs: nvs_set_blob bt_cfg_key0 475\nD (98425) nvs: nvs_close 4\nD (98425) nvs: nvs_open_from_partition bt_config.conf 1\nD (98425) nvs: nvs_set_blob bt_cfg_key0 475\nD (98485) nvs: nvs_close 5\nD (98485) nvs: nvs_open_from_partition bt_config.conf 1\nD (98485) nvs: nvs_set_blob bt_cfg_key0 475\nD (98495) nvs: nvs_close 6\nD (98495) nvs: nvs_open_from_partition bt_config.conf 1\nD (98495) nvs: nvs_set_blob bt_cfg_key0 475\nD (98515) nvs: nvs_close 7\nD (98515) nvs: nvs_open_from_partition bt_config.conf 1\nD (98515) nvs: nvs_set_blob bt_cfg_key0 475\nD (98515) nvs: nvs_close 8\nV (98515) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (98525) BLE_HEART_RATE:     remote BD_ADDR: 5d5308bb0efd\nI (98525) BLE_HEART_RATE:     address type = 1\nI (98535) BLE_HEART_RATE:     pair status = success\nI (98535) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_BOND\nI (98545) BLE_HEART_RATE:     Bonded devices number : 1\nI (98545) BLE_HEART_RATE:     Bonded devices list :\nI (98555) BLE_HEART_RATE:        0 :   5d:53:08:bb:0e:fd\nV (99025) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99025) BLE_HEART_RATE:     event nor handled\nV (99545) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99545) BLE_HEART_RATE:     event nor handled\nV (99755) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99755) BLE_HEART_RATE:     event nor handled```\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_out-displayonly\">ESP_IO_CAP_OUT (DisplayOnly)</h1>\n<p>表示機器のみ必要。<br />\n自分が指定するpasskeyをコンソール等に表示し、相手側(ホスト)にpasskey(PINcode)入力させる。</p>\n\n<p>passkeyは<code class=\"language-plaintext highlighter-rouge\">esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, ~);</code>で設定するので、<br />\n必ず表示しなくてはいけない、ということはない(BTヘッドフォンなどでマニュアルに「0000を入力」などと書かれているのと同じ)。</p>\n\n<p>相手側には入力手段が必須。</p>\n\n<p>GAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:               // passkey通知要求イベント\n        // 自身がDisplayOnly(ESP_IO_CAP_OUT)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_PASSKEY_NOTIF_EVT ====\");\n        // passkeyの表示\n        printf(\"**** The passkey Notify number:%06d\\n\", param->ble_security.key_notif.passkey);\n        break;\n</code></pre></div></div>\n\n<p>相手側で入力されたpasskeyが正しければ鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (17105) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (17105) BLE_HEART_RATE:     connection start\nV (17775) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17775) BLE_HEART_RATE:     event nor handled\nV (18025) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (18025) BLE_HEART_RATE:     event nor handled\nV (21935) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_PASSKEY_NOTIF_EVT(11)\nI (21935) BLE_HEART_RATE:     ==== ESP_GAP_BLE_PASSKEY_NOTIF_EVT ====\n**** The passkey Notify number:123456                     ← 相手側にこのpasskeyを入力\nV (22185) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (22185) BLE_HEART_RATE:     event nor handled\nW (33505) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (33535) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33535) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (33535) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33535) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (33545) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33545) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (33575) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33575) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (33575) nvs: nvs_open_from_partition bt_config.conf 1\nD (33575) nvs: nvs_set_blob bt_cfg_key0 250\nD (33595) nvs: nvs_close 4\nD (33595) nvs: nvs_open_from_partition bt_config.conf 1\nD (33595) nvs: nvs_set_blob bt_cfg_key0 264\nD (33605) nvs: nvs_close 5\nD (33605) nvs: nvs_open_from_partition bt_config.conf 1\nD (33605) nvs: nvs_set_blob bt_cfg_key0 347\nD (33625) nvs: nvs_close 6\nD (33625) nvs: nvs_open_from_partition bt_config.conf 1\nD (33625) nvs: nvs_set_blob bt_cfg_key0 407\nD (33625) nvs: nvs_close 7\nD (33625) nvs: nvs_open_from_partition bt_config.conf 1\nD (33635) nvs: nvs_set_blob bt_cfg_key0 462\nD (33635) nvs: nvs_close 8\nD (33645) nvs: nvs_open_from_partition bt_config.conf 1\nD (33645) nvs: nvs_set_blob bt_cfg_key0 476\nD (33655) nvs: nvs_close 9\nV (33655) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (33655) BLE_HEART_RATE:     remote BD_ADDR: 786562f732fc\nI (33655) BLE_HEART_RATE:     address type = 1\nI (33665) BLE_HEART_RATE:     pair status = success\nI (33665) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (33675) BLE_HEART_RATE:     Bonded devices number : 1\nI (33675) BLE_HEART_RATE:     Bonded devices list :\nI (33685) BLE_HEART_RATE:        0 :   78:65:62:f7:32:fc\nV (34185) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34185) BLE_HEART_RATE:     event nor handled\nV (34695) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34695) BLE_HEART_RATE:     event nor handled\nV (34885) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34885) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<p>passkeyを間違えると当然接続されない。<br />\n接続が成功したかどうかは、ログの以下の部分で判別できる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (27095) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (27095) BLE_HEART_RATE:     remote BD_ADDR: 67c015dc4505\nI (27105) BLE_HEART_RATE:     address type = 1\nI (27105) BLE_HEART_RATE:     pair status = fail            ← failしている\nI (27115) BLE_HEART_RATE:     reason = 0x51                 ← 失敗した原因だけど、ドキュメントがない...\nI (27115) BLE_HEART_RATE:     Bonded devices number : 0\nI (27125) BLE_HEART_RATE:     Bonded devices list :\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_in--keyboardonly\">ESP_IO_CAP_IN  (KeyboardOnly)</h1>\n<p>入力機器のみ必要。<br />\n相手側に表示されたpasskeyをコンソール等から入力する。</p>\n\n<p>passkeyは相手側から指定される値なので、どのような値かは相手の仕様による。<br />\n相手側には表示手段が必須。</p>\n\n<p>GAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_PASSKEY_REQ_EVT:                 // passkey 要求\n        // KeyboardOnly(ESP_IO_CAP_IN)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_PASSKEY_REQ_EVT ====\");\n        // 以下の関数で相手側に表示されたパスキーを返す\n        uint32_t    passkey;\n        char        passkey_buff[16];\n        int         passkey_len;\n        do {\n            printf(\"**** input paskey : \");\n            fflush(stdout);\n            passkey_len = uart_gets(passkey_buff, sizeof(passkey_buff));\n        } while (passkey_len == 0);\n        passkey = (uint32_t)strtol(passkey_buff, NULL, 10);\n        esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, passkey);\n        break;\n</code></pre></div></div>\n\n<p>passkeyに使用している<code class=\"language-plaintext highlighter-rouge\">uart_gets()</code>関数については後述。</p>\n\n<p>入力したpasskeyが正しければ鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (16805) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (16805) BLE_HEART_RATE:     connection start\nV (17425) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17425) BLE_HEART_RATE:     event nor handled\nV (17675) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17685) BLE_HEART_RATE:     event nor handled\nE (20765) BT_BTM: btm_ble_remove_resolving_list_entry_complete remove resolving list error 0x2\nV (20955) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_PASSKEY_REQ_EVT(12)\nI (20955) BLE_HEART_RATE:     ==== ESP_GAP_BLE_PASSKEY_REQ_EVT ====\n**** input paskey : 047528                                  ← 相手側で表示されているpasskeyを入力\nV (36455) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (36455) BLE_HEART_RATE:     event nor handled\nW (37335) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (37375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37375) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (37375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37375) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (37385) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37385) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (37405) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37405) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (37415) nvs: nvs_open_from_partition bt_config.conf 1\nD (37415) nvs: nvs_set_blob bt_cfg_key0 476\nD (37425) nvs: nvs_close 4\nD (37425) nvs: nvs_open_from_partition bt_config.conf 1\nD (37425) nvs: nvs_set_blob bt_cfg_key0 476\nD (37495) nvs: nvs_close 5\nD (37495) nvs: nvs_open_from_partition bt_config.conf 1\nD (37495) nvs: nvs_set_blob bt_cfg_key0 476\nD (37505) nvs: nvs_close 6\nD (37505) nvs: nvs_open_from_partition bt_config.conf 1\nD (37505) nvs: nvs_set_blob bt_cfg_key0 476\nD (37525) nvs: nvs_close 7\nD (37525) nvs: nvs_open_from_partition bt_config.conf 1\nD (37525) nvs: nvs_set_blob bt_cfg_key0 476\nD (37525) nvs: nvs_close 8\nV (37525) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (37535) BLE_HEART_RATE:     remote BD_ADDR: 786562f732fc\nI (37535) BLE_HEART_RATE:     address type = 1\nI (37545) BLE_HEART_RATE:     pair status = success\nI (37545) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (37555) BLE_HEART_RATE:     Bonded devices number : 1\nI (37555) BLE_HEART_RATE:     Bonded devices list :\nI (37565) BLE_HEART_RATE:        0 :   78:65:62:f7:32:fc\nV (38255) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (38255) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<p>passkeyを間違えたときの動作は <code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_OUT</code>(DisplayOnly)の場合と同様。</p>\n\n<h1 id=\"esp_io_cap_io-displayyesno\">ESP_IO_CAP_IO (DisplayYesNo)</h1>\n<p>入力機器/表示機器 両方必要。</p>\n\n<p>相手側に表示されたpasskeyとコンソールに表示されたpasskeyを目視確認して等しければyを入力し、相手側でも接続許可をタップする。\n確認せずにYesを選択しても良いけど、それならこのモードを指定する必要はないでしょう。</p>\n\n<p>相手側にも入力/表示手段が必須。<br />\nGAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_NC_REQ_EVT:                      // 数値比較リクエスト イベント\n        // DisplayYesNo(ESP_IO_CAP_IO)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_NC_REQ_EVT ====\");\n        printf(\"**** the passkey Notify number:%d\\n\", param->ble_security.key_notif.passkey);\n        printf(\"**** Accept? (y/n) : \");\n        fflush(stdout);\n        int kb_key = uart_getchar();\n        printf(\"%c\\n\", kb_key);\n        if (kb_key == 'y' || kb_key == 'Y') {\n            // 接続受け入れ\n            esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true);\n        }\n        else {\n            // 接続拒否\n            esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, false);\n        }\n        break;\n</code></pre></div></div>\n\n<p>両方でyesを選択すれば鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (14185) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (14185) BLE_HEART_RATE:     connection start\nV (14855) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (14855) BLE_HEART_RATE:     event nor handled\nV (15145) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (15145) BLE_HEART_RATE:     event nor handled\nE (18775) BT_SMP: Value for numeric comparison = 260195\nV (18775) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_NC_REQ_EVT(16)\nI (18775) BLE_HEART_RATE:     ==== ESP_GAP_BLE_NC_REQ_EVT ====\n**** the passkey Notify number:260195                                               ← 相手側で表示されている数値と目視比較\n**** Accept? (y/n) : y                                                              ← y 入力、相手側でもyesクリック\nV (26785) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (26785) BLE_HEART_RATE:     event nor handled\nW (28245) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (28275) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28275) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (28275) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28285) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (28285) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28295) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (28305) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28305) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (28315) nvs: nvs_open_from_partition bt_config.conf 1\nD (28315) nvs: nvs_set_blob bt_cfg_key0 250\nD (28325) nvs: nvs_close 4\nD (28325) nvs: nvs_open_from_partition bt_config.conf 1\nD (28325) nvs: nvs_set_blob bt_cfg_key0 264\nD (28335) nvs: nvs_close 5\nD (28335) nvs: nvs_open_from_partition bt_config.conf 1\nD (28335) nvs: nvs_set_blob bt_cfg_key0 347\nD (28355) nvs: nvs_close 6\nD (28355) nvs: nvs_open_from_partition bt_config.conf 1\nD (28355) nvs: nvs_set_blob bt_cfg_key0 407\nD (28365) nvs: nvs_close 7\nD (28365) nvs: nvs_open_from_partition bt_config.conf 1\nD (28365) nvs: nvs_set_blob bt_cfg_key0 462\nD (28385) nvs: nvs_close 8\nD (28385) nvs: nvs_open_from_partition bt_config.conf 1\nD (28385) nvs: nvs_set_blob bt_cfg_key0 476\nD (28395) nvs: nvs_close 9\nV (28395) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (28395) BLE_HEART_RATE:     remote BD_ADDR: 612610f26701\nI (28395) BLE_HEART_RATE:     address type = 1\nI (28405) BLE_HEART_RATE:     pair status = success\nI (28405) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (28415) BLE_HEART_RATE:     Bonded devices number : 1\nI (28415) BLE_HEART_RATE:     Bonded devices list :\nI (28425) BLE_HEART_RATE:        0 :   61:26:10:f2:67:01\nV (28905) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (28905) BLE_HEART_RATE:     event nor handled\nV (29435) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (29435) BLE_HEART_RATE:     event nor handled\nV (29655) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (29655) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_kbdisp-keyboard-display\">ESP_IO_CAP_KBDISP (Keyboard display)</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_OUT</code>(DisplayOnly) と <code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_IN</code>(KeyboardOnly) の合わせ技かと思いきや、<br />\n<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_IO</code>(DisplayYesNo)と同じ動作。<br />\nたしかにキーボードと表示両方必要だわな。。。</p>\n\n<h1 id=\"コンソール入力ルーチン\">コンソール入力ルーチン</h1>\n<p>passkeyの入力など、コンソールからの入力が必要な場合、<code class=\"language-plaintext highlighter-rouge\">gets()</code>などを使用するとキー入力待ちの間タスク切り替えが行われずに他のタスクが動作できない。<br />\n(esp-idfはFreeRTOSを使用したマルチタスク構成)。\nそこで、<code class=\"language-plaintext highlighter-rouge\">gets()</code>/<code class=\"language-plaintext highlighter-rouge\">getchar()</code>の代わりとなる関数を用意した。<br />\n動作としては、キー入力待ちの少しの間、<code class=\"language-plaintext highlighter-rouge\">vTaskDelay()</code>でCPUを解放して他のタスクの動作を阻害しないようにしている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">uart_checkkey()</code>は今回使ってないけど、〇秒以内に入力がなければデフォルトで動作、のような動作を実現するのに使用する関数。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">printf()</code>もあちこちのタスクから出力する場合はセマフォで排他処理した方が良いけど、今回は特に問題になりそうにないのでそのまま使用。</p>\n\n<p>Buildは これらのファイルをsrcディレクトリにぶち込むだけでOK。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  uart_console.h\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#include    <stdio.h>\n#include    <stdint.h>\n#include    <stdbool.h>\n\nextern bool uart_checkkey(int loop_num);\nextern int uart_getchar(void);\nextern int uart_gets(char* buf, int max);\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  uart_console.c\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#include    <stdio.h>\n#include    <stdint.h>\n#include    <stdbool.h>\n#include    <string.h>\n#include    <stdarg.h>\n\n#include    \"freertos/FreeRTOS.h\"\n#include    \"freertos/task.h\"\n#include    \"esp_system.h\"\n#include    \"rom/uart.h\"\n\n#include    \"uart_console.h\"\n\n// ========= UARTからの入力待ち ===============================================\n// param    loop_num: 待ち時間(単位100msec)\n// return   true: キー入力があった     false: キー入力はなかった\nbool uart_checkkey(int loop_num)\n{\n    bool    ret = false;\n    uint8_t ch;\n     for (int loop_cnt = 0; loop_cnt < loop_num; loop_cnt++) {\n        // UARTから1文字取得\n        if (uart_rx_one_char(&ch) == OK) {\n            // 入力あり\n            ret = true;\n            break;\n        }\n        if ((loop_cnt % 5)== 0) {\n            // たくさん出ると鬱陶しいので5回毎に\n            putchar('.');\n            fflush(stdout);\n        }\n        // 100ms待つ\n        vTaskDelay(100 / portTICK_RATE_MS);\n    }\n    putchar('\\n');\n\n    // バッファにたまっているデータを読み捨てる\n    while (uart_rx_one_char(&ch) == OK);\n    return ret;\n}\n\n\n// ========= UARTから1文字取得 ================================================\n// param    なし\n// return   文字コード\n// note     CRは無視するので注意\nint uart_getchar(void)\n{\n    uint8_t ch;\n    while (1) {\n        // UARTから1文字取得\n        if (uart_rx_one_char(&ch) == OK) {\n            // 入力あり\n            if (ch == '\\r') {\n                // CRなら次の値を取得\n                continue;\n            }\n            // 入力された値を返す\n            return ch;\n        }\n        // 100ms待つ(CPUを握りっぱなしにしないように)\n        vTaskDelay(100 / portTICK_RATE_MS);\n    }\n}\n\n// ========= UARTから1行取得 ===================================================\n// param    buf: 文字列格納領域へのポインタ\n//          max: 最大文字列長\n// return   入力された文字列長\nint uart_gets(char* buf, int max)\n{\n    int     i = 0;\n    while (i < (max - 1)) {     // null terminate の分を空けておくので max - 1\n        char ch = uart_getchar();\n        if (ch == '\\n') {\n            // LFで終了\n            putchar(ch);\n            fflush(stdout);\n            break;\n        }\n        if (ch == '\\b' || ch == 0x7f) {     // BackSpace or DEL\n            if (i > 0) {        // 先頭でない\n                i--;            // ポインタを一つ前に\n                putchar('\\b');  // 前の文字の表示を削除\n                putchar(' ');\n                putchar('\\b');\n                fflush(stdout);\n            }\n        }\n        else {\n            // それ以外の文字はバッファに格納\n            buf[i] = ch;\n            i++;\n            putchar(ch);        // 表示\n            fflush(stdout);\n        }\n    }\n    buf[i] = '\\0';          // null terminate\n    return i;\n}\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry PiでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry PiでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に Raspberry Pi からアクセスしてみる方法についてのメモ。</p>\n\n<p>Androidでアクセスすると、色々とブラックボックスで処理されてどうなってるのか分かり難いので理解を深める意味で試してみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"メモ\">メモ</h1>\n\n<p>ここにあるように、BLEでは「ボンディング(参照先ではペアリングと表記)なし」で実行するのが無難と思われる<br />\n<a href=\"https://www.musen-connect.co.jp/blog/course/trial-production/ble-beginner-8/\" target=\"_blank\">【サルでもわかるBLE入門】(8) ペアリング</a></p>\n\n<p>Wiresharkによるパケットキャプチャの解説(たぶん、そんなレイヤでデバッグすることはないと思うけど)<br />\n<a href=\"https://re-engines.com/2021/08/16/ble-secure/\" target=\"_blank\">BLEのペアリングをWiresharkでキャプチャしながら学ぶ</a></p>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<h1 id=\"ペリフェラル機器をスキャン\">ペリフェラル機器をスキャン</h1>\n\n<p>まずは接続可能デバイスをスキャンしないと始まらないので、スキャンする。<br />\nもちろん、ESP32側はAdvertising 開始状態である必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo timeout </span>5s hcitool lescan        ← 5秒間スキャンしてみる\nLE Scan ...\n48:BA:7E:24:D0:AA <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n50:17:FC:8C:D1:87 ESP_BLE_HR            ←見つかった\nE4:9A:9F:40:AD:09 <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\nC4:49:BB:8A:7F:6C EX-ZR1800-8A7F6B\nC4:49:BB:8A:7F:6C <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hcitool lescan</code>の実行には<code class=\"language-plaintext highlighter-rouge\">sudo</code>必須。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout 5s</code> を付けずにCTRL+Cで停止しても良い。</p>\n\n<h1 id=\"対象デバイスにアクセスしてみる\">対象デバイスにアクセスしてみる</h1>\n\n<blockquote>\n  <p>[!NOTE]\n<strong>UUIDについて</strong></p>\n\n  <p>16bit UUIDは以下のXXXXの部分(それ以外の部分が一致しないものは128bit UUID)<br />\n<code class=\"language-plaintext highlighter-rouge\">0000XXXX-0000-1000-8000-00805f9b34fb</code></p>\n\n  <p>16bit UUIDは 以下のページを参照<br />\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a></p>\n</blockquote>\n\n<h2 id=\"コマンド起動と接続\">コマンド起動と接続</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">gatttool</code>の実行に<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要。<br />\n<code class=\"language-plaintext highlighter-rouge\">«アドレス»</code> には上でみつけたアドレスを指定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>gatttool <span class=\"nt\">-t</span> random <span class=\"nt\">-I</span> <span class=\"nt\">-b</span> «アドレス»             ← ツールの実行   以下、インタラクティブモードに入る\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> connect                  ← 接続 \nAttempting to connect to 50:17:FC:8C:D1:87\nConnection successful                             ← 接続成功  \n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"サービス一覧を取得\">サービス一覧を取得</h2>\n\n<p>サービスの一覧を取得してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> primary\nattr handle: 0x0001, end grp handle: 0x0005 uuid: 00001801-0000-1000-8000-00805f9b34fb\nattr handle: 0x0014, end grp handle: 0x001c uuid: 00001800-0000-1000-8000-00805f9b34fb\nattr handle: 0x0028, end grp handle: 0xffff uuid: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<p>それぞれこんな意味</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>UUID</th>\n      <th>種別</th>\n      <th>ハンドル範囲</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>1801</td>\n      <td>Generic Attribute</td>\n      <td>0x0001 ~ 0x0005</td>\n    </tr>\n    <tr>\n      <td>1800</td>\n      <td>Generic Acces</td>\n      <td>0x0014 ~ 0x001c</td>\n    </tr>\n    <tr>\n      <td>180d</td>\n      <td>Heart Rate</td>\n      <td>0x0028 ~ 0xffff</td>\n    </tr>\n  </tbody>\n</table>\n\n<h2 id=\"generic-accesを調べてみる\">Generic Accesを調べてみる</h2>\n\n<p>上で調べたGeneric Acces のハンドル範囲を指定して実行。<br />\n表示されるUUIDを\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a>\nで探して右側にメモっておいた。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x14 0x1c\nhandle: 0x0014, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0015, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb        ← device name\nhandle: 0x0017, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb        ← Appearance\nhandle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb        ← Central Address Resolution\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"device-name-を読んでみる\">device name を読んでみる</h2>\n\n<p>とりあえず devece nameを読んでみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x016                       ← handle 0x16<span class=\"o\">(</span>device name<span class=\"o\">)</span> のリード\nCharacteristic value/descriptor: 45 53 50 5f 42 4c 45 5f 48 52     ← 結果\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<p>このままだとなんだかわからん…<br />\n別ウィンドゥで以下を実行。<br />\nただし、<code class=\"language-plaintext highlighter-rouge\">nkf</code>はデフォルトでインストールされていないので<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールする。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">echo</code>の中身には上でリードした結果をコピペする。<br />\nこれを<code class=\"language-plaintext highlighter-rouge\">xxd</code>コマンドでバイナリに変換、<br />\n<code class=\"language-plaintext highlighter-rouge\">nkf</code>で文字コード変換を行う(これだとUTF-8→UTF-8なのであんまり意味ない気が…)。<br />\n結果は改行されずに、プロンプトが続けて表示されるので注意。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">echo</span> <span class=\"s2\">\"45 53 50 5f 42 4c 45 5f 48 52\"</span>  | xxd <span class=\"nt\">-p</span> <span class=\"nt\">-r</span>  | nkf <span class=\"nt\">-WwmQ</span>\nESP_BLE_HR        ← おぉ、読めてる\n<span class=\"nv\">$ </span>\n</code></pre></div></div>\n\n<h2 id=\"heart-rateサービスを調べてみる\">Heart Rateサービスを調べてみる</h2>\n<p>同様にHeart Rateサービスについて調べてみる。<br />\nUUIDについてのメモも同様。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x0028 0xffff\nhandle: 0x0028, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0029, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002a, uuid: 00002a37-0000-1000-8000-00805f9b34fb        ← Heart Rate Measurement\nhandle: 0x002b, uuid: 00002902-0000-1000-8000-00805f9b34fb        ← Client Characteristic Configuration\nhandle: 0x002c, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002d, uuid: 00002a38-0000-1000-8000-00805f9b34fb        ← Body Sensor Location\nhandle: 0x002e, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002f, uuid: 00002a39-0000-1000-8000-00805f9b34fb        ← Heart Rate Control Point\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"heart-rate-control-point-を読み書きしてみる\">Heart Rate Control Point を読み書きしてみる</h2>\n\n<p>Characteristicの読み書きを試すため、Heart Rate Control Point(ハンドル0x2f;c<code class=\"language-plaintext highlighter-rouge\">har-desc</code>の結果から取得)にアクセスしてみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 読んでみる\nCharacteristic value/descriptor: 00                   ← 読めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 01       ← 書いてみる\nCharacteristic value was written successfully         ← 書けた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 確認してみる\nCharacteristic value/descriptor: 01                   ← 書けてる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 0x02     ← 書き込み値に0xを付けたらエラーになる\nError: Characteristic Write Request failed: Attribute value length is invalid\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<h2 id=\"notificationを有効にしてみる\">Notificationを有効にしてみる</h2>\n\n<p>NotificationをONにするにはCCCを操作する。<br />\nNotificationで受信したデータは自動で表示される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 00 00                ← Notification OFFになってる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0100     ← Notification ON にしてみる<span class=\"o\">(</span>0100を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\nNotification handle <span class=\"o\">=</span> 0x002a value: 50 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 51 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 52 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 01 00                ← Notification ONになってる\nNotification handle <span class=\"o\">=</span> 0x002a value: 53 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 54 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 55 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 56 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 57 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0000     ← Notification OFF にしてみる<span class=\"o\">(</span>0000を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>                              ← 以降、Notificationは停止\n</code></pre></div></div>\n\n<h2 id=\"書き込み禁止のcharacteristicに書き込んでみる\">書き込み禁止のCharacteristicに書き込んでみる</h2>\n\n<p>書き込み禁止のCharacteristicに書き込んでみるとどうなるか試してみる。<br />\n当然エラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>50:17:FC:8C:D1:87][LE]> char-write-req 0x2d 01         ← Body Sensor Locationに書き込んでみる\nError: Characteristic Write Request failed: Attribute can<span class=\"s1\">'t be written   ← エラーになった\n</span></code></pre></div></div>\n\n<h2 id=\"切断する\">切断する</h2>\n\n<p>操作が終わったら切断する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> disconnect                        ← 切断\n<span class=\"o\">(</span>gatttool:1840<span class=\"o\">)</span>: GLib-WARNING <span class=\"k\">**</span>: 12:55:27.500: Invalid file descriptor.   ← なんか言われるけど無視して良い\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> <span class=\"nb\">exit</span>                              ← インタラクティブモードの終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る\n</code></pre></div></div>\n\n<h1 id=\"bluetoothctlでアクセス参考\">bluetoothctlでアクセス(参考)</h1>\n\n<p>「ボンディングする」設定の場合、bluetoothctlでアクセスする必要がある。<br />\nボンディングしない設定で使う分には関係ないが、せっかく調べたのでメモっておく。</p>\n\n<p>ボンディング前後でアドレス違ったりしてイマイチ使いにくい。<br />\nどうしても「ボンディングする」にしなければならない場合は、自身のアドレスをパブリックアドレスにしておけばちょっとマシかも。</p>\n\n<h2 id=\"メモ-1\">メモ</h2>\n\n<p>bluetoothctlのコマンド <br />\n<a href=\"https://qiita.com/noraworld/items/55c0cb1eb52cf8dccc12\" target=\"_blank\">bluetoothctl のコマンド一覧と使い方をまとめてみた</a></p>\n\n<p>bluetoothctlだとGATTへのアクセスができないっぽいので、ボンディングの登録/解除以外は使えないっぽいな…</p>\n\n<h2 id=\"前提-1\">前提</h2>\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス           (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングする                           (ESP_LE_AUTH_REQ_SC_MITM_BOND)</li>\n  <li>IO capabilityはcapabilityはDisplayYesNo    (ESP_IO_CAP_IO)</li>\n</ul>\n\n<h2 id=\"起動\">起動</h2>\n\n<p>ツールの起動。<br />\n<code class=\"language-plaintext highlighter-rouge\">sudo</code>必要<br />\n以下インタラクティブモードで操作。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo </span>bluetoothctl                                        ← 起動\n</code></pre></div></div>\n\n<h2 id=\"スキャン\">スキャン</h2>\n\n<p>接続可能デバイスを見つけるためにスキャンする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# scan on                                       ← スキャン開始\nDiscovery started\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>NEW] Device 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\n<span class=\"o\">[</span>NEW] Device 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\n<span class=\"o\">[</span>NEW] Device 62:D1:88:DD:4F:7C リビングルーム\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E RSSI: <span class=\"nt\">-38</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower: 3\n・・・\n<span class=\"o\">[</span>bluetooth]# scan off                                      ← スキャン停止\nDiscovery stopped\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: no\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower is nil\n・・・\n<span class=\"o\">[</span>bluetooth]# devices                                       ← 接続可能デバイスの表示\nDevice 5A:E1:9A:05:96:E0 ESP_BLE_HR                        ← これがESP32<span class=\"o\">(</span>ランダムアドレスなので起動の度に変化する<span class=\"o\">)</span>\nDevice 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\nDevice 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\nDevice 62:D1:88:DD:4F:7C リビングルーム\n\n</code></pre></div></div>\n\n<h2 id=\"agentの登録\">agentの登録</h2>\n\n<p>ボンディングのために、agentを登録する(数字を入力したり、Yes/Noを選択したりするやつ)。<br />\nこちらの設定と相手側の設定の組み合わせで最終的にどの方法が使われるか決定される。<br />\nたとえば、こちら側を NoInputNoOutput に設定しておけば、相手側が DisplayYesNo であってもYes/Noの入力は求められない。<br />\n逆の設定でも同様。</p>\n\n<p>登録された状態で他のCapabilityで登録しようとしても「既に登録済み」と言われるので、念のため一旦登録解除してから登録しておく。<br />\nこのあたり、情報少なくてイマイチよく分からない…</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# agent off                                    ← 一旦agentの登録解除\nAgent unregistered                                         ← 解除された\n<span class=\"o\">[</span>ESP_BLE_HR]# agent DisplayYesNo                           ← DisplayYesNoで登録\nAgent registered                                           ← 登録された\n</code></pre></div></div>\n\n<h2 id=\"接続\">接続</h2>\n\n<p>接続する。<code class=\"language-plaintext highlighter-rouge\">connect</code>でなく、<code class=\"language-plaintext highlighter-rouge\">pair</code>で実行。<br />\n<code class=\"language-plaintext highlighter-rouge\">connect</code>による接続は後述。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# pair 5A:E1:9A:05:96:E0                       ← 接続\nAttempting to pair with 5A:E1:9A:05:96:E0\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 Connected: <span class=\"nb\">yes\n</span>Request confirmation\n<span class=\"o\">[</span>agent] Confirm passkey 680456 <span class=\"o\">(</span><span class=\"nb\">yes</span>/no<span class=\"o\">)</span>:                   ← agentがYes/Noを聞いてくる\n<span class=\"o\">[</span>NEW] Primary Service                                      ← これが自動的に表示されて上の質問を見失うので注意!!\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001\n        00001801-0000-1000-8000-00805f9b34fb\n        Generic Attribute Profile\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001/char0002\n        00002a05-0000-1000-8000-00805f9b34fb\n        Service Changed\n・・・\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0028/char002e\n        00002a39-0000-1000-8000-00805f9b34fb\n        Heart Rate Control Point\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001800-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001801-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 ServicesResolved: <span class=\"nb\">yes\nyes</span>                                                         ← yesを入力<span class=\"o\">(</span>同時に相手側でもyes入力<span class=\"o\">)</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Address: 94:B9:7E:65:AF:5E\nPairing successful                                         ← 接続された\n<span class=\"o\">[</span>ESP_BLE_HR]# paired-devices                               ← ボンディング結果を確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR                        ← advertisingがランダムアドレスでもパブリックアドレスで登録されるので注意!!\n<span class=\"o\">[</span>ESP_BLE_HR]#                                                以降、接続はこのアドレスを使用する!!\n</code></pre></div></div>\n\n<h2 id=\"切断\">切断</h2>\n\n<p>切断する。<br />\nCharacteristicアクセスできないので、実質ボンディングするのみ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断する\nAttempting to disconnect from 94:B9:7E:65:AF:5E            ← パブリックアドレスが表示されている\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<h2 id=\"再接続\">再接続</h2>\n\n<p>ボンディング済みのデバイスに再接続する場合の手順。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスの表示\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# connect 94:B9:7E:65:AF:5E                     ← 表示されたアドレスで接続\nAttempting to connect to 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: <span class=\"nb\">yes\n</span>Connection successful                                      ← 接続された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断\nAttempting to disconnect from 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<p>ボンディングしてない機器に対して<code class=\"language-plaintext highlighter-rouge\">connect</code>すると、<code class=\"language-plaintext highlighter-rouge\">agent off</code> で <code class=\"language-plaintext highlighter-rouge\">pair</code> したような動作になる模様。</p>\n\n<h2 id=\"ボンディング解除\">ボンディング解除</h2>\n\n<p>ボンディング済みデバイスを登録削除する。<br />\nESP32側も忘れず登録削除しておくこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスを確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# remove 94:B9:7E:65:AF:5E                      ← ボンディング解除\n<span class=\"o\">[</span>DEL] Descriptor                                           ← なんか ずらずらっと削除されたと出る\n        /org/bluez/hci0/dev_5F_76_EF_D2_45_E7/service0001/char0002/desc0004\n        00002902-0000-1000-8000-00805f9b34fb\n        Client Characteristic Configuration\n・・・\nDevice has been removed                                    ← 削除された\n<span class=\"o\">[</span>bluetooth]# paired-devices                                ← 確認\n<span class=\"o\">[</span>bluetooth]#                                               ← 削除されてる\n</code></pre></div></div>\n\n<h2 id=\"ツールの終了\">ツールの終了</h2>\n\n<p>ツールを終了してShellに戻る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# <span class=\"nb\">exit</span>                                          ← またはquitまたはCTRL+Dで終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る \n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>pythonでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に pythonスクリプトでアクセスしてみる方法についてのメモ。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<p>pythonスクリプトはRaspberryPiで動作している(実際に試したのはPi4だが、Pi3/Pi0wでも同様)。<br />\nubuntu-PCでも同様にできるはずだが、うちのマシンは内蔵Bluetoothのバージョンが古くてBLE非対応だったので試してない。<br />\nwindows-PCはよくわからん…</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/test1\n<span class=\"nb\">cd</span> /work/ble/test1\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.9.10 bluepy\npyenv <span class=\"nb\">local </span>bluepy\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>bluepy\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/9bbdfa53526411967975097cfbcc66e6.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>ESP32側はAdvertising 開始状態にしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>python ble_hr.py\n</code></pre></div></div>\n<p>デバイスのスキャンを行うので<code class=\"language-plaintext highlighter-rouge\">sudo</code>が必要。</p>\n<blockquote>\n  <p>[!NOTE]\nもし、scanせずにアドレスを指定して実行するだけの処理に書き換えれば<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要になる。</p>\n</blockquote>\n\n<h1 id=\"説明\">説明</h1>\n\n<h2 id=\"ble_hr_delegateクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR_Delegate</code>クラス</h2>\n<p>Notifyを受け取っての処理は<code class=\"language-plaintext highlighter-rouge\">bluepy.btle.DefaultDelegate</code>クラスを継承したクラスを作成して登録する必要がある。<br />\n処理自体は<code class=\"language-plaintext highlighter-rouge\">handleNotification</code>メソッドをオーバーライドして定義する。<br />\n受け取るデータ<code class=\"language-plaintext highlighter-rouge\">data</code>はbytes型なので、数値として使用する場合は<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換してやる必要があるが、<br />\nこの時のエンディアンは接続しているデバイスのFW仕様によるので、どちらを使うかはあらかじめ確認しておく必要がある。<br />\n(大抵はFWを動かしているCPUのエンディアンなのかな?)</p>\n\n<h2 id=\"ble_hrクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR</code>クラス</h2>\n<p>peripheralを操作するための処理をクラス化してある。<br />\nクラス化は必須ではないけど、処理をまとめておいた方が分かりやすいかな?と思ったので。</p>\n\n<p>コンストラクタ、接続、Characteristicのリード/ライト、Notifyの有効化/無効化/ポーリング、切断などの処理がある。</p>\n\n<h2 id=\"main関数\"><code class=\"language-plaintext highlighter-rouge\">main</code>関数</h2>\n<p>メイン処理。<br />\n処理の流れはこんな感じ。</p>\n<ul>\n  <li>デバイスのスキャン</li>\n  <li>スキャン結果から指定されたUUIDを持つデバイスを探す\n    <ul>\n      <li>UUIDやデバイス名が必ずしも同じところにあるとは限らないので色々読んでみる必要がある</li>\n    </ul>\n  </li>\n  <li>複数のデバイスを同時に操作することも可能だが、今回は最初の1個だけを決め打ちで使う</li>\n  <li>接続</li>\n  <li>Characteristicのリード\n    <ul>\n      <li>ここもリード結果はbytes型なので、<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換する</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト\n    <ul>\n      <li>ライトデータはbytes型に変換する必要があるが、この処理は、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.write()</code>で変換しているのでここではそのまま。</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト結果の確認\n    <ul>\n      <li>ライトできたか確認するために、再度リードしている</li>\n    </ul>\n  </li>\n  <li>Notifyの有効化</li>\n  <li>Notifyが通知されることを確認するために少し待つ\n    <ul>\n      <li>Notifyを待つ間、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.waitForNotifications()</code>(<code class=\"language-plaintext highlighter-rouge\">Peripheral.waitForNotifications()</code>のラッパ)をコールし続ける必要がある。<br />\nこれをコールしないとNotifyを受信できない(キューイングされるがコールバックは実行されない)。</li>\n    </ul>\n  </li>\n  <li>Notifyの無効化\n    <ul>\n      <li>Notifyが入らないことを確認するためにちょっと待つ</li>\n    </ul>\n  </li>\n  <li>切断</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>BLEでアプリケーションパラメータ設定</title>\n  </head>\n  <body>\n    <header>\n      <h1>BLEでアプリケーションパラメータ設定</h1>\n      <p>ESP32 BLEを使用してアプリケーションパラメータの設定を変更する処理の雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>アプリケーションを作成したとき、マシン名のように端末毎に変更を変更したり、\nサーバ名のように設置条件によって変更したいパラメータってありますよね。<br />\nいつもは起動時に設定モードに入ったり、動作中に簡易シェルを動かしてコンソール(UART)から設定していましたが、<br />\n実装面積などの関係でUARTが接続できなかったりした場合、それ以外の方法としてBLEで設定する方法を考えました。<br />\n(ESP32の場合、Flash書き換えでUART使うので繋がない訳にはいかないのですが…)</p>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nを参考にカスタムプロファイルでアプリケーションパラメータをread/writeできるようにしてみました。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは<a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a><br />\nにあるのでcloneしてください。</p>\n\n<p>このプログラムではアプリケーションはWi-Fiに接続するだけの処理です。<br />\nうまくパラメータが設定できて、nvsに保存しておけば、2回目以降はBLEによる設定なしにWi-Fiに接続することができます。<br />\n接続できれば、外部マシンからpingを打って応答があることが確認できます。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a> のREADME.mdを参照してください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nパラメータの設定はRaspberryPiのpythonから行っていますが、その気になればAndroidのBLE接続確認ツールなどからでも設定できます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n設定パラメータにループインターバルがありますが、プログラム中では参照していません。<br />\n数値を設定する例として入れてあります。</p>\n</blockquote>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>設定したいパラメータが増えてたら、Characteristicを増やしていけばいくらでも対応できるハズ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Bluetooth classic でシリアル通信(SPP)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Bluetooth classic でシリアル通信(SPP)</h1>\n      <p>ESP32 Bluetooth classic(SPP)を使用してシリアル通信するデモプログラム</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>シリアル通信でデータを送受信したいけど、有線接続はできない場合にBluetooth classicのSPP(Serial Port Profile )を使用して\nCOMポートとして接続する方法のデモ。<br />\nesp-idfのサンプルプログラムが私にとっては複雑怪奇だったので、ちょっとシンプルにしてみた。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは</p>\n<ul>\n  <li>VFS版: <a href=\"https://github.com/ippei8jp/BT_SPP_VFS\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_VFS</a></li>\n  <li>Callback版: <a href=\"https://github.com/ippei8jp/BT_SPP_CB\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_CB</a></li>\n</ul>\n\n<p>にあるのでcloneしてください。</p>\n\n<p>このプログラムではPC等のCOMポートへ/から接続して送信したデータをエコーバックするだけのデモプログラムです。<br />\nそれぞれのイベント発生時に発生イベントとパラメータを表示するようにしてあるので、動作の理解の一助になります…\nなったらいいな…でも期待はするな….</p>\n\n<p>上記2つのリポジトリはファイル構成を合わせてあるので、diffをとるとVFSとCallbackでどのような違いがあるのか分かりやすい<br />\n… かもね…</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<ul>\n  <li>VFS版: <a href=\"https://github.com/ippei8jp/BT_SPP_VFS#readme\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_VFS#readme</a></li>\n  <li>Callback版: <a href=\"https://github.com/ippei8jp/BT_SPP_CB#readme\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_CB#readme</a></li>\n</ul>\n\n<p>を参照してください。</p>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ <br />\n最近こればっかりや…</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>エコーバックタスクをコマンドシェルタスクなどに入れ替えるとすぐ使える…とも思えんけど…<br />\n踏み台くらいにはなるでしょう。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール</h1>\n      <p>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロード\">ダウンロード</h1>\n\n<p><a href=\"https://www.raspberrypi.com/software/operating-systems/\" target=\"_blank\">Raspberry Pi OS</a>ページの <br />\n「Manually install an operating system image」の「See all download options」をクリック、<br />\n「Raspberry Pi OS (64-bit)」の「Raspberry Pi OS with desktop」の「Download」をクリックしてダウンロード<br />\n試したのは Release date: January 28th 2022</p>\n\n<blockquote>\n  <p>[!NOTE]\n「Archive」リンクから過去のリリースも入手できる</p>\n</blockquote>\n\n<p>なんか見るたびにページ構成変わるよなぁ….😩💨</p>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nシリアルコンソールの送信改行コードはCRにしておくこと。<br />\nそうしないと、ビミョーに悲しいことが起こる場合がある。</p>\n\n</blockquote>\n\n<h2 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h2>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>の  最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group</code>と<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>については使用するモニタに合わせる。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group=2</code>はモニタ種別でDMT(一般的にモニタディスプレイ)、<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_mode=82</code>が 1920x1080 60Hz(1080p)を示している。<br />\n設定値の内容については、<a href=\"https://www.raspberrypi.com/documentation/computers/config_txt.html#hdmi-mode\" target=\"_blank\">HDMI Mode</a>を参照。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>はテキストモードで表示したいサイズに合わせる。1920と1080とか、1280と720とか。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># display resolution force setting</span>\n<span class=\"nv\">hdmi_group</span><span class=\"o\">=</span>2\n<span class=\"nv\">hdmi_mode</span><span class=\"o\">=</span>82\n<span class=\"nv\">framebuffer_width</span><span class=\"o\">=</span>1920\n<span class=\"nv\">framebuffer_height</span><span class=\"o\">=</span>1080\n<span class=\"nv\">hdmi_force_hotplug</span><span class=\"o\">=</span>1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nHDMIディスプレイを常に接続しているなら設定しなくても問題ないが、\nHDMIディスプレイをはずしてVNCでリモート接続だけする場合は設定しておかないと\n解像度が1024x768までしか設定できなくなるので注意。</p>\n</blockquote>\n\n<h3 id=\"vncが遅い問題対応\">VNCが遅い問題対応</h3>\n<p>このバージョンではHDMIディスプレイを繋いでいない状態でVNCで接続すると表示がとても遅くなる問題がある。<br />\n回避するには、<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code>に以下追記する。<br />\n<code class=\"language-plaintext highlighter-rouge\">1920x1080@60D</code>の部分は上記の<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>や<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>の設定値に合わせる。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>video=HDMI-A-1:1920x1080@60D\n</code></pre></div></div>\n\n<p>具体的にはこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>console=serial0,115200 console=tty1 root=PARTUUID=b635b4ec-02 rootfstype=ext4 fsck.repair=yes video=HDMI-A-1:1920x1080@60D rootwait\n</code></pre></div></div>\n\n<p>参考URL:<a href=\"https://forums.raspberrypi.com/viewtopic.php?p=1935714#p1935711\">Re: Bullseye vncserver is very slow without display</a></p>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。<br />\nSSID名は ダブルクォーテーションで囲む。<br />\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://qiita.com/mt08/items/2da1cce534dfdc84f5e3#%E7%92%B0%E5%A2%83\" target=\"_blank\">[メモ] (らずぱい)Windows上から固定IP設定 (Raspberry Pi Static IP)</a>\nにWindows版の<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase.exe</code>へのリンクがある。<br />\nワタシはUbuntuや別のRasberryPiで作ったから使ってないけど…</p>\n</blockquote>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase \"SSID名\" \"暗号化キー\"\n        ↓ 実行結果\nnetwork={\n        ssid=\"SSID名\"\n        #psk=\"暗号化キー\"\n        psk=ほにゃらら~~~ほにゃらら~~~\n}\n</code></pre></div></div>\n\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。<br />\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<blockquote>\n  <p>[!NOTE]\n起動後、公開鍵ファイルの設置を行うには、<br />\n<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">ubuntuにSSHサーバをセットアップする</a> <br />\nの「秘密鍵と公開鍵の生成と公開鍵ファイルの設置」の部分を参照。<br />\n(ページはUbuntuについて書いてあるけど、サーバがセットアップ済みなことを除けばRaspberry Pi OSでも同じ)</p>\n</blockquote>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># アップデート実行\nsudo apt update\nsudo apt upgrade\n# リブート\nsudo reboot\n</code></pre></div></div>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S7 Splash Screen\n            Would you like to show the splash screen at boot?\n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこの操作で/boot/cmdline.txtが書き換えられるらしい。</p>\n\n</blockquote>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# 新ユーザのパスワード変更する\npasswd\n《パスワードを設定》\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\" target=\"_blank\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n            B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/4f39afbcd8471426421944b597f3a5f2963984c6/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nresize.pyは以前python2ベースで作ってあったが、<br />\nこのバージョンからpython2がデフォルトでインストールされなくなったので、<br />\npython3ベースに修正したのでURLが変更されています。</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n\n<p>物理キーボード接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]<br />\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n\n</blockquote>\n\n<h1 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h1>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n\n<p>まずはワークディレクトリの作成</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo service smbd reload\nsudo service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo vi /etc/hostname\nsudo vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>s``udo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    3 Interfacing Options\n        I3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>\n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n\n<p>Windows側のクライアントは、<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a>\nから VNC Viewerをダウンロード。\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。\n日本語化の手順はこちらを参考に。 <a href=\"http://xn--u9j0md1592aqmt715c.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>SDカードイメージのバックアップを取るならこちら。<br />\n<a href=\"/memoBlog/2021/07/18/sd_image_2.html\" target=\"_blank\">Raspbian SDカードイメージファイルの作成(改訂版)</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>aspberry Pi OS(64bit)がリリースされたが、openVINOのBuild済みモジュールはまだこれに対応していない。<br />\nそのうち対応されると思うけど、とりあえず自前でBuildする方法を調べてみた。<br />\nついでにCPU Extensionも作成しておく。<br />\nなお、Raspberry Pi OS(32bit Buster)向けのBuild手順については、\n『<a href=\"/memoBlog/2021/10/28/openVINO_build.html\" target=\"_blank\">openVINO(Raspberry Pi向け)のbuild</a>』を参照。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<p>今回もARM版Dockerコンテナを使用してセルフコンパイルする方法で行う。<br />\n手順そのものは特殊なことはないので、Raspberry Pi上のNative環境でもBuildできそうだけど、\nディスク容量とかスワップ領域とか気にしないといけないかもしれないので試してない。<br />\n(今回はクロスコンパイル環境はなし。cythonの出力モジュールも使いたかったので)</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_emu\n</code></pre></div></div>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h2 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h2>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n32bit版との差分はこんな感じ。<br />\nあれ?32bit版の<code class=\"language-plaintext highlighter-rouge\">python-minimal</code>って間違ってる?<br />\n<code class=\"language-plaintext highlighter-rouge\">python3-numpy</code>で依存モジュールとしてインストールされて事なきを得たのか?<br />\n実質、ベースイメージを変更してるだけだな。</p>\n\n  <div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- Dockerfile.old\t2022-03-01 07:26:28.774187231 +0900\n</span><span class=\"gi\">+++ Dockerfile\t2022-03-01 07:19:45.668393598 +0900\n</span><span class=\"p\">@@ -1,4 +1,4 @@</span>\n<span class=\"gd\">-FROM arm32v7/debian:buster\n</span><span class=\"gi\">+FROM arm64v8/debian:bullseye\n</span> \n USER root\n \n<span class=\"p\">@@ -18,7 +18,7 @@</span>\n     libprotobuf-dev libprotoc-dev protobuf-compiler \\\n     cmake \\\n     python3-pip \\\n<span class=\"gd\">-    python-minimal \\\n</span><span class=\"gi\">+    python3-minimal \\\n</span>     python3-numpy cython3 scons\n \n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_emu_1 ov_pi64_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<p>数時間レベルでかかるので、のんびり待ちましょう。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"その他細々したところ\">その他細々したところ</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コメント\">コメント</h3>\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール\">実機へのインストール</h2>\n\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>を適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>ついでにopenCVのBuild方法についてもメモっておく。</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>openCVのリポジトリをcloneしておく。<br />\n指定するタグは適宜変更してください。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n<p>新しいDockerコンテナ作っても良いけど、別にその必要もないので上記のコンテナをそのまま使用する。</p>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n  <h2 id=\"本番-1\">本番</h2>\n</blockquote>\n\n<h3 id=\"準備-2\">準備</h3>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk2.0-dev  libjpeg-dev libpng-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev\n</code></pre></div></div>\n\n<h3 id=\"build\">Build</h3>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n\n<span class=\"c\"># インストール</span>\nmake <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf opencv.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コンテナから出る-1\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール-1\">実機へのインストール</h2>\n<p>openVINOをBuildしたコンテナで続けてBuildした場合は<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>にopenVINO、openCVがインストールされている。<br />\nこれを適当なディレクトリに展開して環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば良い。</p>\n\n<p>別のコンテナを使用したり、openVINOのBuild結果を削除していた場合は、<br />\n最終的に作成した<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>をopenVINOをインストールしたディレクトリに展開する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINOのクロスコンパイル</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINOのクロスコンパイル</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild(クロスコンパイル環境)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi OS(64bit)向けにopenVINOをクロスコンパイルする方法についてまとめた。<br />\nセルフコンパイル(Docker使用)については『<a href=\"/memoBlog/2022/03/07/openVINO_build_2.html\" target=\"_blank\">openVINO(Raspberry Pi OS(64bit)向け)のbuild</a>』を参照。<br />\nただ、クロスコンパイルだとセルフコンパイルの10倍くらい速い(環境によるけど)ので、クロスコンパイルがおススメ。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_cross <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_cross\n</code></pre></div></div>\n\n<h2 id=\"ソースの取得\">ソースの取得</h2>\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h3>\n<p>以下の1つのpatchファイルを作成する。<br />\nサンプル(テスト?)プログラムのBuildを抑制してコンパイル時間の短縮を計っている。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"opencv-の-gitリポジトリを-clone\">openCV の gitリポジトリを clone</h3>\n<p>opencv のリポジトリをcloneする(opencvのBuildを行わない場合は不要)。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libgtk-3-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_cross <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_cross_1 ov_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_cross_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_cross_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n<p>ここからコンテナ内</p>\n\n<h2 id=\"buildディレクトリの作成\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openvino/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/openvino/build\n</code></pre></div></div>\n\n<h2 id=\"cmake実行\">cmake実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm64.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_SAMPLES</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLANG_FORMAT</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_OPENCV</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n    .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>サンプルはBuildしないので、ENABLE_SAMPLES=OFF を設定</li>\n    <li>ソースをいじるわけではないので、ENABLE_CLANG_FORMAT=OFF を設定</li>\n    <li>openCVインストールされていないので、ENABLE_OPENCV=OFF を設定<br />\n(サンプルのBuildしないのでopenCVなくても大丈夫)</li>\n  </ul>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nログには いくつかWarningがあるが、とくに問題はなさそう</p>\n</blockquote>\n\n<h2 id=\"make\">make</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h2 id=\"その他細々したところ\">その他細々したところ</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"c\"># クロスコンパイルを反映したファイル名になっていないので修正</span>\n<span class=\"nb\">mv</span> /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-x86_64-linux-gnu.so /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-aarch64-linux-gnu.so\n\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>CPU Extentionは<code class=\"language-plaintext highlighter-rouge\">make install</code>でコピーされないので手動でインストールする。</li>\n    <li>バイナリリリースに<code class=\"language-plaintext highlighter-rouge\">inference_engine</code>のシンボリックリンクがあるので同様に作成しておく。</li>\n    <li>ngraphのライブラリファイルのファイル名がx86_64(ホスト環境の名前)になっているので、aarch64に修正。<br />\nバイナリ自体はaarch64になっているので、ファイル名のリネームだけでOK。<br />\n本来はファイル名決めてるところで対処するのが良いのだろうけど、とりあえず力技で。</li>\n  </ul>\n</blockquote>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<p>openCVのBuild方法についてもメモっておく。<br />\npythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。<br />\nその場合は、ここはスキップしても大丈夫。<br />\nopenVINOをBuildしたDockerコンテナで引き続き作業を行う</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk-3-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libjpeg-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libpng-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev:arm64\n</code></pre></div></div>\n<h2 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n</code></pre></div></div>\n<h2 id=\"cmakeの実行\">cmakeの実行</h2>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PKG_CONFIG_LIBDIR</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_ENABLE_PKG_CONFIG</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_FIND_ROOT_PATH</span><span class=\"o\">=</span>/ <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span>/work/opencv/platforms/linux/aarch64-gnu.toolchain.cmake <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_NUMPY_INCLUDE_DIRS</span><span class=\"o\">=</span>/usr/lib/python3/dist-packages/numpy/core/include <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n       .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあらかじめ環境変数<code class=\"language-plaintext highlighter-rouge\">PKG_CONFIG_LIBDIR</code>を設定して<code class=\"language-plaintext highlighter-rouge\">pkg-config</code>でaarch64のライブラリとNativeのツール類を参照するように設定しておく。<br />\nこれをやらないと、libjpegとかをインストールしてあることを検出できない</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeのオプションに <code class=\"language-plaintext highlighter-rouge\">-D CMAKE_FIND_DEBUG_MODE=1</code>を追加すると\ncmake中の<code class=\"language-plaintext highlighter-rouge\">find_xxx</code>の動作のログが出力されるので、パッケージのサーチなどの検索パスの確認などが容易になる。</p>\n</blockquote>\n\n<h2 id=\"make-1\">make</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install-1\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino/opencv</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/opencv</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-D CMAKE_INSTALL_PREFIX=/work/opt/intel/openvino/opencv</code>の部分を変更すれば良いけど、ここはopenVINOのインストール先と合わせておかないとうまく動かない。</p>\n\n<h1 id=\"実機へのインストール\">実機へのインストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">opt</code>ディレクトリ以下を丸ごとアーカイブする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<p>作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>をRaspberryPiの適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"コンテナから出る\">コンテナから出る</h1>\n<p>Dockerコンテナは作業終了したら終了しておく。<br />\nCTRL-D でshell終了</p>\n\n<h1 id=\"補足\">補足</h1>\n<p>コンテナにインストールされているパッケージは以下の通り。<br />\nバージョン違いで動かなくなることもあるかもしれんので、念のため。</p>\n\n<p>こんな感じで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span> | <span class=\"nb\">grep</span> <span class=\"nt\">-v</span> automatic\n</code></pre></div></div>\n\n<p>で、こんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>build-essential/stable,now 12.9 amd64 [installed]\ncmake/stable,now 3.18.4-2+deb11u1 amd64 [installed]\ncrossbuild-essential-arm64/stable,stable,now 12.9 all [installed]\ncython3/stable,now 0.29.21-3+b1 amd64 [installed]\ngit/stable,now 1:2.30.2-1 amd64 [installed]\nlibavcodec-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibavformat-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibgstreamer-plugins-base1.0-dev/stable,now 1.18.4-2 arm64 [installed]\nlibgstreamer1.0-dev/stable,now 1.18.4-2.1 arm64 [installed]\nlibgtk-3-dev/stable,now 3.24.24-4 arm64 [installed]\nlibjpeg-dev/stable,now 1:2.0.6-4 arm64 [installed]\nlibpng-dev/stable,now 1.6.37-3 arm64 [installed]\nlibprotobuf-dev/stable,now 3.12.4-1 arm64 [installed]\nlibprotoc-dev/stable,now 3.12.4-1 arm64 [installed]\nlibpython3-dev/stable,now 3.9.2-3 arm64 [installed]\nlibswscale-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibtiff-dev/stable,now 4.2.0-1 arm64 [installed]\nlibusb-1.0-0-dev/stable,now 2:1.0.24-3 arm64 [installed]\nlibwebp-dev/stable,now 0.6.1-2.1 arm64 [installed]\nprotobuf-compiler/stable,now 3.12.4-1 amd64 [installed]\npython3-minimal/stable,now 3.9.2-3 amd64 [installed]\npython3-numpy/stable,now 1:1.19.5-1 amd64 [installed]\npython3-pip/stable,stable,now 20.3.4-4 all [installed]\nscons/stable,stable,now 4.0.1+dfsg-2 all [installed]\nwget/stable,now 1.21-1+deb11u1 amd64 [installed]\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MediaPipeで手の認識</title>\n  </head>\n  <body>\n    <header>\n      <h1>MediaPipeで手の認識</h1>\n      <p>MediaPipe Handsで手の認識処理をやってみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>MediaPipe Handsを使って手の認識処理を行ってみる。<br />\nMediaPipeを使用するとかなり簡単に手の特徴点を取得できる。<br />\nまた、各特徴点の位置がわかるので、それらの位置関係からポーズを取得することもできる。</p>\n\n<p>参考: <a href=\"https://google.github.io/mediapipe/solutions/hands.html\" target=\"_blank\">https://google.github.io/mediapipe/solutions/hands.html</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/mediapipe\n<span class=\"nb\">cd</span> /work/ble/mediapipe\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 mediapipe\npyenv <span class=\"nb\">local </span>mediapipe\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>mediapipe\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<h2 id=\"共通ルーチン\">共通ルーチン</h2>\n\n<p>各指の関節と指先の位置関係から指が伸びているのか、曲がっているのかを判別し(親指だけは各関節の角度から判別)、<br />\nその組み合わせからどのようなポーズなのかを判別している。<br />\nアルゴリズムは <a href=\"https://github.com/geaxgx/openvino_hand_tracker\">https://github.com/geaxgx/openvino_hand_tracker</a> から拝借した。<br />\n元のプログラムは各関節の位置を検出された手の画像を回転して角度調整した画像のY座標から取得しているが、<br />\n今回は手の角度が分からないので、手首から各関節位置までの距離を比較するように変更した。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  hand_gesture.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">HandLandmark</span> <span class=\"o\">=</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">distance</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">):</span>\n    <span class=\"c1\"># a, b: 2 points in 3D (x,y,z)\n</span>    <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">a</span> <span class=\"o\">-</span> <span class=\"n\">b</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">angle</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">,</span> <span class=\"n\">c</span><span class=\"p\">):</span>\n    <span class=\"c1\"># a, b and c : points as np.array([x, y, z]) \n</span>    <span class=\"n\">ba</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">-</span> <span class=\"n\">b</span>\n    <span class=\"n\">bc</span> <span class=\"o\">=</span> <span class=\"n\">c</span> <span class=\"o\">-</span> <span class=\"n\">b</span>\n    <span class=\"n\">cosine_angle</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">dot</span><span class=\"p\">(</span><span class=\"n\">ba</span><span class=\"p\">,</span> <span class=\"n\">bc</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">ba</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">bc</span><span class=\"p\">))</span>\n    <span class=\"n\">angle</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arccos</span><span class=\"p\">(</span><span class=\"n\">cosine_angle</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">degrees</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ジェスチャの認識\n# 参考: https://github.com/geaxgx/openvino_hand_tracker\n</span><span class=\"k\">def</span> <span class=\"nf\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">debug</span> <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">):</span>\n    <span class=\"c1\"># 各landmarkの手首からの距離を求める\n</span>    <span class=\"n\">lm_pos</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([[</span><span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">z</span><span class=\"p\">]</span> <span class=\"k\">for</span> <span class=\"n\">lm</span> <span class=\"ow\">in</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">])</span>    <span class=\"c1\"># 計算のためndarray化\n</span>    <span class=\"c1\"># lm_pos = np.array([[lm.x, lm.y] for lm in landmarks.landmark])          # 計算のためndarray化(zは無視)\n</span>    <span class=\"n\">r_</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span> <span class=\"o\">-</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">WRIST</span><span class=\"p\">],</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>        <span class=\"c1\"># numpyなので一括計算\n</span>    \n    <span class=\"c1\"># 親指の角度で状態判別\n</span>    <span class=\"n\">distance0</span> <span class=\"o\">=</span> <span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">],</span>     <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指の第二関節と人差し指の付け根の距離\n</span>    <span class=\"n\">distance1</span> <span class=\"o\">=</span> <span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span>    <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">]</span>        <span class=\"p\">)</span>     <span class=\"c1\"># 親指の付け根と親指の第二関節の距離\n</span>    <span class=\"n\">angle0</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">WRIST</span><span class=\"p\">],</span>      <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_CMC</span><span class=\"p\">],</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指付け根の角度\n</span>    <span class=\"n\">angle1</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_CMC</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">]</span> <span class=\"p\">)</span>     <span class=\"c1\"># 親指第二関節の角度\n</span>    <span class=\"n\">angle2</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_TIP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指第一関節の角度\n</span>    <span class=\"n\">thumb_angle</span> <span class=\"o\">=</span> <span class=\"n\">angle0</span> <span class=\"o\">+</span> <span class=\"n\">angle1</span> <span class=\"o\">+</span> <span class=\"n\">angle2</span>\n    <span class=\"k\">if</span> <span class=\"n\">thumb_angle</span> <span class=\"o\">></span> <span class=\"mi\">460</span> <span class=\"ow\">and</span> <span class=\"n\">distance0</span> <span class=\"o\">/</span> <span class=\"n\">distance1</span> <span class=\"o\">></span> <span class=\"mf\">1.2</span><span class=\"p\">:</span> \n        <span class=\"n\">thumb_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">thumb_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># 人差し指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 中指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 薬指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 小指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># Gesture\n</span>    <span class=\"k\">if</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FIST\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"OK\"</span> \n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"PEACE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"ONE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"TWO\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"THREE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>      <span class=\"c1\"># 日本型の3\n</span>        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"THREE_J\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FOUR\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FIVE\"</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># for debug\n</span>    <span class=\"c1\"># print(f'{r_[HandLandmark.INDEX_FINGER_MCP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_PIP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_DIP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_TIP]:6.3f}    {index_state}')\n</span>\n    <span class=\"k\">if</span> <span class=\"n\">debug</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">21</span><span class=\"p\">):</span>\n            <span class=\"n\">lm_x</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"c1\"># * image_width\n</span>            <span class=\"n\">lm_y</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"c1\"># * image_height\n</span>            <span class=\"n\">lm_z</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">z</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">HandLandmark</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">))</span><span class=\"si\">:</span><span class=\"mi\">32</span><span class=\"n\">s</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">:</span><span class=\"mi\">2</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">):   </span><span class=\"si\">{</span><span class=\"n\">lm_x</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">lm_y</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">lm_z</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">:</span><span class=\"mf\">6.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">gesture</span>\n</code></pre></div></div>\n\n<h2 id=\"カメラ画像から認識\">カメラ画像から認識</h2>\n<p>カメラ画像から認識してみる。<br />\nこっちの方が用途は多いかな。<br />\nコマンドラインオプションについてはソース見てちょ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  test_camera.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span>  <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span>         <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-nh\"</span><span class=\"p\">,</span> <span class=\"s\">\"--num_hand\"</span><span class=\"p\">,</span>         <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span>   <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Max number of hands\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num_hand</span>            <span class=\"c1\"># 検出する手の個数\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">verbose2</span>                 <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>\n<span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">True</span>                    <span class=\"c1\"># 鏡像使用\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># カメラ\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span>   <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">,</span>            <span class=\"c1\"># 動画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>        <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 前のフレーム処理完了時刻を初期化\n</span>    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># キャプチャ\n</span>        <span class=\"n\">success</span><span class=\"p\">,</span> <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">success</span><span class=\"p\">:</span>\n            <span class=\"c1\"># エラーになったら再度キャプチャ\n</span>            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Ignoring empty camera frame.\"</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>        <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n            <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像サイズ\n</span>        <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n        \n        <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>        <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># 検出結果の処理\n</span>        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">handedness</span> <span class=\"ow\">in</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_handedness</span><span class=\"p\">):</span>\n                <span class=\"k\">if</span> <span class=\"n\">verbose</span> <span class=\"ow\">or</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'--------------------------------------------------------------------------'</span><span class=\"p\">)</span>\n                \n                <span class=\"c1\"># データは鏡像として判別されているので、鏡像でなければラベルを入れ替え\n</span>                <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span> <span class=\"o\">==</span> <span class=\"s\">\"Left\"</span> <span class=\"p\">:</span>\n                        <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Right\"</span>\n                    <span class=\"k\">else</span> <span class=\"p\">:</span>\n                        <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Left\"</span>\n                \n                <span class=\"c1\"># ジェスチャの認識\n</span>                <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n                \n                <span class=\"k\">if</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'==== sore ======================='</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">index</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'score   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">score</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'label   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>            <span class=\"c1\"># あんまりあてにならないな...\n</span>                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'gesture : </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'================================='</span><span class=\"p\">)</span>\n                \n                <span class=\"c1\"># landmarkの描画\n</span>                <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">draw_landmarks</span><span class=\"p\">(</span>\n                    <span class=\"n\">image</span><span class=\"p\">,</span>                              <span class=\"c1\"># 画像\n</span>                    <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span>                     <span class=\"c1\"># ランドマーク\n</span>                    <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span>          <span class=\"c1\"># ランドマーク接続リスト\n</span>                    <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_landmarks_style</span><span class=\"p\">(),</span>       <span class=\"c1\"># ランドマーク描画スタイル\n</span>                    <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_connections_style</span><span class=\"p\">()</span>      <span class=\"c1\"># 接続描画スタイル\n</span>                <span class=\"p\">)</span>\n                <span class=\"c1\"># ジェスチャ表示\n</span>                <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># 人差し指の付け根あたりに表示\n</span>                    <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n                    <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                        <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                        <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>     <span class=\"c1\"># 文字列\n</span>                        <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">),</span>                     <span class=\"c1\"># 座標\n</span>                        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                        <span class=\"mi\">1</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                        <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                        <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>                    <span class=\"p\">)</span>\n        \n        <span class=\"c1\"># フレーム処理時間\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 現在のフレーム処理完了時刻\n</span>        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>                   <span class=\"c1\"># このフレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        \n        <span class=\"c1\"># FPS表示\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                <span class=\"sa\">f</span><span class=\"s\">'FPS:</span><span class=\"si\">{</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>  <span class=\"c1\"># 文字列\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">50</span><span class=\"p\">),</span>                    <span class=\"c1\"># 座標\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>            <span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示終了待ち\n</span>        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'v'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'b'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose2</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose2</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"c1\"># ウィンドウをすべて閉じる\n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># カメラリリース\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"静止画像から認識\">静止画像から認識</h2>\n\n<p>デバッグ用途など、静止画から認識する場合はこちら。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  test_photo.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'input'</span><span class=\"p\">,</span> <span class=\"n\">metavar</span><span class=\"o\">=</span><span class=\"s\">\"INPUT_FILE\"</span><span class=\"p\">,</span>                          <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Path to the input picture \"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                 <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--world'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                         <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp world landmark map\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-nh\"</span><span class=\"p\">,</span> <span class=\"s\">\"--num_hand\"</span><span class=\"p\">,</span>         <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span>   <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Max number of hands\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># 入力ファイル名\n</span><span class=\"nb\">file</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num_hand</span>            <span class=\"c1\"># 検出する手の個数\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">False</span>                    <span class=\"c1\"># 鏡像使用しない\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span> <span class=\"o\">=</span> <span class=\"bp\">True</span><span class=\"p\">,</span>               <span class=\"c1\"># 静止画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>                    <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"c1\"># 画像読み込み\n</span>    <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'file name : </span><span class=\"si\">{</span><span class=\"nb\">file</span><span class=\"si\">}</span><span class=\"s\">   image size : </span><span class=\"si\">{</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>    <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n        <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    \n    <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>    <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># 検出結果の処理\n</span>    <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">handedness</span> <span class=\"ow\">in</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_handedness</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">verbose</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'--------------------------------------------------------------------------'</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># データは鏡像として判別されているので、鏡像でなければラベルを入れ替え\n</span>            <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n                <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span> <span class=\"o\">==</span> <span class=\"s\">\"Left\"</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Right\"</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Left\"</span>\n            \n            <span class=\"c1\"># ジェスチャの認識\n</span>            <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n            \n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'==== sore ======================='</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">index</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'score   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">score</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'label   : </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'gesture : </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'================================='</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># landmarkの描画\n</span>            <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">draw_landmarks</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                              <span class=\"c1\"># 画像\n</span>                <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span>                     <span class=\"c1\"># ランドマーク\n</span>                <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span>          <span class=\"c1\"># ランドマーク接続リスト\n</span>                <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_landmarks_style</span><span class=\"p\">(),</span>       <span class=\"c1\"># ランドマーク描画スタイル\n</span>                <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_connections_style</span><span class=\"p\">()</span>      <span class=\"c1\"># 接続描画スタイル\n</span>            <span class=\"p\">)</span>\n            <span class=\"c1\"># ジェスチャ表示\n</span>            <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># 人差し指の付け根あたりに表示\n</span>                <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n                <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                    <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                    <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>     <span class=\"c1\"># 文字列\n</span>                    <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">),</span>                     <span class=\"c1\"># 座標\n</span>                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                    <span class=\"mi\">1</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                    <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                    <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>                <span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"** NO HANDS **\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 表示終了待ち\n</span>    <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'p'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imwrite</span><span class=\"p\">(</span>\n                    <span class=\"s\">'output_'</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">),</span> \n                    <span class=\"n\">image</span>\n                <span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"ow\">not</span> <span class=\"n\">k</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n          <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># ウィンドウをすべて閉じる\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">world</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># hand world landmarks の 3D座標の表示\n</span>        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_world_landmarks</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">hand_world_landmarks</span> <span class=\"ow\">in</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_world_landmarks</span><span class=\"p\">:</span>\n                <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">plot_landmarks</span><span class=\"p\">(</span>\n                                <span class=\"n\">hand_world_landmarks</span><span class=\"p\">,</span> \n                                <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span> \n                                <span class=\"n\">azimuth</span><span class=\"o\">=</span><span class=\"mi\">5</span>\n                            <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<h2 id=\"カメラ画像から認識-1\">カメラ画像から認識</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: test_camera.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-nh</span> NUM_HAND]\n                      <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">-nh</span> NUM_HAND, <span class=\"nt\">--num_hand</span> NUM_HAND\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Max number of hands\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h2 id=\"静止画像から認識-1\">静止画像から認識</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: test_photo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--world</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-nh</span> NUM_HAND]\n                     <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n                     INPUT_FILE\n\npositional arguments:\n  INPUT_FILE            Path to the input picture\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">--world</span>               <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp world landmark map\n  <span class=\"nt\">-nh</span> NUM_HAND, <span class=\"nt\">--num_hand</span> NUM_HAND\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Max number of hands\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h1 id=\"説明\">説明</h1>\n\n<p>説明….するほどのことはないな。<br />\nほとんど出来あいの処理。</p>\n\n<p>各指の状態からポーズを取得する処理を変更すれば、ほかの認識(ジャンケン認識など)にも変更可能。<br />\nまた、人差し指の指先をトラッキングしていけば、バーチャルお絵描きなんてのもできるかも。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MediaPipeの手の認識でお絵かき</title>\n  </head>\n  <body>\n    <header>\n      <h1>MediaPipeの手の認識でお絵かき</h1>\n      <p>MediaPipe Handsでの手の認識結果と使ってお絵かきしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>MediaPipeで手の認識</p>\n\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』の手の認識子処理を使って空間にお絵かきしてみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』を参照。</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<h2 id=\"共通ルーチン\">共通ルーチン</h2>\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』を参照。</p>\n\n<h2 id=\"お絵かきプログラム\">お絵かきプログラム</h2>\n\n<p>お絵かきプログラム本体。<br />\n人差し指先端に点を打っていくことでお絵かきしている。<br />\n人差し指だけ立てた状態(ジェスチャ ONE)だと赤、人差し指と中指を立てた状態(ジェスチャ PEACE)だと緑で描画するようにしてあるが、この組み合わせにあまり意味はない。なんとなく色を切り替えてみたかったので。<br />\nコマンドラインオプションと表示中操作についてはソース見てちょ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  oekaki.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n<span class=\"n\">HandLandmark</span> <span class=\"o\">=</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span>  <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span>         <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n<span class=\"c1\">#     parser.add_argument(\"-nh\", \"--num_hand\",         default=2,   type=int,     help=\"(optional) Max number of hands\")\n</span>    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n# max_num_hands            = args.num_hand            # 検出する手の個数\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"mi\">1</span>                        <span class=\"c1\"># 検出する手の個数 今回は1固定\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">verbose2</span>                 <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>\n\n<span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">True</span>                    <span class=\"c1\"># 鏡像使用\n</span><span class=\"n\">fg_only</span>                  <span class=\"o\">=</span> <span class=\"bp\">False</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"n\">COLOR_WHITE</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_BLUE</span>  <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_GREEN</span> <span class=\"o\">=</span> <span class=\"p\">(</span>  <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_RED</span>   <span class=\"o\">=</span> <span class=\"p\">(</span>  <span class=\"mi\">0</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># カメラ\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像サイズ\n</span><span class=\"n\">image_width</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n<span class=\"n\">image_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n<span class=\"n\">fps</span>          <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'image size : </span><span class=\"si\">{</span><span class=\"n\">image_width</span><span class=\"si\">}</span><span class=\"s\"> x </span><span class=\"si\">{</span><span class=\"n\">image_height</span><span class=\"si\">}</span><span class=\"s\"> @ </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">Hz'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前景イメージを作成\n</span><span class=\"n\">image_fg</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">full</span><span class=\"p\">((</span><span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span>   <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">,</span>            <span class=\"c1\"># 動画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>        <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 前のフレーム処理完了時刻を初期化\n</span>    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># キャプチャ\n</span>        <span class=\"n\">success</span><span class=\"p\">,</span> <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">success</span><span class=\"p\">:</span>\n            <span class=\"c1\"># エラーになったら再度キャプチャ\n</span>            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Ignoring empty camera frame.\"</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>        <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n            <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        \n        <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>        <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>        <span class=\"c1\"># 検出できたか?\n</span>            <span class=\"c1\"># ポーズの認識\n</span>            <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 人差し指先の位置\n</span>            <span class=\"n\">finger_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n            <span class=\"n\">finger_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'(</span><span class=\"si\">{</span><span class=\"n\">finger_x</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">finger_y</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">)  </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ポーズによって色を変更\n</span>            <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"o\">==</span> <span class=\"s\">'ONE'</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"n\">COLOR_RED</span>           <span class=\"c1\"># 赤\n</span>            <span class=\"k\">elif</span> <span class=\"n\">gesture</span> <span class=\"o\">==</span> <span class=\"s\">'PEACE'</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"n\">COLOR_GREEN</span>         <span class=\"c1\"># 緑\n</span>            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n            <span class=\"k\">if</span> <span class=\"n\">color</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># 前景イメージに点を打つ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">circle</span><span class=\"p\">(</span><span class=\"n\">image_fg</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">finger_x</span><span class=\"p\">,</span> <span class=\"n\">finger_y</span><span class=\"p\">)</span> <span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span><span class=\"o\">=-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># フレーム処理時間\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 現在のフレーム処理完了時刻\n</span>        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>                   <span class=\"c1\"># このフレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        \n        <span class=\"c1\"># FPS表示\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                <span class=\"sa\">f</span><span class=\"s\">'FPS:</span><span class=\"si\">{</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>  <span class=\"c1\"># 文字列\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">50</span><span class=\"p\">),</span>                    <span class=\"c1\"># 座標\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                <span class=\"n\">COLOR_RED</span><span class=\"p\">,</span>                  <span class=\"c1\"># 色\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>            <span class=\"p\">)</span>\n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"n\">fg_only</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 前景イメージだけ表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image_fg</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 画像を重ね合わせ(COLOR_WHITEを透過色として指定)て表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">where</span><span class=\"p\">(</span><span class=\"n\">image_fg</span> <span class=\"o\">==</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">image_fg</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># 表示終了待ち\n</span>        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'c'</span><span class=\"p\">):</span>\n            <span class=\"c1\"># 前景イメージを初期化\n</span>            <span class=\"n\">image_fg</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">full</span><span class=\"p\">((</span><span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'d'</span><span class=\"p\">):</span>\n            <span class=\"n\">fg_only</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">fg_only</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'v'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'b'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose2</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose2</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'p'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imwrite</span><span class=\"p\">(</span>\n                    <span class=\"sa\">f</span><span class=\"s\">'z_oekaki_</span><span class=\"si\">{</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">now</span><span class=\"p\">().</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s\">\"%d_%H%M%S\"</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">.jpg'</span><span class=\"p\">,</span> \n                    <span class=\"n\">image_fg</span>\n                <span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"c1\"># ウィンドウをすべて閉じる\n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># カメラリリース\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: oekaki.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD]\n                 <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h1 id=\"感想\">感想</h1>\n\n<p>それなりにお絵かきできるけど…</p>\n<ul>\n  <li>認識処理が遅いと手をゆっくり動かさないと線にならない</li>\n  <li>ポーズの認識の精度がイマイチで描画結果が微妙な感じになる</li>\n</ul>\n\n<p>実際にユーザインタフェースとして使うには色々と工夫が必要かな。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi で python で PWM</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi で python で PWM</h1>\n      <p>Raspberry Pi 上で python で PWMの制御を行うブログラムの雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Piでロボットアームを制御するのに、PWMのテストを行ったときのプログラムソースを貼っておく。<br />\n使ったロボットアーム: <a href=\"https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1\" target=\"_blank\">https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1</a></p>\n\n<p>ソフトウェアPWMだと他の処理の負荷によってジッタが発生し、ガタガタいうのでこの使い方はあまり実用的ではない。<br />\nハードウェアPWMを使う(pigpio か wiringpi が必要)、PWM制御を担うMCUを用意してコマンド通信(TCP/IPやBluetoothなど経由)で制御するのが現実的かも。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>PRi.GPIOを使うので、インストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>RPi.GPIO\n</code></pre></div></div>\n\n<p>プログラムの設定にあわせてGPIOとサーボモータを接続しておく(または接続に合わせてプログラム修正)。<br />\nスイッチで調整できるようにしてあるけど、キーボードから調整できるのでスイッチの接続は必須ではない。</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/0e8eeedb37d59c85b6ae6085da2a2cb4.js\"></script>\n</dev>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">GPIO.add_event_detect()</code>には<code class=\"language-plaintext highlighter-rouge\">bouncetime=«チャタリング除去時間(msec)»</code>を追加しておくのが良いかも。<br />\n参考: <a href=\"https://tomosoft.jp/design/?p=8685\" target=\"_blank\">GPIOエッジ検出コールバック関数 | TomoSoft</a></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n公式マニュアルは存在しないらしい。<br />\n唯一以下のページがそれっぽい情報を掲載している。<br />\n<a href=\"https://sourceforge.net/p/raspberry-gpio-python/wiki/Examples/\" target=\"_blank\">raspberry-gpio-python / Wiki / Examples</a><br />\nあとはソース読むしかないんだけど、python - C インタフェースを理解してないと苦しい…<br />\nソース全体を<code class=\"language-plaintext highlighter-rouge\">python function</code>で検索すると出てくるけど全部じゃない…<br />\nソースはここ: <a href=\"https://pypi.org/project/RPi.GPIO/#files\" target=\"_blank\">RPi.GPIO · PyPI</a></p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>プログラム実行して、スイッチかキーボードで出力値変えてみる。<br />\n設定値の範囲は個体差があるので、適当に変更必要。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Pythonのasyncioでnon-blockingなコンソール入力</title>\n  </head>\n  <body>\n    <header>\n      <h1>Pythonのasyncioでnon-blockingなコンソール入力</h1>\n      <p>Pythonのasyncioでnon-blockingなコンソール入力を行うためのクラス</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでasyncioを使ったときにnon-blockingなコンソール入力(キーボード入力)ができなくて困ったので、実現するためのクラスを作ってみた。</p>\n\n<p>もともと Linux用に作ったら、Windowsだとうまく動かない。<br />\nちょっと汚い方法だけど、とりあえず動くようにしてお茶を濁しておく。<br />\n(あんまりテストしてないから動かなかったらごめん)</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/5033eec9b9b774ede4f87604a51fb162.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>お試しならこのソースをそのまま実行すると実行できます。<br />\n<code class=\"language-plaintext highlighter-rouge\">char_mode = False</code> の部分を変更すると、1行入力モードと1文字入力モードを切り替えられます。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout_mode = True</code> の部分を変更すると、タイムアウトなしとタイムアウトありを切り替えられます。</p>\n\n<p>実際に使用するには、このソースをimportして使ってください。</p>\n\n<h1 id=\"注意\">注意</h1>\n\n<p>Linuxで1文字入力モードを使っている場合は、終了時(例外で死んだ場合も含めて)<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行しないと悲しいことになります。<br />\n(ターミナルの入力モードが変更されてしまうので、うまく入力できなくなる)<br />\nそのために、<code class=\"language-plaintext highlighter-rouge\">atexit.retister()</code>で終了処理ルーチンを登録し、その中で<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行するようにしています。</p>\n\n<h1 id=\"ひとりごと\">ひとりごと</h1>\n\n<p>asyncioのサンプルって、タスク1個で動かしてることが多いからあんまり ありがたみが分からんのかな…<br />\nあと、タスクとコルーチンが同じように語られていて分かり難いのもあると思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</h1>\n      <p>Raspberry Pi OS(64bit)のRaspberry Pi Imagerを使用したインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>また手順が変わったみたいなので、メモも更新。<br />\n(2023/10/15 最新版での試行結果を反映)</p>\n\n<h1 id=\"sdカードへの書き込み\">SDカードへの書き込み</h1>\n\n<p>Raspberry Pi Imager なるツールを使うようになったらしい。<br />\n使い方はあちこちに書いてあるけど、例えばこちら。</p>\n<ul>\n  <li><a href=\"https://ascii.jp/elem/000/004/094/4094421/\" target=\"_blank\">Raspberry Pi Imagerの使い方 ― v1.7.2以降 対応版</a></li>\n  <li><a href=\"https://www.mikan-tech.net/entry/raspi-imager-headless-setup\" target=\"_blank\">Raspberry Pi Imagerが新しくなった!Lite版もらくらくHeadless Setup</a></li>\n</ul>\n\n<p>これを使うと、最初のユーザを自由に設定できるので、これまでのpiユーザを変更するなんてことはやらなくて済む。<br />\nWi-Fiの設定やSSHの設定も(なんかWindowsが適切に設定されてれば公開鍵が自動で設定されるみたい)ここでできる。</p>\n\n<p>パスワードが設定ファイルに書き出されるので(さすがに平文ではない、最初の起動が終わったら削除される)、<br />\nセキュリティ上気になる場合は仮パスワードを設定しておいて<br />\n最初にログインしたときに変更する、なんてことをやった方が良いと言ってる解説ページもあった。</p>\n\n<blockquote>\n  <p>[!WARNING]\n<del>なぜかSSHの認証方法が毎回「パスワード認証を使う」になってしまうので、公開鍵を使うときは再度設定が必要。</del> \n(1.7.5では改善された模様)</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\n<del>(少なくとも)2023/10以降のバージョンはopenSSHのバージョンがRSA非対応になっているので、 \n 鍵ファイル作成の際はRSA以外(ed25519など)で作成する必要がある。</del> <br />\n(2023/10/21 誤解してたので書き直し)<br />\n(少なくとも)2023/10以降のバージョンはopenSSHのバージョンが SSH-RSA 非対応になっているので、<br />\nTeraterm Ver4.106以前など RSA-SHA2未対応の環境ではRSA鍵では繋がらない。 \nその場合は RSA以外(ed25519など)で作成すれば良い。<br />\nssh-keygenのデフォルトはRSAなので、<code class=\"language-plaintext highlighter-rouge\">ssh-keygen -t ed25519</code> などとする。<br />\nもちろん、Teraterm Ver4.107以降に変更するという手もある。</p>\n</blockquote>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1\n</code></pre></div></div>\n<h2 id=\"ipv6の無効化\">IPv6の無効化</h2>\n<p>IPv6を無効化しておきたいときは、\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する。<br />\nこのファイルは1行で書かないといけないので、改行してはいけない。</p>\n\n<blockquote>\n  <p>[!WARNING]\n<del>以前はこれで無効化できていたはずだけど、2023/10現在 この手順では無効化できないらしい。<br />\n下でセットアップスクリプトで無効化処理を実行するように変更した。</del> <br />\n(2023/10/21 間違ってたので削除)</p>\n</blockquote>\n\n<h2 id=\"ブートログの表示\">ブートログの表示</h2>\n\n<p>ブートログが見えないと不安な人は、<br />\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> から <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code>\nを削除しておくとよい。</p>\n<blockquote>\n  <p>[!NOTE]\nLITE版では<code class=\"language-plaintext highlighter-rouge\">quiet</code>を削除(それ以外は指定されていないので)</p>\n</blockquote>\n\n<h1 id=\"最初の起動\">最初の起動</h1>\n<p>書き込んだSDカードをRaspberry Piに挿入して電源ON。<br />\nごちょごちょと設定したあと、起動する(途中2回ほどrebootしてるらしい)</p>\n\n<p>あとは起動後の設定。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># アップデート実行\nsudo apt update\nsudo apt upgrade\n\n# リブート\nsudo reboot\n</code></pre></div></div>\n\n<h1 id=\"カスタマイズ\">カスタマイズ</h1>\n\n<blockquote>\n  <p>[!NOTE]\n以降の処理をスクリプトにまとめました。<br />\n<a href=\"https://gist.github.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c\" target=\"_blank\">Raspberry Pi セットアップスクリプト </a><br />\n以下の手順で実行できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.githubusercontent.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c/raw/pi_setup1.sh\nbash pi_setup1.sh\n</code></pre></div>  </div>\n  <p>LITE版を使うときは変数<code class=\"language-plaintext highlighter-rouge\">LITE_OS</code>に<code class=\"language-plaintext highlighter-rouge\">1</code>を設定して実行します。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> <span class=\"nv\">LITE_OS</span><span class=\"o\">=</span>1 bash pi_setup1.sh\n</code></pre></div>  </div>\n\n  <p>途中でパスワード入力しないといけないので、完全自動じゃないけど、かなり手間は省けるはず。<br />\n実行後、<code class=\"language-plaintext highlighter-rouge\">pi_setup1.sh</code>は不要なので削除して可。<br />\n実行が終わったらリブートすること。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>reboot\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h2 id=\"resizeスクリプトの取得\">resizeスクリプトの取得</h2>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/4f39afbcd8471426421944b597f3a5f2963984c6/resize.py\n\n<span class=\"nb\">chmod</span> +x resize.py\n\n./resize.py\n</code></pre></div></div>\n\n<h2 id=\"ロケールの変更\">ロケールの変更</h2>\n<p>日本語表示のため、ロケールを変更する。<br />\n(imagerだとキーボードレイアウトの変更はやってくれるけど、ロケールの変更はやってくれないらしいので)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ロケールの変更</span>\n<span class=\"nb\">sudo </span>raspi-config nonint do_change_locale ja_JP.UTF-8\n\n<span class=\"c\"># リブートまでとりあえずLANGのみ変更で日本語表示</span>\n<span class=\"nb\">export </span><span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF-8\n</code></pre></div></div>\n\n<h2 id=\"bashrc-の変更\">.bashrc の変更</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n</code></pre></div></div>\n\n<h2 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h2>\n\n<p>物理キーボード接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]<br />\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n\n</blockquote>\n\n<h2 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h2>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h2 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h2>\n\n<p>まずはワークディレクトリの作成</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown $USER:$USER /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a $USER\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo service smbd reload\nsudo service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"vncサーバの有効化\">VNCサーバの有効化</h2>\n\n<p>リモートデスクトップを使うために、VNCサーバの有効化を行う。<br />\nLITE版では不要。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    # VNCサーバの有効化\n    3 Interfacing Options\n        I3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>\n            The VNC Server is enabled\n            と表示されるので <Ok>\n\n    # VNC解像度の設定\n    2 Display Options\n        D5 VNC Resolution\n        \n            解像度が色々表示されるので、\n            使いたい解像度を選択(例えば 1920x1080 )して<Select>\n            The resolution is set to «選択した解像度»\n            と表示されるので <Ok>\n    # 設定終了\n    <Finish>\n</code></pre></div></div>\n\n<h2 id=\"ipv6-の無効化\">IPv6 の無効化</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code>での設定では無効化できなくなったと思ったけど、勘違いだった。<br />\nなので、上記の<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する方法でOK。</p>\n\n<p>でも、その時に<code class=\"language-plaintext highlighter-rouge\">mncli</code>コマンドで無効化するスクリプトを作ったので、せっかくなので残しておく。</p>\n\n<p>接続名一覧を取得し、 それぞれに対して無効化するコマンドを実行する。<br />\n接続名に「有線接続 1」と空白が含まれている接続があるので、一時的に空白をセミコロンに置換して処理を行っている。<br />\n(これをやらないと「有線接続」と「1」に分けて処理されてしまう)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 接続一覧を取得</span>\n<span class=\"nv\">conn_data</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli <span class=\"nt\">-t</span> connection<span class=\"si\">)</span>\n\n<span class=\"c\"># 空白を\";\"に置換(配列代入時に誤動作するのを防止)</span>\n<span class=\"nv\">conn_data</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">conn_data</span><span class=\"p\">// /</span><span class=\"s2\">\";\"</span><span class=\"k\">}</span>\n\n<span class=\"c\"># ':'区切りで1列目をconnections配列に格納</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"s2\">\"</span><span class=\"nv\">$conn_data</span><span class=\"s2\">\"</span> | <span class=\"nb\">cut</span> <span class=\"nt\">-d</span><span class=\"s2\">\":\"</span> <span class=\"nt\">-f1</span><span class=\"si\">)</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 配列の要素を処理</span>\n<span class=\"k\">for </span>connection <span class=\"k\">in</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[@]</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 上で;に置換した空白を戻す</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"p\">//</span><span class=\"s2\">\";\"</span><span class=\"p\">/</span><span class=\"s2\">\" \"</span><span class=\"k\">}</span>\n\n    <span class=\"k\">if</span> <span class=\"o\">[[</span> <span class=\"s2\">\"</span><span class=\"nv\">$connection</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s1\">'lo'</span> <span class=\"o\">]]</span><span class=\"p\">;</span> <span class=\"k\">then</span>    <span class=\"c\"># loデバイスは無効にできないので除外</span>\n      <span class=\"nb\">echo</span> <span class=\"s2\">\"disable </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span> \n      <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> ipv6.method </span><span class=\"se\">\\\"</span><span class=\"s2\">disabled</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n      <span class=\"c\"># 有効にする場合はこちら</span>\n      <span class=\"c\"># cmd=\"sudo nmcli connection modify \\\"${connection}\\\" ipv6.method \\\"auto\\\"\"</span>\n      <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n      <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone</span>\n</code></pre></div></div>\n\n<h1 id=\"splash-screenの再有効化\">Splash screenの再有効化</h1>\n\n<p>セットアップ時にブートログが表示されるようにしたけど、<br />\nやっぱり表示したくなくなった(Splash screenを表示)、てなときは以下で。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S6 Splash Screen\n            Would you like to show the splash screen at boot?\n            と聞かれるので有効化するときは <Yes> を選択\n            Splash screen at boot is enabled)\n            と表示されるので <Ok>\n\n    Would you like to reboot now?\n    と聞かれるので、その場でリブートしてよければ<Yes>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n直接<code class=\"language-plaintext highlighter-rouge\">/boot/cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code> を追加しても良い。<br />\nLITE版では <code class=\"language-plaintext highlighter-rouge\">quiet</code>のみ追加。</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 22.04のVirtualBoxへのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 22.04のVirtualBoxへのインストール</h1>\n      <p>Ubuntu 22.04のVirtualBoxへのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 22.04のVirtualBoxへのインストール手順をまとめてみた。\n20.04と大差ないけど、微妙に違う点もあるので。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2204-インストール媒体の入手\">Ubuntu 22.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら:\n<a href=\"https://www.ubuntulinux.jp/products/JA-Localized/download\" target=\"_blank\">Ubuntu Desktop 日本語 Remixのダウンロード</a><br />\n日本語環境構築するなら本家よりRemix版を使った方がなにかと便利(な気がする)。<br />\n<a href=\"https://jp.ubuntu.com/download\" target=\"_blank\">本家はこちら</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを4096MB以上に設定しておくこと</strong></p>\n<blockquote>\n  <p>[!NOTE]\n推奨環境が4GB以上なので。<br />\nウィンドウマネージャだけ動いている状態で1GBちょい使用だったので、\n2048MBでも動くと思う。でも、何か動かしたらすぐ足りなくなりそう。 <br />\nそれにしても、どんどん必要メモリが大きくなるな。<br />\n仮想環境で4GBってことは、HostOS環境下には8GB以上は必要ってことだよな。<br />\nプロセッサも2個割り当てておいた方が良いのかな?<br />\nこれは様子見てからどうするか決めよう。</p>\n</blockquote>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<blockquote>\n  <p>[!TIP]\nウィンドウが画面からはみ出して「続ける」ボタンが押せないときは、Alt+F7キーを押したあと、マウスでドラッグすると\nウィンドウを移動できるので、ボタンが見えるようところまで移動してクリックしてちょ。</p>\n</blockquote>\n\n<p>以下の説明が図付きで分かりやすい:\n<a href=\"https://qiita.com/HirMtsd/items/d43fc5215a88cbf414c9\" target=\"_blank\">Windows11上のVirtualBoxにUbuntu22.04LTSをインストール</a><br />\nWindows11って書いてあるけど、Windows10でも同じ。<br />\nここの説明では「不完全な言語サポート」うんぬんの説明があるけど、日本語Remix版でインストールすると、この部分は不要みたい。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<p>まだGuestAdditionをインストールしてないからコピペできないけど、BashのTab補完が効くので、\nちょろっと入力してあとは補完に頼れば大丈夫。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面 を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源管理を選択<br />\n右側で画面のブランクのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>裏でソフトウェアの更新が動いていると、ロックファイルがロックされてしばらく適用できないので、<br />\nそうなっちゃったらお茶でも飲んでしばらくお待ちください。<br />\nソフトウェアの更新による自動更新を止める方法は後ほど。</p>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweaks \n</code></pre></div></div>\n\n<h3 id=\"一旦リブート\">一旦リブート</h3>\n<p>更新適用のため。</p>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>以前にマウントしたものが残ってたらアンマウントしておくこと(インストール後初めてなのでマウントされてることはないけれど)。<br />\nVirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<blockquote>\n  <p>[!TIPS]\nプログラムが自動で始まらない場合は、CDROMのマウント先(たぶん、<code class=\"language-plaintext highlighter-rouge\">/media/<USER>/VBox_GAs_x.x.xx/</code>)に移動して<code class=\"language-plaintext highlighter-rouge\">sudo VBoxLinuxAdditions.run</code>を実行すれば良い。</p>\n</blockquote>\n\n<h3 id=\"再度リブート\">再度リブート</h3>\n<p>GuestAdditionによる更新適用のため。</p>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから「デバイス」→「クリップボードの共有」→「双方向」<br />\nを選択。\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<h3 id=\"使わないのでアンインストール\">使わないのでアンインストール</h3>\n\n<p>使うツールがあったら残してちょ。</p>\n\n<h4 id=\"ツール類\">ツール類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h4 id=\"ゲーム類\">ゲーム類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h4 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"お好みで\">お好みで</h2>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>ディレクトリにコピるだけ。<br />\n下では全部コピってるけど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.0.0/UDEVGothic_v1.0.0.zip \nunzip UDEVGothic_v1.0.0.zip \n<span class=\"nb\">mkdir</span> ~/.fonts\n<span class=\"nb\">cp </span>UDEVGothic_v1.0.0/<span class=\"k\">*</span>.ttf ~/.fonts/\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。<br />\nさっきフォントのインストールに使った端末ウィンドウを使うと\nエラーで端末ウィンドウが落ちるかもしれないんで一旦終了して新しいウィンドウで。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<h3 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h3>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h3 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h3>\n\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h3 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h3>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>~/.bashrcに以下を追記。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"c\"># Ubuntu22.04だとwaylandになるらしい</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"wayland\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vi\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># # venvの仮想環境名を表示するための設定</span>\n    <span class=\"c\"># show_virtual_env() {</span>\n    <span class=\"c\">#   if [ -n \"$VIRTUAL_ENV\" ]; then</span>\n    <span class=\"c\">#     echo \"($(basename $VIRTUAL_ENV))\"</span>\n    <span class=\"c\">#   fi</span>\n    <span class=\"c\"># }</span>\n    <span class=\"c\"># PS1='$(show_virtual_env)'$PS1</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># openVINO の設定はdirenvで</span>\n<span class=\"c\"># for openVINO</span>\n<span class=\"c\"># source /opt/intel/openvino_2021/bin/setupvars.sh</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nUbuntu20.04とちょっとキーが変更されてる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-home <span class=\"nb\">false \n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"sambaのインストール\">sambaのインストール</h3>\n\n<p>ツール本体のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加<br />\n作らなかったワークディレクトリの部分は削除してね。<br />\n他にも共有したいディレクトリがあったら追加してちょ。<br />\nここではOpenVINOのサンプルとか見たかったのでoptを共有してます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n<span class=\"c\"># abcの下にリモートのファイルが見えたらOK</span>\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"ファイルnautilusのデフォルト動作変更\">ファイル(nautilus)のデフォルト動作変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アドレスバーをテキスト形式にする</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences always-use-location-entry <span class=\"nb\">true</span> \n\n<span class=\"c\"># 詳細表示をデフォルトに</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences default-folder-viewer <span class=\"s1\">'list-view'</span> \n\n<span class=\"c\"># 隠しファイルを表示する</span>\n<span class=\"c\"># 隠しファイルの表示はちょっと場所が違う</span>\ngsettings <span class=\"nb\">set </span>org.gtk.Settings.FileChooser show-hidden <span class=\"nb\">true</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアの更新(update-manager)を起動\n    <ul>\n      <li>更新のチェックが始まった場合はちょっと待つ</li>\n      <li>設定…をクリック\n        <ul>\n          <li>アップデートタブを選択</li>\n          <li>アップデートの自動確認を「なし」に変更</li>\n          <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n          <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n          <li>閉じるをクリック</li>\n        </ul>\n      </li>\n      <li>OKで終了</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a><br />\nリンク先は「Ubuntu 20.04/18.04 LTS」となっているが、Ubuntu22.04でも同じらしい。<br />\nNative環境にインストールしてないので未確認だけど…</p>\n\n<p>リブート必要だが、以下のIPv6無効化とまとめてリブートでも可。</p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<p>マスタイメージを残しておいて、色々な環境をお試しするには仮想マシンをクローンして使うのがおススメ。<br />\nVirtualBoxのメインウィンドウでマスタイメージの仮想マシンを右クリック→クローンを選択、名前とパスを設定し、あとはごにょごにょ…</p>\n\n<p>クローンした仮想マシンを起動し、必要な変更を加える。</p>\n\n<h2 id=\"ネットワーク設定の変更\">ネットワーク設定の変更</h2>\n\n<p>マシン名とか同じ名前だと色々不都合があるので、変更しておく。<br />\n他のクローン仮想環境と同時に使わないならそのままでも良いけど。<br />\nIPアドレスも固定で割り振っておくと名前が引けない時にさくっと分かってなにかと便利…なんだけど、最近はWindowsもUbuntuもRaspberryPiもmDNSがサポートされてるから自動割り当てのままでもそんなに不便はないかも。</p>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<p>このコマンドで<code class=\"language-plaintext highlighter-rouge\">/etc/hostname</code>が書き換えられる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<p>もちろん、vimとかで書き換えても可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<p>下のコマンドを実行するための接続名を確認しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<p>IPアドレスを手動割り当てに変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> \n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<p>IPアドレスを手動割り当てに変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> gw4 <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nIPアドレスの変更をGUIで行うには以下。<br />\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>まとめて実行するならこちら。<br />\nホスト名、接続名、IPアドレスなどは適宜変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># マシン番号の設定とホスト名の設定</span>\n<span class=\"nv\">number</span><span class=\"o\">=</span>30\n<span class=\"nv\">new_hostname</span><span class=\"o\">=</span>skull<span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span>\n\n<span class=\"c\"># HOSTNAMEの変更</span>\n<span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/ubuntu-22.*</span><span class=\"nv\">$/</span><span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span><span class=\"s2\">/\"</span> /etc/hosts\n\n<span class=\"c\"># HOST ONLY ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.56.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n\n<span class=\"c\"># BRIDGE ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.78.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> gw4 <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<h2 id=\"あとはお約束\">あとはお約束</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>VirtalBoxのバージョンが変更されているときは、GuestAdditionのバージョンアップも忘れずに。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</h1>\n      <p>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使うためのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1ではpypiからモジュールインストールするだけで使えるようになったのだけれど(python使用時)、<br />\nNCS2を使用しようとすると以下のようなエラーが発生します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>RuntimeError: Cannot load library 'libopenvino_intel_myriad_plugin.so: libopenvino_intel_myriad_plugin.so: cannot open shared object file: No such file or directory\n</code></pre></div></div>\n\n<p>どうやらNCS2(myriad)用のshared libraryがないらしい。<br />\nインストールミスか?と思ったけど、pypiのインストールファイル確認してみたけど、やっぱり入っていない。</p>\n<blockquote>\n  <p>[!NOTE]\nwhlファイルの拡張子をzipに変更するとファイルの中身を確認できる</p>\n</blockquote>\n\n<p>そこで、ソースからNCS2用のshared libraryをbuildしてみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p>参考: <a href=\"https://github.com/openvinotoolkit/openvino/wiki/BuildingForLinux\" target=\"_blank\">BuildingForLinux</a></p>\n\n<p>今回はWSL2の仮想マシンでbuildしてみることにする。<br />\nまた、NCS2用のshared libraryだけが目的なので、pythonモジュールとかはbuildしていない。<br />\nたぶん、ちゃんとCMAKEのオプション設定すればbuild時間が短くなるかもしれないけど、そこはお手軽最優先で。</p>\n\n<blockquote>\n  <p>[!NOTE]\n色々とbuildのために``apt install`するので、WSL2上のcloneした仮想マシンで実行した。<br />\nNCS2はWSL2上で使えないけど、buildするだけなら大丈夫みたい。<br />\n仮想マシンはUbuntu22.04を使用。 たぶん、20.04でも同様と思われる。<br />\nまぁ、Docker使えという説もある…</p>\n</blockquote>\n\n<h2 id=\"ソース取得\">ソース取得</h2>\n\n<p>openVINOのリポジトリからソース取得。<br />\n例によって<code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけてディスク容量&通信時間節約。<br />\n今回はcontribは使わない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> /work  clone  <span class=\"nt\">-b</span> 2022.1.0 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> /work/openvino submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n<span class=\"nb\">cd</span> /work/openvino\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこれ書いてる時点で2022.1.1がリリースされているけど、-bオプション変えればOKでしょう。\nたぶん。。。</p>\n</blockquote>\n\n<h2 id=\"必要なモジュールのインストール\">必要なモジュールのインストール</h2>\n\n<p>必要なモジュールはスクリプトファイルにまとめられているので、それを実行するだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash install_build_dependencies.sh \n</code></pre></div></div>\n\n<p>cmakeのバージョン3.17以上が必要なので、cmakeがそれ以下だとcmakeをソースからbuildしてくれる。<br />\nUbuntu22.04のデフォルト状態だとcmakeのバージョンは3.16なのでbuildが実行される。<br />\nちょっと時間がかかるけど、気長にお待ちください。</p>\n\n<h1 id=\"build\">build</h1>\n\n<p>準備ができたので、buildを実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>make.log\n</code></pre></div></div>\n\n<p>あとはひたすら待つ。<br />\n(うちの環境では1時間くらいだったかな)</p>\n\n<h1 id=\"ターゲットマシンにコピー\">ターゲットマシンにコピー</h1>\n\n<p>makeが終わると、以下のファイルが出来ているはず。<br />\nこの2つをNCS2を使用するターゲットマシンにコピーする。</p>\n\n<ul>\n  <li>openvino/bin/intel64/Release/lib/libopenvino_intel_myriad_plugin.so</li>\n  <li>openvino/bin/intel64/Release/lib/usb-ma2x8x.mvcmd</li>\n</ul>\n\n<p>ターゲットマシンのコピー先はopenVINOモジュールのインストール先の<code class=\"language-plaintext highlighter-rouge\">openvino/libs/</code>ディレクトリの下。<br />\n<code class=\"language-plaintext highlighter-rouge\">libopenvino.so</code>など、soファイルが並んでいるはず。</p>\n\n<p>なお、openVINOモジュールのインストール先は以下のようなコマンドで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"^openvino\"</span>\n</code></pre></div></div>\n\n<p>コピーの方法はエクスプローラでもrcpでも何でもよい。 \nエクスプローラなど、Windows経由でコピーすると実行属性が落ちてしまうけど、<br />\nそもそも実行属性必要ないので気にしなくて良いです。</p>\n\n<h1 id=\"テスト\">テスト</h1>\n<p>NCS2を使用してプログラム実行してみて、エラーにならずに実行できればOK。</p>\n\n<h1 id=\"つぶやき\">つぶやき</h1>\n<p>でも、なんでNCS2用のライブラリ入ってないんだろ?<br />\n単なる入れ忘れ? サポート終了目前?</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINO 2022.1のbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1はRaspberry Pi OS(64bit)向けのバイナリがリリースされていないので、自力でbuildしてみます。</p>\n\n<p>今回もUbuntu上のDockerコンテナを使用しましたが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思います。</p>\n\n<p>前回はPythonを諦めてクロスコンパイルする方法とbuild時間を諦めてセルフコンパイル(エミュレーション)する方法を使いましたが、<br />\n今回はPython以外をクロスコンパイル、Python関連部をセルフコンパイル(エミュレーション)して生成物をマージする方法をとってみます。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_2022.1_pi64 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_2022.1_pi64\n</code></pre></div></div>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>workディレクトリを作成し、openvino と openvino_contrib のリポジトリをcloneします。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 2022.1.1 <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib checkout 1a28b530ab40d2ad79ab29021dfddfbbc7d2db0b\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の2022.1だと一部のノードが未対応とエラーになるため、対応済みのcommitを使用します。<br />\ntagが振られていないので、commit IDを指定してcheckoutします。<br />\nこれ以降のcommitではopenvinoのバージョン2022.2が必要になります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ntagやbranchが設定されていない場合はcloneでcheckoutするバージョンを指定できないため、\n一旦cloneしてからcommit IDを指定してcheckoutします。<br />\nsubmoluleのcheckoutは対象のバージョンをcheckoutしてから行います。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の最新commit(試した時点ではcommit ID <code class=\"language-plaintext highlighter-rouge\">fd2ac364435757d23a9b3e91d67235b5e6555bf9</code>)を使用する場合は\nopenvinoのバージョン2022.2を使用する必要がありますが、試した時点で <code class=\"language-plaintext highlighter-rouge\">2022.2.0.dev20220829</code> がリリースされているので\nこれを使用します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0.dev20220829  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit -C ./work/openvino_contrib checkout fd2ac364435757d23a9b3e91d67235b5e6555bf9\ngit -C ./work/openvino_contrib submodule update --init --recursive --depth 1\n</code></pre></div>  </div>\n  <blockquote>\n    <p>2022.2.0正式リリース後はこんな感じになるのかな?</p>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  -b 2022.2    --recursive --depth 1 https://github.com/openvinotoolkit/openvino_contrib.git\n</code></pre></div>    </div>\n  </blockquote>\n\n  <p>この場合、NVIDIA GPUのpluginのbuildでエラーになるため、以下のcmakeのオプションに以下のオプションを追加します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      -D BUILD_nvidia_plugin=OFF\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h1 id=\"openvinoのbuildクロスコンパイル\">openVINOのBuild(クロスコンパイル)</h1>\n\n<p>クロスコンパイルでpython関連以外の部分をbuildします。</p>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir cross</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">cross/Dockerfile</code>を作成します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cross/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates:arm64 <span class=\"se\">\\\n</span>    libboost-regex-dev:arm64 <span class=\"se\">\\\n</span>    libgtk2.0-dev:arm64 <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev:arm64 <span class=\"se\">\\\n</span>    libcairo2-dev:arm64 <span class=\"se\">\\\n</span>    libpango1.0-dev:arm64 <span class=\"se\">\\\n</span>    libglib2.0-dev:arm64 <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev:arm64 <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗します</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeは新しめのをインストールしておきたいので、3.23.2をbuildして使用しています。<br />\nもしかすると、<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたものをそのまま使っても大丈夫かもしれませんが。</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_cross cross\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\ncacheを使わずimage buildしたい場合は<code class=\"language-plaintext highlighter-rouge\">--no-cache</code>オプションを追加します。<br />\n以前に作ったイメージのキャッシュを使って<code class=\"language-plaintext highlighter-rouge\">apt install</code>がエラーになったことがあったので。<br />\n(デフォルトのリポジトリに変更があったらしい)</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_cross_2 ov_2022.1_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_cross_2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_2022.1_pi64_cross_2 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/cmake/arm64.toolchain.cmake <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_BEH_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLDNN</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_FUNCTIONAL_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">THREADING</span><span class=\"o\">=</span>SEQ <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">CONTRIB_TOP</span><span class=\"k\">}</span>/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span> 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=${WORK_DIR}/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"クロスコンパイル終了\">クロスコンパイル終了</h3>\n<p>クロスコンパイルはここまでなので、コンテナから抜ける。</p>\n\n<h1 id=\"openvinoのbuildセルフコンパイル\">openVINOのBuild(セルフコンパイル)</h1>\n\n<p>セルフコンパイルでpython関連部分をbuildします。<br />\ncythonを使うときにクロスコンパイルする方法が分からないので、セルフコンパイルで。</p>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir emu</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">emu/Dockerfile</code>を作成します。</p>\n\n<p>python部だけなので、こんなにライブラリとか要らない気もしますが、全部セルフコンパイルするときのことも考えて\n全部入りのイメージを作っておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  emu/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates <span class=\"se\">\\\n</span>    libboost-regex-dev <span class=\"se\">\\\n</span>    libgtk2.0-dev <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev <span class=\"se\">\\\n</span>    libcairo2-dev <span class=\"se\">\\\n</span>    libpango1.0-dev <span class=\"se\">\\\n</span>    libglib2.0-dev <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_emu emu\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_emu_2 ov_2022.1_pi64_emu /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_emu_2\n</code></pre></div></div>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成-1\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build_python <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build_python\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">InferenceEngineDeveloperPackage_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/build <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/src/bindings/python 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">CMAKE_INSTALL_PREFIX</code>の設定はクロスコンパイルのときと同じ設定にしてください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npyenvでインストールしたpythonなど、デフォルトでないpythonを使用する場合に指定します。<br />\n(以下の設定値はubuntu 22.04の標準インストールの場合のパスなのであまり参考にならないかも)</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  -D PYTHON_EXECUTABLE=/usr/bin/python3.8 \\\n  -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.8.so \\\n  -D PYTHON_INCLUDE_DIR=/usr/include/python3.8 \\\n  -D PYTHON_MODULE_EXTENSION=\".so\" \\\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"make-1\">make</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。</p>\n\n<h3 id=\"セルフコンパイル終了\">セルフコンパイル終了</h3>\n<p>セルフコンパイルはここまでなので、コンテナから抜けます。</p>\n\n<h1 id=\"インストール媒体の作成\">インストール媒体の作成</h1>\n\n<p>ホスト側の<code class=\"language-plaintext highlighter-rouge\">work</code>ディレクトリ内を見ると、<code class=\"language-plaintext highlighter-rouge\">intel</code>ディレクトリが出来ているので、ここをtarなどで固めておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>work\n<span class=\"nb\">tar </span>czvf ov1.tar.gz intel/\n</code></pre></div></div>\n\n<p>この<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiにコピーして展開します。</p>\n\n<h1 id=\"raspberrypiへのインストール\">RaspberryPiへのインストール</h1>\n\n<h2 id=\"インストール\">インストール</h2>\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiの適当なディレクトリに展開します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/proj</code>ディレクトリに展開しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /proj/\n<span class=\"nb\">tar </span>xzvf ov1.tar.gz \n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<p>これで<code class=\"language-plaintext highlighter-rouge\">/proj/intel/openvino</code>ディレクトリにインストールされました。</p>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n<p>環境変数の設定のため、以下を実行します。<br />\nshell起動の度に実行が必要なので<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>などに書いておくと良いです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/intel/openvino/setupvars.sh \n</code></pre></div></div>\n\n<h2 id=\"udevルールの設定\">udevルールの設定</h2>\n<p>以下のスクリプトを実行すればNCS2を挿せば認識されるようになります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/proj/intel/openvino/install_dependencies/install_NCS_udev_rules.sh \n</code></pre></div></div>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n<p>openCVの必要になるので、インストールしておきます。<br />\n今回はお手軽にpipでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認用のプログラムは<a href=\"https://github.com/ippei8jp/ov_trial_2022.1\" target=\"_blank\">https://github.com/ippei8jp/ov_trial_2022.1</a> とかにあります。<br />\nでもモデルのダウンロード/コンバートはRaspberryPiではできないので、UbuntuやWondowsで実行したものをコピーして使用してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>test shellのひな型</title>\n  </head>\n  <body>\n    <header>\n      <h1>test shellのひな型</h1>\n      <p>linuxでのテストプログラム用コマンド入力処理のサンプル</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>linuxでプログラムを作ったとき、ユニットテストを各処理(コマンド)単位で行いたいときに、テストシェルを作ると便利。<br />\nでも、その都度作っていると効率悪いので、ひな型を作ってみた。<br />\nどうせなら、コマンドヒストリとか、入力補完とかあると便利だなぁ~、ということで、<br />\n<code class=\"language-plaintext highlighter-rouge\">readline</code>使ってそれらを実現しておく。</p>\n\n<p>たぶん、bash使ってるシステムなら<code class=\"language-plaintext highlighter-rouge\">libreadline</code>も入ってるだろうから、特にインストールとかも不要。</p>\n\n<h1 id=\"コンパイル方法\">コンパイル方法</h1>\n<p>以下のコマンドでコンパイルできる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gcc test_shell.c <span class=\"nt\">-lreadline</span> <span class=\"nt\">-o</span> test_shell\n</code></pre></div></div>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n『コマンド定義』の部分を所望のコマンドと処理に書き換えて使ってちょ。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/fbccd09aefa28dd097a13c68d0111d0d\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/fbccd09aefa28dd097a13c68d0111d0d.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>test shellのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>test shellのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用コマンド入力処理のサンプルのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/15/test_shell_1.html\" target=\"_blank\">test shellのひな型</a>\nでC言語版を作ったので、python版も作っておこうかと作ってみた。</p>\n\n<p>pythonには『行指向のコマンドインタープリタのサポート』というcmdモジュールが標準で用意されている。<br />\nこれを使用すれば、そんなに手間もかからず実装できる。<br />\n補完処理やヘルプ表示も簡単。<br />\nコマンドの大文字/小文字同一視はできなかったけど…</p>\n\n<p>コマンド補完だけでなく、パラメータ補完も可能。<br />\nもちろん、補完のための処理は書かないといけないけど。</p>\n\n<p>標準モジュールしか使ってないので、モジュールをインストールする必要なし。</p>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n大体コメントに書いたつもり。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>キーボードコマンダーのひな型(C言語版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>キーボードコマンダーのひな型(C言語版)</h1>\n      <p>linuxでのテストプログラム用キーボードコマンダー</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/15/test_shell_1.html\" target=\"_blank\">test shellのひな型</a>\nのようなテストシェルでコマンド処理するほどでもないが、いくつかのパターンを繰り返し実行してテストしてみたい\n場合に使えるキーボードコマンダー(という名前がふさわしいか分からないが)のひな型を作ってみた。</p>\n\n<p>キー入力1個(例えば<code class=\"language-plaintext highlighter-rouge\">a</code>キー)でリターンを押さずに何らかの処理が実行できると便利な時がある。<br />\nまた、ターゲットボードのスイッチ入力の代替処理としても便利かもしれない。</p>\n\n<p>Windowsの<code class=\"language-plaintext highlighter-rouge\">getch()</code>関数みたいなものと言えば分かるかな?<br />\nキー入力自体はブロッキング処理なので、<code class=\"language-plaintext highlighter-rouge\">kbhit()</code>みたいな使い方はできない。<br />\n(これを行うには<code class=\"language-plaintext highlighter-rouge\">select()</code>をタイムアウト付きで組み合わせて使う必要があるが、\n簡単なテスト用を想定しているので そこまでは対応しない)</p>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n大体コメントに書いたつもり。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6435ac7e3381ec2f8af0b1fdb166d469\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6435ac7e3381ec2f8af0b1fdb166d469.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>キーボードコマンダーのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>キーボードコマンダーのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用キーボードコマンダーのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/18/key_commander_1.html\" target=\"_blank\">キーボードコマンダーのひな型(C言語版)</a>\nのpython版も作/memoBlog定して使うだけなんだけど、<br />\nstdinの設定を元に戻すのを忘れないように、クラス化してデストラクタで設定を戻すようにしてみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれまでatexitモジュール使って終了処理ルーチン登録して<br />\nそこで元に戻してたけど、処理追加忘れて悲しいことになったことが数知れず…</p>\n</blockquote>\n\n<h1 id=\"ちょっと解説\">ちょっと解説</h1>\n<p>このクラスは、複数の箇所からインスタンスを作成してしまうとstdinの設定変更が複数箇所で行われてしまい、<br />\nデストラクタの実行順序によっては正常に元に戻せなくなる可能性がある。<br />\nそれを回避するため、Singletonパターンを適用し、インスタンスが一つだけ保持するようにした。</p>\n\n<p>しかし、これだけでは不十分で、コンストラクタ(<code class=\"language-plaintext highlighter-rouge\">__init__()</code>)が<code class=\"language-plaintext highlighter-rouge\">KeyReader()</code>実行の度に実行されてしまう。(下のNOTE参照) <br />\nそこで、インスタンス変数にコンストラクタ実行済みフラグ(<code class=\"language-plaintext highlighter-rouge\">_inited</code>)を用意し、\nこれが存在しないときのみコンストラクタ処理を実行するようにしている。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">__new__</code>、<code class=\"language-plaintext highlighter-rouge\">__init__</code>、<code class=\"language-plaintext highlighter-rouge\">__del__</code>の実行タイミングは以下のプログラムで確認できる。</p>\n\n  <pre><code class=\"language-pythn\">class Hoge:\n    def __new__(cls, *args, **kargs):\n        print(\"__new__\")\n        if not hasattr(cls, \"_instance\"):\n            print(\"create\")\n            cls._instance = super().__new__(cls)\n        return cls._instance\n    \n    # コンストラクタ\n    def __init__(self):\n        print(\"__init__\")\n        if not hasattr(self, \"_inited\"):\n            print(\"init\")\n            self._inited = True\n    \n    # デストラクタ\n    def __del__(self):\n        print(\"__del__\")\n    \n    def __call__(self):\n        print(\"__call__\")\n\ndef func2() :\n    h2 = Hoge()\n    print(\"h2 before\")\n    h2()\n    print(\"h2 after\")\n\ndef func1() :\n    h1 = Hoge()\n    print(\"h1 before\")\n    h1()\n    print(\"h1 after\")\n\nprint(\"func1 before\")\nfunc1()\nprint(\"func1 after\")\n\nprint(\"func2 before\")\nfunc2()\nprint(\"func2 after\")\n\nprint(\"end\")\n\n</code></pre>\n  <p>実行結果は以下。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>func1 before\n__new__\ncreate                  ← 1回だけ表示されている\n__init__\ninit                    ← 1回だけ表示されている\nh1 before\n__call__\nh1 after\nfunc1 after\nfunc2 before\n__new__\n__init__\nh2 before\n__call__\nh2 after\nfunc2 after\nend\n__del__\n</code></pre></div>  </div>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">Hoge()</code>が実行されると、<code class=\"language-plaintext highlighter-rouge\">__new__()</code>が実行されるが、\n2回目以降は新たにインスタンスを作成せずクラス変数<code class=\"language-plaintext highlighter-rouge\">_instance</code>に格納されたインスタンスを返す。<br />\n(2回目は「create」が表示されていない)</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__init__()</code>が<code class=\"language-plaintext highlighter-rouge\">Hoge()</code>実行の度に実行されているのが分かる。<br />\n(つまりインスタンス生成時に実行されるわけではない)<br />\n<code class=\"language-plaintext highlighter-rouge\">__init__()</code>内でインスタンス変数<code class=\"language-plaintext highlighter-rouge\">_inited</code>の存在をチェックしているので<br />\n「init」は1回しか表示されていないのが分かる。</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__del__()</code> はインスタンス破棄時に実行されるので、1回しか実行されない。</p>\n\n</blockquote>\n\n<p>その他のプログラムの動作についてはソース読んでちょ。<br />\nって、ほとんど何もしてないけど。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico Wでmicropython with Visual Studio Code</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico Wでmicropython with Visual Studio Code</h1>\n      <p>Raspberry Pi Pico W でmicropython の開発にVisual Studio Codeを使用する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico Wでmicropython を使用する際の開発環境(IDE)に 公式では Thonny が推奨されていますが、\nVisual Studio Codeを使用することもできます。<br />\nこのとき、拡張機能 「MicroPico」(旧称Pico-W-Go) を使用します。<br />\nここでは先人の成果を<del>パクり</del> 参照しつつ、なんとなく手順を書いてみることにします。</p>\n\n<h1 id=\"環境構築\">環境構築</h1>\n\n<h2 id=\"pc側の準備\">PC側の準備</h2>\n<p>セットアップ手順は以下が分かりやすい。<br />\n<a href=\"https://flatisle.com/raspberrypi/2289/\" target=\"_blank\">Pico W で遊ぼう(環境構築)</a><br />\nただし、モジュール名が「Pico-W-Go」から「MicroPico」に変更されているので、読み替え必要。</p>\n\n<p>PC側はVisual Studio Code がインストールされていれば 拡張機能で「MicroPico」を検索してインストールするだけ。</p>\n\n<h2 id=\"本体側の準備\">本体側の準備</h2>\n<p>本体側はファームウェアの書き換えを行う。<br />\nファームウェアの最新版は\n<a href=\"https://www.raspberrypi.com/documentation/microcontrollers/micropython.html\" target=\"_blank\">Raspberry Pi Documentation > MicroPython</a>\nからダウンロードできます。<br />\nまた、<a href=\"https://micropython.org/download/RPI_PICO_W/\" target=\"_blank\">MicroPython > DOWNLOAD > Pico W</a>\nには、Nightly buildsのバイナリもあったりします。</p>\n\n<h2 id=\"動作確認\">動作確認</h2>\n<p>Raspberry pi Pico をPCに接続しておいて、Visual Studio Code を起動。</p>\n\n<ul>\n  <li>メニューの「ターミナル」→「新しいターミナル」でターミナルウィンドウを開く(デフォルト状態だとPowershellが実行される)。</li>\n  <li>ターミナルウィンドウの右上の「+」ボタン(新しいターミナル)のドロップダウンリストを開いて\n「Pico(W) vREPL」を選択してvREPLに接続する。<br />\n(+をクリックするとPowershellが新しく開かれるので右のvっぽい記号をクリックする)</li>\n  <li>以下のような表示が出る。<br />\n(バージョン番号とかはファームウェアによって異なる)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>MicroPython v1.20.0-198-g0eacdeb1c on 2023-06-13; Raspberry Pi Pico W with RP2040\nType \"help()\" for more information or .cls/.clear to clear the terminal.\n\n>>> \n</code></pre></div></div>\n\n<p>ここで色々コマンドを入力すれば実行できる</p>\n\n<h1 id=\"いつでもwifiにつなげるように準備\">いつでもwifiにつなげるように準備</h1>\n\n<p>適当なところにフォルダを作成し(以下の例では「test」)、その下にlibフォルダを作り、\nその下にmy_wifi.py として以下のファイルを作成しておく。<br />\n1行目~2行目は自分の環境に合わせて変更しておくこと。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    test\n     +-- lib\n          +-- my_wifi.py\n          \n</code></pre></div></div>\n\n<!-- ファイル名を付けたいときはこれを指定-->\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  my_wifi.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SSID_NAME</span> <span class=\"o\">=</span> <span class=\"s\">\"SSID名\"</span>\n<span class=\"n\">SSID_PASS</span> <span class=\"o\">=</span> <span class=\"s\">\"SSIDパスワード\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">utime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">network</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n<span class=\"c1\"># ==== connecti to wifi access point ============================================\n</span><span class=\"k\">def</span> <span class=\"nf\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">,</span> <span class=\"n\">timeout</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">):</span>\n    <span class=\"n\">wifi</span><span class=\"o\">=</span> <span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">WLAN</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">STA_IF</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'already Connected.    connect skip'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">active</span><span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">)</span>\n        <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"ow\">and</span> <span class=\"n\">timeout</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'.'</span><span class=\"p\">,</span> <span class=\"n\">end</span><span class=\"o\">=</span><span class=\"s\">''</span><span class=\"p\">)</span>\n            <span class=\"n\">utime</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">timeout</span> <span class=\"o\">-=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">():</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">Connected'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Connection failed!'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">False</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">disconnect</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">disconnect</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"n\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">SSID_NAME</span><span class=\"p\">,</span> <span class=\"n\">SSID_PASS</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">ifconfig</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n<p>Visual Studio Code のエクスプローラウィンドウで「フォルダを開く」ボタンをクリック\n(またはメニューの「ファイル」→「フォルダを開く」を選択)し、\n上で作成したフォルダ(例ではtest)を開きます。</p>\n\n<p>コマンドパレットで「MicroPico: Upload project to Pico」を選択します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n現在書き込まれているファイルをすべて消去するには<br />\nコマンドパレットで「MicroPico: Delete all files from board」を選択します。</p>\n\n</blockquote>\n\n<p>実際に書き込まれたかはターミナルウィンドウで以下のように実行することで確認できます。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">>>></span> <span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'lib'</span><span class=\"p\">]</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/lib'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'my_wifi.py'</span><span class=\"p\">]</span>\n</code></pre></div></div>\n<p>または後述の仮想ファイルシステムを使用しても確認できます。</p>\n\n<p>でもって、使用するプログラムで<code class=\"language-plaintext highlighter-rouge\">import my_wifi</code> とやれば接続できます。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">my_wifi.isconnected()</code> で接続中かが分かります。\n<code class=\"language-plaintext highlighter-rouge\">my_wifi.disconnect()</code> でAPから切断できます。</p>\n\n<h1 id=\"仮想ファイルシステムを使用する\">仮想ファイルシステムを使用する</h1>\n<p>仮想ファイルシステムを使用すると、現在PaspberryPi Pico(W)のストレージに書き込まれているファイルを\n直接確認/操作することができます。</p>\n\n<ul>\n  <li>コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n  <li>エクスプローラウィンドウに「Pico (W) Remote Workspace」ができ、その下にディレクトリ/ファイルが表示される</li>\n</ul>\n\n<p>ここのファイルを開くとPaspberryPi Pico(W)のストレージにあるファイルを直接参照できます。<br />\nまた、内容を変更して保存すると PaspberryPi Pico(W)のストレージに直接格納されます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPC上のファイルとPaspberryPi Pico(W)のストレージ上のファイルをあちこち弄くると\nどちらをどう書き換えたか分からなくなるので、できるだけPC上のファイルを書き換えて「Upload project to Pico」で\nPaspberryPi Pico(W)のストレージを同期するのが良いと思います。</p>\n</blockquote>\n\n<p>mipコマンドでダウンロードしたモジュールや、プログラムでPaspberryPi Pico(W)のストレージ上に作成したファイルをPCのコピーするには、</p>\n<ul>\n  <li>エクスプローラウィンドウで仮想ファイルシステム上のコピーしたいフォルダまたはファイルを選択</li>\n  <li>CTRLキーを押しながらコピーしたいPC上のフォルダの位置にドラッグ&ドロップ\n    <ul>\n      <li>CTRLキーを押さないでドラッグ&ドロップした場合は移動になるので、「移動しますか?」と聞かれる。移動するなら「移動」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<p>仮想ファイルシステムを消すには、</p>\n<ul>\n  <li>再度コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n</ul>\n\n<p>で、エクスプローラウィンドウから「Pico (W) Remote Workspace」が消えます。<br />\n(エクスプローラウィンドウの表示が消えるだけで、PaspberryPi Pico(W)のストレージから消えるわけではありません)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W で SDK</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W で SDK</h1>\n      <p>Raspberry Pi Pico W で SDK を使用したプログラム開発</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico W で SDK を使用したプログラム開発方法のメモ</p>\n\n<p><a href=\"https://www.raspberrypi.com/documentation/microcontrollers/\" target=\"_blank\">公式ドキュメントサイト</a></p>\n\n<h1 id=\"セットアップ手順\">セットアップ手順</h1>\n<p>以下を参考すれば大体分かります。 <br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico-JP.pdf\" target=\"_blank\">公式スタートアップガイド(日本語版)</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a></p>\n\n<p>以下は作業メモ。<br />\n環境はWSL2上のubuntu20.04。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPi用のセットアップのスクリプトは<a href=\"https://github.com/raspberrypi/pico-setup\" target=\"_blank\">ここ</a> にある <code class=\"language-plaintext highlighter-rouge\">pico_setup.sh</code> <br />\nそれ以外のLinuxでもうごくっぽいですが、余計なものまで入ってしまいそうなので、ここでは手動でセットアップします。</p>\n</blockquote>\n\n<h2 id=\"必要なツールをインストールする\">必要なツールをインストールする</h2>\n\n<p>以下のコマンドでインストールできます。\ngitとかは既に入ってるものとして。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential\n</code></pre></div></div>\n\n<h2 id=\"sdkをダウンロードする\">SDKをダウンロードする</h2>\n\n<p>ますは作業ディレクトリを作成してSDKをダウンロードします。<br />\n以下では <code class=\"language-plaintext highlighter-rouge\">/work/Pico</code> を作業ディレクトリとしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Pico <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Pico\ngit clone https://github.com/raspberrypi/pico-sdk.git\n<span class=\"nb\">cd </span>pico-sdk/\ngit submodule update <span class=\"nt\">--init</span>\n<span class=\"nb\">cd</span> ..\n</code></pre></div></div>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n\n<p>以下のコマンドを実行し、環境変数を設定します。<br />\n上でSDKのダウンロード先を変更している場合はそれにあわせて変更してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PICO_SDK_PATH</span><span class=\"o\">=</span>/work/Pico/pico-sdk\n</code></pre></div></div>\n\n<p>次回起動時にそなえて、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code> に同様のコマンドを追加しておきます。</p>\n\n<h2 id=\"サンプルプログラムをダウンロードする\">サンプルプログラムをダウンロードする</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/raspberrypi/pico-examples.git\n</code></pre></div></div>\n\n<h2 id=\"lチカしてみる\">Lチカしてみる</h2>\n\n<p><a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a>の\n「Chapter 3. Blinking an LED in C」にあるのはPico用のサンプルなので、Pico Wでは使えません。<br />\n(正確にはGPIO端子にLEDを接続すれば使えるが、オンボードのLEDは点滅しない)<br />\nで、Pico W 用の手順をまとめてみました。</p>\n\n<h3 id=\"cmakeの実行\">cmakeの実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>pico-examples\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake .. <span class=\"nt\">-DPICO_BOARD</span><span class=\"o\">=</span>pico_w\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ncmake のオプションに <code class=\"language-plaintext highlighter-rouge\">-DPICO_BOARD=pico_w</code>を追加することでPico W用の設定が有効になります。</p>\n</blockquote>\n\n<h3 id=\"lチカプログラムのビルド\">Lチカプログラムのビルド</h3>\n\n<p>その場でmakeするとすべてのサンプルプログラムがビルドされますが、時間がかかるので\nLチカプログラムだけビルドします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>pico_w/wifi/blink/\nmake\n\n</code></pre></div></div>\n\n<p>これで <code class=\"language-plaintext highlighter-rouge\">pico-examples/build/pico_w/wifi/blink</code> の <code class=\"language-plaintext highlighter-rouge\">picow_blink.uf2</code>をpicoに書き込めばボード上のLEDが点滅するはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPico W のLチカのソースは <code class=\"language-plaintext highlighter-rouge\">pico-examples/pico_w/wifi/blink</code></p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">pico-examples\\pico</code> はpico用(Wなし)なので、実行してもオンボードのLEDが点灯しません。 \nこれを実行するには外付けLEDが必要です。</p>\n</blockquote>\n\n<h1 id=\"コンソール出力をusbに出力する\">コンソール出力をUSBに出力する</h1>\n\n<p>デフォルトでコンソール入出力はUART0に割り当てられています(端子はGP0(TX)/GP1(RX))。<br />\nUARTに接続するのが面倒なときはUSBから仮想COMポートに入出力できます。<br />\n手順は、ソースディレクトリの <code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>に以下を追加してmakeします。<br />\n例ではターゲット名に<code class=\"language-plaintext highlighter-rouge\">picow_blink</code>を使用していますが、使用するターゲットに合わせて変更してください。</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># enable usb output, disable uart output</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>picow_blink 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>picow_blink 0<span class=\"p\">)</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>を変更した場合でも <code class=\"language-plaintext highlighter-rouge\">make</code>を実行すればこの変更も反映されます。</p>\n</blockquote>\n\n<p>出来上がったuf2ファイルをPicoに書き込んだら自動的にリブートされるので、<br />\nPCに仮想COMポートドライバがインストールされたらTeratermで対象のCOMポートに接続します。</p>\n\n<h1 id=\"自作プロジェクトの作成\">自作プロジェクトの作成</h1>\n<p>サンプルプログラムを改造してうんぬんするのはダサいので、自作のプロジェクトを作ってみます。<br />\n一から作るのは面倒なので、プロジェクト生成ツールを使います。</p>\n\n<h2 id=\"プロジェクト生成ツールのダウンロード\">プロジェクト生成ツールのダウンロード</h2>\n\n<p>githubにプロジェクト生成ツールのリポジトリがあるのでダウンロードします。<br />\n以下では 前に作成した作業ディレクトリ <code class=\"language-plaintext highlighter-rouge\">/work/Pico</code> をダウンロードディレクトリとしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/Pico\ngit clone https://github.com/raspberrypi/pico-project-generator.git\n</code></pre></div></div>\n\n<p>ダウロードしたプログラムを直接起動しても良いですが、<br />\nオプション指定など忘れっぽいので起動スクリプトを用意しておきます。</p>\n\n<p>pathの通ったディレクトリ(<code class=\"language-plaintext highlighter-rouge\">~/bin</code>など)に以下の内容でファイルを作成し、実行属性を付与します。<br />\nファイル名は<code class=\"language-plaintext highlighter-rouge\">pico_project</code>とでもしておいてください。<br />\n実行ファイルのパスはダウンロード先に合わせて変更してね。<br />\n追加したいオプションがあったらご自由にどうぞ。<br />\nGUIを起動するので、最後に & をつけてバックグラウンド実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/Pico/pico-project-generator/pico_project.py <span class=\"nt\">--nouart</span> <span class=\"nt\">--usb</span>  <span class=\"nt\">--gui</span> &\n</code></pre></div></div>\n\n<h2 id=\"プロジェクトの作成\">プロジェクトの作成</h2>\n\n<p>上で作成したスクリプトを実行するとProject Generator のウィンドウが表示されます。<br />\nこのウィンドウで必要な設定を行います。</p>\n\n<ul>\n  <li>Project Name に プロジェクト名を設定</li>\n  <li>Board Type でpico_w を選択</li>\n  <li>Library Options   PiCO Wirless Options で必要なオプションをチェック</li>\n  <li>Console Options は必要なら変更してください。<br />\n(常にUART使うなら起動スクリプトのオプション変更した方が良いかも)</li>\n  <li>Code Options は 必要なら設定。 Advancedボタンをクリックすればさらに多くのパラメータが設定できます。</li>\n  <li>その下は必要なら設定してちょ。</li>\n</ul>\n\n<p>OKボタンをクリックしたらプロジェクトが作成され、cmakeが実行されます。<br />\n実行結果を表示するウィンドウが表示されますので、確認してOKボタンでクローズしてください。<br />\nLocationで指定したディレクトリ下のProjectNameで指定した名前のディレクトリに\nProjectNameで指定した名前.c が生成されているので必要な変更を行います。</p>\n\n<p>あとはコンソールでLocationで指定したディレクトリ下のProjectNameで指定したディレクトリ下の\nbuildディレクトリに移動し、<code class=\"language-plaintext highlighter-rouge\">make</code>を実行します。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</h1>\n      <p>Raspberry Pi Pico W の SDK を使用したプログラムをRaspberryPi3 + Visual Studio CodeでSWDデバッグする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico W の SDK を使用したプログラムをRaspberryPi3 + Visual Studio CodeでSWDデバッグするときのメモ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPi4 や Pi ZERO 2 W でも同様だと思うが、実際に試したのが Pi3 だったので。<br />\nたぶん Pi ZERO や Pi2 ではやめておいた方が無難。<br />\nPi ZERO 2 W やRAM512KByteだからビミョーかも…</p>\n</blockquote>\n\n<p><a href=\"https://www.raspberrypi.com/documentation/microcontrollers/\" target=\"_blank\">公式ドキュメントサイト</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico-JP.pdf\" target=\"_blank\">公式スタートアップガイド(日本語版)</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a></p>\n\n<p>試したときはRaspberryPi OS Lite(64bit) 使用(通常版でも大丈夫と思う)。</p>\n\n<h1 id=\"raspberrypi3のセットアップ\">RaspberryPi3のセットアップ</h1>\n\n<p>RaspberryPi3をセットアップします。<br />\nVisual Studio Code で リモートSSH接続するので、SSHが公開鍵認証で接続できるようにしておくこと。<br />\nセットアップの手順は\n<a href=\"https://ippei8jp.github.io/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</a>\nなど参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\nターゲットボードにPico W を使用する場合はボード種別を指定しておくこと</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"export PICO_BOARD=pico_w\"</span> <span class=\"o\">>></span> ~/.bashrc\n<span class=\"nb\">source</span> ~/.bashrc\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"セットアップスクリプトの実行\">セットアップスクリプトの実行</h2>\n<p>公式ドキュメントに記載されている通り、セットアップスクリプトを実行すればセットアップはほぼ自動です。<br />\nただし、今回はVisual Studio CodeをRaspberryPi上ではなく、WindowsPC上で動かし、\nリモートSSHでRaspberryPiに接続する方法をとるので、Visual Studio Codeのインストールは不要です。<br />\nまた、私はRaspberryPiのシリアルコンソールを残しておきたいので、UARTのセットアップも行いません。<br />\n(UARTは別途USB-Serialアダプタを使用して接続)</p>\n\n<p>以下のようにセットアップスクリプトを実行します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/work</code>ディレクトリにインストールすることにしています。<br />\n別のディレクトリにインストールする場合は読み替えてください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n\n<span class=\"c\"># スクリプトダウンロード</span>\nwget https://raw.githubusercontent.com/raspberrypi/pico-setup/master/pico_setup.sh \n\n<span class=\"c\"># VSCODEのインストールとUARTの設定をスキップしてセットアップ</span>\n<span class=\"nv\">SKIP_VSCODE</span><span class=\"o\">=</span>1 <span class=\"nv\">SKIP_UART</span><span class=\"o\">=</span>1 bash pico_setup.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nopenOCDのコンパイルとかで時間がかかるので(私が試したときは30分くらい)、<br />\nお茶でも飲んでのんびりお待ちくらはい。</p>\n</blockquote>\n\n<h2 id=\"セットアップスクリプト後の変更\">セットアップスクリプト後の変更</h2>\n\n<p>セットアップスクリプトでサンプルプログラムを一部ビルドしてくれますが、\nVisual Studio Code上の開発環境で作り直すので<code class=\"language-plaintext highlighter-rouge\">pico-examples/build</code>ディレクトリは削除しておいてください。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> /work/pico/pico-examples/build\n</code></pre></div></div>\n\n<p>また、Visual Studio Codeの設定ファイルを<code class=\"language-plaintext highlighter-rouge\">pico-examples/.vscode</code>ディレクトリに作成しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/pico/pico-examples\n<span class=\"nb\">mkdir</span> .vscode\n<span class=\"nb\">cp </span>ide/vscode/launch-raspberrypi-swd.json .vscode/launch.json\n<span class=\"nb\">cp </span>ide/vscode/settings.json .vscode/settings.json\n</code></pre></div></div>\n\n<p>このままだとビルドが全ビルドになってしまい、時間がかかってしまうのでビルドターゲットを指定できるように変更しておきます。<br />\n【2024.08.29修正】\nどこかのタイミングのバージョンアップで設定できる内容が大幅に変更されたようなので、setting.jsonを以下の内容で全書き換えしておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  settings.json\n</p>\n\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"p\">{</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.configureOnOpen\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"kc\">false</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.advanced\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n    </span><span class=\"nl\">\"build\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"buildTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"ctest\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"debug\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"launchTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n     </span><span class=\"nl\">\"launch\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"workflow\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"cpack\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">}</span><span class=\"w\">    \n  </span><span class=\"p\">},</span><span class=\"w\">\n</span><span class=\"p\">}</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h1 id=\"raspberry-pi3とraspberry-pi-pico-の接続\">Raspberry Pi3とRaspberry Pi Pico の接続</h1>\n<p>この辺で一旦Raspberry Pi3をシャットダウンし、Raspberry Pi Picoと接続します(最初に接続しておいても良いけど)。<br />\n接続方法は 公式スタートアップガイド の 「Chapter 5. Flash Programming with SWD」の下の「5.2. SWD Port Wiring」\nあたりを参照してください。<br />\n私はPicoのシリアルポートをRaspberryPiではなくUSB-Serialに接続するようにしたので、図の上3本の結線は行わず\nPi3のGPIO24とPicoのSWDIO、Pi3のGPIO25とPicoのSWDCLK、双方のGND同士 の3本を結線しました。<br />\n(PicoのPin1~3はUSB-Serialに接続し、WindowsPCかRaspberry Pi3に接続)</p>\n\n<h2 id=\"visual-studio-coce-起動フォルダのオープン\">Visual Studio COCE 起動&フォルダのオープン</h2>\n\n<p>ホストPCでVisual Studio COCE 起動。<br />\nリモートSSHでRaspberryPi3 に接続し、セットアップツールでインストールした\nサンプルプログラムのディレクトリを開きます(上の例では/work/pico/pico-example)</p>\n\n<h2 id=\"拡張機能のインストール\">拡張機能のインストール</h2>\n<p>これは最初の起動時のみ実行します。</p>\n\n<p>拡張機能で「Cmake Tools」「C/C++(C/C++ for Visual Studio Code)」「Cortex Debug」をRaspberry Pi3 にインストールします。<br />\n(ホストPCではないのでSSH接続した後でインストールすること)</p>\n\n<p>「Cmake Tools」のインストールが完了したら歯車アイコン(設定)をクリックして設定画面を開き、\n“CMake: Parallel Jobs” の設定値を0から1(または2)に変更\n(0だと設定できる上限値になるはずだけど、プロセッサ数4に対して6が設定されてしまい、システムがハングアップしてしまうことがあるので)</p>\n\n<p>右下に「プロジェクト”pico-examples”を構成しますか? ソース:CMake Tools(拡張機能)」と表示されるのでYesをクリック<br />\n続いて「プロジェクトを開いたときに常に構成しますか? ソース:CMake Tools(拡張機能)」 と表示されるので「はい」をクリック</p>\n\n<h2 id=\"ビルドデバッグ\">ビルド~デバッグ</h2>\n<p>ステータスバーの「キットが選択されていません」をクリックすると\nウィンドウ上部に「pico-examplesのキットを選択してください」と表示されるので\n「GCC 12.2.1  arm-none-eabi」を選択(バージョンは異なるかも)</p>\n\n<blockquote>\n  <p>[!NOTE]\n「この大規模なワークスペース フォルダーでのファイルの変更をウォッチできません。\nこの問題を解決するには、手順のリンクに従ってください。 」\nと表示された場合\n/etc/sysctl.conf に以下を追記</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>fs.inotify.max_user_watches = 524288\n</code></pre></div>  </div>\n  <p>設定を反映</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sysctl <span class=\"nt\">-p</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>ステータスバーで「プロジェクトを構成しています: pico-examples」が消えるのを待つ)</p>\n\n<p>ステータスバーで「既定のビルドターゲットの設定(ステータスバーの表示にマウスカーソルをあてると表示されるメッセージ)」と\n「起動するターゲットを選択します(ステータスバーの表示にマウスカーソルをあてると表示されるメッセージ)」を\nクリックしてデバッグしたいターゲットに設定します(例えば、picow_blink)。\nこれらば同じターゲットを指定する必要があります。(ビルドターゲットはallでも良いが、ビルドに時間がかかる)</p>\n<blockquote>\n  <p>[!NOTE]\nサンプルにあるide/vscode/settings.json そのままだと「既定のビルドターゲットの設定」がallのまま変更できないのでビルドに時間がかかるため\n上記の変更を行っています。</p>\n</blockquote>\n\n<p>構成が完了したら「実行とデバッグ」ウィンドウを開いて、右向き三角マーク(デバッグの開始)をクリック<br />\n(右向き三角マーク(デバッグの開始)が無ければ「実行とデバッグ」をクリック)<br />\nbuildが始まって、終わったらデバッガが起動します。<br />\nあとは他のデバッグ同様、RUNやSTEPなどでデバッグしてください。</p>\n\n<h1 id=\"自作プロジェクトの作成\">自作プロジェクトの作成</h1>\n\n<p>サンプルプログラムを改造してうんぬんするのはダサいだけでなく、関係ない処理が色々動いて\nビルドに時間がかかるので、自作プロジェクトの作成をした方が良いです。</p>\n\n<p><a href=\"https://ippei8jp.github.io/memoBlog/2023/10/11/RasPiPico_2.html\" target=\"_blank\">Raspberry Pi Pico W で SDK</a>\nの「自作プロジェクトの作成」にまとめておきましたが、デバッガの指定など追加手順もあるので\n再掲します。</p>\n\n<h2 id=\"プロジェクト生成ツールのインストール\">プロジェクト生成ツールのインストール</h2>\n<p>プロジェクト生成ツールをインストールして起動スクリプトを作成します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ダウンロード</span>\n<span class=\"nb\">cd</span> /work/pico/\ngit clone https://github.com/raspberrypi/pico-project-generator.git\n\n<span class=\"c\"># 起動用スクリプトの作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ~/bin\n<span class=\"nb\">cat</span> <span class=\"o\">></span> ~/bin/pico_project <span class=\"o\"><<</span> <span class=\"sh\">\"</span><span class=\"no\">_EOF_</span><span class=\"sh\">\"\n/work/Pico/pico-project-generator/pico_project.py --nouart --usb  --gui &\n</span><span class=\"no\">_EOF_\n\n</span><span class=\"nb\">chmod</span> +x ~/bin/pico_project\n\n<span class=\"c\"># tkinter のインストール(RaspberryPi OS lite の場合は要インストール)</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>python3-tk\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nそれまで<code class=\"language-plaintext highlighter-rouge\">~/bin</code>が存在していない場合は一旦ログアウトして再ログインで\n<code class=\"language-plaintext highlighter-rouge\">~/bin</code>にpathを通す(変数ゴチョゴチョやっても良いけど、再ログインが手っ取り早い)。</p>\n</blockquote>\n\n<h2 id=\"プロジェクト生成ツールの起動プロジェクト出力\">プロジェクト生成ツールの起動~プロジェクト出力</h2>\n\n<p>リモート接続で使用している場合はDISPLAY変数が設定されていること(ホストマシン)と、\nホストマシンでX-serverが動作していることを確認し、\nプロジェクト生成ツール起動スクリプトを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pico_project\n</code></pre></div></div>\n<p>ホストマシン上にプロジェクト生成ツールのウィンドウが表示されます。</p>\n\n<p>各パラメータを設定し、OKボタンをクリックしてプロジェクトを生成します。<br />\nこのウィンドウで必要な設定を行います。</p>\n\n<ul>\n  <li>Project Name に プロジェクト名を設定</li>\n  <li>Board Type でpico_w を選択</li>\n  <li>Library Options   PiCO Wirless Options で必要なオプションをチェック</li>\n  <li>Console Options は必要なら変更してください。<br />\n(常にUART使うなら起動スクリプトのオプション変更した方が良いかも)</li>\n  <li>Code Options は 必要なら設定。 Advancedボタンをクリックすればさらに多くのパラメータが設定できます。</li>\n  <li>その下は必要なら設定してちょ。</li>\n  <li>一番下の IDE Options は、「Create VSCode Project」をチェックし、「Debugger」に「SWD」を選択します。</li>\n</ul>\n\n<p>OKボタンをクリックしたらプロジェクトが作成され、cmakeが実行されます。<br />\n実行結果を表示するウィンドウが表示されますので、確認してOKボタンでクローズしてください。</p>\n\n<p>プロジェクト生成ツールはもう不要なのでクローズしてください。</p>\n\n<p>生成されたプロジェクトディレクトリの<code class=\"language-plaintext highlighter-rouge\">.vscode/settings.json</code> を以下の内容で全書き換えします。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  settings.json\n</p>\n\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"p\">{</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.configureOnOpen\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"kc\">false</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.advanced\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n    </span><span class=\"nl\">\"build\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"buildTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"ctest\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"debug\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"launchTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n     </span><span class=\"nl\">\"launch\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"workflow\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"cpack\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">}</span><span class=\"w\">    \n  </span><span class=\"p\">},</span><span class=\"w\">\n</span><span class=\"p\">}</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n毎回修正するのが面倒なら、<code class=\"language-plaintext highlighter-rouge\">pico_project.py</code>の\n関数<code class=\"language-plaintext highlighter-rouge\">generateProjectFiles</code>内の変数<code class=\"language-plaintext highlighter-rouge\">s1</code>の定義(1195行目あたり)\nを上記の内容で書き換えてしまえば生成時にこの内容にできる。<br />\n(そのうち公式さんが修正するだろうけど)</p>\n</blockquote>\n\n<h2 id=\"visual-studio-code-でプロジェクトを開くデバッグ\">Visual Studio Code でプロジェクトを開く~デバッグ</h2>\n\n<p>Visual Studio Code のリモートエクスプローラからRaspberry Pi に接続し、作成したディレクトリを開きます。</p>\n\n<p>ProjectNameで指定した名前.c が生成されているので必要な変更を行います。<br />\nファイルを追加する場合は <code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code> の修正も忘れずに。</p>\n\n<p>ステータスバーの「キットが選択されていません」をクリックすると 上に「XXXXのキットを選択してください」と表示されるので\n「GCC 12.2.1  arm-none-eabi」を選択(バージョンは異なるかも)<br />\n構成が完了したら「実行とデバッグ」ウィンドウを開いて、右向き三角マーク(デバッグの開始)をクリック<br />\n(右向き三角マーク(デバッグの開始)が無ければ「実行とデバッグ」をクリック)<br />\n上中央に「ターゲットの起動対象を選択します」と表示されるので、プロジェクト名で指定した名前を選択します。</p>\n\n<p>コンパイルが始まり、エラーがなければそのままデバッガが起動し、main関数の先頭でbreakします。</p>\n\n<p>あとは普通にデバッグしてくらはい。</p>\n\n<h2 id=\"ソースファイルの追加\">ソースファイルの追加</h2>\n\n<p>ソースファイルを追加する場合は<code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code> の <code class=\"language-plaintext highlighter-rouge\">add_executable</code>に追加するソースファイルを追加します。</p>\n\n<p>変更前</p>\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">add_executable</span><span class=\"p\">(</span>test1 test1.c<span class=\"p\">)</span>\n</code></pre></div></div>\n<p>変更後</p>\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">add_executable</span><span class=\"p\">(</span>test1 test1.c sub.c<span class=\"p\">)</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) でI2C Slave</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) でI2C Slave</h1>\n      <p>Raspberry Pi Pico W の SDK を使用してI2C Slaveプログラムを作成する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico のI2C マスタを使用してI2Cデバイスにアクセスするプログラムプログラムは\nネット上のあちこちに落ちているのですが、\nI2Cスレーブとしてホストデバイスからアクセスされるサンプルはあまりありません。<br />\nそこで、あちこち探してプログラム作ったのでメモを残しておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n【ホントのところ】<br />\n「I2Cデバイスをポチったけど、納期が長くてプログラム開発に取り掛かれない~」となって\nなんちゃってI2Cデバイスを作って先行デバッグしようとしました。</p>\n</blockquote>\n\n<p>通信プログラムなので通信相手が必要ですが、今回はRaspberry Pi3上でpython3で動く\n簡単な動作確認プログラムを載せておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n公式サンプルは<code class=\"language-plaintext highlighter-rouge\">pico-examples/i2c/slave_mem_i2c</code>にあります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nmicropython版の例は<a href=\"https://python-academia.com/raspberry-pi-pico-slave/\" target=\"_blank\">ここ</a>\nとかにあるけど、ちぃーっと無理くり感が…</p>\n</blockquote>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"i2cの結線\">I2Cの結線</h2>\n\n<p>以下のように結線します。<br />\nPico側はソース中の割り当て端子を変更すれば別の端子でもOKです。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>Pi3</th>\n      <th>Pico</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>SDA1(pin3)</td>\n      <td>I2C0_SDA/GP16(Pin21)</td>\n    </tr>\n    <tr>\n      <td>SCL1(pin5)</td>\n      <td>I2C0_SCL/GP17(Pin22)</td>\n    </tr>\n  </tbody>\n</table>\n\n<h2 id=\"pi3でのi2c有効化\">Pi3でのI2C有効化</h2>\n\n<p>Pi3で以下のコマンドを実行し、I2Cを有効化します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config nonint do_i2c 0\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nまたは以下のように手動で設定</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config\n</code></pre></div>  </div>\n\n  <p>以下のように設定</p>\n  <ul>\n    <li>3 Interface Options\n      <ul>\n        <li>I4 I2C\n          <ul>\n            <li>「Would you like the ARM I2C interface to be enabled?」<br />\n に対して「はい」を選択</li>\n            <li>「The ARM I2C interface is enabled」\nと表示されるので「了解」</li>\n          </ul>\n        </li>\n        <li>「Finish」で終了</li>\n      </ul>\n    </li>\n  </ul>\n\n</blockquote>\n\n<p>実行後、<code class=\"language-plaintext highlighter-rouge\">/dev/i2c-1</code>ファイルが存在することを確認してください。<br />\nリブートは不要です。</p>\n\n<h2 id=\"i2cツールのインストール\">I2Cツールのインストール</h2>\n\n<p>Pi3に<code class=\"language-plaintext highlighter-rouge\">i2cdetect</code>などのツールをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>i2c-tools\n</code></pre></div></div>\n\n<h1 id=\"picoのプログラム\">Picoのプログラム</h1>\n\n<p>作成したプログラムを以下に示します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n今回元にしたI2Cデバイスは先頭アドレスからのバーストリードのみサポートしていたので<br />\nちょっと一般的なアドレス/データ指定の方法と違うけど、なんとなく想像はつくでしょう…</p>\n</blockquote>\n\n<h2 id=\"メインルーチン\">メインルーチン</h2>\n\n<p>メインルーチンはI2Cを初期化したあと無限ループします。<br />\nループ内ではI2Cに関する処理はなく、生存確認用のLチカと\nデバッグ用に送信データが更新されたときにデータを表示しているだけです。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_test.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/stdlib.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/cyw43_arch.h\"</span><span class=\"cp\">\n</span>\n<span class=\"c1\">// プロトタイプ宣言</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n\n<span class=\"kt\">int</span> <span class=\"nf\">main</span><span class=\"p\">()</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">stdio_init_all</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// STDIOがUSBのとき、USB認識されないことがあるのでstdio初期化の後、ちょっと待つ</span>\n    <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">3000</span><span class=\"p\">);</span>\n\n    <span class=\"n\">puts</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">I2C slave test\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// LEDを使うためにwifi初期化</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">cyw43_arch_init</span><span class=\"p\">())</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"Wi-Fi init failed\"</span><span class=\"p\">);</span>\n        <span class=\"k\">return</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\">// I2Cスレーブ 初期化</span>\n    <span class=\"n\">setup_i2c_slave</span><span class=\"p\">();</span>\n    \n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">disp_next_data</span><span class=\"p\">();</span>\n        <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">1000</span><span class=\"p\">);</span>\n\n        <span class=\"c1\">// ==== 生存確認用にLチカ ====</span>\n        <span class=\"c1\">// 現在の出力値取得</span>\n        <span class=\"n\">bool</span> <span class=\"n\">led_out</span> <span class=\"o\">=</span> <span class=\"n\">cyw43_arch_gpio_get</span> <span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">);</span>\n        <span class=\"c1\">// 出力反転</span>\n        <span class=\"n\">cyw43_arch_gpio_put</span><span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">,</span> <span class=\"o\">!</span><span class=\"n\">led_out</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"i2c処理\">I2C処理</h2>\n\n<h3 id=\"初期化\">初期化</h3>\n<p>I2Cの初期化は<code class=\"language-plaintext highlighter-rouge\">setup_i2c_slave</code>です。<br />\n主に端子の初期化とI2Cの初期化、\nI2Cスレーブの初期化(I2C割り込みハンドラからのコールバックの登録)を行っています。</p>\n\n<h3 id=\"処理本体\">処理本体</h3>\n<p>I2C処理本体は<code class=\"language-plaintext highlighter-rouge\">i2c_slave_handler()</code>です。</p>\n\n<p>これはI2C割り込みハンドラからのコールバック処理です。<br />\nなので、できるだけ速やかにリターンする必要があります\n(printfなどの時間のかかる処理は行わないほうが良い)。</p>\n\n<p>なお、今回はマスタの通信プログラムをデバッグするためのダミーデバイスという位置づけで作ったので\n通信を行うたびに異なるデータを送信するようにしてあります。\nこのデータの更新処理をストップ/リスタートコンディション時に行うようにしてあります。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_test.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">16</span><span class=\"p\">;</span>  <span class=\"c1\">//GP16(Pin21)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">17</span><span class=\"p\">;</span>  <span class=\"c1\">//GP17(Pin22)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">16</span><span class=\"p\">];</span>            <span class=\"c1\">// 読み出しデータ</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>        <span class=\"c1\">// 読み出しインデックス</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_REQ</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// 表示要求あり</span>\n        <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"NEXT: %02x %02x %02x %02x : %02x %02x %02x %02x : %02x %02x %02x %02x : %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">14</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">i</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\">// 次に送信するデータの表示を要求</span>\n    <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n\n<span class=\"c1\">// 読み出しデータの更新</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">update_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"o\">++</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\">// 次に送信するデータの表示を要求</span>\n    <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではない</span>\n<span class=\"c1\">// 例えば、表示要求フラグを立ててメインルーチン側で表示してもらうようにするなど</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"p\">{</span>\n            <span class=\"c1\">// ライト動作はサポートしないのでとりあえず読み捨てておく</span>\n            <span class=\"k\">volatile</span> <span class=\"kt\">uint8_t</span> <span class=\"n\">dummy</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span><span class=\"n\">dummy</span><span class=\"p\">;</span>    <span class=\"c1\">// ワーニング対策</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// 1バイト送信する</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">]);</span>\n        <span class=\"c1\">// 次の転送に備えてインデックスを更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// オーバフローしたら0にもどしておく</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// リードポインタを初期化しておく</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        \n        <span class=\"c1\">// テスト用ダミーデータなので、次の読み出しに備えて値を更新しておく</span>\n        <span class=\"n\">update_data</span><span class=\"p\">();</span>\n        \n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave  done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"cmake設定ファイル\">cmake設定ファイル</h3>\n\n<p>プロジェクト生成ツールで作成したプロジェクト(一般的な設定に「I2C interface」のチェックを追加)に\n<code class=\"language-plaintext highlighter-rouge\">target_link_libraries</code> に <code class=\"language-plaintext highlighter-rouge\">pico_i2c_slave</code>を追加します。<br />\nまた、今回はメインルーチンとI2C処理を別ファイルに分けたので、\n<code class=\"language-plaintext highlighter-rouge\">add_executable</code> に <code class=\"language-plaintext highlighter-rouge\">i2c_slave0.c</code>(追加したファイル名)を追加します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  CMakeLists.txt\n</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># Generated Cmake Pico project file</span>\n\n<span class=\"nb\">cmake_minimum_required</span><span class=\"p\">(</span>VERSION 3.13<span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_C_STANDARD 11<span class=\"p\">)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_CXX_STANDARD 17<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise pico_sdk from installed location</span>\n<span class=\"c1\"># (note this can come from environment, CMake cache etc)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_SDK_PATH <span class=\"s2\">\"/work/pico/pico-sdk\"</span><span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_BOARD pico_w CACHE STRING <span class=\"s2\">\"Board type\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># Pull in Raspberry Pi Pico SDK (must be before project)</span>\n<span class=\"nb\">include</span><span class=\"p\">(</span>pico_sdk_import.cmake<span class=\"p\">)</span>\n\n<span class=\"nb\">if</span> <span class=\"p\">(</span>PICO_SDK_VERSION_STRING VERSION_LESS <span class=\"s2\">\"1.4.0\"</span><span class=\"p\">)</span>\n  <span class=\"nb\">message</span><span class=\"p\">(</span>FATAL_ERROR <span class=\"s2\">\"Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is </span><span class=\"si\">${</span><span class=\"nv\">PICO_SDK_VERSION_STRING</span><span class=\"si\">}</span><span class=\"s2\">\"</span><span class=\"p\">)</span>\n<span class=\"nb\">endif</span><span class=\"p\">()</span>\n\n<span class=\"nb\">project</span><span class=\"p\">(</span>i2c_slave_test C CXX ASM<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise the Raspberry Pi Pico SDK</span>\n<span class=\"nf\">pico_sdk_init</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># Add executable. Default name is the project name, version 0.1</span>\n\n<span class=\"nb\">add_executable</span><span class=\"p\">(</span>i2c_slave_test i2c_slave_test.c i2c_slave0.c<span class=\"p\">)</span>\n\n<span class=\"nf\">pico_set_program_name</span><span class=\"p\">(</span>i2c_slave_test <span class=\"s2\">\"i2c_slave_test\"</span><span class=\"p\">)</span>\n<span class=\"nf\">pico_set_program_version</span><span class=\"p\">(</span>i2c_slave_test <span class=\"s2\">\"0.1\"</span><span class=\"p\">)</span>\n\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>i2c_slave_test 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>i2c_slave_test 0<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard library to the build</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_test\n        pico_stdlib<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard include files to the build</span>\n<span class=\"nb\">target_include_directories</span><span class=\"p\">(</span>i2c_slave_test PRIVATE\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>/.. <span class=\"c1\"># for our common lwipopts or any other standard includes, if required</span>\n<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add any user requested libraries</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_test \n        pico_i2c_slave\n        hardware_i2c\n        pico_cyw43_arch_none\n        <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_add_extra_outputs</span><span class=\"p\">(</span>i2c_slave_test<span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>あとはビルドしてRaspberry Pi Picoに書き込みます。</p>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認です。<br />\nここからはRaspberry Pi3 での作業です。</p>\n\n<h2 id=\"i2cdetect\">i2cdetect</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdetect</code> で I2Cバス上でデバイスが検出されるか確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n\n<p>Picoのプログラムで設定したスレーブアドレス(<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>の設定値。上のプログラムだと0x17)\nが表示されていればOKです。<br />\n表示されていない場合はPicoのプログラムやボードの結線を見直してください。</p>\n\n<h2 id=\"レジスタリードプログラム\">レジスタリードプログラム</h2>\n<p>Raspberry Pi3で以下のプログラムを実行します。<br />\n<code class=\"language-plaintext highlighter-rouge\">i2c_address</code>の設定値は上のプログラムの<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>の設定値に合わせます。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">smbus2</span> <span class=\"kn\">import</span> <span class=\"n\">SMBus</span><span class=\"p\">,</span> <span class=\"n\">i2c_msg</span>\n\n<span class=\"n\">i2c_bus</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>                 <span class=\"c1\"># バス番号\n</span><span class=\"n\">i2c_address</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span>          <span class=\"c1\"># スレーブアドレス\n</span><span class=\"n\">data_size</span> <span class=\"o\">=</span> <span class=\"mi\">16</span>              <span class=\"c1\"># リードデータサイズ\n</span>\n<span class=\"c1\"># バスオープン\n</span><span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">SMBus</span><span class=\"p\">(</span><span class=\"n\">i2c_bus</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ読み出し\n</span><span class=\"n\">read</span> <span class=\"o\">=</span> <span class=\"n\">i2c_msg</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">(</span><span class=\"n\">i2c_address</span><span class=\"p\">,</span> <span class=\"n\">data_size</span><span class=\"p\">)</span>\n<span class=\"n\">bus</span><span class=\"p\">.</span><span class=\"n\">i2c_rdwr</span><span class=\"p\">(</span><span class=\"n\">read</span><span class=\"p\">)</span>\n<span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">read</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>正常に読み出せれば、以下のように結果が表示されます(10進数)。<br />\n(以下は何回か実行したあとの結果です)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n</code></pre></div></div>\n\n<p>同時にPicoのシリアルポートからは以下のように次に読み出せるデータが表示されます(16進数)。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>NEXT: 06 07 08 09 : 0a 0b 0c 0d : 0e 0f 10 11 : 12 13 14 15\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 22.04をNative環境にインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 22.04をNative環境にインストール</h1>\n      <p>Ubuntu 22.04をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuのダウンロード\">Ubuntuのダウンロード</h1>\n<p><a href=\"https://www.ubuntulinux.jp/download\" target=\"_blank\">Ubuntuの入手</a>からダウンロード<br />\nSecure Boot環境で日本語RemixのISOファイルを使うと<code class=\"language-plaintext highlighter-rouge\">Verification failed: (0x1A) Security Violation</code>\nと怒らたので、jp.ubuntu.comのダウンロードページからUbuntu Desktopをダウンロードした。<br />\nブータブルUSBを作るには、Rufus等を使う(ググってちょ)。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<p>以下の参考ページを参照して起動するとこまでやってちょ。</p>\n\n<ul>\n  <li><a href=\"https://ippei8jp.github.io/memoBlog/2021/07/15/install2004_native.html\" target=\"_blank\">UbuntuをNative環境にインストールする(20.04)</a></li>\n  <li><a href=\"https://ippei8jp.github.io/memoBlog/2022/07/24/install2204.html\" target=\"_blank\">Ubuntu 22.04のVirtualBoxへのインストール</a></li>\n  <li>Ubuntu 22.04 デュアルブートのインストール方法は以下を参考\n    <ul>\n      <li><a href=\"https://dailylife.pman-bros.com/ubuntu22_install/\" target=\"_blank\">Ubuntu 22.04 LTS をインストールする -【マルチブート編】</a></li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"お好みで\">お好みで</h1>\n<p>作業中に画面が消えると鬱陶しいのでパワマネ無効化。<br />\nTAB補完使えばコピペするほどでもないので、最初にやっとく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h1 id=\"最新版にupdate\">最新版にupdate</h1>\n\n<p>とりあえず最新版に</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ついでにsshもインストールしておく。<br />\nwebで調べたコマンドをコピペしたいので。<br />\n参考:<a href=\"https://ippei8jp.github.io/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">ubuntuにSSHサーバをセットアップする</a></p>\n\n<ul>\n  <li>パッケージをインストール\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\n</code></pre></div>    </div>\n    <ul>\n      <li>これだけでパスワード認証は繋がるはず。</li>\n    </ul>\n  </li>\n  <li>公開鍵認証を使用する場合は、公開鍵を<code class=\"language-plaintext highlighter-rouge\">~/.ssh/authorized_keys</code>に追記し、attribute変更。<br />\n(コピペで追記したいのでsshで接続したターミナルから作業するのがベター)</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/.ssh\nvi ~/.ssh/authorized_keys\n<span class=\"c\">### 公開鍵を追記 ###</span>\n<span class=\"nb\">chmod </span>600 ~/.ssh/authorized_keys\n</code></pre></div></div>\n\n<p>念のためここでリブート。</p>\n\n<h1 id=\"chromeとリモートデスクトップのインストール\">chromeとリモートデスクトップのインストール</h1>\n<p>参考: <a href=\"https://qiita.com/grgrjnjn/items/a5c4da336031b63f09a6\" target=\"_blank\">UbuntuにChromeをインストールする手順</a><br />\n参考: <a href=\"https://zenn.dev/karaage0703/articles/cfde5e6a4f43c3\" target=\"_blank\">Linux(Ubuntu)のリモートデスクトップ設定(Google Chrome リモートデスクトップ/xrdp)</a></p>\n\n<h2 id=\"おまじない\">おまじない</h2>\n<p>chrome リモートデスクトップをインストールすると、ローカル端末でのログインができなくなるので、\n以下の処理を行う。</p>\n\n<p>新しく使用する<code class=\"language-plaintext highlighter-rouge\">.desktop</code>ファイルを作成(ubuntuをベースに使用)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /usr/share/xsessions/\n<span class=\"nb\">sudo cp </span>ubuntu.desktop ubuntu-local.desktop\n</code></pre></div></div>\n\n<p>以下のパッチをあてる。</p>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">Name</code>の変更と<code class=\"language-plaintext highlighter-rouge\">Exec</code>に<code class=\"language-plaintext highlighter-rouge\">DISPLAY=\":0\"</code>を追加</p>\n</blockquote>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ubuntu.desktop      2022-04-08 04:07:53.000000000 +0900\n</span><span class=\"gi\">+++ ubuntu-local.desktop        2023-11-11 07:25:37.223280734 +0900\n</span><span class=\"p\">@@ -1,7 +1,7 @@</span>\n [Desktop Entry]\n<span class=\"gd\">-Name=Ubuntu\n</span><span class=\"gi\">+Name=Ubuntu on local\n</span> Comment=This session logs you into Ubuntu\n<span class=\"gd\">-Exec=env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu\n</span><span class=\"gi\">+Exec=env DISPLAY=\":0\" GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu\n</span> TryExec=/usr/bin/gnome-shell\n Type=Application\n DesktopNames=ubuntu:GNOME\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nローカル端末でログインするときはユーザ名選択後、画面右下の歯車アイコンをクリックし、\n「Ubuntu on local」を選択(一度選択すれば記憶されるので2度目以降は確認だけでOK)してログインする。\n (作成したセッションを選択可能にするには、リブートが必要)</p>\n</blockquote>\n\n<h2 id=\"chromeとリモートデスクトップのインストール-1\">chromeとリモートデスクトップのインストール</h2>\n\n<p>手間を省くためにコマンドラインで以下を実行(sshからで可)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール時にエラーにならないようおまじない</span>\n<span class=\"nb\">mkdir</span> ~/.config/chrome-remote-desktop\n\n<span class=\"c\"># リブート時に消せるようにダウンロード先に/tmpを使う</span>\n<span class=\"nb\">cd</span> /tmp\n\n<span class=\"c\"># chromeのダウンロード</span>\nwget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb\n<span class=\"c\"># chromeのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> ./google-chrome-stable_current_amd64.deb\n\n<span class=\"c\"># remote desktopのダウンロード</span>\nwget https://dl.google.com/linux/direct/chrome-remote-desktop_current_amd64.deb\n<span class=\"c\"># remote desktopのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> ./chrome-remote-desktop_current_amd64.deb\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nインストール時、以下のように提案/推奨されるが、入れなくても大丈夫。<br />\n提案パッケージ:<br />\n  python-psutil-doc x11-xfs-utils<br />\n推奨パッケージ:<br />\n  xserver-xorg-video-dummy pipewire</p>\n</blockquote>\n\n<h2 id=\"chrome起動して初期設定googleにログイン\">chrome起動して初期設定&Googleにログイン</h2>\n<p>ローカル端末でchrome起動</p>\n<ul>\n  <li>既定のブラウザにするか、障害レポートを送信するかを選んでOK</li>\n  <li>「Chromeを独自にカスタマイズ」で「開始する」をクリック\n    <ul>\n      <li>あとはお好みで設定</li>\n    </ul>\n  </li>\n  <li>「あなたのChromeをいつでもどこでも」で「続行」をクリック\n    <ul>\n      <li>chromeへのログインで使用するGoogleアカウントにログイン</li>\n    </ul>\n  </li>\n  <li>リモートデスクトップを検索し、「Chromeリモートデスクトップ」を開く\n    <ul>\n      <li><a href=\"https://remotedesktop.google.com/?hl=ja&pli=1\" target=\"_blank\">https://remotedesktop.google.com/?hl=ja&pli=1</a></li>\n    </ul>\n  </li>\n  <li>「パソコンにアクセス」をクリック</li>\n  <li>「リモートアクセスの設定」の「ONにする」ボタンをクリック</li>\n  <li>「名前の設定」で名前を設定して「次へ」</li>\n  <li>「PINの入力」で設定するPINを2回入力して「起動」</li>\n  <li>\n    <p>パスワード入力を求められるのでパスワード入力</p>\n  </li>\n  <li>ローカル端末でログアウト\n    <blockquote>\n      <p>[!WARNING]\nローカル端末でログインしたままだとリモートデスクトップがつながっても画面表示されない</p>\n    </blockquote>\n  </li>\n</ul>\n\n<h2 id=\"window-pc側から接続\">Window PC側から接続</h2>\n<p>Windows PCでリモートデスクトップアプリを起動し、Ubuntuマシンに接続する<br />\nセッションの選択ではUbunto on Xorg または Ubuntuを選択(たぶんどっちも同じ)</p>\n\n<h3 id=\"おまじない1\">おまじない1</h3>\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。<br />\nこのダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下の内容で作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n<p>参考: <a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></p>\n\n<h3 id=\"おまじない2\">おまじない2</h3>\n<p>接続時、毎回セッションの選択をするのは面倒なので、自動で選択できるようにしようとしたが、<br />\nこれをやるとローカル端末でログインできなくなるのでやめておく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n参考までに手順を記載しておく<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.chrome-remote-desktop-session</code>を以下の内容で作成する</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>exec /etc/X11/Xsession 'env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu'\n</code></pre></div>  </div>\n  <p>env以下は使用するセッションに合わせて変更すること。<br />\n(<code class=\"language-plaintext highlighter-rouge\">/usr/share/xsessions/≪セッション名≫.desktop</code>の<code class=\"language-plaintext highlighter-rouge\">Exec</code>行の内容)</p>\n</blockquote>\n\n<h1 id=\"使いそうなプログラムのインストールと使わないプログラムのアンインストール\">使いそうなプログラムのインストールと使わないプログラムのアンインストール</h1>\n\n<h2 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h2>\n\n<p>ま、使うでしょ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweaks \n</code></pre></div></div>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>使うツールがあったら残してちょ。</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h2 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"お好みで-1\">お好みで</h2>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>ディレクトリにコピるだけ。<br />\n下では全部コピってるけど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.0.0/UDEVGothic_v1.0.0.zip \nunzip UDEVGothic_v1.0.0.zip \n<span class=\"nb\">mkdir</span> ~/.fonts\n<span class=\"nb\">cp </span>UDEVGothic_v1.0.0/<span class=\"k\">*</span>.ttf ~/.fonts/\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。<br />\nさっきフォントのインストールに使った端末ウィンドウを使うと\nエラーで端末ウィンドウが落ちるかもしれないんで一旦終了して新しいウィンドウで。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<h1 id=\"その他設定\">その他設定</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>~/.bashrcに以下を追記。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"c\"># Ubuntu22.04だとwaylandになるらしい</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"wayland\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vi\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># # venvの仮想環境名を表示するための設定</span>\n    <span class=\"c\"># show_virtual_env() {</span>\n    <span class=\"c\">#   if [ -n \"$VIRTUAL_ENV\" ]; then</span>\n    <span class=\"c\">#     echo \"($(basename $VIRTUAL_ENV))\"</span>\n    <span class=\"c\">#   fi</span>\n    <span class=\"c\"># }</span>\n    <span class=\"c\"># PS1='$(show_virtual_env)'$PS1</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nUbuntu20.04とちょっとキーが変更されてる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-home <span class=\"nb\">false \n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"ファイルnautilusのデフォルト動作変更\">ファイル(nautilus)のデフォルト動作変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アドレスバーをテキスト形式にする</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences always-use-location-entry <span class=\"nb\">true</span> \n\n<span class=\"c\"># 詳細表示をデフォルトに</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences default-folder-viewer <span class=\"s1\">'list-view'</span> \n\n<span class=\"c\"># 隠しファイルを表示する</span>\n<span class=\"c\"># 隠しファイルの表示はちょっと場所が違う</span>\ngsettings <span class=\"nb\">set </span>org.gtk.Settings.FileChooser show-hidden <span class=\"nb\">true</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアの更新(update-manager)を起動\n    <ul>\n      <li>更新のチェックが始まった場合はちょっと待つ</li>\n      <li>設定…をクリック\n        <ul>\n          <li>アップデートタブを選択</li>\n          <li>アップデートの自動確認を「なし」に変更</li>\n          <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n          <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n          <li>閉じるをクリック</li>\n        </ul>\n      </li>\n      <li>OKで終了</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Chromeリモートデスクトップ環境ではWindowsで設定したのが有効になっているので必要ないが、\nローカル端末で使用する場合に備えて入れ替えを設定しておく。<br />\n方法は、<code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code> に <code class=\"language-plaintext highlighter-rouge\">XKBOPTIONS=\"ctrl:nocaps\"</code> を追加。<br />\n設定を有効にするにはリブート必要。</p>\n\n<p>参考:<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a><br />\nリンク先は「Ubuntu 20.04/18.04 LTS」となっているが、Ubuntu22.04でも同じらしい。</p>\n\n<h3 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h3>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h1 id=\"sambaのインストール\">sambaのインストール</h1>\n\n<p>ツール本体のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加<br />\n作らなかったワークディレクトリの部分は削除してね。<br />\n他にも共有したいディレクトリがあったら追加してちょ。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">force group</code>に設定するグループは存在するグループ(またはユーザ)名に変更してください。</p>\n\n<p>ここではちょっと見たいファイルがあったのでoptも共有してます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"nfsのインストール\">NFSのインストール</h1>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/exports</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n<span class=\"c\"># abcの下にリモートのファイルが見えたらOK</span>\n</code></pre></div></div>\n\n<h1 id=\"pyenvのインストール\">pyenvのインストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<h3 id=\"必要なモジュールをインストール\">必要なモジュールをインストール</h3>\n<p>インストールに必要なモジュールをインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div></div>\n\n<h3 id=\"bluetoothを使用する場合\">bluetoothを使用する場合</h3>\n<p>bluetoothを使用する場合は以下も必要</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>pyenvの設定のため、~/.bashrc に以下を追加。 <br />\n(上記手順で記載済み。念のため再掲しておく)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h2 id=\"sudoでpyenv環境を実行するように設定する\">sudoでpyenv環境を実行するように設定する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo</code>でpythonを実行すると、pyenvの設定に関係なくsystemのpythonが実行されてしまいます。<br />\nこれを防ぐためには、<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers</code>の<code class=\"language-plaintext highlighter-rouge\">Defaults secure_path</code>に以下のpathを追加します。</p>\n\n<ul>\n  <li>«pyenvインストール先»/plugins/pyenv-virtualenv/shims:</li>\n  <li>«pyenvインストール先»shims:</li>\n  <li>«pyenvインストール先»/bin:</li>\n</ul>\n\n<p>具体的には以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 変更前\nDefaults  secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n    ↓\n# 変更後\nDefaults  secure_path=\"/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n</code></pre></div></div>\n<ul>\n  <li></li>\n</ul>\n\n<h2 id=\"pythonのインストール-以降\">pythonのインストール 以降</h2>\n\n<p>参考: <a href=\"http://localhost:4000/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi で Text To Speech(音声合成)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi で Text To Speech(音声合成)</h1>\n      <p>Raspberry Pi でpythonを使用してText To Speech(音声合成)を試す</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi でText To Speech(音声合成)をofflineで実行することを試してみます。<br />\n(初回実行時は辞書データをダウンロードするのでインターネットにつながっている必要があります)</p>\n\n<blockquote>\n  <p>[!NOTE]\n環境変数 DISPLAY が設定されている場合、変数が示すマシンでXサーバが実行されている必要があります。<br />\n実行されていない場合は、オーディオ再生の際、コマンドがハングアップします、<br />\nその際は対象マシンでXサーバを実行するか、<code class=\"language-plaintext highlighter-rouge\">unset DISPLAY</code>で環境変数を削除してください。</p>\n</blockquote>\n\n<h1 id=\"スピーカの準備\">スピーカの準備</h1>\n<p>Raspberry Pi5ではオーディオジャックがなくなったので、\n将来のことを考えてUSBスピーカ(USBヘッドセット)を使用することにします。</p>\n\n<h2 id=\"スピーカの接続\">スピーカの接続</h2>\n\n<p>まず、USBスピーカをUSBポートに接続し、スピーカが認識されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>lsusb\nBus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub\nBus 001 Device 003: ID 0c76:161f JMTek, LLC. USB PnP Audio Device   ← これ\nBus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub\nBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub\n</code></pre></div></div>\n\n<h2 id=\"カード番号とデバイス番号の確認\">カード番号とデバイス番号の確認</h2>\n<p>使用するカード番号/デバイス番号を確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay <span class=\"nt\">-l</span>\n<span class=\"k\">****</span> ハードウェアデバイス PLAYBACK のリスト <span class=\"k\">****</span>\nカード 0: vc4hdmi0 <span class=\"o\">[</span>vc4-hdmi-0], デバイス 0: MAI PCM i2s-hifi-0 <span class=\"o\">[</span>MAI PCM i2s-hifi-0]\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\nカード 1: vc4hdmi1 <span class=\"o\">[</span>vc4-hdmi-1], デバイス 0: MAI PCM i2s-hifi-0 <span class=\"o\">[</span>MAI PCM i2s-hifi-0]\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\nカード 2: Headphones <span class=\"o\">[</span>bcm2835 Headphones], デバイス 0: bcm2835 Headphones <span class=\"o\">[</span>bcm2835 Headphones]\n  サブデバイス: 8/8\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\n  サブデバイス <span class=\"c\">#1: subdevice #1</span>\n  サブデバイス <span class=\"c\">#2: subdevice #2</span>\n  サブデバイス <span class=\"c\">#3: subdevice #3</span>\n  サブデバイス <span class=\"c\">#4: subdevice #4</span>\n  サブデバイス <span class=\"c\">#5: subdevice #5</span>\n  サブデバイス <span class=\"c\">#6: subdevice #6</span>\n  サブデバイス <span class=\"c\">#7: subdevice #7</span>\nカード 3: Device <span class=\"o\">[</span>USB PnP Audio Device], デバイス 0: USB Audio <span class=\"o\">[</span>USB Audio]         ← これ\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\n</code></pre></div></div>\n\n<p>カード番号が 3 または ‘Device’、デバイス番号が0であることが分かります</p>\n\n<h2 id=\"テスト再生\">テスト再生</h2>\n<p>テスト再生してみます。<br />\n-D オプションのパラメータは、<code class=\"language-plaintext highlighter-rouge\">plughw:</code>に続けて上で調べたカード番号、<code class=\"language-plaintext highlighter-rouge\">,</code>を挟んでデバイス番号を指定します。<br />\nwavファイルは何でもかまいません。下記はデフォルトでインストール済みのファイルなのでそれを使いました。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay <span class=\"nt\">-D</span> plughw:Device,0 /usr/share/sounds/alsa/Front_Center.wav\n再生中 WAVE <span class=\"s1\">'/usr/share/sounds/alsa/Front_Center.wav'</span> : Signed 16 bit Little Endian, レート 48000 Hz, モノラル\n</code></pre></div></div>\n\n<h2 id=\"デフォルトのオーディオデバイスの設定\">デフォルトのオーディオデバイスの設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">sudo raspi-config</code> を実行し、以下の順で選択します。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">1 System Options</code>\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">S2 Audio</code>\n        <ul>\n          <li>使用するオーディオデバイス( <code class=\"language-plaintext highlighter-rouge\">71 USB PnP Audio Device</code>など )</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">Finish</code>で終了</li>\n</ul>\n\n<p>デフォルト設定が変更されたことを確認するため、上記テスト再生のコマンドから-Dオプションを削除して再生されることを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay /usr/share/sounds/alsa/Front_Center.wav\n再生中 WAVE <span class=\"s1\">'/usr/share/sounds/alsa/Front_Center.wav'</span> : Signed 16 bit Little Endian, レート 48000 Hz, モノラル\n</code></pre></div></div>\n\n<h1 id=\"python仮想環境の作成とモジュールのインストール\">python仮想環境の作成とモジュールのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openjtalk\n<span class=\"nb\">cd</span> /work/openjtalk\n\npyenv virtualenv 3.11.9 openjtalk\npyenv <span class=\"nb\">local </span>openjtalk \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># pyopenjtalkのインストールに必要なのでcmakeをインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n\n<span class=\"c\"># pyopenjtalkのインストールbuildが実行されるので時間がかかる</span>\npip <span class=\"nb\">install </span>pyopenjtalk\n\n<span class=\"c\"># wavファイルの保存に使用するのでscipyもインストール</span>\npip <span class=\"nb\">install </span>scipy\n\n<span class=\"c\"># marineを使う場合は以下も実行</span>\npip <span class=\"nb\">install </span>pyopenjtalk[marine]\n</code></pre></div></div>\n\n<h1 id=\"pyopenjtalk-を実行してみる\">pyopenjtalk を実行してみる</h1>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  talk_test1.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">pyopenjtalk</span>\n<span class=\"kn\">from</span> <span class=\"nn\">scipy.io</span> <span class=\"kn\">import</span> <span class=\"n\">wavfile</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"c1\"># marineを使用する場合はrun_marineをTrueにする\n</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">sr</span> <span class=\"o\">=</span> <span class=\"n\">pyopenjtalk</span><span class=\"p\">.</span><span class=\"n\">tts</span><span class=\"p\">(</span><span class=\"s\">\"おめでとうございます\"</span><span class=\"p\">,</span> <span class=\"n\">run_marine</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n<span class=\"n\">wavfile</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">\"test1.wav\"</span><span class=\"p\">,</span> <span class=\"n\">sr</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">int16</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python talk_test1.py\n</code></pre></div></div>\n\n<p>再生します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>aplay test1.wav\n</code></pre></div></div>\n\n<p>スピーカーから「おめでとうございます」と聞こえたら成功です。おめでとうございます。</p>\n\n<h1 id=\"pythonからオーディオ再生する\">pythonからオーディオ再生する</h1>\n\n<p>オーディオ再生のためのモジュールは色々ありますが、\n下の直接再生に使用するにはnumpyデータを入力できることが必須となるので\nsimpleaudioを使用してみます。</p>\n\n<p>モジュールをインストールします。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># simpleaudioのインストールに必要なパッケージのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libasound2-dev\n\n<span class=\"c\"># インストール</span>\npip <span class=\"nb\">install </span>simpleaudio\n</code></pre></div></div>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  play_test1.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">simpleaudio</span>\n\n<span class=\"n\">wav_obj</span> <span class=\"o\">=</span> <span class=\"n\">simpleaudio</span><span class=\"p\">.</span><span class=\"n\">WaveObject</span><span class=\"p\">.</span><span class=\"n\">from_wave_file</span><span class=\"p\">(</span><span class=\"s\">\"test1.wav\"</span><span class=\"p\">)</span>\n<span class=\"n\">play_obj</span> <span class=\"o\">=</span> <span class=\"n\">wav_obj</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n<span class=\"n\">play_obj</span><span class=\"p\">.</span><span class=\"n\">wait_done</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python play_test1.py\n</code></pre></div></div>\n<h1 id=\"pyopenjtalkで作成した音声を直接再生する\">pyopenjtalkで作成した音声を直接再生する</h1>\n\n<p>逐一wavファイルを作成するのは面倒なので、合成したらすぐ再生するようにしてみます。</p>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  talk_test2.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">pyopenjtalk</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">simpleaudio</span>\n\n<span class=\"c1\"># marineを使用する場合はrun_marineをTrueにする\n</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">sr</span> <span class=\"o\">=</span> <span class=\"n\">pyopenjtalk</span><span class=\"p\">.</span><span class=\"n\">tts</span><span class=\"p\">(</span><span class=\"s\">\"直接再生します\"</span><span class=\"p\">,</span> <span class=\"n\">run_marine</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n<span class=\"c1\"># x : waveform\n# sr: sampling rate\n</span>\n<span class=\"n\">wav_obj</span> <span class=\"o\">=</span> <span class=\"n\">simpleaudio</span><span class=\"p\">.</span><span class=\"n\">WaveObject</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">int16</span><span class=\"p\">),</span> <span class=\"n\">num_channels</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">bytes_per_sample</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">sample_rate</span><span class=\"o\">=</span><span class=\"n\">sr</span><span class=\"p\">)</span>\n<span class=\"n\">play_obj</span> <span class=\"o\">=</span> <span class=\"n\">wav_obj</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n<span class=\"n\">play_obj</span><span class=\"p\">.</span><span class=\"n\">wait_done</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python talk_test2.py\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(Bookworm)のインストール(Raspberry Pi Imager)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(Bookworm)のインストール(Raspberry Pi Imager)</h1>\n      <p>Raspberry Pi OS(bookworm)のRaspberry Pi Imagerを使用したインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>RaspberrypiOSがBookwormになったので、インストール方法のメモ。<br />\n基本的にBullseyeのときと変わらないけど、ちょっと変わったところもあるので。<br />\n<a href=\"/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Bullseyeのときの手順メモ</a>も参照してください。</p>\n\n<h1 id=\"sdカードへの書き込み\">SDカードへの書き込み</h1>\n<p>Raspberry Pi Imager で書き込み。<br />\n使い方はあちこちに書いてあるけど、例えばこちら。</p>\n<ul>\n  <li><a href=\"https://qiita.com/mmake/items/576a2f60dffcd9291da3/\" target=\"_blank\">Raspberry Pi Imager のインストールと使い方</a></li>\n</ul>\n\n<p>バージョン変わると微妙に手順が変わったりするので、最新情報はぐぐってちょ。</p>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n<blockquote>\n  <p>[!NOTE]\n下記の変更をイッパツで行うスクリプトは以下。<br />\nWindowsのコマンドプロンプトで実行すると想定。  Windows版python必要。<br />\nそれぞれの<code class=\"language-plaintext highlighter-rouge\">F=</code>の部分を対象のドライブレターに変更する。</p>\n\n  <ul>\n    <li>UARTにUARTコネクタを使用する場合はこちら\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import re;F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">onfig.txt';a=open(F).read();a=re.sub(r'</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">(?!.*</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">)', '[pi5]</span><span class=\"se\">\\n</span><span class=\"s2\">dtparam=uart0</span><span class=\"se\">\\n\\n</span><span class=\"s2\">[all]</span><span class=\"se\">\\n</span><span class=\"s2\">enable_uart=1</span><span class=\"se\">\\n</span><span class=\"s2\">', a, flags=re.DOTALL);open(F, 'w').write(a)\"</span>\npython <span class=\"nt\">-c</span> <span class=\"s2\">\"F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">mdline.txt';a=open(F).read();a=a.replace(' quiet', '').replace(' splash', '').replace(' plymouth.ignore-serial-consoles', '')+' ipv6.disable=1';open(F, 'w').write(a)\"</span>\n</code></pre></div>      </div>\n    </li>\n    <li>UARTに40pinヘッダのpin8/10(GPIOs 14 & 15)を使用する場合はこちら\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import re;F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">onfig.txt';a=open(F).read();a=re.sub(r'</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">(?!.*</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">)', '[pi5]</span><span class=\"se\">\\n</span><span class=\"s2\">dtparam=uart0_console</span><span class=\"se\">\\n\\n</span><span class=\"s2\">[all]</span><span class=\"se\">\\n</span><span class=\"s2\">enable_uart=1</span><span class=\"se\">\\n</span><span class=\"s2\">', a, flags=re.DOTALL);open(F, 'w').write(a)\"</span>\npython <span class=\"nt\">-c</span> <span class=\"s2\">\"F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">mdline.txt';a=open(F).read();a=a.replace(' quiet', '').replace(' splash', '').replace(' plymouth.ignore-serial-consoles', '')+' ipv6.disable=1';open(F, 'w').write(a)\"</span>\n</code></pre></div>      </div>\n    </li>\n  </ul>\n</blockquote>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行を以下に変更</p>\n\n<ul>\n  <li>UARTにUARTコネクタを使用する場合はこちら</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[pi5]\ndtparam=uart0\n\n[all]\nenable_uart=1\n</code></pre></div></div>\n\n<ul>\n  <li>UARTに40pinヘッダのpin8/10(GPIOs 14 & 15)を使用する場合はこちら</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[pi5]\ndtparam=uart0_console\n\n[all]\nenable_uart=1\n</code></pre></div></div>\n\n<h2 id=\"ipv6の無効化\">IPv6の無効化</h2>\n<p>IPv6を無効化しておきたいときは、\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する。<br />\nこのファイルは1行で書かないといけないので、改行してはいけない。</p>\n\n<h2 id=\"ブートログの表示\">ブートログの表示</h2>\n\n<p>ブートログが見えないと不安な人は、<br />\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> から <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code>\nを削除しておくとよい。</p>\n<blockquote>\n  <p>[!NOTE]\nLITE版では<code class=\"language-plaintext highlighter-rouge\">quiet</code>を削除(それ以外は指定されていないので)</p>\n</blockquote>\n\n<h1 id=\"最初の起動\">最初の起動</h1>\n<p>書き込んだSDカードをRaspberry Piに挿入して電源ON。<br />\nごちょごちょと設定したあと、起動する(途中2回ほどrebootしてるらしい)</p>\n\n<h1 id=\"お約束\">お約束</h1>\n\n<p>ソフト類を最新版にする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n<span class=\"nb\">sudo </span>reboot \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <h4 id=\"ウィンドウマネージャをopenboxに変更したい場合\">ウィンドウマネージャをOpenboxに変更したい場合</h4>\n  <p>VNCに不具合がるなどの理由で以前のバージョンと同じX11ベースのOpenboxに変更したい場合は以下の手順で変更する。<br />\nちなみにOpenboxに変更したい場合は以下のコマンドで変更できる。<br />\nVNCを有効化した後にウィンドウマネージャを変更すると動作が不安定になることがあるので、VNCを有効化する前に変更するのがベター。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config nonint do_wayland W1\n<span class=\"nb\">sudo </span>reboot \n</code></pre></div>  </div>\n\n  <p>VNC有効化後、以下のコマンドでデフォルトのウィンドウマネージャ(wayfire)が無効になっていることを確認する。<br />\nなにも表示されなければOK</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pgrep wayfire\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"お好みで\">お好みで</h1>\n\n<p>その他お好み設定は\n<a href=\"/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</a>\nと同じ。<br />\nめんどくさいのでスクリプトを実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.githubusercontent.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c/raw/pi_setup1.sh\nbash pi_setup1.sh \n<span class=\"c\"># 途中sambaのパスワード設定がある  </span>\n<span class=\"nb\">sudo </span>reboot \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nIpV6無効の環境でwayfireでVNCを有効にする場合、VNCを有効化する前に\n以下のコマンドでwayfireでIPv4を使用するように設定する必要がある。<br />\nこの処理は上の<code class=\"language-plaintext highlighter-rouge\">pi_setup1.sh</code>の処理に含まれている。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /etc/wayvnc/config /etc/wayvnc/config.org\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s/</span><span class=\"se\">\\:\\:</span><span class=\"s2\">/0</span><span class=\"se\">\\.</span><span class=\"s2\">0</span><span class=\"se\">\\.</span><span class=\"s2\">0</span><span class=\"se\">\\.</span><span class=\"s2\">0/g\"</span> /etc/wayvnc/config\n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">/etc/wayvnc/config</code>の2行目の<code class=\"language-plaintext highlighter-rouge\">address=::</code>を<code class=\"language-plaintext highlighter-rouge\">address=0.0.0.0</code>に変更している。</p>\n</blockquote>\n\n<h1 id=\"pyenvのインストール\">pyenvのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<p>ここで一旦ログアウト&再ログイン</p>\n\n<h1 id=\"pythonのインストール\">pythonのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.11.9\npyenv shell 3.11.9 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\npyenv shell <span class=\"nt\">--unset</span> \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSBデバイスを使う(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSBデバイスを使う(その1)</h1>\n      <p>WSLでUSBデバイスを使う(その1:準備&USB-Serial編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLでUSBを使う方法。あちこちに情報があるけど、なんとなく自分なりにまとめておく。<br />\n<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb\" target=\"_blank\">本家の説明</a></p>\n\n<p>ますは、準備とLinuxカーネルのビルドが必要ないUSB-Serialデバイスから。</p>\n\n<h1 id=\"wsl側の準備\">WSL側の準備</h1>\n\n<h2 id=\"wslのバージョン\">WSLのバージョン</h2>\n<p>使用したWSLのバージョンは以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wsl <span class=\"nt\">--version</span>\n\nWSL バージョン: 2.2.4.0\nカーネル バージョン: 5.15.153.1-2\nWSLg バージョン: 1.0.61\nMSRDC バージョン: 1.2.5326\nDirect3D バージョン: 1.611.1-81528511\nDXCore バージョン: 10.0.26091.1-240325-1447.ge-release\nWindows バージョン: 10.0.19045.4529\n</code></pre></div></div>\n\n<p>使用したディストリビューションは「Ubuntu 22.04 LTS」</p>\n\n<h2 id=\"wslディストリビューションでsystemdの有効化\">WSLディストリビューションでsystemdの有効化</h2>\n\n<blockquote>\n  <p>[!NOTE]\nインストールしたタイミングによっては既に有効化されているかも。</p>\n</blockquote>\n\n<p>USBのホットプラグ処理は systemd + udev がよしなに行ってくれるみたいなので、systemdを有効化しておく。<br />\n使用するディストリビューションを起動し、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下の設定を行う。</p>\n\n<p>デフォルト(古いデフォルト?)のSystemVinitだとバカチョンで動かなかった…udevサービス再起動とかやったら動いたけど。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdを有効にするか否かはディストリビューション毎の設定</p>\n</blockquote>\n\n<p>設定後、WSLをシャットダウン(コマンドプロンプト等から<code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行)し、<br />\n再度ディストリビューションを起動する。</p>\n\n<p>参考:<a href=\"https://qiita.com/curacao/items/fb9adaf1c097b1acd6a8\" target=\"_blank\">WSL2でsystemctlを使う方法</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdが動作しているか確認するには、<code class=\"language-plaintext highlighter-rouge\">systemctl is-system-running</code> を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">running</code>(起動中) <code class=\"language-plaintext highlighter-rouge\">degraded</code>(起動中だが失敗したサービスなどが存在) と表示されれば動作している。<br />\n<code class=\"language-plaintext highlighter-rouge\">offline</code> と表示されれば起動していない。<br />\nその他使い方についてはぐぐってちょ。</p>\n</blockquote>\n\n<h2 id=\"必要なパッケージをインストール\">必要なパッケージをインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic hwdata\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nlinux-tools-generic : usbipコマンド等が入る<br />\nhwdata : USB ID等のデータベースが入る<br />\nlinux-tools-generic インストールしたら自動でhwdata入るけど….<br />\n参考にしたサイトにこう書いてあったので。<br />\nlinux-tools-virtualと書いてあるサイトもあるけど、ubuntu 22.04だとchangelogとcopyrightしか違わないみたい。<br />\n </p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /usr/lib/linux-tools\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> 5.15.0-113-generic <span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあちこちに<code class=\"language-plaintext highlighter-rouge\">sudo update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20</code>\nでコマンドのバージョン管理を行う例が書かれているけど、なんとなくシンボリックリンクを張る方がしっくりするのでこっちにした。</p>\n\n  <p>本来、usbipを実行すると <code class=\"language-plaintext highlighter-rouge\">/usr/bin/usbip</code> が <code class=\"language-plaintext highlighter-rouge\">/usr/lib/linux-tools/≪カーネルバージョン≫/usbip</code><br />\nを起動してくれるらしいのだけど、WSL環境では≪カーネルバージョン≫がカスタマイズバージョンでうまく働かないので<br />\n/usr/lib/linux-tools/≪カーネルバージョン≫をインストールされているバージョンに飛ばしてやればいい。<br />\nカーネルバージョンが変更されたら動かなくなるけど、そのときは、新しいカーネルバージョン名のシンボリックリンクを作ってやればよい。<br />\nもちろん、linux-tools-genericのアップデートが必要か判断して、必要ならアップデートする。</p>\n</blockquote>\n\n<h1 id=\"windows側の準備\">windows側の準備</h1>\n<h2 id=\"usbipd-win-のインストール\">usbipd-win のインストール</h2>\n<p>まずはUSBをTCP/IP経由で接続させるためのツール、usbipd-win をwindowsにインストールする。<br />\nインストールするには、<a href=\"https://github.com/dorssel/usbipd-win/releases\" target=\"_blank\">ダウンロードページ</a>  から\n最新版(以下の手順で使用したのは4.2.0)のmsiファイルをダウンロードして実行するだけ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストール時PATHが変更されるので、既に開いているコマンドプロンプトorPowerShellは一旦閉じて再実行する。</p>\n</blockquote>\n\n<h1 id=\"usbデバイスの操作\">USBデバイスの操作</h1>\n<p>WSLで使用したいUSBデバイスはあらかじめPCに接続しておく。</p>\n\n<p>以下の処理はコマンドプロンプトorPowerShellで行う。<br />\nただし、bind/unbindサブコマンドは管理者権限が必要なので、管理者として開いたコマンドプロンプトorPowerShellで実行する。</p>\n\n<h2 id=\"接続したいデバイスのbusidを調べる\">接続したいデバイスのBusIDを調べる</h2>\n\n<p>以下のコマンドを実行する。<br />\n結果は例。今回は3-4のUSB Serial Converter を使う。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">list</span><span class=\"w\">\n</span><span class=\"err\">≪結果≫</span><span class=\"w\">\n</span><span class=\"n\">Connected:</span><span class=\"w\">\n</span><span class=\"nx\">BUSID</span><span class=\"w\">  </span><span class=\"nx\">VID:PID</span><span class=\"w\">    </span><span class=\"nx\">DEVICE</span><span class=\"w\">                                                        </span><span class=\"nx\">STATE</span><span class=\"w\">\n</span><span class=\"mi\">2</span><span class=\"nt\">-1</span><span class=\"w\">    </span><span class=\"mi\">1</span><span class=\"n\">f75:0918</span><span class=\"w\">  </span><span class=\"nx\">USB</span><span class=\"w\"> </span><span class=\"err\">大容量記憶装置</span><span class=\"w\">                                            </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span><span class=\"mi\">2</span><span class=\"nt\">-2</span><span class=\"w\">    </span><span class=\"mi\">056</span><span class=\"n\">e:700a</span><span class=\"w\">  </span><span class=\"nx\">Venus</span><span class=\"w\"> </span><span class=\"nx\">USB2.0</span><span class=\"w\"> </span><span class=\"nx\">Camera</span><span class=\"w\">                                           </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span><span class=\"mi\">3</span><span class=\"nt\">-4</span><span class=\"w\">    </span><span class=\"mi\">0403</span><span class=\"p\">:</span><span class=\"mi\">6001</span><span class=\"w\">  </span><span class=\"n\">USB</span><span class=\"w\"> </span><span class=\"nx\">Serial</span><span class=\"w\"> </span><span class=\"nx\">Converter</span><span class=\"w\">                                          </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>ここで表示されたWSLで使用したいUSBデバイスのBUSID(例えば3-4)を覚えておく。</p>\n\n<h2 id=\"デバイスを共有設定する\">デバイスを共有設定する</h2>\n\n<p>管理者として開いたコマンドプロンプトorPowerShellで以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">bind</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">        </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">usbipd: warning: USB filter 'USBPcap' is known to be incompatible with this software; 'bind --force' will be required.</code><br />\nと出た時は、一旦unbindして、–forceオプションを追加して実行<br />\n(うちのPCはWiresharkインストールしてUSBPcap入ってるからだろうなぁ…)</p>\n</blockquote>\n\n<p>実行後、<code class=\"language-plaintext highlighter-rouge\">usbipd list</code>を実行すると、対象デバイスのステータスが Shared または Shared (forced) になっている</p>\n\n<h2 id=\"ディストリビューションの起動\">ディストリビューションの起動</h2>\n\n<p>接続するためのWSLのディストリビューションを起動しておく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n起動してないと<code class=\"language-plaintext highlighter-rouge\">usbipd: error: There is no WSL 2 distribution running; keep a command prompt to a WSL 2 distribution open to leave it running.</code>とエラーになる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nこのとき、複数のディストリビューションが起動していると変なことが起こりそうなので(未確認)\n対象のディストリビューションだけ起動しておくのが良いと思う。</p>\n</blockquote>\n\n<h2 id=\"デバイスを接続する\">デバイスを接続する</h2>\n\n<p>bindしただけではまだWSL側からはUSBデバイスは見えない。</p>\n\n<h3 id=\"windows側から接続する場合\">Windows側から接続する場合</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">attach</span><span class=\"w\"> </span><span class=\"nt\">--wsl</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">             </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"linux側から接続する場合\">linux側から接続する場合</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip attach <span class=\"nt\">-r</span> 172.20.160.1 <span class=\"nt\">-b</span> 3-4    <span class=\"c\"># 172.20.160.1 はWindows側のIPアドレス</span>\n                                            <span class=\"c\"># 3-4は接続するデバイスのBusID</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWindows側のIPアドレスはコマンドプロンプトorPowerShellから<code class=\"language-plaintext highlighter-rouge\">ipconfig</code>コマンドを実行し、<br />\n<code class=\"language-plaintext highlighter-rouge\">Ethernet adapter vEthernet (WSL):</code> に表示されているIPアドレスを使用する。<br />\nでもWSLがミラーネットワークモードになってたらどうなるんだろう???</p>\n</blockquote>\n\n<h2 id=\"デバイス接続を確認する\">デバイス接続を確認する</h2>\n<p>linux側で以下を実行し、接続されたデバイスが表示されていることを確認する。 \n以下のように接続したデバイスが表示されていればOK<br />\n(以下では2行目のFT232 Serial (UART) IC)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n≪結果≫\nBus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub\nBus 001 Device 003: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial <span class=\"o\">(</span>UART<span class=\"o\">)</span> IC\nBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub<span class=\"sb\">```</span>\n</code></pre></div></div>\n\n<h1 id=\"usb-serialデバイスを接続\">USB-Serialデバイスを接続</h1>\n<p>上記操作で接続したUSBデバイスがUSB-Serialデバイス(上記の例では FT232 Serial (UART) IC) であれば、\n<code class=\"language-plaintext highlighter-rouge\">/dev/ttyUSBx</code>(xは数字。通常0から順に割り当てられる)に割り当てられる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> <span class=\"nt\">-la</span> /dev/ttyUSB<span class=\"k\">*</span>\n≪結果≫\ncrw-rw---- 1 root dialout 188, 0  7月  3 11:02 /dev/ttyUSB0\n</code></pre></div></div>\n\n<p>一応、ログを確認してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dmesg\n≪結果≫\n・・・・・・\n<span class=\"o\">[</span>  189.418189] vhci_hcd vhci_hcd.0: pdev<span class=\"o\">(</span>0<span class=\"o\">)</span> rhport<span class=\"o\">(</span>0<span class=\"o\">)</span> sockfd<span class=\"o\">(</span>3<span class=\"o\">)</span>\n<span class=\"o\">[</span>  189.418196] vhci_hcd vhci_hcd.0: devid<span class=\"o\">(</span>196612<span class=\"o\">)</span> speed<span class=\"o\">(</span>2<span class=\"o\">)</span> speed_str<span class=\"o\">(</span>full-speed<span class=\"o\">)</span>\n<span class=\"o\">[</span>  189.418249] vhci_hcd vhci_hcd.0: Device attached\n<span class=\"o\">[</span>  189.690366] vhci_hcd: vhci_device speed not <span class=\"nb\">set</span>\n<span class=\"o\">[</span>  189.760405] usb 1-1: new full-speed USB device number 2 using vhci_hcd\n<span class=\"o\">[</span>  189.840475] vhci_hcd: vhci_device speed not <span class=\"nb\">set</span>\n<span class=\"o\">[</span>  189.910358] usb 1-1: SetAddress Request <span class=\"o\">(</span>2<span class=\"o\">)</span> to port 0\n<span class=\"o\">[</span>  190.135906] usb 1-1: New USB device found, <span class=\"nv\">idVendor</span><span class=\"o\">=</span>0403, <span class=\"nv\">idProduct</span><span class=\"o\">=</span>6001, <span class=\"nv\">bcdDevice</span><span class=\"o\">=</span> 6.00\n<span class=\"o\">[</span>  190.135918] usb 1-1: New USB device strings: <span class=\"nv\">Mfr</span><span class=\"o\">=</span>1, <span class=\"nv\">Product</span><span class=\"o\">=</span>2, <span class=\"nv\">SerialNumber</span><span class=\"o\">=</span>3\n<span class=\"o\">[</span>  190.135921] usb 1-1: Product: FT232R USB UART\n<span class=\"o\">[</span>  190.135923] usb 1-1: Manufacturer: FTDI\n<span class=\"o\">[</span>  190.135924] usb 1-1: SerialNumber: A50285BI\n<span class=\"o\">[</span>  190.511832] usbcore: registered new interface driver ftdi_sio\n<span class=\"o\">[</span>  190.511852] usbserial: USB Serial support registered <span class=\"k\">for </span>FTDI USB Serial Device\n<span class=\"o\">[</span>  190.511881] ftdi_sio 1-1:1.0: FTDI USB Serial Device converter detected\n<span class=\"o\">[</span>  190.511904] usb 1-1: Detected FT232RL\n<span class=\"o\">[</span>  190.521353] usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB0       ← /dev/ttyUSB0が割り当てられたことが分かる\n</code></pre></div></div>\n\n<p>デフォルトで使用できるUSB-Serialデバイスは、\nSilicon Labs社製 CP210x、FTDI社製シリアルコンバータ(FT232)、CH34x(安い中国製Arduinoで使われているらしい)らしい。</p>\n\n<p>/dev/ttyUSBxが割り当てられていない場合は、対応しているUSB-Serialデバイスか、systemdが有効になっているか、等を確認してください。</p>\n\n<blockquote>\n  <p>[!NOTE]\n参考:<a href=\"https://another.maple4ever.net/archives/3221/?fbclid=IwZXh0bgNhZW0CMTAAAR2mnOe2c5FmYg3ig1IQbB1r4Y3t43MLJyqvzAx6tyjuiWCjETjj_x9Rkd0_aem_EpK6sQQOwszToANXZLsfiQ\" target=\"_blank\">Windows WSL2 の Ubuntu 22.04 上から USB-UART 経由で M5Stack に書き込みする</a><br />\n上記サイトではudevルールをplatform.ioのサイトから拝借してきているが、上記の製品なら持ってこなくても可。<br />\n互換品とかでうまく認識しないときは試してみると動くかも(試してないので無責任発言)。</p>\n</blockquote>\n\n<h2 id=\"シリアルポートを使ってみる\">シリアルポートを使ってみる</h2>\n\n<p>シリアルポートを使うツールは色々あると思うけど、とりあえず動いているか確認するならこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>pyserial-miniterm <span class=\"nt\">--parity</span> N /dev/ttyUSB0 115200\n</code></pre></div></div>\n\n<p>終了するにはCTRL+]を入力する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nsudoなしで実行するには、自分のアカウントにdialoutグループを追加すればよい。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> dialout\n</code></pre></div>  </div>\n  <p>一旦ログアウトして再ログイン必要。</p>\n</blockquote>\n\n<h2 id=\"デバイスを接続解除する\">デバイスを接続解除する</h2>\n\n<p>WSLをシャットダウンしたら(ディストリビューションのシャットダウンではなくWSL全体)接続解除されるけど、\n手動で接続解除するには以下のコマンドを実行する。</p>\n\n<h3 id=\"windows側から接続解除する場合\">Windows側から接続解除する場合</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\">  </span><span class=\"nx\">detach</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">              </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"linux側から接続解除する場合\">linux側から接続解除する場合</h3>\n<p>linuxから解除するには、まずポート番号を確認する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip port\n≪結果≫\nImported USB devices\n<span class=\"o\">====================</span>\nPort 00: <Port <span class=\"k\">in </span>Use> at Full Speed<span class=\"o\">(</span>12Mbps<span class=\"o\">)</span>\n       Future Technology Devices International, Ltd : FT232 Serial <span class=\"o\">(</span>UART<span class=\"o\">)</span> IC <span class=\"o\">(</span>0403:6001<span class=\"o\">)</span>\n       1-1 -> usbip://172.20.160.1:3240/3-4       ← ホストアドレス\n           -> remote bus/dev 003/004              ← BusID\n           \n</code></pre></div></div>\n\n<p>上記の例ではポート番号は00なので、これをportオプションに指定して以下のように実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip detach <span class=\"nt\">--port</span> 00\n</code></pre></div></div>\n\n<h2 id=\"デバイスを共有解除する\">デバイスを共有解除する</h2>\n\n<p>USBデバイスを共有解除するには、管理者として開いたコマンドプロンプトorPowerShellで以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">unbind</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">           </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nデバイスの共有解除しなければ、PCを再起動しても共有設定されたままになる。<br />\nただし、使用しているUSBポートに別のUSBデバイスを挿入すると共有解除されるが、再度同じUSBデバイスを挿入すれば共有設定される。<br />\n何言ってるか分からんと思うけど、USBデバイス挿抜してみて確かめてみて。</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLのカーネルをビルドする</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLのカーネルをビルドする</h1>\n      <p>WSLのカーネルをビルドする手順(Docker使用)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLでUSBストレージ(USBメモリなど)を使う方法を書こうと手順をまとめている間に、カーネル v6.6.36.3 がリリースされてしまいました。<br />\nこのバージョンは自前でビルドしなくてもUSBストレージ関連のドライバが入っています(Builtinモジュールではなくロードモジュールとして)。<br />\nで、バイナリリリースされてしまえば何もしなくてもUSBストレージが使えるようになる(ハズ)ですが、\n今日の段階はまだバイナリリリースされてないので自前でビルドしてみることにしました。<br />\n以下はその時のメモ。<br />\nで、手順は以下のサイトのDockerを使用して開発環境を構築する方法を <del>パクった</del>  参考にしました。<br />\n(もともとカーネル差し替えずにドライバ組み込む手順を調べてて参考にしたサイト)</p>\n\n<p>参照:<a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">カーネルモジュールのビルドと使用</a></p>\n\n<h1 id=\"準備の準備\">準備の準備</h1>\n\n<h2 id=\"wslディストリビューションでsystemdの有効化\">WSLディストリビューションでsystemdの有効化</h2>\n\n<p>systemdの方がDockerのサービスの操作とかやりやすい(情報が多い?)のでsystemdを有効化しておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストールしたタイミングによっては既に有効化されているかも。</p>\n</blockquote>\n\n<p> \n使用するディストリビューションを起動し、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下の設定を行います。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdを有効にするか否かはディストリビューション毎の設定</p>\n</blockquote>\n\n<p>設定後、WSLをシャットダウン(コマンドプロンプト等から<code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行)し、<br />\n再度ディストリビューションを起動します。</p>\n\n<p>参考:<a href=\"https://qiita.com/curacao/items/fb9adaf1c097b1acd6a8\" target=\"_blank\">WSL2でsystemctlを使う方法</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdが動作しているか確認するには、<code class=\"language-plaintext highlighter-rouge\">systemctl is-system-running</code> を実行します。<br />\n<code class=\"language-plaintext highlighter-rouge\">running</code>(起動中) <code class=\"language-plaintext highlighter-rouge\">degraded</code>(起動中だが失敗したサービスなどが存在) と表示されれば動作しています。<br />\n<code class=\"language-plaintext highlighter-rouge\">offline</code> と表示されれば起動していません。<br />\nその他使い方についてはぐぐってちょ。</p>\n</blockquote>\n\n<h1 id=\"linuxカーネルのビルド環境の構築\">Linuxカーネルのビルド環境の構築</h1>\n\n<h2 id=\"dockerの準備\">Dockerの準備</h2>\n\n<p>コンパイル環境はDockerコンテナを使用するので、Dockerをインストールします。<br />\nWindows上で使用できるDocker Desktop for Windowsでも良いのですが、ディストリビューション上にDockerをインストールすることにします。</p>\n\n<blockquote>\n  <p>[!NOTE]\nDocker Desktop for Windows を使用する場合は「WSL統合」でDockerを統合したディストリビューションで作業することになるようです。<br />\n試してないから分からんけど….</p>\n</blockquote>\n\n<p>インストール方法は先人の知恵を拝借→<a href=\"https://zenn.dev/thyt_lab/articles/fee07c278fcaa8\" target=\"_blank\">WSL(Ubuntu)にDocker環境を構築する</a><br />\nこのページの通りに実行すればDockerがインストールできます。</p>\n\n<p>また、Dockerをsudoなしで実行できるように、dockerグループを追加しておきます。<br />\n追加しなくてもsudoで実行できますが、作成されたファイルのオーナーがrootになってしまって面倒なのでおススメしません。</p>\n\n<p>以下、私が実際に行ったコマンドです。上記サイトの手順ほとんどそのままです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># apt keyring ファイル格納ディレクトリを作成</span>\n<span class=\"nb\">sudo install</span> <span class=\"nt\">-m</span> 0755 <span class=\"nt\">-d</span> /etc/apt/keyrings\n\n<span class=\"c\"># 鍵ファイルの作成&リード属性付与</span>\ncurl <span class=\"nt\">-fsSL</span> https://download.docker.com/linux/ubuntu/gpg | <span class=\"nb\">sudo </span>gpg <span class=\"nt\">--dearmor</span> <span class=\"nt\">-o</span> /etc/apt/keyrings/docker.gpg\n<span class=\"nb\">sudo chmod </span>a+r /etc/apt/keyrings/docker.gpg\n\n<span class=\"c\"># aptリポジトリの追加</span>\n<span class=\"nb\">echo</span>   <span class=\"s2\">\"deb [arch=\"</span><span class=\"si\">$(</span>dpkg <span class=\"nt\">--print-architecture</span><span class=\"si\">)</span><span class=\"s2\">\" signed-by=/etc/apt/keyrings/docker.gpg] </span><span class=\"se\">\\</span><span class=\"s2\">\n        https://download.docker.com/linux/ubuntu </span><span class=\"se\">\\</span><span class=\"s2\">\n        \"</span><span class=\"si\">$(</span><span class=\"nb\">.</span> /etc/os-release <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"s2\">\"</span><span class=\"nv\">$VERSION_CODENAME</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"s2\">\" stable\"</span> <span class=\"se\">\\</span>\n        | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/docker.list\n\n<span class=\"c\"># 追加したリポジトリも含めてaptデータベースの更新</span>\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># Dockerのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n\n<span class=\"c\"># 自身にdockerグループを追加</span>\n<span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> docker\n</code></pre></div></div>\n\n<p>dockerグループの追加を有効にするため、<strong>ここで一旦ログアウトして再ログイン</strong></p>\n\n<p>dockerグループが追加されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">groups</span>\n</code></pre></div></div>\n\n<p>以下のようにdockerグループが追加されていればOK。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XXXX adm cdrom <span class=\"nb\">sudo </span>dip plugdev lxd docker\n</code></pre></div></div>\n\n<h3 id=\"dockerのテスト\">Dockerのテスト</h3>\n\n<p>Dockerが正常にインストールできたか確認するため、hello-worldを実行します。<br />\n実行後、コンテナを削除するように<code class=\"language-plaintext highlighter-rouge\">--rm</code>オプションを指定。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">--rm</span> hello-world\n</code></pre></div></div>\n\n<p>以下のように表示されればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・・\nHello from Docker!\nThis message shows that your installation appears to be working correctly.\n・・・・\n</code></pre></div></div>\n\n<p>使用したhello-worldイメージはもう使わないので削除しておきます。</p>\n\n<p>まずコンテナが残ってないか確認します。<br />\n<code class=\"language-plaintext highlighter-rouge\">-a</code>をつけるのを忘れずに!</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n\n<p>以下のようにヘッダ行だけ表示されればコンテナは残っていません(OKです)。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nもしコンテナが残っていたら(rmオプション付け忘れなど)以下のように表示されます。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES\nae8523f06af4   hello-world   \"/hello\"   13 seconds ago   Exited (0) 10 seconds ago             romantic_booth\n</code></pre></div>  </div>\n  <p>この場合は以下のコマンドで削除します(CONTAINER IDやNAMEは上で表示されたものを使用)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CONTAINER ID で指定</span>\ndocker <span class=\"nb\">rm </span>ae8523f06af4\n<span class=\"c\"># または NAME で指定</span>\ndocker <span class=\"nb\">rm </span>romantic_booth\n</code></pre></div>  </div>\n</blockquote>\n\n<p>イメージを確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<p>結果はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>REPOSITORY    TAG       IMAGE ID       CREATED         SIZE\nhello-world   latest    d2c94e258dcb   14 months ago   13.3kB\n</code></pre></div></div>\n\n<p>イメージを削除します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image <span class=\"nb\">rm </span>hello-world\n</code></pre></div></div>\n\n<p>結果はこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Untagged: hello-world:latest\nUntagged: hello-world@sha256:94323f3e5e09a8b9515d74337010375a456c909543e1ff1538f5116d38ab3989\nDeleted: sha256:d2c94e258dcb3c5ac2798d32e1249e42ef01cba4841c2234249495f87264ac5a\nDeleted: sha256:ac28800ec8bb38d5c35b49d45a6ac4777544941199075dff8c4eb63e093aa81e\n</code></pre></div></div>\n\n<p>削除されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<p>結果はこんな感じでヘッダ行だけ表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>REPOSITORY   TAG       IMAGE ID   CREATED   SIZE\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nカーネル入れ替えたり、なんやかんやしてるうちにDockerが起動しなくなることがありました。<br />\nそのときは <code class=\"language-plaintext highlighter-rouge\">systemctl status docker</code> を実行して <code class=\"language-plaintext highlighter-rouge\">Active</code>の表示を確認します。\n<code class=\"language-plaintext highlighter-rouge\">failed</code>になっていたら起動に失敗しています。<br />\n原因の調査方法はいろいろありますが、私が遭遇したパターンでは\n<code class=\"language-plaintext highlighter-rouge\">sudo dockerd --debug</code> を実行してエラーメッセージを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">networks have same bridge name</code> と出ている場合は\n<code class=\"language-plaintext highlighter-rouge\">/var/lib/docker/network</code>ディレクトリを消して(不安ならリネームして)、\n<code class=\"language-plaintext highlighter-rouge\">sudo systemctl start docker</code> を実行します。<br />\nこの後、 <code class=\"language-plaintext highlighter-rouge\">systemctl status docker</code> を実行して \n<code class=\"language-plaintext highlighter-rouge\">Active</code>の表示が<code class=\"language-plaintext highlighter-rouge\">active (running)</code>になっていればOKのはず。</p>\n\n</blockquote>\n\n<h1 id=\"カーネルのビルド\">カーネルのビルド</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<p>たとえば、以下。 どこでも良いけど、以下の手順はこのディレクトリで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /proj/wsl_kernel <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /proj/wsl_kernel\n</code></pre></div></div>\n\n<h2 id=\"カーネルソースの取得\">カーネルソースの取得</h2>\n<p>作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)にカーネルソースをダウンロードします。<br />\ngitリポジトリをcloneするか、リリースソースをダウンロードして展開します。</p>\n\n<h3 id=\"gitでcloneする場合\">gitでcloneする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/microsoft/WSL2-Linux-Kernel.git\n\n<span class=\"c\"># 目的のタグをチェックアウト</span>\ngit <span class=\"nt\">-C</span> WSL2-Linux-Kernel checkout <span class=\"nt\">-b</span> WSL-6.6.36.3 refs/tags/linux-msft-wsl-6.6.36.3\n\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> WSL2-Linux-Kernel linux\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nclone済みなら念のため<code class=\"language-plaintext highlighter-rouge\">git pull</code>して最新状態にしておく</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nブランチ作る必要ないけど、念のため。</p>\n</blockquote>\n\n<h3 id=\"リリースソースzipをダウンロードする場合\">リリースソース(zip)をダウンロードする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-6.6.36.3.zip\nunzip linux-msft-wsl-6.6.36.3.zip\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> linux-msft-wsl-6.6.36.3 linux\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nunzipはデフォルトではインストールされていないのでインストール必要。</p>\n</blockquote>\n\n<h2 id=\"スクリプトdockerfileの入手\">スクリプト&Dockerfileの入手</h2>\n<blockquote>\n  <p>[!NOTE]\nGistに必要なスクリプト&<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>を置いておいたので以下のページの<code class=\"language-plaintext highlighter-rouge\">DownloadZIP</code>ボタンからダウンロードして\n作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)に展開してください。<br />\n<a href=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021\" target=\"_blank\">Gist:WSLカーネルビルド環境</a></p>\n\n  <p>または以下のコマンドで取得できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021/archive/main.zip\nunzip <span class=\"nt\">-j</span> main.zip\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージを作成\">Dockerイメージを作成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>は上のサイトからダウンロードしてください。<br />\n<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>があるディレクトリで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker build <span class=\"nt\">-t</span> wslkernelbuilder:2.0 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<p>Dockerfileの内容は以下の通り。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=Dockerfile\"></script>\n</dev>\n\n<h2 id=\"dockerコンテナの起動確認\">Dockerコンテナの起動確認</h2>\n<p>上で作成したDockerイメージでコンテナを起動できることを確認します。<br />\nこのスクリプトは上のDockerイメージでDockerコンテナを起動し、シェルを実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_interactive.sh\n</code></pre></div></div>\n<p>プロンプトが以下のように変わればOKです(最後のディレクトリはlinuxのリンク先の実体のディレクトリ名になります)。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>builder [ /usr/src/WSL2-Linux-Kernel ]$\n</code></pre></div></div>\n<p>適当なコマンドを入力して遊んでみてください(カレントディレクトリのファイルは消さないように)。<br />\n最後は<code class=\"language-plaintext highlighter-rouge\">exit</code>で終了します。<br />\n起動時に<code class=\"language-plaintext highlighter-rouge\">--rm</code>しているので、終了時コンテナは削除されます。<br />\nなので、<code class=\"language-plaintext highlighter-rouge\">/usr/src</code>ディレクトリ以外にファイルを作っても終了後はなくなります。<br />\nもちろん<code class=\"language-plaintext highlighter-rouge\">tdnf install</code>(marinerなのでaptではない)でインストールしたアプリケーションもきれいさっぱりなくなります。<br />\n<code class=\"language-plaintext highlighter-rouge\">/usr/src</code>ディレクトリはスクリプトを起動したディレクトリをマウントしていますので、\nここに作成したファイルはコンテナ終了後も残ります(逆に削除するとホストからも削除されます)。</p>\n\n<h2 id=\"カーネルのビルド-1\">カーネルのビルド</h2>\n\n<p>カーネルソースの取得、Dockeイメージのビルドが終わったら、以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_kernel.sh\n</code></pre></div></div>\n\n<p>実行には1時間とか2時間とかのオーダーの時間がかかりますので、お茶でも飲んで気長に待ってください。</p>\n\n<p>実行完了後、<code class=\"language-plaintext highlighter-rouge\">out</code>ディレクトリに<code class=\"language-plaintext highlighter-rouge\">bzImage</code>と<code class=\"language-plaintext highlighter-rouge\">linux-module-6.6.36.3-microsoft-standard-wsl2_6.6.36.3-3_amd64.deb</code>ができます。<br />\nこれらを使用するPCのWindowsから見えるフォルダ(例えば、<code class=\"language-plaintext highlighter-rouge\">c:\\WSL_KERNEL\\</code>)にコピーします。</p>\n\n<h3 id=\"カーネルビルド用スクリプト\">カーネルビルド用スクリプト</h3>\n\n<p>用意したスクリプトの概要は以下の通りです。</p>\n\n<h4 id=\"build_functionssh\">build_functions.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_functions.sh</code>はビルドに関わる処理を関数化したものをまとめたファイルです。<br />\n以下のスクリプトからインクルードして使用します。</p>\n\n<p>Dockerコンテナを使用するので、あらかじめDockerイメージを作成しておく必要があります。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_functions.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_kernelsh\">build_wsl_kernel.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_kernel.sh</code>はカーネルのビルドを行います。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_kernel.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_interactivesh\">build_wsl_interactive.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_interactive.sh</code>はコンテナ内でインタラクティブにビルド操作をしたい場合に使用します。<br />\nたとえば、新しくモジュールを有効化したいとき、<code class=\"language-plaintext highlighter-rouge\">make menuconfig</code>して<code class=\"language-plaintext highlighter-rouge\">make</code>するような場合です。<br />\n実行するとコンテナ内のシェルが起動するので、実行したいコマンドを実行してください。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_interactive.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_usb-storagesh\">build_wsl_usb-storage.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_usb-storage.sh</code>はUSBストレージのカーネルモジュールのビルドを行います。<br />\nバージョン6.6.<em>ではすでに有効になっているので、使用しません。<br />\nバージョン5.15.</em>で標準カーネルのままカーネルモジュールをビルドして使用するときに使用します。<br />\n6.6.*でも他のモジュールを有効化するときに参考になるかもと残しています。</p>\n\n<p><a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">参照先</a>\nの処理を少し書き換えただけです。</p>\n\n<p>outディレクトリに作成された<code class=\"language-plaintext highlighter-rouge\">linux-module-usb-storage-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64</code>を使用するディストリビューションにコピーし、\n以下のように実行しますが、インストール先の<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/</code>が書き込み禁止のため\nあらかじめここにoverlayfsをマウントしておく必要があります。<br />\nマウント方法やその他使用方法は\n<a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">参照先</a>\nを参照してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> linux-module-usb-storage-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64\n</code></pre></div></div>\n<p>標準カーネルを使用することを前提にしているので、カーネルの差し替えは必要ありません。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_usb-storage.sh\"></script>\n</dev>\n\n<blockquote>\n  <p>[!NOTE]\nこのスクリプトは使用するWSLカーネルで実行されているディストリビューションで実行してください。<br />\nそうしないとBTFの確認(<code class=\"language-plaintext highlighter-rouge\">check_btf</code>関数)が失敗します。</p>\n</blockquote>\n\n<h1 id=\"差し替えたカーネルで実行\">差し替えたカーネルで実行</h1>\n\n<h2 id=\"wslの停止\">WSLの停止</h2>\n<p>WSL実行中の場合はすべてのウィンドウを閉じます。<br />\nさらにWSLを完全に終了するために以下のコマンドを実行します。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--shutdown</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>念のため、すべて停止していることを確認を確認)</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>結果はこんな感じで<code class=\"language-plaintext highlighter-rouge\">STATE</code>がすべて<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  NAME              STATE           VERSION\n* Ubuntu-20.04-1    Stopped         2\n  ubuntu-22.04-2    Stopped         2\n  test_6_6          Stopped         2\n</code></pre></div></div>\n\n<h2 id=\"差し替えカーネルの設定\">差し替えカーネルの設定</h2>\n\n<p>差し替えカーネルを設定するため、<code class=\"language-plaintext highlighter-rouge\">%USERPROFILE%\\.wslconfig</code> に以下を追記(なければ新規作成)します。<br />\nここで指定しているのは先にコピーしたbzImageファイルのパスです。<br />\nただし、フォルダ区切りの<code class=\"language-plaintext highlighter-rouge\">\\</code>は<code class=\"language-plaintext highlighter-rouge\">\\\\</code>に置き換える必要があります。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[wsl2]\nkernel=c:\\\\WSL_KERNEL\\\\bzImage\n</code></pre></div></div>\n\n<h2 id=\"差し替えカーネルでの起動\">差し替えカーネルでの起動</h2>\n<p>通常通り、ディストリビューションを起動します。<br />\n起動後、ディストリビューション内のシェルで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">uname</span> <span class=\"nt\">-r</span>\n</code></pre></div></div>\n<p>結果が<code class=\"language-plaintext highlighter-rouge\">6.6.36.3-microsoft-standard-WSL2</code>と差し替えたカーネルのバージョンになっていることを確認します。</p>\n\n<h2 id=\"カーネルモジュールのインストール\">カーネルモジュールのインストール</h2>\n\n<p>次に先ほどコピーしたカーネルモジュールをインストールします。</p>\n<blockquote>\n  <p>[!NOTE]\nカーネルモジュールのインストールはカーネル差し替え後に行ってください。<br />\n差し替え前が標準カーネルだった場合、インストール先がリードオンリーのため、インストールに失敗します。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> /mnt/c/WSL_KERNEL/linux-module-6.6.36.3-microsoft-standard-wsl2_6.6.36.3-3_amd64.deb\n</code></pre></div></div>\n\n<p>インストールされると、<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/6.6.36.3-microsoft-standard-WSL2/</code>以下に各種ファイルが作成されます。</p>\n\n<p>インストールしたモジュールを読み込むため、ディストリビューションを再起動します。<br />\nWSLを完全に終了するために以下のコマンドを実行します。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--shutdown</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>念のため、すべて停止していることを確認(<code class=\"language-plaintext highlighter-rouge\">STATE</code>が<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていることを確認)</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  NAME              STATE           VERSION\n* Ubuntu-20.04-1    Stopped         2\n  ubuntu-22.04-2    Stopped         2\n  test_6_6          Stopped         2\n</code></pre></div></div>\n\n<p>再度カーネルモジュールをインストールしたディストリビューションを起動し、\n起動したディストリビューションでモジュールが読み込まれていることを確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsmod\n</code></pre></div></div>\n<p>以下のように、いくつかのモジュールが読み込まれていることを確認します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Module                  Size  Used by\nintel_rapl_msr         16384  0\nintel_rapl_common      36864  1 intel_rapl_msr\ncrc32c_intel           16384  0\nconfigfs               61440  0\nip_tables              32768  0\nautofs4                53248  0\n</code></pre></div></div>\n\n<h1 id=\"おわり\">おわり</h1>\n<p>この状態でカーネルの差し替えは完了です。<br />\nusbipd-win を使用すれば、USBシリアルやUSBストレージ、USBカメラも使えるようになります。\nただし、モジュールvhci-hcd(USB 仮想ホストコントローラインターフェース)が読み込まれていないので、\n以下のコマンドで読み込んでおく必要があります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe vhci-hcd\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n起動時にモジュールを読み込むには、通常<code class=\"language-plaintext highlighter-rouge\">/etc/modules</code>に設定しておけば良いのですが、\n試してみましたがうまくいきませんでした。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下のように記述しておくとうまくいくかもしれません。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\ncommand=modprobe vhci-hcd\n</code></pre></div>  </div>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSBデバイスを使う(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSBデバイスを使う(その3)</h1>\n      <p>WSLでUSBデバイスを使う(その3:USBカメラ編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>で\nWSLカーネル v6.6.36.3 をビルドしたのでもうv5.15.153は使わなくて良くなったのですが、\nやっぱりカーネル入れ替えずにUSBカメラ使いたい衝動にかられ、手順をまとめてみました。<br />\n(その2でUSBストレージ編を書こうと思っていたので、その2は欠番、その3になりました)</p>\n\n<p>参考:<br />\n<a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a><br />\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a></p>\n\n<h1 id=\"開発環境の準備\">開発環境の準備</h1>\n<p>開発環境の準備については、\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>\nの「Linuxカーネルのビルド環境の構築」を参照してください。</p>\n\n<h1 id=\"カーネルモジュールのビルド\">カーネルモジュールのビルド</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<p>たとえば、以下。 どこでも良いけど、以下の手順はこのディレクトリで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /proj/wsl_kernel <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /proj/wsl_kernel\n</code></pre></div></div>\n\n<h2 id=\"カーネルソースの取得\">カーネルソースの取得</h2>\n<p>作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)にカーネルソースをダウンロードします。<br />\ngitリポジトリをcloneするか、リリースソースをダウンロードして展開します。</p>\n\n<h3 id=\"gitでcloneする場合\">gitでcloneする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/microsoft/WSL2-Linux-Kernel.git\n\n<span class=\"c\"># 目的のタグをチェックアウト</span>\ngit <span class=\"nt\">-C</span> WSL2-Linux-Kernel checkout <span class=\"nt\">-b</span> WSL-5.15.153.1 refs/tags/linux-msft-wsl-5.15.153.1\n\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> WSL2-Linux-Kernel linux\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nclone済みなら念のため<code class=\"language-plaintext highlighter-rouge\">git pull</code>して最新状態にしておく</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nブランチ作る必要ないけど、念のため。</p>\n</blockquote>\n\n<h3 id=\"リリースソースzipをダウンロードする場合\">リリースソース(zip)をダウンロードする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-5.15.153.1.zip\nunzip linux-msft-wsl-5.15.153.1.zip\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> linux-msft-wsl-5.15.153.1 linux\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nunzipはデフォルトではインストールされていないのでインストール必要。</p>\n</blockquote>\n\n<h2 id=\"スクリプトdockerfileの入手\">スクリプト&Dockerfileの入手</h2>\n<blockquote>\n  <p>[!NOTE]\nGistに必要なスクリプト&<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>を置いておいたので以下のページの<code class=\"language-plaintext highlighter-rouge\">DownloadZIP</code>ボタンからダウンロードして\n作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)に展開してください。<br />\n<a href=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021\" target=\"_blank\">Gist:WSLカーネルビルド環境</a></p>\n\n  <p>または以下のコマンドで取得できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021/archive/main.zip\nunzip <span class=\"nt\">-j</span> main.zip\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージを作成起動確認\">Dockerイメージを作成~起動確認</h2>\n<p>Dockerイメージを作成~起動確認は\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>\nのDockerイメージを作成~起動確認 を参照してください。<br />\n作成済みならスキップしてください。</p>\n\n<h2 id=\"カーネルモジュールのビルド-1\">カーネルモジュールのビルド</h2>\n\n<p>カーネルソースの取得、Dockeイメージのビルドが終わったら、以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_multimedia.sh\n</code></pre></div></div>\n\n<p>実行には数十分~1時間程度かかります(PCのスペックによる)。</p>\n\n<p>実行完了後、<code class=\"language-plaintext highlighter-rouge\">out</code>ディレクトリに<code class=\"language-plaintext highlighter-rouge\">linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb</code>ができます。<br />\nこれを使用するディストリビューションから見えるフォルダ(ディストリビューション内でなくWindowsのディレクトリでも可)にコピーします。</p>\n\n<h3 id=\"カーネルビルド用スクリプト\">カーネルビルド用スクリプト</h3>\n\n<p>用意したスクリプトの概要は以下の通りです。</p>\n\n<h4 id=\"build_functionssh\">build_functions.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_functions.sh</code>はビルドに関わる処理を関数化したものをまとめたファイルです。<br />\n以下のスクリプトからインクルードして使用します。</p>\n\n<p>Dockerコンテナを使用するので、あらかじめDockerイメージを作成しておく必要があります。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_functions.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_multimediash\">build_wsl_multimedia.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_multimedia.sh</code>はマルチメディア関連のカーネルモジュールのビルドを行います。<br />\n<code class=\"language-plaintext highlighter-rouge\">build_wsl_usb-storage.sh</code>の<code class=\"language-plaintext highlighter-rouge\">ADD_CONFIG</code>変数の設定値を変更しただけです。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_multimedia.sh\"></script>\n</dev>\n\n<p>その他は<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>を参照してください。</p>\n\n<h1 id=\"実行環境の準備\">実行環境の準備</h1>\n<p>実行環境の準備は <a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a>\nと同じです。<br />\n使用するUSBデバイスがUSBカメラに変わるだけです。</p>\n\n<h2 id=\"実行ディストリビューションの準備\">実行ディストリビューションの準備</h2>\n\n<p>デフォルト状態ではカーネルモジュールのインストール先(<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/</code>)が書き込みできないので、\noverlayfsで書き込みできるファイルシステムをマウントします。</p>\n\n<p>まず、マウントする(実際に書き込むための)ディレクトリを用意します。<br />\nupperとworkの2つが必要です。workにはなにも書き込まないでください。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> /modules_overlay/upper/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> /modules_overlay/work/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n</code></pre></div></div>\n\n<p>次にお試しマウントしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> overlay overlay <span class=\"nt\">-o</span> <span class=\"se\">\\</span>\n    <span class=\"nv\">lowerdir</span><span class=\"o\">=</span>/usr/lib/modules/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>,<span class=\"se\">\\</span>\n    <span class=\"nv\">upperdir</span><span class=\"o\">=</span>/modules_overlay/upper/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>,<span class=\"se\">\\</span>\n    <span class=\"nv\">workdir</span><span class=\"o\">=</span>/modules_overlay/work/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span> <span class=\"se\">\\</span>\n    /usr/lib/modules/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n</code></pre></div></div>\n\n<p>マウントできたか確認するため、ファイルを作成してみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo </span>hogehoge | <span class=\"nb\">sudo tee</span> /usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt</code>が出来ていること(内容が正しいこと)と、\n<code class=\"language-plaintext highlighter-rouge\">/modules_overlay/upper/5.15.153.1-microsoft-standard-WSL2/test.txt</code>に同じファイルがあることを確認します。</p>\n\n<p>終わったら削除しておきましょう。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo rm</span> /usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt\n</code></pre></div></div>\n\n<p>再起動したときに自動的にマウントされるように、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に先ほどのマウントコマンドを\n<code class=\"language-plaintext highlighter-rouge\">command=</code>に指定します。<br />\n以下は書き込んだ後の<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>の例。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\ncommand=mount -t overlay overlay -o \\\n    lowerdir=/usr/lib/modules/$(uname -r),\\\n    upperdir=/modules_overlay/upper/$(uname -r),\\\n    workdir=/modules_overlay/work/$(uname -r) \\\n    /usr/lib/modules/$(uname -r)\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>が正常に変更できたか確認するにはWSLの再起動が必要です(ウィンドウ閉じただけではダメ)。</p>\n\n<h2 id=\"カーネルモジュールのインストール\">カーネルモジュールのインストール</h2>\n\n<p>先ほど作成した<code class=\"language-plaintext highlighter-rouge\">linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb</code>を使用して\n以下のように実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb\n</code></pre></div></div>\n\n<h1 id=\"usbカメラを繋いでみる\">USBカメラを繋いでみる</h1>\n\n<p>実行手順は\n実行環境の準備は <a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a>\nの「USB-Serialデバイスを接続」を参照してください。</p>\n\n<p>USBカメラのを接続したときのログはこんな感じ</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[22183.171276] vhci_hcd vhci_hcd.0: pdev(0) rhport(0) sockfd(3)\n[22183.171281] vhci_hcd vhci_hcd.0: devid(196610) speed(3) speed_str(high-speed)\n[22183.171334] vhci_hcd vhci_hcd.0: Device attached\n[22183.550422] usb 1-1: new high-speed USB device number 3 using vhci_hcd\n[22183.700457] usb 1-1: SetAddress Request (3) to port 0\n[22183.786408] usb 1-1: New USB device found, idVendor=056e, idProduct=700a, bcdDevice= 1.00\n[22183.786412] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0\n[22183.786414] usb 1-1: Product: Venus USB2.0 Camera\n[22183.786416] usb 1-1: Manufacturer: Vimicro Corp.\n[22183.799190] usb 1-1: Found UVC 1.00 device Venus USB2.0 Camera (056e:700a)\n[22183.844401] input: Venus USB2.0 Camera: Venus USB2 as /devices/platform/vhci_hcd.0/usb1/1-1/1-1:1.0/input/input1\n</code></pre></div></div>\n\n<h2 id=\"画出し確認\">画出し確認</h2>\n\n<p>pythonのopwnCVでもguvcviewでもお好きな方でどうぞ。</p>\n\n<p>データ転送帯域が足りなくて画像が表示できない場合は、解像度を落としたり、\nフォーマットをYUYV等からMKPEGに変更したりしてデータ量を少なくして試してみてください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 24.04のVirtualBoxへのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 24.04のVirtualBoxへのインストール</h1>\n      <p>Ubuntu 24.04のVirtualBoxへのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 24.04のVirtualBoxへのインストール手順をまとめてみた。<br />\n今回は 極力コマンドコピペで実行できるように書いてみた。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2404-インストール媒体の入手\">Ubuntu 24.04 インストール媒体の入手</h2>\n<p>24.04は日本語Remixがリリースされないので(<a href=\"https://www.ubuntulinux.jp/News/ubuntu2404-ja-remix\" target=\"_blank\">ニュース</a>)、\n<a href=\"https://jp.ubuntu.com/download\" target=\"_blank\">本家</a>\nからダウンロードする必要がありますが、海外にあるサーバなのでとっても遅いです。<br />\n国内のミラーサーバの一覧が<a href=\"https://www.ubuntulinux.jp/ubuntu/mirrors#imagemirror\" target=\"_blank\">ここ</a>\nにあるので、お好きなところからダウンロードしてください。<br />\n(私がダウンロードしたときはKDDI研究所が速かった)</p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、CPU数2個以上、メインメモリーを4096MB以上に設定しておくこと</strong></p>\n<blockquote>\n  <p>[!NOTE]\n推奨環境が2 GHzデュアルコアプロセッサ以上、4GBシステムメモリなので。</p>\n</blockquote>\n\n<p>普通にインストール媒体からインストール。<br />\n以下の説明が図付きで分かりやすい:<br />\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a></p>\n\n<blockquote>\n  <p>[!TIP]\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a>では、「仮想マシンの作成」の「ハードウェア」で「EFIを有効化・・・チェックを入れます。」となっているが、\n入れなくて可(入れて試してないので入れて動くのか未確認。図でもチェック入ってないし)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nインストーラにアップデートがある場合は「今すぐアップデート」をクリックしてアップデートし、\n完了したら一旦インストーラを閉じる。<br />\nデスクトップにインストーラアイコンが出来ているので、そこから再度インストーラを起動し、\n最初から設定を行う(これまでの入力は覚えているっぽい)<br />\n参照:<a href=\"https://pc.watch.impress.co.jp/docs/column/ubuntu/1590461.html\" target=\"_blank\">Ubuntu24.04 LTSの新インストーラを徹底解説</a>\nの「インストーラにアップデートがあった場合」</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a>では、「アプリケーション」での「拡張選択」を選択とあるが、\n余計なアプリを入れたくないので「既定の選択」のままにしておく。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n</blockquote>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<blockquote>\n  <p>[!NOTE]\n設定アプリ等のGUIで設定を変更した内容をスクリプト化したいとき、どのパスを変更すれば良いか調べるには、ターミナルで</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf watch /\n</code></pre></div>  </div>\n  <p>と実行しておくと、変更される度にパスと設定値が表示される。<br />\nこれを <code class=\"language-plaintext highlighter-rouge\">dconf write</code> で書き込めばGUIで設定した内容をコマンドラインで再現できる。<br />\n参考:<a href=\"https://qiita.com/liqsuq/items/2c7aa741caa94508050b\" target=\"_blank\">デスクトップで変えた設定をCUIでやりたい!(gnome限定)</a><br />\nその関係で前回まで<code class=\"language-plaintext highlighter-rouge\">gsettings</code>コマンドでの設定手順を載せていたが、今回は<code class=\"language-plaintext highlighter-rouge\">dconf</code>コマンドに変更した。</p>\n\n</blockquote>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<p>まだGuestAdditionをインストールしてないからコピペできないけど、BashのTab補完が効くので、\nちょろっと入力してあとは補完に頼れば大丈夫。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">dconf</code>だと変更済みのパスしか補完対象にならないらしく入力が面倒なので、\nここは補完が効く<code class=\"language-plaintext highlighter-rouge\">gsettings</code>コマンドで。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">dconf</code>だとこんな感じ。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ndconf write /org/gnome/desktop/session/idle-delay 0\n\n<span class=\"c\"># 自動画面ロック OFF</span>\ndconf write /org/gnome/desktop/screensaver/lock-enabled <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\n設定 → Privacy & Security → Screen Lock → 自動画面ロックを off に</p>\n\n  <p>==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\n設定 → Privacy & Security → Screen Lock → Blank Screen Delay を「しない」に</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>裏でソフトウェアの更新が動いていると、ロックファイルがロックされてしばらく適用できないので、<br />\nそうなっちゃったらお茶でも飲んでしばらくお待ちください。<br />\nソフトウェアの更新による自動更新を止める方法は後ほど。</p>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">upgrade</code> や <code class=\"language-plaintext highlighter-rouge\">install</code> 時にオプション <code class=\"language-plaintext highlighter-rouge\">-U</code> (<code class=\"language-plaintext highlighter-rouge\">--update</code>)をつけると\n<code class=\"language-plaintext highlighter-rouge\">update</code>も一緒に実行してくれるので命令ひとつで済む。<br />\n(ubuntu 24.04に搭載された2.7.14以降)</p>\n</blockquote>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools dconf-editor gnome-tweaks \n</code></pre></div></div>\n\n<h3 id=\"一旦リブート\">一旦リブート</h3>\n<p>念のため一旦リブートしておく。</p>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>以前にマウントしたものが残ってたらアンマウントしておくこと(インストール後初めてなのでマウントされてることはないけれど)。<br />\nVirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<blockquote>\n  <p>[!TIPS]\nプログラムが自動で始まらない場合は、CDROMのマウント先(たぶん、<code class=\"language-plaintext highlighter-rouge\">/media/${USER}/VBox_GAs_x.x.xx/</code>)に移動して<code class=\"language-plaintext highlighter-rouge\">sudo ./VBoxLinuxAdditions.run</code>を実行すれば良い。</p>\n</blockquote>\n\n<h3 id=\"再度リブート\">再度リブート</h3>\n<p>GuestAdditionによる更新適用のため、もう一度リブート。<br />\n(再ログインだけでもよさそうな感じではあるが、念のため)</p>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから<br />\n「デバイス」→「クリップボードの共有」→「双方向」 を選択。<br />\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<p>また、デスクトップサイズの変更(仮想マシンのウィンドウのサイズ変更)にも対応できる。</p>\n\n<h3 id=\"使わないアプリのアンインストール\">使わないアプリのアンインストール</h3>\n<p>「アプリケーション」で「既定の選択」を選んでいれば要らないアプリは入っていないハズ。</p>\n\n<h2 id=\"お好みで\">お好みで</h2>\n\n<h3 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h3>\n\n<p>bashでクリップボードからペーストするとペーストした文字が反転表示になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n以前の動作が良い場合は<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>に設定を追加するため、以下を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/inputrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n# disable bracked-paste mode\nset enable-bracketed-paste off\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<blockquote>\n  <p>[!NOTE]\nteraterm使ってるときはteratermが確認ダイアログ出すので邪魔なんだけど、<br />\ngnome-terminalだと誤ペースト防止にそのままが良いかも。</p>\n</blockquote>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>以下のコマンドで~/.bashrcに設定を追加。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.bashrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n# プロンプトの設定\nPS1=\"</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\n\n# キーバインドの設定\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-n\": history-search-forward'\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-p\": history-search-backward'\n\n# ディレクトリスタックの表示改善\nfunction pushd() {\n    command pushd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction popd() {\n    command popd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction dirs() {\n    command dirs -v\n}\n\n# 表示色変更\nexport LS_COLORS='di=01;32:ln=01;36:ex=01;31:'\nexport GREP_COLORS='mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'\n\n# lessのオプション\nexport LESS=\"-iMR\"\n\n# grepのオプション指定(GREP_OPTIONS)は廃止されたのでaliasで設定\n# export GREP_OPTIONS=\"--exclude-dir .git\"\nalias grep='grep --exclude-dir .git'\n\n# for pyenv\nexport PYENV_ROOT=/proj/.pyenv    #環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    # 仮想環境名をプロンプトに表示しない場合は以下を有効化\n    # export VIRTUAL_ENV_DISABLE_PROMPT=1\n    eval \"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"sh\">\"          # pyenv 2.0以降で必要\n    eval \"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"sh\">\"\n    eval \"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"sh\">\"\n    export PYTHON_CONFIGURE_OPTS=\"</span><span class=\"se\">\\</span><span class=\"sh\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"sh\">\n    \"\nfi\n\n# for nodenv\nexport NODENV_ROOT=/proj/.nodenv    # 環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    eval \"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"sh\">\"\nfi\n\n# x11からのログイン以外ならDISPLAYを設定する\n# Ubuntu22.04/24.04だとwaylandになるらしい\nif [ \"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"sh\">\" != \"x11\" ] && [ \"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"sh\">\" != \"wayland\" ]; then\n    export DISPLAY=192.168.78.200:0.0\nfi\necho DISPLAY=\"</span><span class=\"nv\">$DISPLAY</span><span class=\"sh\">\"\n\n# direnv 設定\nif type direnv > /dev/null 2>&1; then\n    export EDITOR=vi\n    eval \"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"sh\">\"\n    \n    # # venvの仮想環境名を表示するための設定\n    # show_virtual_env() {\n    #   if [ -n \"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"sh\">\" ]; then\n    #     echo \"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"sh\">)\"\n    #   fi\n    # }\n    # PS1='</span><span class=\"si\">$(</span>show_virtual_env<span class=\"si\">)</span><span class=\"sh\">'</span><span class=\"nv\">$PS1</span><span class=\"sh\">\nfi\n\n# __pycache__ディレクトリの生成を抑制する\nexport PYTHONDONTWRITEBYTECODE=1\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nヒアドキュメント内での変数展開やコマンド置換を抑止するには、\nヒアドキュメント開始文字列(上記では__EOF__)をシングルクォートで囲む。<br />\n参考:<a href=\"https://qiita.com/take4s5i/items/e207cee4fb04385a9952#%E5%A4%89%E6%95%B0%E5%B1%95%E9%96%8B%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E7%BD%AE%E6%8F%9B\" target=\"_blank\">bashのヒアドキュメントを活用する/変数展開・コマンド置換</a></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npython でimportする度に<code class=\"language-plaintext highlighter-rouge\">__pycache__</code>ディレクトリ<code class=\"language-plaintext highlighter-rouge\">*.pyc</code>ファイルが作成されるのが\n鬱陶しかったので、<code class=\"language-plaintext highlighter-rouge\">PYTHONDONTWRITEBYTECODE</code>に1を設定している。<br />\n2回目以降、若干実行時間が延びるかもしれないが、気にするほどでもないので。<br />\n通常の動作がよければ削除してください。</p>\n</blockquote>\n\n<h3 id=\"ubuntu-japanese-teamのパッケージリポジトリを追加\">Ubuntu Japanese Teamのパッケージリポジトリを追加</h3>\n\n<p>日本語特有のパッケージをインストールするため、Ubuntu Japanese Teamのパッケージリポジトリを追加します。<br />\n参考:<a href=\"https://www.ubuntulinux.jp/News/ubuntu2404-ja-remix\" target=\"_blank\">Ubuntu 24.04 LTSの日本語Remixについて</a>\nの最後の部分</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>wget https://www.ubuntulinux.jp/sources.list.d/noble.sources <span class=\"nt\">-O</span> /etc/apt/sources.list.d/ubuntu-ja.sources <span class=\"o\">&&</span><span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade <span class=\"o\">&&</span><span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ubuntu-defaults-ja\n</code></pre></div></div>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">/usr/share/fonts</code>の下(自分専用なら<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>の下)にコピるだけ。<br />\n下では全部コピってる(移動だけど)けど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp/ <span class=\"o\">&&</span> <span class=\"se\">\\</span>\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.3.1/UDEVGothic_v1.3.1.zip <span class=\"o\">&&</span> <span class=\"se\">\\</span>\nunzip UDEVGothic_v1.3.1.zip <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo mv </span>UDEVGothic_v1.3.1 /usr/share/fonts/truetype/ <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<p>設定を反映するため、開いている端末をすべて閉じで、再度起動します。<br />\n開いたままだと設定が中途半端に反映されてしまいます。<br />\nまた、一つでも端末が残っていると新しく開いた端末にも正常な反映がされません。</p>\n\n<blockquote>\n  <p>[!NOTE]\nCLIで設定するならこちら….なんだけど、UUIDが同じとは限らないので参考まで。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/use-system-font    <span class=\"nb\">false\n</span>dconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/font               <span class=\"s2\">\"'UDEV Gothic JPDOC 12'\"</span>\ndconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/default-size-rows  40\n</code></pre></div>  </div>\n\n  <p>すべてのプロファイルに適用するならこんな感じでもできるかな。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">for </span>prof <span class=\"k\">in</span> <span class=\"si\">$(</span>dconf list /org/gnome/terminal/legacy/profiles:/<span class=\"si\">)</span> <span class=\"p\">;</span> <span class=\"k\">do\n    </span>dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>use-system-font    <span class=\"nb\">false</span>                       <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n    dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>font               <span class=\"s2\">\"'UDEV Gothic JPDOC 12'\"</span>    <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n    dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>default-size-rows  40\n<span class=\"k\">done</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h3>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /NFSROOT <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span> /proj /work /NFSROOT\n</code></pre></div></div>\n\n<h3 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h3>\n\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく<br />\n(CLIでも「どこにインストールする?」と聞かれて「どこだっけ?」となるのでその予防)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<p>設定が正常に行われたか確認するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<p>正常に設定されていれば、以下のような結果が出力される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>0 /dev/sda\n</code></pre></div></div>\n<h3 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h3>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gnome-extensions disable tiling-assistant@ubuntu.com <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/mutter/edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/desktop/wm/preferences/focus-mode        <span class=\"s2\">\"'sloppy'\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/desktop/wm/preferences/auto-raise        <span class=\"nb\">false</span>      <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/desktop/wm/preferences/raise-on-click    <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。<br />\nと書いてあったけど、同じ動き(フォーカスがはずれる)に見える….</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/ding/show-home  <span class=\"nb\">false</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/shell/extensions/ding/show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/desktop/interface/cursor-size 48\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nGUIで設定する場合は「設定」→「アクセシビリティ」→「Seeing」→「Cursor Size」で選択<br />\n(数値ではなく画像で選択)</p>\n</blockquote>\n\n<h3 id=\"ファイルnautilusの設定変更\">ファイル(nautilus)の設定変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<h4 id=\"ロケーションバーをデフォルトにする\">ロケーションバーをデフォルトにする</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/nautilus/preferences/always-use-location-entry <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h4 id=\"詳細表示をデフォルトに\">詳細表示をデフォルトに</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/nautilus/preferences/default-folder-viewer <span class=\"s2\">\"'list-view'\"</span> \n</code></pre></div></div>\n\n<h4 id=\"隠しファイルを表示する\">隠しファイルを表示する</h4>\n<p>隠しファイルの表示はちょっと場所が違う</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gtk/gtk4/settings/file-chooser/show-hidden <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n\n<h4 id=\"ゴミ箱削除\">ゴミ箱削除</h4>\n\n<p>私はゴミ箱使わないので消しときます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n<h4 id=\"dockバーを画面下に表示\">Dockバーを画面下に表示</h4>\n\n<p>Windows7っぽく下に移動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/dock-position <span class=\"s2\">\"'BOTTOM'\"</span>\n</code></pre></div></div>\n\n<h4 id=\"アプリケーションをdockバーの上または左に表示\">アプリケーションをDockバーの上(または左)に表示</h4>\n\n<p>Windows7のスタートボタンっぽく左に移動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/show-apps-at-top <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h4 id=\"アイコンサイズの変更\">アイコンサイズの変更</h4>\n\n<p>最後の数字が大きさなので、お好みの大きさにしてください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/dash-max-icon-size 20\n</code></pre></div></div>\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアとアップデート(software-properties-gtk)を起動\n    <ul>\n      <li>アップデートタブを選択</li>\n      <li>アップデートの自動確認を「なし」に変更</li>\n      <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n      <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n      <li>閉じるをクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a></p>\n\n<p>tewaksを使用する<br />\n<a href=\"https://yassan.hatenablog.jp/entry/2024/05/01/Ubuntu_Bdgie%E3%83%A1%E3%83%A2%EF%BC%9A_Tweeks%E3%81%A7Caps%E3%81%A8Ctrl%E3%81%AESwap\" target=\"_blank\">Ubuntu Bdgieメモ: TweeksでCapsとCtrlのSwap</a><br />\nというのもある。 お好きな方で。</p>\n\n<p>Native環境にインストールしてないので未確認だけど…</p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下のように「quiet splash」を削除。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h2 id=\"ネットワークアダプタの追加\">ネットワークアダプタの追加</h2>\n<p>ホストのWindowsや外部マシンからアクセスできるようにデフォルトのNAT以外にネットワークアダプタを追加します。<br />\n仮想マシンの設定を変更する必要があるので、一旦仮想マシンをシャットダウンしてください。</p>\n\n<h3 id=\"ネットワークアダプタ追加設定\">ネットワークアダプタ追加設定</h3>\n<ul>\n  <li>Virtualboxマネージャ で対象の仮想マシンを選択し、設定ボタンをクリック。</li>\n  <li>開いたウィンドウの左側で「ネットワーク」を選択</li>\n  <li>右側のウィンドウで「アダプタ2」をクリック\n    <ul>\n      <li>「ネットワークアダプタを有効化」にチェックを入れる</li>\n      <li>「割り当て」で「ホストオンリーアダプター」を選択</li>\n    </ul>\n  </li>\n  <li>右側のウィンドウで「アダプタ3」をクリック\n    <ul>\n      <li>「ネットワークアダプタを有効化」にチェックを入れる</li>\n      <li>「割り当て」で「ブリッジアダプター」を選択</li>\n      <li>「名前」で割り当てる物理的なネットワークアダプタを選択</li>\n    </ul>\n  </li>\n  <li>OKをクリック</li>\n</ul>\n\n<p>設定が終わったら仮想マシンを起動します。</p>\n\n<blockquote>\n  <p>[!NOTE]\nNATも削除してブリッジアダプターだけでも大丈夫な気もするが、ネットワーク不調になっても\nホストOS(Windows)からアクセスできるようにホストオンリーアダプターも追加しておく。<br />\nまた、ホストオンリーアダプターも不調になったときでも\nWebアクセスなど最低限のアクセスができるようNATも残しておく。<br />\n要らないと思ったら上記の設定の「ネットワークアダプタを有効化」のチェックをはずせば良い。</p>\n</blockquote>\n\n<h3 id=\"ネットワークのコネクション名の変更\">ネットワークのコネクション名の変更</h3>\n\n<p>ネットワークコントローラを追加したので、ネットワークマネージャのコネクション一覧を見てみます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection \n</code></pre></div></div>\n\n<p>結果はこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>NAME            UUID                                  TYPE      DEVICE \nnetplan-enp0s3  1eef7e45-3b9d-3043-bee3-fc5925c90273  ethernet  enp0s3 \n有線接続 1      eef7ccb4-2a33-336f-bb48-701058d5e6ce  ethernet  enp0s8 \n有線接続 2      eff49436-1aac-36eb-b1f6-2a32cc246b83  ethernet  enp0s9 \nlo              d30bde24-f5dd-458d-86b0-b5c8870f4485  loopback  lo     \n</code></pre></div></div>\n<p>「有線接続 1」と「有線接続 2」がさきほど追加したホストオンリーアダプターとブリッジアダプターなのですが、\nどっちがどっちか判別できません。<br />\nそこで判別できるような名前に変更しておきます。<br />\n(192.168.xx.xxのものだけ変更。NATとloはそのまま)<br />\n変更後のコネクション名はネットワークとの対応が分かりやすくなるよう、\n≪IPアドレスの3桁目≫_LINE としています。<br />\nお好みの名前に変更してください。<br />\n(現在、日本語だと文字化けするバグがあるようです。そのうち直ると思いますが)</p>\n\n<p>手動で設定するのは面倒なので、以下のスクリプトファイルを作成して実行してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># すべてのコネクション名を改行区切りで配列に取得</span>\n<span class=\"nv\">ORG_IFS</span><span class=\"o\">=</span><span class=\"nv\">$IFS</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"s1\">$'</span><span class=\"se\">\\n</span><span class=\"s1\">'</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span>nmcli  <span class=\"nt\">-t</span> <span class=\"nt\">-f</span> NAME connection<span class=\"si\">)</span><span class=\"o\">)</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"nv\">$ORG_IFS</span>        <span class=\"c\"># 元に戻す</span>\n\n<span class=\"k\">for </span>i <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"p\">!connections[@]</span><span class=\"k\">}</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各コネクションについて</span>\n    <span class=\"c\"># 直接取り出すとうまくいかないのでインデックス取り出して内容取得</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[</span><span class=\"nv\">$i</span><span class=\"p\">]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n\n    <span class=\"c\"># 現在設定されているIPv4アドレスを取得</span>\n    <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.ADDRESS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n    <span class=\"c\"># 結果⇒ 「IP4.ADDRESS[1]: 192.168.78.215/24」</span>\n    \n    <span class=\"c\"># IPアドスの各桁とサブネットマスクを空白区切りで取得し、配列に代入</span>\n    <span class=\"c\"># 1個目のsed ⇒ 192.168.78.215/24</span>\n    <span class=\"c\"># 2個目のsed ⇒ 192 168 78 215 24</span>\n    <span class=\"nv\">ipv4octet</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/[</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]/ /g\"</span><span class=\"si\">)</span><span class=\"o\">)</span>\n\n    <span class=\"c\"># echo ${str}</span>\n    <span class=\"c\"># echo ${ipv4octet[0]}  ${ipv4octet[1]}  ${ipv4octet[2]}  ${ipv4octet[3]}  ${ipv4octet[4]}</span>\n    \n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 192 <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 168 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n        <span class=\"c\"># 192.168.XX.XX のコネクション</span>\n        <span class=\"c\"># echo \"**** ${str} ****\"</span>\n\n        <span class=\"c\"># コネクション名を\"≪IPアドレスの3桁目≫_LINE\"変更する</span>\n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> connection.id </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[2]</span><span class=\"k\">}</span><span class=\"s2\">_LINE</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone\n\n</span><span class=\"nb\">echo</span> <span class=\"o\">==</span><span class=\"nv\">RESULT</span><span class=\"o\">==</span>\nnmcli  connection\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)→<br />\n左側のネットワークを選択し、対象のNICの設定ボタン(歯車アイコン)をクリック→<br />\n開いたウィンドウで「identity」タブをクリック→<br />\n「名前」に設定する名前を設定→<br />\n「適用」をクリック</p>\n</blockquote>\n\n<h3 id=\"sambaのインストール\">sambaのインストール</h3>\n\n<h4 id=\"ツール本体のインストール\">ツール本体のインストール</h4>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<h4 id=\"etcsambasmbconf-の設定を変更\">/etc/samba/smb.conf の設定を変更</h4>\n\n<p>以下のコマンドを実行します。<br />\n変更内容は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code>をバックアップ</li>\n  <li>[homes]セクションを有効化</li>\n  <li>[homes]セクションの「read only」を「no」に設定</li>\n  <li>[global]セクションに「map archive = no」を追加</li>\n  <li>ファイル末尾に[proj][work][NFSROOT]セクションを追加<br />\n他にも追加したいセクション(ディレクトリの設定)があったら追加してください。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /etc/samba/smb.conf /etc/samba/smb.conf.org     <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'/\\[homes\\]/s/;//g'</span> /etc/samba/smb.conf     <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'/\\[homes\\]/,/\\[/ {s/^;[^\\[]//g}'</span> /etc/samba/smb.conf   <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"/</span><span class=\"se\">\\[</span><span class=\"s2\">homes</span><span class=\"se\">\\]</span><span class=\"s2\">/,/^</span><span class=\"se\">\\[\\|</span><span class=\"s2\">^;</span><span class=\"se\">\\s</span><span class=\"s2\">*</span><span class=\"se\">\\[</span><span class=\"s2\">/ s/read only = .*/read only = no/1\"</span> /etc/samba/smb.conf <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'s/\\(^\\[global\\].*\\)/\\1\\n\\n    map archive = no/'</span> /etc/samba/smb.conf   <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/samba/smb.conf <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n</span><span class=\"no\">\n__EOF__\n</span></code></pre></div></div>\n\n<h4 id=\"ユーザの追加\">ユーザの追加</h4>\n\n<p>sambaのためのユーザを追加します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>pdbedit <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n</code></pre></div></div>\n\n<p>新しいパスワードを聞かれるので入力</p>\n\n<blockquote>\n  <p>[!NOTE]\n以前は<code class=\"language-plaintext highlighter-rouge\">sudo smbpasswd -a $USER</code> だったけど、最近は上のコマンドが正式らしい。<br />\n(まだ <code class=\"language-plaintext highlighter-rouge\">smbpasswd</code>も使えるけど)</p>\n</blockquote>\n\n<h4 id=\"sambaの再起動\">sambaの再起動</h4>\n\n<p>設定を反映するため、sambaを再起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl reload  smbd.service <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>systemctl restart smbd.service\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">Warning: The unit file, source configuration file or drop-ins of smbd.service changed on disk. Run 'systemctl daemon-reload' to reload units.</code>\nと言われたときは、<code class=\"language-plaintext highlighter-rouge\">sudo systemctl daemon-reload</code>を実行</p>\n</blockquote>\n\n<h3 id=\"nfsのインストール\">NFSのインストール</h3>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<h4 id=\"インストール-1\">インストール</h4>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<h4 id=\"設定ファイルの変更\">設定ファイルの変更</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">/NFSROOT</code>をエクスポートするため、<code class=\"language-plaintext highlighter-rouge\">/etc/exports</code>を修正。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/exports <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<h4 id=\"再起動\">再起動</h4>\n\n<p>変更した設定を反映するため、NFSを再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl restart nfs-server.service \n</code></pre></div></div>\n\n<h4 id=\"確認\">確認</h4>\n\n<h5 id=\"exportできているか確認\">exportできているか確認</h5>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>こんな感じで表示されればOK</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT      \t192.168.0.0/255.255.0.0\n</code></pre></div></div>\n\n<h5 id=\"別のマシンからマウントしてみる\">別のマシンからマウントしてみる</h5>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n\n<p>別のマシンから以下のコマンドを実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">abc</code>の下に今インストールしているPCの<code class=\"language-plaintext highlighter-rouge\">/NFSROOT</code>ディレクトリのファイルが見えたらOK</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<p>マスタイメージを残しておいて、色々な環境をお試しするには仮想マシンをクローンして使うのがおススメ。</p>\n<ul>\n  <li>VirtualBoxのメインウィンドウでマスタイメージの仮想マシンを右クリック→クローンを選択。</li>\n  <li>名前とパスを設定し、MACアドレスのポリシーは「すべてのネットワークアダプタでMACアドレスを生成」を選択。</li>\n  <li>「次へ」をクリック</li>\n  <li>すべてをクローンにチェックが入っていることを確認し、「完了」をクリック\nクローンが終了するまで待つ。</li>\n</ul>\n\n<p>クローンした仮想マシンを起動し、必要な変更を加える。</p>\n\n<h2 id=\"ネットワーク設定の変更\">ネットワーク設定の変更</h2>\n\n<p>マシン名とか同じ名前だと色々不都合があるので、変更しておく。<br />\n他のクローン仮想環境と同時に使わないならそのままでも良いけど。<br />\nIPアドレスも固定で割り振っておくと名前が引けない時にさくっと分かってなにかと便利…\nなんだけど、最近はWindowsもUbuntuもRaspberryPiもmDNSがサポートされてるから自動割り当てのままでもそんなに不便はないかも。</p>\n\n<p>ポリシー</p>\n<ul>\n  <li>IPアドレスの最終桁を決める(numberとする)。</li>\n  <li>ホスト名をskull≪number≫とする</li>\n  <li>ホストオンリーアダプタ/ブリッジアダプタの設定変更\n    <ul>\n      <li>IPv4アドレスを手動設定にする</li>\n      <li>IPv4アドレスの1桁目~3桁目、サブネットマスクを現在のIPアドレスと同じにする</li>\n      <li>IPv4アドレスの最終桁をnumberにする</li>\n      <li>GW、DNSが設定されていれば同じアドレスを設定する</li>\n    </ul>\n  </li>\n</ul>\n\n<p>以下の内容でスクリプトファイルを作成し、実行する。<br />\nホスト名などは適宜変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/usr/bin/env bash</span>\n\n<span class=\"c\"># 設定する数値の入力</span>\n<span class=\"nb\">read</span> <span class=\"nt\">-p</span> <span class=\"s2\">\"数値を入力してください: \"</span> number \n\n<span class=\"c\"># echo ${number}</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[[</span> <span class=\"o\">!</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">=</span>~ ^[0-9]+<span class=\"nv\">$ </span><span class=\"o\">]]</span><span class=\"p\">;</span> <span class=\"k\">then\n  </span><span class=\"nb\">echo</span> <span class=\"s1\">'数値ではありません'</span>\n  <span class=\"nb\">exit </span>1\n<span class=\"k\">fi\n\nif</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"nt\">-lt</span> 2 <span class=\"o\">]</span> <span class=\"o\">||</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"nt\">-gt</span> 254 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n  </span><span class=\"nb\">echo</span> <span class=\"s1\">'数値は2~254でなければなりません'</span>\n  <span class=\"nb\">exit </span>1\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># ホスト名の変更</span>\n<span class=\"nv\">old_name</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">hostname</span><span class=\"si\">)</span>\n<span class=\"nv\">new_name</span><span class=\"o\">=</span><span class=\"s2\">\"skull</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo nmcli general hostname </span><span class=\"k\">${</span><span class=\"nv\">new_name</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n<span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo sed -i -e \"</span>s/<span class=\"k\">${</span><span class=\"nv\">old_name</span><span class=\"k\">}</span>/<span class=\"k\">${</span><span class=\"nv\">new_name</span><span class=\"k\">}</span>/<span class=\"s2\">\" /etc/hosts\"</span>\n<span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n<span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n\n<span class=\"c\"># すべてのコネクション名を改行区切りで配列に取得</span>\n<span class=\"nv\">ORG_IFS</span><span class=\"o\">=</span><span class=\"nv\">$IFS</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"s1\">$'</span><span class=\"se\">\\n</span><span class=\"s1\">'</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span>nmcli  <span class=\"nt\">-t</span> <span class=\"nt\">-f</span> NAME connection<span class=\"si\">)</span><span class=\"o\">)</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"nv\">$ORG_IFS</span>        <span class=\"c\"># 元に戻す</span>\n\n<span class=\"k\">for </span>i <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"p\">!connections[@]</span><span class=\"k\">}</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各コネクションについて</span>\n    <span class=\"c\"># 直接取り出すとうまくいかないのでインデックス取り出して内容取得</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[</span><span class=\"nv\">$i</span><span class=\"p\">]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># 現在設定されているIPv4アドレスを取得</span>\n    <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.ADDRESS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n    <span class=\"c\"># 結果⇒ 「IP4.ADDRESS[1]: 192.168.78.215/24」</span>\n    \n    <span class=\"c\"># IPアドスの各桁とサブネットマスクを空白区切りで取得し、配列に代入</span>\n    <span class=\"c\"># 1個目のsed ⇒ 192.168.78.215/24</span>\n    <span class=\"c\"># 2個目のsed ⇒ 192 168 78 215 24</span>\n    <span class=\"nv\">ipv4octet</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/[</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]/ /g\"</span><span class=\"si\">)</span><span class=\"o\">)</span>\n    \n    <span class=\"c\"># echo ${str}</span>\n    <span class=\"c\"># echo ${ipv4octet[0]}  ${ipv4octet[1]}  ${ipv4octet[2]}  ${ipv4octet[3]}  ${ipv4octet[4]}</span>\n    \n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 192 <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 168 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n        <span class=\"c\"># 192.168.XX.XX のコネクション</span>\n        <span class=\"c\"># echo \"**** ${str} ****\"</span>\n        \n        <span class=\"c\"># 現在設定されているIPv4GWアドレスを取得</span>\n        <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.GATEWAY\"</span> <span class=\"si\">)</span>\n        <span class=\"c\"># 結果⇒ 「IP4.GATEWAY: 192.168.78.1」</span>\n        \n        <span class=\"c\"># IPv4GWアドレスを抽出(未定義では--なので-も抽出対象)</span>\n        <span class=\"nv\">gwaddr</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.</span><span class=\"s2\">-]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span><span class=\"si\">)</span>\n        <span class=\"c\"># \"--\" だったら空文字にする</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">=</span> <span class=\"s2\">\"--\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then </span><span class=\"nv\">gwaddr</span><span class=\"o\">=</span><span class=\"s2\">\"\"</span><span class=\"p\">;</span> <span class=\"k\">fi</span>\n        \n        <span class=\"c\"># 現在設定されているIPv4DNSアドレスを取得(未定義ならこのエントリがない)</span>\n        <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.DNS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n        <span class=\"c\"># 結果⇒ 「IP4.DNS[1]: 192.168.78.1」</span>\n        \n        <span class=\"c\"># IPv4DNSアドレスを抽出</span>\n        <span class=\"nv\">dnsaddr</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span><span class=\"si\">)</span>\n        \n        <span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"ipv4.method manual ipv4.addresses </span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[2]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[4]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n            </span><span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\"> ipv4.gateway </span><span class=\"k\">${</span><span class=\"nv\">gwaddr</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">fi\n        if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n            </span><span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\"> ipv4.dns </span><span class=\"k\">${</span><span class=\"nv\">dnsaddr</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">fi</span>\n        \n        <span class=\"c\"># echo ipv4.method manual ${set_str}</span>\n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n        \n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection down   </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n        \n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection up     </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone\n\n</span><span class=\"nb\">echo</span> <span class=\"o\">==</span><span class=\"nv\">DONE</span><span class=\"o\">==</span>\n</code></pre></div></div>\n\n<p>実行後、<br />\n<code class=\"language-plaintext highlighter-rouge\">ip address</code>や<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPアドレスが変更されていること、<br />\n<code class=\"language-plaintext highlighter-rouge\">hostname</code>でホスト名が変更されていること、<br />\n<code class=\"language-plaintext highlighter-rouge\">cat /etc/hosts</code>でhostsが変更されていること、\nをそれぞれ確認する。</p>\n\n<blockquote>\n  <p>[!TIP]\nIPアドレスの変更をGUIで行うには以下。<br />\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nこのスクリプトをマスタイメージのどこか(例えば<code class=\"language-plaintext highlighter-rouge\">~/bin</code>とか)に保存しておけば、\nクローンする度にスクリプトを実行すればIPアドレスとホスト名の変更をイッパツで完了できる。</p>\n</blockquote>\n\n<h2 id=\"あとはお約束\">あとはお約束</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade\n</code></pre></div></div>\n\n<p>VirtalBoxのバージョンが変更されているときは、GuestAdditionのバージョンアップも忘れずに。<br />\nまた、マスタイメージは定期的に<code class=\"language-plaintext highlighter-rouge\">sudo apt -U upgrade</code>しておくと\nクローン時のアップデート時間が短くて済む。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2 メモ(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2 メモ(改訂版)</h1>\n      <p>WSL2のディストリビューションインストール~初期設定に関するメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"インストール\">インストール</h1>\n<p>WSL自体はインストール済みとします。<br />\n(インストール方法はぐぐってちょ)</p>\n\n<p>ディストリビューションのインストールはコマンドプロンプト等で行います。</p>\n\n<h2 id=\"インストール可能なディストリビューション\">インストール可能なディストリビューション</h2>\n<p>オンラインでインストールできるディストリビューションの一覧は以下で表示できます。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--online</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"新しいディストリビューションのインストール\">新しいディストリビューションのインストール</h2>\n<p>表示されたディストリビューションからインストールしたいディストリビューションを選んでインストールします。<br />\n以下は Ubuntu-24.04 をインストールする例。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--install</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>インストールが終了したら自動的にディストリビューションが起動してユーザアカウントとパスワードの設定が行われますので、\n使用したいユーザ名とパスワードを設定してください。</p>\n\n<h1 id=\"セットアップ\">セットアップ</h1>\n\n<p>引き続きセットアップを行います。</p>\n\n<h2 id=\"アップデート\">アップデート</h2>\n<p>まずはアップデート</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nubuntu 24.04以降なら<code class=\"language-plaintext highlighter-rouge\">sudo apt -U upgrade</code> でもOK。</p>\n</blockquote>\n\n<h2 id=\"日本語化\">日本語化</h2>\n<p>日本語化のため、以下のインストール/設定を行います。</p>\n\n<ul>\n  <li>日本語ランゲージパックのインストール</li>\n  <li>ロケールの設定</li>\n  <li>日本語manページのインストール</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>language-pack-ja <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>update-locale <span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF8 <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>manpages-ja manpages-ja-dev \n</code></pre></div></div>\n\n<h2 id=\"クローンしたあとのデフォルトユーザを設定\">クローンしたあとのデフォルトユーザを設定</h2>\n\n<p>クローンした環境ではデフォルトでrootでログインしてしまうので、<br />\n現在のユーザをデフォルトユーザに設定しておきます。<br />\n(マスタで設定しておけば、クローンする毎に設定しなくて済むので)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span>  /etc/wsl.conf <span class=\"o\"><<</span> <span class=\"no\">__EOF__</span><span class=\"sh\">\n\n[user]\ndefault=</span><span class=\"nv\">$USER</span><span class=\"sh\">\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nPATHにWindowsのPATHを引き継がせない設定<br />\n仮想マシン起動語、PATHにWindows環境のPATHが引き継がれます。<br />\nWindows環境のPATHを引き継がせないようにすることもできます。</p>\n\n  <p>設定方法は <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に 以下の設定を追加します。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>interop]\nappendWindowsPath <span class=\"o\">=</span> <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n\n  <p>参考: <a href=\"https://zenn.dev/o2z/articles/zenn-20210524-01\" target=\"_blank\">WSL2でWindowsのPATH設定が引き継がれるのを解除する</a></p>\n\n  <p>なお、下の .bashrcの設定 ではWindowsのPATHを引き継いだうえで、\nWINDOWSディレクトリ下、VS Code格納ディレクトリ下以外のPATHを削除して不要なPATHを残さないようにしています。</p>\n</blockquote>\n\n<h2 id=\"ミニミニスクリプト\">ミニミニスクリプト</h2>\n<p>ちょっとした不便を解消するミニミニスクリプトを作成しておきます。</p>\n\n<p>以下はExplorerと秀丸をシンボリックリンクでも実体を追いかけて開いてくれるスクリプト</p>\n\n<blockquote>\n  <p>[!NOTE]\nたとえば、<code class=\"language-plaintext highlighter-rouge\">explorer.exe /lib</code>と実行するとエクスプローラでは<code class=\"language-plaintext highlighter-rouge\">/lib</code>を開けません。<br />\n以下のスクリプトを作成した後、<code class=\"language-plaintext highlighter-rouge\">explorer /lib</code>と実行すると\n<code class=\"language-plaintext highlighter-rouge\">/lib</code>の実体である<code class=\"language-plaintext highlighter-rouge\">/usr/lib</code>が開かれます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">~/bin</code>にpathを通すには、作成後再ログイン必要。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/bin\n\n<span class=\"nb\">tee</span> <span class=\"nt\">-a</span>  ~/bin/explorer <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n#!/usr/bin/env bash\n/mnt/c/WINDOWS/explorer.exe </span><span class=\"si\">$(</span>wslpath <span class=\"nt\">-w</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"sh\">\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">tee</span> <span class=\"nt\">-a</span>  ~/bin/hidemaru <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n#!/usr/bin/env bash\nEDITOR=\"/mnt/c/Program Files (x86)/Hidemaru/Hidemaru.exe\"\n\"</span><span class=\"k\">${</span><span class=\"nv\">EDITOR</span><span class=\"k\">}</span><span class=\"sh\">\" </span><span class=\"si\">$(</span>wslpath <span class=\"nt\">-w</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"sh\">&\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">chmod</span> +x ~/bin/<span class=\"k\">*</span>\n</code></pre></div></div>\n\n<h2 id=\"bashrcの設定\">.bashrcの設定</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に必要な変更/追加を行います。<br />\n以下は私の好みの設定なので、好みに合わせて変更してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.bashrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n\n# プロンプトの設定\n# PS1=\"</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\nPS1=\"</span><span class=\"se\">\\[\\e</span><span class=\"sh\">[36m</span><span class=\"se\">\\]</span><span class=\"nv\">$WSL_DISTRO_NAME</span><span class=\"se\">\\[\\e</span><span class=\"sh\">[0m</span><span class=\"se\">\\]</span><span class=\"sh\">:</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\n\n# キーバインドの設定\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-n\": history-search-forward'\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-p\": history-search-backward'\n\n# ディレクトリスタックの表示改善\nfunction pushd() {\n    command pushd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction popd() {\n    command popd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction dirs() {\n    command dirs -v\n}\n\n# 表示色変更\nexport LS_COLORS='di=01;32:ln=01;36:ex=01;31:'\nexport GREP_COLORS='mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'\n\n# lessのオプション\nexport LESS=\"-iMRq\"\n\n# grepのオプション指定(GREP_OPTIONS)は廃止されたのでaliasで設定\n# export GREP_OPTIONS=\"--exclude-dir .git\"\nalias grep='grep --exclude-dir .git'\n\n# WindowsのPATHのうち、\"WINDOWS\"を含むディレクトリ、\"VS Code\"を含むディレクトリ以外を削除\nexport PATH=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$PATH</span> | python3 <span class=\"nt\">-c</span> <span class=\"s1\">'import re,sys;PPP=sys.stdin.readline();print(\":\".join([a for a in PPP.split(\":\") if re.match(r\"^(?!\\/mnt)\", a) or re.match(r\"(^/mnt.*WINDOWS.*$|^/mnt.*VS Code.*$)\", a)]))'</span><span class=\"si\">)</span><span class=\"sh\">\n\n# for pyenv\nexport PYENV_ROOT=/proj/.pyenv    #環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    # 仮想環境名をプロンプトに表示しない場合は以下を有効化\n    # export VIRTUAL_ENV_DISABLE_PROMPT=1\n    eval \"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"sh\">\"          # pyenv 2.0以降で必要\n    eval \"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"sh\">\"\n    eval \"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"sh\">\"\n    export PYTHON_CONFIGURE_OPTS=\"</span><span class=\"se\">\\</span><span class=\"sh\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"sh\">\n    \"\nfi\n\n# for nodenv\nexport NODENV_ROOT=/proj/.nodenv    # 環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    eval \"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"sh\">\"\nfi\n\n# __pycache__ディレクトリの生成を抑制する\nexport PYTHONDONTWRITEBYTECODE=1\n\n<< '__COMMENT__'\n# この部分はミラーモードでは使えないし、WSLgサポートされたので特に必要ないのでコメントアウト\n# NATモードでは使えるが、hostコマンドインストール必要。(sudo apt install bind9-host)\n# HOSTのIPアドレス取得\n# export HOST_IP_ADDR=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span><span class=\"si\">)</span><span class=\"sh\">\n# HOSTのIPアドレス取得(アドレスが2つ以上返ってきたときは1個目だけ取り出す)\nexport HOST_IP_ADDR=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-n</span> 1p<span class=\"si\">)</span><span class=\"sh\">\n\n# DISPLAY変数が未定義(SSHログイン等)ならDISPLAYを設定する\nif [ -v </span><span class=\"nv\">$DISPLAY</span><span class=\"sh\"> ]; then\n    export DISPLAY=</span><span class=\"k\">${</span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"k\">}</span><span class=\"sh\">:0.0\nfi\necho DISPLAY=\"</span><span class=\"nv\">$DISPLAY</span><span class=\"sh\">\"\n__COMMENT__\n\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<p>変更した内容を有効にするには、再ログインするか、<code class=\"language-plaintext highlighter-rouge\">source ~/.bashrc</code>してください。</p>\n\n<h2 id=\"readlinebash等の設定\">readline(bash等)の設定</h2>\n\n<ul>\n  <li>beepを鳴らさない設定</li>\n  <li>ブラケットペーストモードを無効化する設定(コメントアウト)<br />\n無効化したければ<code class=\"language-plaintext highlighter-rouge\">enable-bracketed-paste</code> の行を有効にします</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalではブラケットペーストモードを無効にすると確認ダイアログでチェックできるようになりますが、\nブラケットペーストモードを有効にすると確認ダイアログは出ず入力欄で確認できるようになります。<br />\nTeraterm のように二重チェックにならないので有効にしてもストレスは少ないと思い無効にしていません。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span>  /etc/inputrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\nset bell-style visible\n# set enable-bracketed-paste off\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalの場合、beepを鳴らさない設定は <br />\n設定→各仮想環境の設定画面→詳細設定→ベル通知スタイル<br />\nからも変更できる。</p>\n</blockquote>\n\n<h2 id=\"vimの設定\">vimの設定</h2>\n\n<p>私はシンプルな1色表示が好きなのでsyntax highlightを無効にしておきます。<br />\nまた、<code class=\"language-plaintext highlighter-rouge\">sudo vi</code>実行時にも同じように動作するように、<code class=\"language-plaintext highlighter-rouge\">/root</code>にもコピーしておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">/etc/vim/vimrc</code>または<code class=\"language-plaintext highlighter-rouge\">/etc/vim/vimrc.local</code>に記述するとシステム全体で有効なはずですが、\nなぜかうまくいかないので自分とrootの設定を書き換えておきます。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.vimrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\nsyntax off\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">sudo cp</span> ~/.vimrc /root/\n\n</code></pre></div></div>\n\n<h2 id=\"一旦リブート\">一旦リブート</h2>\n\n<p>ここまでの設定を反映するため、念のためリブートしておきます。</p>\n\n<p>まず、ディストリビューションを停止します。<br />\n<code class=\"language-plaintext highlighter-rouge\">exit</code>コマンドやCTRL-Dでシェルを終了します。<br />\nこれだけではディストリビューションは終了していません。<br />\n(<code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>で「Running」になっている)<br />\nコマンドプロンプト等から以下のコマンドでディストリビューションを終了します。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>で「Stopped」になっていることを確認し、再度ディストリビューションを起動します。<br />\nこのとき、既に実行中のWindowsTerminalのドロップダウンメニューには新しいディストリビューションは表示されません。<br />\nあたらしくWindowsTerminalを開くとそのウィンドウのドロップダウンメニューには表示されますので、そこから実行します。</p>\n\n<p>引き続きセットアップを行います。</p>\n\n<h2 id=\"ワークディレクトリの作成\">ワークディレクトリの作成</h2>\n\n<p>ホームに色々置くのが嫌いなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span> /proj /work\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshをbashに変更\">デフォルトshをbashに変更</h2>\n\n<p>なんとなくいつも変更してるので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /usr/bin <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<h2 id=\"ツール類インストール\">ツール類インストール</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ifconfig</code>とか<code class=\"language-plaintext highlighter-rouge\">route</code>とかを使いたいので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n\n<h3 id=\"必要なツール類をインストール\">必要なツール類をインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev <span class=\"se\">\\</span>\n                    libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\n                    xz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div></div>\n\n<h3 id=\"pyenvのインストール-1\">pyenvのインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv  <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<p>pyenvを有効にするため、再ログイン(.bashrcに必要な処理は記載済み)。</p>\n\n<h3 id=\"pythonのインストール\">pythonのインストール</h3>\n\n<p>使いたいpythonのバージョンはそのシチュエーションで変わるので、<br />\nインストールするのはマスタからクローンした環境で行う方がいいかも。</p>\n\n<h4 id=\"インストール可能なバージョンを確認\">インストール可能なバージョンを確認</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span> | less\n</code></pre></div></div>\n\n<h4 id=\"インストール-1\">インストール</h4>\n\n<p>インストールが終わったらpip他をアップデートしておく。<br />\n(「pip 古いでぇ~」とうるさいので言われる前にやっとく)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.12.4\npyenv shell 3.12.4\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h1 id=\"仮想環境の複製\">仮想環境の複製</h1>\n\n<p>それまでの状態を保持した状態で新しい仮想環境を作成できます。<br />\n今までは一旦tarファイルにエクスポートしてからインポートしていましたが、\nvhdxファイルから直接インポートできるようになりました。</p>\n\n<h2 id=\"仮想hddファイルvhdxを探す\">仮想HDDファイル(.vhdx)を探す</h2>\n<p>インストールしたディストリビューションを含む各仮想環境の名前とパスの一覧は\n以下をコマンドプロンプト等で実行すると表示できる。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">reg</span><span class=\"w\"> </span><span class=\"nx\">query</span><span class=\"w\"> </span><span class=\"nx\">HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Lxss</span><span class=\"w\"> </span><span class=\"nx\">/s</span><span class=\"w\"> </span><span class=\"err\">^</span><span class=\"w\">\n</span><span class=\"o\">|</span><span class=\"w\"> </span><span class=\"n\">findstr</span><span class=\"w\"> </span><span class=\"s2\">\"BasePath DistributionName HKEY_CURRENT_USER\"</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n1行目末の<code class=\"language-plaintext highlighter-rouge\">^</code>は次行に続くことを示す。linuxの<code class=\"language-plaintext highlighter-rouge\">\\</code>と同じ</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">HKEY_CURRENT_USER</code>を検索しているのは区切り位置を見やすくするため</p>\n</blockquote>\n\n<h2 id=\"仮想環境をクローンする\">仮想環境をクローンする</h2>\n\n<p>クローンする仮想環境を停止する</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>確認(Stoppedになっていることを確認)</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\"> </span><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">-l</span><span class=\"w\"> </span><span class=\"nt\">-v</span><span class=\"w\">\n</span><span class=\"err\">・・・・・</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"仮想環境をクローンする-1\">仮想環境をクローンする</h2>\n<p>クローン先に移動しておく</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">cd</span><span class=\"w\"> </span><span class=\"nx\">F:\\WSL_VMs</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>クローンを作成するには以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"err\">≪クローンの名前≫</span><span class=\"w\"> </span><span class=\"err\">≪クローンの保存先≫</span><span class=\"w\"> </span><span class=\"err\">≪クローン元の</span><span class=\"nx\">vhdx</span><span class=\"err\">ファイル≫</span><span class=\"w\"> </span><span class=\"nt\">--vhd</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>例えば、</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04-temp1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">\\Ubuntu-24.04-temp1</span><span class=\"w\"> </span><span class=\"o\">%</span><span class=\"nx\">LOCALAPPDATA</span><span class=\"o\">%</span><span class=\"nx\">\\Packages\\CanonicalGroupLimited.Ubuntu24.04LTS_79rhkp1fndgsc\\LocalState\\\\ext4.vhdx</span><span class=\"w\"> </span><span class=\"nt\">--vhd</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>クローンが完了したらクローンした仮想環境を実行します。</p>\n\n<h3 id=\"削除\">削除</h3>\n<p>不要になった仮想環境は削除する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"err\">«削除する仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04-2</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h1 id=\"wsl2上のサーバプログラムへのアクセス\">WSL2上のサーバプログラムへのアクセス</h1>\n<p>参考:<a href=\"https://www.atmarkit.co.jp/ait/articles/1909/09/news020.html\" target=\"_blank\">Linuxがほぼそのまま動くようになった「WSL2」のネットワーク機能</a></p>\n\n<table>\n  <thead>\n    <tr>\n      <th>向き</th>\n      <th>可否</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>HOST → WSL2</td>\n      <td>localhost でアクセスできる</td>\n    </tr>\n    <tr>\n      <td>WSL2 → HOST</td>\n      <td>localhost でアクセスできない。<br /> IPアドレス指定ならアクセスできる。</td>\n    </tr>\n  </tbody>\n</table>\n\n<p>Windows11の場合は、ネットワークをミラーモードに設定するとどちらもlocalhostでアクセスできます。<br />\nそれどころか、外部PCからWSLの仮想環境内に直接アクセスできます。<br />\nただし、ポート番号はWindows、各仮想環境で共通で使用されるので、\n他で使用していないポート番号を使用しなければなりません。<br />\nミラーモードに設定するには、<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%\\.wslconfig</code> に以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[wsl2]\nnetworkingMode=mirrored\n</code></pre></div></div>\n<p>参考:<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/networking#mirrored-mode-networking\" target=\"_blank\">WSL を使用したネットワーク アプリケーションへのアクセス/ミラー モードのネットワーク</a></p>\n\n<h1 id=\"virtualboxとの共存\">Virtualboxとの共存</h1>\n\n<p>参考:<a href=\"https://zenn.dev/yuni_hutsuka/articles/46923a0b345619\" target=\"_blank\">【REPORT】Ubuntu Desktop on VirtualBox と wsl2 の共存</a></p>\n\n<p>要は「Windows ハイパーバイザープラットフォームを有効化する」だけど、設定箇所にたどり着くのがメンドクサイので\n上の参考サイトを見てね。</p>\n\n<h1 id=\"なんかのときに使うかも\">なんかのときに使うかも</h1>\n\n<h2 id=\"仮想ディスクが肥大化した場合の対処方法\">仮想ディスクが肥大化した場合の対処方法</h2>\n<p><del><a href=\"https://qiita.com/386jp/items/e469333c5a74789db46d\" target=\"_blank\">WSL2を使っているパソコンのディスク容量が枯渇したときにやってみるべきこと</a></del><br />\nこっちの方が分かりやすかった。<br />\n<a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1271vhdexpcmd/vhdexpcmd.html\" target=\"_blank\">仮想ディスクをコマンドラインから拡大/縮小する</a></p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>PS: XXXX> diskpart                                                 ← コマンド起動\n\nMicrosoft DiskPart バージョン 10.0.19041.964\n\nCopyright (C) Microsoft Corporation.\nコンピューター: XXXXXX\n\nDISKPART> select vdisk file=\"f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\" ← 圧縮したいvhdxファイル\n\nDiskPart により、仮想ディスク ファイルが選択されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   20 GB\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART> compact vdisk                                            ← 縮小の実行\n\n  100% 完了しました                       ← ちょっと時間がかかる\n\nDiskPart により、仮想ディスク ファイルは正常に圧縮されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   12 GB                      ← 小さくなった\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART>exit                                                      ← 終了\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>HTMLで疑似トースト表示</title>\n  </head>\n  <body>\n    <header>\n      <h1>HTMLで疑似トースト表示</h1>\n      <p>HTMLで疑似(なんちゃって)トースト表示するサンプル</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Javascriptでスクリプト書いていて、alert表示するとOKボタン押すまで戻ってこなくて使い勝手が悪いので、\n一定時間表示して勝手に消えるトースト表示みたいな表示ができないかと作ってみた。<br />\nあくまで簡易的なものなので、ウィンドウ作ったりとかはしてない。</p>\n\n<p>妙なこだわりで、消えるときはふわと消える(フェードアウト)にしてみた。<br />\n<code class=\"language-plaintext highlighter-rouge\">fadetime</code>を0にしたらぱっと消える。<br />\nま、ぱっと出てぱっと消えるなら<code class=\"language-plaintext highlighter-rouge\">style.visibility =\"visible\"</code>と<code class=\"language-plaintext highlighter-rouge\">style.visibility =\"hidden\"</code>でいいけど。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>以下のソースを適当に保存して、ブラウザで開いてちょ。<br />\nローカルファイル(file://)で開いてもOK。</p>\n\n<p>説明するほどのことはないので省略。</p>\n\n<p>ページの先頭に固定なので、スクロールしたら消えちゃうけど、\n表示領域の固定(position: fixed など)を使えばなんとかなりそう。</p>\n\n<p>表示が消える前に次の表示を始めたらうまくいかないかも…</p>\n\n<div class=\"language-html highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\"><!DOCTYPE HTML></span>\n<span class=\"nt\"><html</span> <span class=\"na\">lang=</span><span class=\"s\">\"ja\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><head></span>\n<span class=\"nt\"><meta</span> <span class=\"na\">charset=</span><span class=\"s\">\"UTF-8\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><title></span>疑似トースト表示<span class=\"nt\"></title></span>\n<span class=\"nt\"><script></span>\n<span class=\"c1\">// msgをdisptime(msec)表示後、fadetime(msec)でフェードアウトする</span>\n<span class=\"kd\">function</span> <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"nx\">msg</span><span class=\"p\">,</span> <span class=\"nx\">disptime</span><span class=\"o\">=</span><span class=\"mi\">2000</span><span class=\"p\">,</span> <span class=\"nx\">fadetime</span><span class=\"o\">=</span><span class=\"mi\">2000</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"kd\">let</span> <span class=\"nx\">elm</span> <span class=\"o\">=</span> <span class=\"nb\">document</span><span class=\"p\">.</span><span class=\"nx\">getElementById</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">toast</span><span class=\"dl\">\"</span><span class=\"p\">)</span>\n  <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">innerText</span> <span class=\"o\">=</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>            <span class=\"c1\">// 表示メッセージの変更</span>\n  <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">style</span><span class=\"p\">.</span><span class=\"nx\">animation</span> <span class=\"o\">=</span> <span class=\"dl\">\"</span><span class=\"s2\">none</span><span class=\"dl\">\"</span><span class=\"p\">;</span>   <span class=\"c1\">// アニメーションをキャンセルして表示する</span>\n  <span class=\"nx\">setTimeout</span><span class=\"p\">(()</span> <span class=\"o\">=></span> <span class=\"p\">{</span>              <span class=\"c1\">// disptime経過後、アニメーションを開始する。</span>\n    <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">style</span><span class=\"p\">.</span><span class=\"nx\">animation</span> <span class=\"o\">=</span> <span class=\"s2\">`fadeOut </span><span class=\"p\">${</span><span class=\"nx\">fadetime</span><span class=\"p\">}</span><span class=\"s2\">ms forwards`</span><span class=\"p\">;</span>\n  <span class=\"p\">},</span> <span class=\"nx\">disptime</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// ボタンクリック時にコールされる関数</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message1</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ1</span><span class=\"dl\">\"</span><span class=\"p\">,</span><span class=\"mi\">1000</span><span class=\"p\">,</span> <span class=\"mi\">4000</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message2</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ2</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"mi\">3000</span><span class=\"p\">,</span> <span class=\"mi\">1000</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message3</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ3</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message4</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ4</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"mi\">3000</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"nt\"></script></span>\n<span class=\"nt\"></head></span>\n\n<span class=\"nt\"><style></span>\n<span class=\"c\">/* フェードアウトのキーフレーム */</span>\n<span class=\"k\">@keyframes</span> <span class=\"n\">fadeOut</span> <span class=\"p\">{</span>\n  <span class=\"err\">0</span><span class=\"o\">%</span> <span class=\"p\">{</span>\n    <span class=\"nl\">opacity</span><span class=\"p\">:</span> <span class=\"m\">1</span><span class=\"p\">;</span>\n  <span class=\"p\">}</span>\n  <span class=\"err\">100</span><span class=\"o\">%</span> <span class=\"p\">{</span>\n    <span class=\"nl\">opacity</span><span class=\"p\">:</span> <span class=\"m\">0</span><span class=\"p\">;</span>\n  <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c\">/* トースト表示領域 */</span>\n<span class=\"nf\">#toast</span><span class=\"p\">{</span>\n  <span class=\"c\">/* 背景色 */</span>\n  <span class=\"nl\">background-color</span><span class=\"p\">:</span> <span class=\"nb\">rgb</span><span class=\"p\">(</span><span class=\"m\">128</span><span class=\"p\">,</span><span class=\"m\">256</span><span class=\"p\">,</span><span class=\"m\">128</span><span class=\"p\">);</span>\n  <span class=\"c\">/* 0secでアニメーションして表示を消しておく */</span>\n  <span class=\"nl\">animation</span><span class=\"p\">:</span> <span class=\"n\">fadeOut</span> <span class=\"m\">0s</span> <span class=\"n\">forwards</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n<span class=\"c\">/* ボタンを大きくしたいので */</span>\n<span class=\"nc\">.font-large</span><span class=\"p\">{</span>\n    <span class=\"nl\">font-size</span><span class=\"p\">:</span> <span class=\"m\">130%</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n<span class=\"nt\"></style></span>\n\n<span class=\"nt\"><body></span>\n<span class=\"nt\"><font</span> <span class=\"na\">size=</span><span class=\"s\">\"5\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><div></span>\n  <span class=\"nt\"><H3></span>疑似トースト表示<span class=\"nt\"></H3></span>\n  <span class=\"c\"><!-- トースト表示領域 --></span>\n  <span class=\"nt\"><div</span> <span class=\"na\">id=</span><span class=\"s\">\"toast\"</span><span class=\"nt\">></span>\n    メッセージ領域\n  <span class=\"nt\"></div></span>\n  \n  <span class=\"c\"><!-- テスト用ボタン --></span>\n  <span class=\"nt\"><div></span>\n    <span class=\"nt\"><p></span>\n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ1\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message1();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ2\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message2();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ3\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message3();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ4\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message4();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n    <span class=\"nt\"></p></span>\n  <span class=\"nt\"><div></span>\n<span class=\"nt\"></div></span>\n<span class=\"nt\"></font></span>\n<span class=\"nt\"></body></span>\n<span class=\"nt\"></html></span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Web Bluetooth APIを試す</title>\n  </head>\n  <body>\n    <header>\n      <h1>Web Bluetooth APIを試す</h1>\n      <p>Web bluetooth APIを試した時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>ブラウザからBluetoothにアクセスできる<a href=\"https://developer.mozilla.org/ja/docs/Web/API/Web_Bluetooth_API\" target=\"_blank\">Web Bluetooth API</a>\nを試してみた時に作ったプログラムを貼っておきます。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"ペリフェラル機器\">ペリフェラル機器</h2>\n\n<p>BLEは通信なので、通信相手が必要です。<br />\n市販機器を使うと仕様を調べるのが大変なので、エイヤッと自分で作っりました。<br />\nといっても Raspberry Pi Pico W にmicropythonのF/Wを書き込んでプログラム実行するだけ。<br />\n(使用したmicropython F/Wは「MicroPython v1.23.0 on 2024-06-02」です)</p>\n\n<p>以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。 と言ってもWi-Fiとか要らないからパクり先のリンク貼ってあるだけだけど。</p>\n\n<p>ということで、以下のソースを Raspberry Pi Pico で実行しておきます。<br />\n(特にH/W依存なことはしてないので、ESP32でも動くかも)</p>\n\n<p>BLEの処理については「micropython aioble」とかでググってください。<br />\nでも、公式のサンプル動かした例ばっかりであんまりないんだよなぁ…</p>\n\n<p>==懺悔==<br />\nUUIDはどっかのサンプルの値をちょこっといじったものです。<br />\n(調べたら温度計用のUUIDでした)<br />\n本来ならUUIDをちゃんと生成しないといけません。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=ble_peripheral.py\"></script>\n</dev>\n\n<h2 id=\"webサーバ\">Webサーバ</h2>\n<p>Web Bluetooth APIを使用するのは、HTMLファイルをHTTPSサーバからロードしなければならない仕様のようです。\n(httpやfileでは不可)<br />\nファイル1個だけなので、どこかのサーバの片隅に置くとかでも良いと思います。<br />\nローカルでサーバを立てるならApacheとかnginxとかで立ててください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsでApacheを使うなら<a href=\"https://nanbu.marune205.net/2022/01/windows10-apache-ssl.html?m=1\" target=\"_blank\">WindowsのApacheサーバーでSSL</a>\nあたりが参考になりました。<br />\nただし、仮の証明書を作るバッチファイルで、Apacheのインストール先がc:¥Apache24 以外の場合は\n以下の設定を追加しておく必要があります。</p>\n  <div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SET</span><span class=\"w\"> </span><span class=\"nx\">OPENSSL_CONF</span><span class=\"o\">=</span><span class=\"err\">≪</span><span class=\"n\">Apache</span><span class=\"err\">のインストール先≫</span><span class=\"nx\">\\conf\\openssl.cnf</span><span class=\"w\">\n</span></code></pre></div>  </div>\n  <p>インストール先を<code class=\"language-plaintext highlighter-rouge\">m:\\Apache24</code>にした場合の変更例はこんな感じ。</p>\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- aaa.txt     2024-07-29 06:58:34.154735900 +0900\n</span><span class=\"gi\">+++ make-snakeoil-cert.bat      2024-07-26 05:09:37.394502700 +0900\n</span><span class=\"p\">@@ -1,8 +1,11 @@</span>\n REM openssl.exe\n<span class=\"gd\">-SET OPENSSL=c:\\Apache24\\bin\\openssl.exe\n</span><span class=\"gi\">+SET OPENSSL=m:\\Apache24\\bin\\openssl.exe\n+\n+REM openssl.cnf\n+SET OPENSSL_CONF=m:\\Apache24\\conf\\openssl.cnf\n</span>\n REM 証明書用データの出力場所\n<span class=\"gd\">-SET ROOTDIR=c:\\Apache24\\certs\n</span><span class=\"gi\">+SET ROOTDIR=m:\\Apache24\\certs\n</span>\n REM サーバーのドメインまたはIPアドレス\n SET IPADDRESS=localhost\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h1 id=\"htmlファイル\">HTMLファイル</h1>\n\n<p>Web Bluetooth API のサンプルプログラムを以下に示します。<br />\nこれをHTTPSサーバに置いておきます</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=BLE_sample.html\"></script>\n</dev>\n\n<h1 id=\"実験\">実験</h1>\n\n<p>ペリフェラルプログラムを動作させておき、\nブラウザで上記HTMLファイルを開きます。</p>\n\n<p>アクセスするPCやスマホはBLE対応のBluetoothが搭載されている必要があります。<br />\nブラウザはChromeかEdge(は試してないけど)で。(firefox不可)</p>\n\n<p>WindowsPCとAndroidスマホのChromeは動作確認しました。<br />\nmacとiPhoneは持ってないので試してません。</p>\n\n<p>次に「接続」ボタンをクリック、「XXXXXがペア接続を要求しています」ダイアログが出るので\n「mpy-sensor」を選択し、「ペア設定」をクリックします。</p>\n\n<p>接続されると DATA1 に受信したデータを表示します。<br />\nDATA1はNotificationありのデータ読み取りです。<br />\nNotificationイベントを受けてデータを読み取ります。<br />\n上は1行を常に書き換えるタイプ。<br />\n下は過去分を含め10行程度表示(それ以前は削除)するタイプです。<br />\n受診自体は1回でページの書き換え処理を2通り行っています。</p>\n\n<p>DATA2はNotificationなしのデータ読み取りです。<br />\nREADボタンをクリックすると読み取った値を表示します。</p>\n\n<p>測定間隔のテキストボックスに数値を入力し、「WRITE」をクリックすると\nDATA1の取得間隔を変更できます。<br />\n値は100~5000が有効で、範囲外の値が設定されると範囲内の値に補正されます(補正はペリフェラル川で行っています)。</p>\n\n<p>接続を終了するには「切断」をクリックします。</p>\n\n<h1 id=\"操作例\">操作例</h1>\n\n<p><a href=\"/memoBlog/misc/WEB_BT_API_2024-07-29_075522.mp4\" target=\"_blank\">操作例の動画</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) でI2C Slave その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) でI2C Slave その2</h1>\n      <p>Raspberry Pi Pico W の SDK を使用してI2C Slaveプログラムを作成する(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/10/28/RasPiPico_i2c_slave.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) でI2C Slave</a>\nでI2Cスレーブのプログラムを載せましたが、ちょっと特殊な構成のデバイスをエミュレートしていたので\n一般的なレジスタアクセスをエミュレートするプログラムを作ってみました。</p>\n\n<blockquote>\n  <p>[!NOTE]\n公式サンプル<code class=\"language-plaintext highlighter-rouge\">pico-examples/i2c/slave_mem_i2c</code>をちょこっと修正しただけですが。</p>\n</blockquote>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"i2cの結線\">I2Cの結線</h2>\n\n<p>以下のように結線します。<br />\nPico側はソース中の割り当て端子を変更すれば別の端子でもOKです。<br />\n今回はI2C0とI2C1を使うので、両方結線します。<br />\npull-up抵抗はPi3についているのでここでは付けません。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>Pi3</th>\n      <th>Pico</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>SDA1(pin3)</td>\n      <td>I2C0_SDA/GP16(Pin21) I2C1_SDA/GP18(Pin24)</td>\n    </tr>\n    <tr>\n      <td>SCL1(pin5)</td>\n      <td>I2C0_SCL/GP17(Pin22) I2C1_SCL/GP19(Pin25)</td>\n    </tr>\n  </tbody>\n</table>\n\n<blockquote>\n  <p>[!NOTE]\n別に2ch使わなくても良いのですが、8bitアクセスと16bitアクセスを作りたかったので。<br />\nそれぞれ別のプログラムにすると動作確認が面倒だったのでまとめちゃいました。</p>\n</blockquote>\n\n<p>その他の準備は\n<a href=\"/memoBlog/2023/10/28/RasPiPico_i2c_slave.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) でI2C Slave</a>\nを参照してください。</p>\n\n<h1 id=\"picoのプログラム\">Picoのプログラム</h1>\n\n<h2 id=\"プロジェクト生成\">プロジェクト生成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">pico_project</code>でプロジェクトを生成します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">pico_project</code>については、\n<a href=\"/memoBlog/2023/10/23/RasPiPico_3.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</a>\nの「自作プロジェクトの作成」を参照してください)</p>\n</blockquote>\n\n<p>設定内容は以下の通りです</p>\n\n<ul>\n  <li>Project Name に プロジェクト名(例:i2c_slave_2ch)</li>\n  <li>Location に プロジェクトを作成するディレクトリ</li>\n  <li>Board Type で「pico_w」を選択</li>\n  <li>Library Options で「I2C interface」を選択</li>\n  <li>Pico wireless Options で「PicoW onboard LED」を選択</li>\n  <li>Console Options では必要な方式をチェック(両方でも可)</li>\n  <li>IDE Options で「Create VSCode Project」にチェック、「Debugger」は「SWD」を選択</li>\n</ul>\n\n<h2 id=\"プログラムの作成\">プログラムの作成</h2>\n<p>作成したプログラムを以下に示します。</p>\n\n<h3 id=\"メインルーチン\">メインルーチン</h3>\n\n<p>メインルーチンはI2Cを初期化したあと無限ループします。<br />\nループ内ではI2Cに関する処理はなく、生存確認用のLチカと\nキー入力監視して入力に応じて処理を行っています。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_2ch.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/stdlib.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"hardware/i2c.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/cyw43_arch.h\"</span><span class=\"cp\">\n</span>\n<span class=\"c1\">// プロトタイプ宣言</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n\n\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n\n\n<span class=\"kt\">int64_t</span> <span class=\"nf\">alarm_callback</span><span class=\"p\">(</span><span class=\"n\">alarm_id_t</span> <span class=\"n\">id</span><span class=\"p\">,</span> <span class=\"kt\">void</span> <span class=\"o\">*</span><span class=\"n\">user_data</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// Put your timeout handler code in here</span>\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"kt\">int</span> <span class=\"nf\">main</span><span class=\"p\">()</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">stdio_init_all</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// STDIOがUSBのとき、USB認識されないことがあるのでstdio初期化の後、ちょっと待つ</span>\n    <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">3000</span><span class=\"p\">);</span>\n\n    <span class=\"n\">puts</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">I2C slave 2ch\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// LEDを使うためにwifi初期化</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">cyw43_arch_init</span><span class=\"p\">())</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"Wi-Fi init failed\"</span><span class=\"p\">);</span>\n        <span class=\"k\">return</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\">// I2Cスレーブ 初期化</span>\n    <span class=\"n\">setup_i2c_slave0</span><span class=\"p\">();</span>\n    <span class=\"n\">setup_i2c_slave1</span><span class=\"p\">();</span>\n    \n\n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// ==== 生存確認用にLチカ ====</span>\n        <span class=\"c1\">// 現在の出力値取得</span>\n        <span class=\"n\">bool</span> <span class=\"n\">led_out</span> <span class=\"o\">=</span> <span class=\"n\">cyw43_arch_gpio_get</span> <span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">);</span>\n        <span class=\"c1\">// 出力反転</span>\n        <span class=\"n\">cyw43_arch_gpio_put</span><span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">,</span> <span class=\"o\">!</span><span class=\"n\">led_out</span><span class=\"p\">);</span>\n\n        <span class=\"c1\">// キー入力監視</span>\n        <span class=\"kt\">int</span> <span class=\"n\">key_in</span> <span class=\"o\">=</span>  <span class=\"n\">getchar_timeout_us</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'D'</span><span class=\"p\">)</span> <span class=\"o\">||</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'d'</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// 表示モード反転</span>\n            <span class=\"n\">DISP_flag</span> <span class=\"o\">=</span> <span class=\"o\">!</span><span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"**** DISP on ****</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"**** DISP off ****</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'0'</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// slave0データ表示</span>\n            <span class=\"n\">disp_data_slave0</span><span class=\"p\">();</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'1'</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// slave1データ表示</span>\n            <span class=\"n\">disp_data_slave1</span><span class=\"p\">();</span>\n        <span class=\"p\">}</span>\n\n\n        <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">1000</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"i2c0処理\">I2C0処理</h3>\n\n<h4 id=\"初期化\">初期化</h4>\n<p>I2C0の初期化は<code class=\"language-plaintext highlighter-rouge\">setup_i2c_slave0</code>です。<br />\n主に端子の初期化とI2C0の初期化、\nI2Cスレーブの初期化(I2C割り込みハンドラからのコールバックの登録)を行っています。</p>\n\n<p>読み書きするデータは1アドレスあたり8bitとしています。</p>\n\n<h4 id=\"処理本体\">処理本体</h4>\n<p>I2C0処理本体は<code class=\"language-plaintext highlighter-rouge\">i2c_slave0_handler()</code>です。</p>\n\n<p>これはI2C割り込みハンドラからのコールバック処理です。<br />\nなので、できるだけ速やかにリターンする必要があります。\nprintfなどの時間のかかる処理は行わないほうが良いのですが、\nデバッグ用途に送受信データを表示したいのでprintfで表示しています。<br />\nprintfをなくして高速に応答できるように、フラグを使用してprintfの有効/無効化を行っています。<br />\nフラグはメインルーチンでコンソールからのキー入力で切り替えています。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave0.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/rand.h></span><span class=\"c1\">      // 乱数</span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"k\">extern</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">16</span><span class=\"p\">;</span>  <span class=\"c1\">//GP16(Pin21)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">17</span><span class=\"p\">;</span>  <span class=\"c1\">//GP17(Pin22)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">256</span><span class=\"p\">];</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>\n    <span class=\"n\">bool</span> <span class=\"n\">mem_address_written</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"== ch0 ==  addr : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"mh\">0xff</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">+=</span><span class=\"mh\">0x10</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"%02x : %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">14</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">get_rand_32</span><span class=\"p\">();</span>        <span class=\"c1\">// 乱数で初期化</span>\n    <span class=\"p\">}</span>\n    <span class=\"c1\">// アドレス初期化</span>\n    <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではないけど使っちゃお...</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave0_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// STOP/RESTART後の最初の書き込みはアドレス更新</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 set memory address : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// メモリ内容書き換え</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 write memory : %02x : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// メモリから1バイト送信する</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">];</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 read memory : %02x : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// 次の書き込みはアドレス更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 STOP/RESTART condition</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch0</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave0_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch0 done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"i2c1処理\">I2C1処理</h3>\n\n<p>I2C1は読み書きするデータが1アドレスあたり16bitとしていることを除けばI2C0と同じです。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave1.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/rand.h></span><span class=\"c1\">      // 乱数</span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"k\">extern</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x32</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">18</span><span class=\"p\">;</span>  <span class=\"c1\">//GP18(Pin24)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">19</span><span class=\"p\">;</span>  <span class=\"c1\">//GP19(Pin25)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">512</span><span class=\"p\">];</span>\n    <span class=\"kt\">uint16_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>\n    <span class=\"n\">bool</span> <span class=\"n\">mem_address_written</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"== ch1 ==  addr : %02x  %s</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">);</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"mh\">0x200</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">+=</span><span class=\"mh\">0x10</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"%03x : %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">14</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">get_rand_32</span><span class=\"p\">();</span>        <span class=\"c1\">// 乱数で初期化</span>\n    <span class=\"p\">}</span>\n    <span class=\"c1\">// アドレス初期化</span>\n    <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではないけど使っちゃお...</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave1_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// STOP/RESTART後の最初の書き込みはアドレス更新</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint16_t</span><span class=\"p\">)</span><span class=\"n\">addr</span> <span class=\"o\">*</span> <span class=\"mi\">2</span><span class=\"p\">;</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 set memory address : %02x(%03x)</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// メモリ内容書き換え</span>\n            <span class=\"kt\">uint16_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n            <span class=\"p\">}</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 write memory : %02x %s : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span>  <span class=\"n\">addr</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// メモリから1バイト送信する</span>\n        <span class=\"kt\">uint16_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"p\">}</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">];</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 read memory : %02x %s : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span>  <span class=\"n\">addr</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// 次の書き込みはアドレス更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 STOP/RESTART condition</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch1</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c1</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c1</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE1_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave1_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch1 done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n</code></pre></div></div>\n\n<h3 id=\"cmake設定ファイル\">cmake設定ファイル</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>の\n<code class=\"language-plaintext highlighter-rouge\">add_executable</code> に <code class=\"language-plaintext highlighter-rouge\">i2c_slave0.c</code>と<code class=\"language-plaintext highlighter-rouge\">i2c_slave1.c</code>(追加したファイル名)を追加します。<br />\n<code class=\"language-plaintext highlighter-rouge\">target_link_libraries</code> に <code class=\"language-plaintext highlighter-rouge\">pico_i2c_slave</code>(I2Cスレーブを使用)と<code class=\"language-plaintext highlighter-rouge\">pico_rand</code>(乱数を使用)を追加します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  CMakeLists.txt\n</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># Generated Cmake Pico project file</span>\n\n<span class=\"nb\">cmake_minimum_required</span><span class=\"p\">(</span>VERSION 3.13<span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_C_STANDARD 11<span class=\"p\">)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_CXX_STANDARD 17<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise pico_sdk from installed location</span>\n<span class=\"c1\"># (note this can come from environment, CMake cache etc)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_SDK_PATH <span class=\"s2\">\"/work/pico/pico-sdk\"</span><span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_BOARD pico_w CACHE STRING <span class=\"s2\">\"Board type\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># Pull in Raspberry Pi Pico SDK (must be before project)</span>\n<span class=\"nb\">include</span><span class=\"p\">(</span>pico_sdk_import.cmake<span class=\"p\">)</span>\n\n<span class=\"nb\">if</span> <span class=\"p\">(</span>PICO_SDK_VERSION_STRING VERSION_LESS <span class=\"s2\">\"1.4.0\"</span><span class=\"p\">)</span>\n  <span class=\"nb\">message</span><span class=\"p\">(</span>FATAL_ERROR <span class=\"s2\">\"Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is </span><span class=\"si\">${</span><span class=\"nv\">PICO_SDK_VERSION_STRING</span><span class=\"si\">}</span><span class=\"s2\">\"</span><span class=\"p\">)</span>\n<span class=\"nb\">endif</span><span class=\"p\">()</span>\n\n<span class=\"nb\">project</span><span class=\"p\">(</span>i2c_slave_2ch C CXX ASM<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise the Raspberry Pi Pico SDK</span>\n<span class=\"nf\">pico_sdk_init</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># Add executable. Default name is the project name, version 0.1</span>\n\n<span class=\"nb\">add_executable</span><span class=\"p\">(</span>i2c_slave_2ch \n                i2c_slave_2ch.c\n                i2c_slave0.c\n                i2c_slave1.c\n                <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_set_program_name</span><span class=\"p\">(</span>i2c_slave_2ch <span class=\"s2\">\"i2c_slave_2ch\"</span><span class=\"p\">)</span>\n<span class=\"nf\">pico_set_program_version</span><span class=\"p\">(</span>i2c_slave_2ch <span class=\"s2\">\"0.1\"</span><span class=\"p\">)</span>\n\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>i2c_slave_2ch 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>i2c_slave_2ch 0<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard library to the build</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_2ch\n        pico_stdlib<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard include files to the build</span>\n<span class=\"nb\">target_include_directories</span><span class=\"p\">(</span>i2c_slave_2ch PRIVATE\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>/.. <span class=\"c1\"># for our common lwipopts or any other standard includes, if required</span>\n<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add any user requested libraries</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_2ch \n        hardware_i2c\n        pico_cyw43_arch_none\n        pico_i2c_slave\n        pico_rand\n        <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_add_extra_outputs</span><span class=\"p\">(</span>i2c_slave_2ch<span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>あとはビルドしてRaspberry Pi Picoに書き込みます。</p>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認です。<br />\nここからはRaspberry Pi3 での作業です。</p>\n\n<h2 id=\"i2cdetect\">i2cdetect</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdetect</code> で I2Cバス上でデバイスが検出されるか確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n\n<p>Picoのプログラムで設定したスレーブアドレス(<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>と<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE1_ADDRESS</code>の設定値。上のプログラムだと0x17と0x32)\nが表示されていればOKです。<br />\n表示されていない場合はPicoのプログラムやボードの結線を見直してください。</p>\n\n<h2 id=\"i2cdump\">i2cdump</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdump</code> で レジスタダンプしてみます。</p>\n\n<h3 id=\"i2c0\">I2C0</h3>\n<p>I2C0のレジスタをダンプしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdump <span class=\"nt\">-y</span> 1 0x17\n</code></pre></div></div>\n<p>RaspberryPiPICOのコンソールで<code class=\"language-plaintext highlighter-rouge\">0</code>を入力し、Slave0のレジスタをダンプした内容と比較して\n内容が同じであることを確認します。</p>\n\n<h3 id=\"i2c1\">I2C1</h3>\n<p>I2C1のレジスタをダンプしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdump <span class=\"nt\">-y</span> 1 0x32 w\n</code></pre></div></div>\n<p>RaspberryPiPICOのコンソールで<code class=\"language-plaintext highlighter-rouge\">1</code>を入力し、Slave1のレジスタをダンプした内容と比較して\n内容が同じであることを確認します。</p>\n\n<h2 id=\"その他\">その他</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cset</code>や<code class=\"language-plaintext highlighter-rouge\">i2cget</code>で色々読み書きしてみてください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tkinter で 低層のウィジェットでイベントを検出する</title>\n  </head>\n  <body>\n    <header>\n      <h1>tkinter で 低層のウィジェットでイベントを検出する</h1>\n      <p>tkinter で 低層のウィジェットでイベントを検出する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>tkinterでイベントを検出する際、対象のウィジェットの手前に別のウィジェットがあるとイベントを検出できません。<br />\nそれを回避し、手前にウィジェットが存在してもイベントが検出できるサンプルプログラムを書いてみました。</p>\n\n<h1 id=\"サンプルプログラム\">サンプルプログラム</h1>\n\n<p>さっそくサンプルプログラムを貼りつけておきます。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/59faf9f974e22d34a8e988954a32518b.js\"></script>\n</dev>\n\n<h2 id=\"解説のようなもの\">解説のようなもの</h2>\n\n<h3 id=\"canvasにバインドしたイベントハンドラ\">canvasにバインドしたイベントハンドラ</h3>\n\n<p>以下の部分が普通にcanvasにマウスクリックイベントをバインドしている部分です。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">test_canvas</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"s\">'<ButtonPress-1>'</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_on_click_canvas</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>canvas上(水色の部分)でクリックすると<code class=\"language-plaintext highlighter-rouge\">_on_click_canvas</code>が実行され、\n<code class=\"language-plaintext highlighter-rouge\">_on_click_canvas : click on canvas</code>と表示されます。<br />\nしかし、その上に配置されたラベル(labex_1x)上でクリックしたときは表示されません。</p>\n\n<p>labelもcanvasの一部なので、ここでもクリック処理が動いてほしいことはよくあると思います。</p>\n\n<h3 id=\"rootにバインドしたイベントハンドラ\">rootにバインドしたイベントハンドラ</h3>\n\n<p>そこで、以下の部分でrootにマウスクリックイベントをバインドします。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">winfo_toplevel</span><span class=\"p\">().</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"s\">'<ButtonPress-1>'</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_on_click</span><span class=\"p\">,</span> <span class=\"s\">\"+\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>これはrootにバインドされたイベントですから、当然canvas以外の部分でも処理が動きます。<br />\nそこで、イベントハンドラでマウス座標を取得し、canvasの範囲内かを確認し、\nそうであればクリック処理(ここでは<code class=\"language-plaintext highlighter-rouge\">_on_click : click on canvas</code>を表示)を実行します。<br />\nパラメータの最後の<code class=\"language-plaintext highlighter-rouge\">\"+\"</code>は、既にバインドされているハンドラがあった時、上書きせずに追加することを指定しています。<br />\n(つまり、以前にバインドしたハンドラと今回のハンドラ両方が実行されます)</p>\n\n<p>こちらの処理はcanvas上(水色の部分)でクリックしたときも\nその上に配置されたラベル(labex_1x)上でクリックしたときもクリック処理が実行されます。</p>\n\n<p>なお、イベントハンドラに渡されるパラメータ<code class=\"language-plaintext highlighter-rouge\">event</code>の<code class=\"language-plaintext highlighter-rouge\">event.x</code>、<code class=\"language-plaintext highlighter-rouge\">event.y</code>はウィジェット内の相対座標なので\n比較には<code class=\"language-plaintext highlighter-rouge\">event.x_root</code>、<code class=\"language-plaintext highlighter-rouge\">event.y_root</code>を使用して画面上の座標を使用します。<br />\n当然比較するcanvasの座標も<code class=\"language-plaintext highlighter-rouge\">widget.winfo_rootx()</code>、<code class=\"language-plaintext highlighter-rouge\">widget.winfo_rooty()</code>で画面上の座標を使用しなければなりません。</p>\n\n<h3 id=\"おまけ\">おまけ</h3>\n\n<p>おまけとして、ダブルクリックした位置に存在するウィジェットの一覧を表示する処理を入れておきました(<code class=\"language-plaintext highlighter-rouge\">_on_doubleclick</code>) 。<br />\nダブルクリックに意味はなく、クリックは既に使っていたのでダブルクリックにしただけです。</p>\n\n<blockquote>\n  <p>おーちゃくせずに別のプログラム書けよ > 自分</p>\n</blockquote>\n\n<h3 id=\"ふと思ったこと\">ふと思ったこと</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">event.widget</code> から 順に <code class=\"language-plaintext highlighter-rouge\">master</code> をたどって行き、対象のウィジェットが見つかるかで判断する方法もあるなぁ…<br />\nrootの <code class=\"language-plaintext highlighter-rouge\">master</code> は <code class=\"language-plaintext highlighter-rouge\">None</code> なのでそこでサーチ終了。<br />\nどっちが簡単かな…</p>\n\n<h3 id=\"ふと思ったこと-その2\">ふと思ったこと その2</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">bind</code>するときに、.winfo_children() を再帰的にサーチしてすべての子ウィジェットにbindしていく、という手もあるなぁ。<br />\nいっぱいウィジェット配置してるとえらいことになるかもしれんけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tkinter で スクロール可能なcanvasを作る</title>\n  </head>\n  <body>\n    <header>\n      <h1>tkinter で スクロール可能なcanvasを作る</h1>\n      <p>tkinter で スクロール可能なcanvasを作る</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>tkinterでスクロール可能なcanvasのクラス<code class=\"language-plaintext highlighter-rouge\">ScrollableCanvas</code>を作ってみました。<br />\nぶっちゃけ、あちこちにその手の記事はあるのですが、なんか自分のコーディングスタイルとあってないの気がしたので\n微妙に書き換えてみました。</p>\n\n<h1 id=\"サンプルプログラム\">サンプルプログラム</h1>\n\n<p>さっそくサンプルプログラムを貼りつけておきます。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/0ccd48b5cec72ad363d7eaa452972b1f.js\"></script>\n</dev>\n\n<h2 id=\"解説のようなもの\">解説のようなもの</h2>\n\n<h3 id=\"canvas-を継承した-scrollablecanvas-クラス\">canvas を継承した ScrollableCanvas クラス</h3>\n<p>ネット上にある例では、Frameクラスを継承してその下にcanvasを貼り付けているものが多いですが、\nなんとなく余分なウィジェットを作りたくない気分だったのでCanvasクラスを継承するようにしてみました。<br />\nまた、コンストラクタ中でpackしている例が多かったですが、配置の自由度を上げるため上位側に任せるようにしました。</p>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>今回は縦スクロールのみ対応なので、canvasの幅はあらかじめ指定しておくようにしてあります。<br />\nまた、表示するウィジェットを配置するためのフレーム(<code class=\"language-plaintext highlighter-rouge\">child_frame</code>)は幅を自由に設定できるようにすると\n親ウィジェットであるcanvasの幅まで大きくなりますが、これだとスクロールバーが見えなくなります。<br />\nそこで、<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の幅はcanvasの幅からスクロールバーの幅を差し引いたサイズを設定しています。</p>\n\n<blockquote>\n  <p>[!NOTE]\n縦横スクロール可能にした場合は このあたり見直さないといけないかもしれない。</p>\n</blockquote>\n\n<p>また、マウスドラッグによるスクロールをスムーズにするため、スクロール量(<code class=\"language-plaintext highlighter-rouge\">yscrollincrement</code>)のデフォルトを1に設定しています。\nこれはScrollableCanvasクラスのインスタンスを生成する際に変更することができます。</p>\n\n<h3 id=\"ウィンドウイベント\">ウィンドウイベント</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">\"<Configure>\"</code> イベントをbindすることで、ウィンドウが移動されたり、リサイズされたりしたときに実行する処理を割り当てています。<br />\n<code class=\"language-plaintext highlighter-rouge\">\"<Configure>\"</code> イベントはウィンドウのリサイズ等だけでなく、pack()等でFrameのサイズが変更されたときも通知されます。</p>\n\n<p>ここではスクロール範囲の再設定を行っています。</p>\n\n<h3 id=\"マウスイベント\">マウスイベント</h3>\n\n<p>マウスイベントのbindは\n<a href=\"/memoBlog/2024/09/14/tkinter_event_1.html\" target=\"_blank\">tkinter で 低層のウィジェットでイベントを検出する</a>\nの方法を使用しています。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>操作</th>\n      <th>処理</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>左クリック</td>\n      <td>ドラッグ開始位置の設定</td>\n    </tr>\n    <tr>\n      <td>左クリック→マウス移動</td>\n      <td>縦方向の移動量に応じたスクロール</td>\n    </tr>\n    <tr>\n      <td>左ダブルクリック</td>\n      <td>子ウィジェットの追加</td>\n    </tr>\n    <tr>\n      <td>ホイール</td>\n      <td>縦方向スクロール</td>\n    </tr>\n    <tr>\n      <td>右クリック</td>\n      <td>子ウィジェットの全削除</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"実は\">実は…</h3>\n\n<p>右クリックで子ウィジェットを全削除した際、<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の高さは削除前の高さのままになっています。<br />\nつまり、なにもないフレームをスクロールできる状態になっています。<br />\n次に左ダブルクリックでウィジェットを追加したときに1ジェット1個分の高さに変更されます。<br />\nこの仕様が気持ち悪くて色々試したのですが、うまくいきませんでした。<br />\nそこで、「cleard」と表示して<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の高さを変更して誤魔化しています。<br />\n子ウィジェットの差し替えしかしないのであれば特に気にしなくても良い部分だと思います。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Renodeお試し</title>\n  </head>\n  <body>\n    <header>\n      <h1>Renodeお試し</h1>\n      <p>シミュレータ Renode を試してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>おいそれと評価ボードを買えないボンビーの味方、シミュレータ(エミュレータ)。<br />\n<a href=\"https://www.qemu.org/\" target=\"_blank\">QEMU</a>が有名だけど、\n最近は<a href=\"https://renode.io/\" target=\"_blank\">Renode</a>というのもあるらしい。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://wokwi.com/\" target=\"_blank\">wokwi</a>というのもある。<br />\n見た目がきれいで惹かれるけど、VScodeで実行する環境のライセンスが\nよく分からんかった(30日は無料らしいけど、その後無料で更新できるのか、有料になるのか読み取れなかった)<br />\n至れり尽くせりなのはイヤだという天邪鬼気質もあるけど…</p>\n</blockquote>\n\n<p>ということで、Renodeをちらっと試してみた時のメモ。</p>\n\n<p>Renodeのドキュメントは<a href=\"https://renode.readthedocs.io/en/latest/\" target=\"_blank\">https://renode.readthedocs.io/en/latest/</a>にあります<br />\nソースやリリースバイナリは<a href=\"https://github.com/renode/renode\" target=\"_blank\">Github</a>にあります。</p>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"環境\">環境</h2>\n<p>今回はWindows11上のWSLのUbuntu 22.04で試してみます。</p>\n\n<h2 id=\"renodeのインストール\">Renodeのインストール</h2>\n<p>インストール用バイナリは<a href=\"https://github.com/renode/renode/releases\" target=\"_blank\">github</a>\nや<a href=\"https://builds.renode.io\" target=\"_blank\">https://builds.renode.io</a>にあります。</p>\n\n<p>プラットフォームはmono版と.NET版がありますが、ここではmono版を使います。<br />\ndebファイルがあるので、aptでもインストールできますが、ここではポータブル版を使います。</p>\n\n<p>以下のように実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /proj\nwget https://builds.renode.io/renode-latest.linux-portable.tar.gz\n<span class=\"nb\">mkdir </span>renode_portable\n<span class=\"nb\">tar </span>xvf  renode-latest.linux-portable.tar.gz <span class=\"nt\">-C</span> renode_portable <span class=\"nt\">--strip-components</span><span class=\"o\">=</span>1\n</code></pre></div></div>\n\n<p>これで <code class=\"language-plaintext highlighter-rouge\">/proj/renode_portable</code> に必要なファイルが展開されます。<br />\nここにPATHを通すため、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># renodeのインストール先をpathに追加</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span>/proj/renode_portable:<span class=\"nv\">$PATH</span>\n</code></pre></div></div>\n\n<h2 id=\"renodeの依存パッケージのインストール\">renodeの依存パッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mono-devel policykit-1 libgtk2.0-0 screen uml-utilities gtk-sharp2 libc6-dev libicu-dev gcc python3 python3-pip\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nmonoのリポジトリを追加してインストールする情報が散見されるが、ubuntu22.04のaptリポジトリにはmono-develも入っているらしい。<br />\nなので、普通に<code class=\"language-plaintext highlighter-rouge\">apt install</code>だけでインストールできる。<br />\nただし、最新版が欲しい場合は以下でインストールする。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ca-certificates gnupg\n<span class=\"nb\">sudo </span>gpg <span class=\"nt\">--homedir</span> /tmp <span class=\"nt\">--no-default-keyring</span> <span class=\"nt\">--keyring</span> /usr/share/keyrings/mono-official-archive-keyring.gpg <span class=\"nt\">--keyserver</span> hkp://keyserver.ubuntu.com:80 <span class=\"nt\">--recv-keys</span> 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF\n<span class=\"nb\">echo</span> <span class=\"s2\">\"deb [signed-by=/usr/share/keyrings/mono-official-archive-keyring.gpg] https://download.mono-project.com/repo/ubuntu stable-focal main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/mono-official-stable.list\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mono-devel\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"gccのインストール\">gccのインストール</h2>\n<p>Renodeの実行自体にコンパイラは不要ですが、実行するバイナリを作成するのに必要なので、gccをインストールします。</p>\n\n<p>ダウンロードサイト:<a href=\"https://developer.arm.com/downloads/-/gnu-rm\" target=\"_blank\">ARM Developer GNU Arm Embedded Toolchain Downloads</a></p>\n\n<p>以下の手順でインストールします(ファイル名/ディレクトリ名はダウンロードしたバージョンに合わせて変更)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /proj\nwget https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz\n<span class=\"nb\">tar </span>xvf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz \n\n<span class=\"c\"># 依存パッケージのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libncursesw5\n</code></pre></div></div>\n\n<p>PATHを通すため、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># arm-gccのインストール先をpathに追加</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span>/proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin:<span class=\"nv\">$PATH</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンパイラだけなら<code class=\"language-plaintext highlighter-rouge\">apt install gcc-arm-none-eabi</code>でインストールできますが、\ngdbが入ってないので上のサイトからダウンロードして使用します。</p>\n</blockquote>\n\n<h2 id=\"その他インストール\">その他インストール</h2>\n<p>ターゲットプログラムのbuild時にcmakeも使用するのでインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n</code></pre></div></div>\n\n<h1 id=\"デモの実行\">デモの実行</h1>\n<p>ドキュメントの<a href=\"https://renode.readthedocs.io/en/latest/introduction/demo.html\" target=\"_blank\">Running your first demo</a>\nにしたがって実行してみます。</p>\n\n<p>renodeを起動します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode\n</code></pre></div></div>\n\n<p>renodeウィンドウが開くのでそこで以下を入力</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>s @scripts/single-node/stm32f4_discovery.resc\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i @scripts/single-node/stm32f4_discovery.resc\ns\n</code></pre></div>  </div>\n  <p>と実行しても可。<br />\n<code class=\"language-plaintext highlighter-rouge\">i</code>は<code class=\"language-plaintext highlighter-rouge\">include</code>のalias<br />\n<code class=\"language-plaintext highlighter-rouge\">s</code>は<code class=\"language-plaintext highlighter-rouge\">start</code>のalias</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nrenode起動時に以下のようにパラメータとしてrescファイルを指定することもできます。<br />\nこれはincludeコマンドを実行するのと同義(というか起動時にincludeコマンドが実行されている)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode /proj/renode_portable/scripts/single-node/stm32f4_discovery.resc\n</code></pre></div>  </div>\n  <p>rescファイルのパスは絶対パス/カレントディレクトリからの相対パスで指定可能。<br />\n<code class=\"language-plaintext highlighter-rouge\">@</code>を使ったrenodeインストールディレクトリからの相対パスは指定不可。</p>\n</blockquote>\n\n<p>プログラムが実行されると uart4ウィンドウが開いてなにやら色々表示されます。</p>\n\n<p>renodeウィンドウで<code class=\"language-plaintext highlighter-rouge\">quit</code>と入力する(CTRL+Dでも可)と終了します。</p>\n\n<h2 id=\"おまけ\">おまけ</h2>\n<h3 id=\"その1\">その1</h3>\n<p>renodeウィンドウが見難かったら以下のように<code class=\"language-plaintext highlighter-rouge\">-P</code>オプションでポート番号を指定して実行し、</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode <span class=\"nt\">-P</span> 1234\n</code></pre></div></div>\n\n<p>他のターミナルから以下のように実行すると普段使っているターミナルから制御できます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>telnet localhost 1234\n</code></pre></div></div>\n\n<h3 id=\"その2\">その2</h3>\n<p>renode起動時に<code class=\"language-plaintext highlighter-rouge\">--console</code> オプションを指定すると、起動したターミナルがコンソールになります。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode <span class=\"nt\">--cnsole</span>\n</code></pre></div></div>\n<p>ログが同じターミナルに表示されるので見難くなったりするかもしれんけど</p>\n\n<h1 id=\"vscodeでデバッグ\">VScodeでデバッグ</h1>\n\n<p><a href=\"https://renode.readthedocs.io/en/latest/debugging/vscode.html\" target=\"_blank\">ドキュメント</a>\nの説明は分かり難いので、解説記事\n<a href=\"https://medium.com/@pc0is0me/getting-started-with-stm32f4-emulation-using-renode-f6cb158d27d1\" target=\"_blank\">Getting Started with STM32F4 Emulation using Renode</a>\nの手順を試してみます。</p>\n\n<h2 id=\"サンプルのリポジトリをclone\">サンプルのリポジトリをclone</h2>\n\n<p>まずはリポジトリをcloneします。<br />\n適当なディレクトリで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/PhanCuong91/data.git\n</code></pre></div></div>\n\n<h2 id=\"とりあえず動作確認\">とりあえず動作確認</h2>\n\n<p>VScodeでデバッグする前にターゲットプログラムのbuildが行えるか、\nbuildしたバイナリが実行できるか確認しておきます。<br />\nプログラムのbuildは以下のコマンドで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>data/renode\nbash build.bat\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nbatファイルなので、Windowsのバッチファイルですが、\n中身はLinuxでもそのまま実行できる内容なので、\nそのままシェルスクリプトとして実行します。</p>\n</blockquote>\n\n<p>こんな感じでbuildが実行されます。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Release build.\n-- The C compiler identification is GNU 13.3.1\n-- The CXX compiler identification is GNU 13.3.1\n-- The ASM compiler identification is GNU\n-- Found assembler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc\n-- Detecting C compiler ABI info\n-- Detecting C compiler ABI info - done\n-- Check for working C compiler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc - skipped\n-- Detecting C compile features\n-- Detecting C compile features - done\n-- Detecting CXX compiler ABI info\n-- Detecting CXX compiler ABI info - done\n-- Check for working CXX compiler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-g++ - skipped\n-- Detecting CXX compile features\n-- Detecting CXX compile features - done\n-- Configuring done\n-- Generating done\n-- Build files have been written to: /work/data/renode/build\n</code></pre></div></div>\n\n<p>正常にbuildできていれば<code class=\"language-plaintext highlighter-rouge\">build/src/STM32F4Template.elf</code>が出来ています。</p>\n\n<p>renodeを実行し、renodeターミナルで以下のように入力し、プログラムを実行します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mach create\nmachine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl\nsysbus LoadELF @/work/data/renode/build/src/STM32F4Template.elf \nshowAnalyzer sysbus.usart2\nstart\n</code></pre></div></div>\n\n<p>UART2ウィンドウに以下のように表示されればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Hello World!\n</code></pre></div></div>\n\n<p>確認したらrenodeを終了します。</p>\n\n<p>次の作業に備えて、buildディレクトリを削除(またはrename)しておきます。</p>\n\n<h2 id=\"vscodeでのデバッグ\">VScodeでのデバッグ</h2>\n\n<h3 id=\"rescファイルの修正\">rescファイルの修正</h3>\n<p>フルパスで記述されている部分を修正します。</p>\n\n<p>修正内容は以下。<br />\n<code class=\"language-plaintext highlighter-rouge\">$ORIGIN</code>を使用してrescファイルからの相対パス指定に変更。<br />\nこれにより、ダブルクォーテーションで囲む必要はなくなる。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/renode/renode-config.resc b/renode/renode-config.resc\nindex 2729cd1..fcb4f34 100644\n</span><span class=\"gd\">--- a/renode/renode-config.resc\n</span><span class=\"gi\">+++ b/renode/renode-config.resc\n</span><span class=\"p\">@@ -2,8 +2,8 @@</span>\n :description: This script runs the usart_printf example on stm32f4 discovery\n\n $name?=\"STM32F4_Discovery\"\n<span class=\"gd\">-$cmm_repl?=\"C:\\working\\data\\renode\\add-ccm.repl\"\n-$bin_path?=\"C:\\working\\data\\renode\\build\\src\\STM32F4Template.elf\"\n</span><span class=\"gi\">+$cmm_repl?=$ORIGIN/add-ccm.repl\n+$bin_path?=$ORIGIN/build/src/STM32F4Template.elf\n</span>\n # create Socket Terminal for UART\n emulation CreateServerSocketTerminal 3456 \"term\" false\n</code></pre></div></div>\n\n<h3 id=\"buildスクリプトに実行属性を付与\">buildスクリプトに実行属性を付与</h3>\n<p>元がwindows用なので、linuxで実行できるように実行属性を付与します。<br />\n中身はそのまま。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod</span> +x build-debug.bat\n</code></pre></div></div>\n\n<h3 id=\"vscodeを起動\">VScodeを起動</h3>\n<p>ホストOS側のVScodeを起動します。<br />\nWSLなので、ターミナルから以下のコマンドで起動してカレントディレクトリを開きます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>code <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"vscodeの拡張機能のインストール\">VScodeの拡張機能のインストール</h3>\n<p>VScodeの拡張機能で</p>\n<ul>\n  <li>C/C++ Extension Pack をインストールします</li>\n  <li>念のため、CMakeを無効化しておきます</li>\n</ul>\n\n<h3 id=\"実行\">実行</h3>\n\n<p>エクスプローラサイドパネルから<code class=\"language-plaintext highlighter-rouge\">src/main.c</code>を開き、<code class=\"language-plaintext highlighter-rouge\">main()</code> のどこかにブレークポイントを設定。<br />\nデバッグサイドパネルで 「Debug application in Renode」 を選んで実行。<br />\nRenoteターミナルとUART2ウィンドウが開き、設定したブレークポイントで停止するはず。<br />\n実行を再開すると、UART2ウィンドウに<code class=\"language-plaintext highlighter-rouge\">Hello World!</code>と表示され、無限ループに入る。</p>\n\n<h1 id=\"renode-interactive-visualization-example\">Renode interactive visualization example</h1>\n<p>組み込みプログラムなので、ターゲットボードの動作を目で見たくなるのが人情…<br />\nということで、Renode interactive visualization exampleを実行してみます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nWSLのネットワークモードは mirrored にしておきます\n(ほかのモードでも動くかもしれんけど、試してないので)</p>\n</blockquote>\n\n<p><a href=\"https://github.com/antmicro/renode-board-visualization\" target=\"_blank\">github</a>\nからソースを取得します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/antmicro/renode-board-visualization.git\n<span class=\"nb\">cd </span>renode-board-visualization/\n</code></pre></div></div>\n\n<p>Renodeを実行します。<br />\n(バイナリファイルがあるのでbuildは不要。というよりソースファイルはない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode scripts/blinky.resc\n</code></pre></div></div>\n\n<p>rescファイルに<code class=\"language-plaintext highlighter-rouge\">start</code>コマンドが書いてあるので、\n起動と同時にターゲットプログラムが実行されます。</p>\n\n<p>renodeを起動したターミナルにはGPIOアクセスのログが以下のように表示されます。<br />\n(ログが表示されるか否かはPeripheralのエミュレーションプログラムによるので、\nどのCPUても表示されるわけではありません)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>11:28:31.6894 [NOISY] gpio0: Setting pin 24 output to False\n11:28:32.6891 [NOISY] gpio0: Setting pin 24 output to True\n11:28:33.6891 [NOISY] gpio0: Setting pin 24 output to False\n11:28:34.6892 [NOISY] gpio0: Setting pin 24 output to True\n11:28:35.6892 [NOISY] gpio0: Setting pin 24 output to False\n</code></pre></div></div>\n\n<p>renodeコンソールで以下のコマンドを実行します。<br />\nこれによりWebサーバが起動します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>serveVisualization 8000\n</code></pre></div></div>\n\n<p>ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページが表示され、ボード左上のLED(赤色)が点滅しているのが確認できます。</p>\n\n<p>Webサーバを停止するため、renodeコンソールで以下のコマンドを実行します。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>stopVisualization\n</code></pre></div></div>\n\n<p>Renodeを終了します。</p>\n<blockquote>\n  <p>[!NOTE]\nWebサーバを停止せずにRenodeを終了しても構いません。<br />\n停止せずに終了すると終了時に python で たくさんEXCEPTIONが起こるので\n気持ち悪い人はWebサーバを停止してから終了しましょう。</p>\n</blockquote>\n\n<h1 id=\"自分の環境を作ってみた\">自分の環境を作ってみた</h1>\n\n<p>以上を踏まえて、一通り作ってみました。<br />\n(公式サンプルにはターゲットプログラムのソースがないので、\nソースからビルドする部分も含めて試してみたかった)</p>\n\n<p>作った環境はgithubに登録しておきました。<br />\n<a href=\"https://github.com/ippei8jp/renode_my_sample\" target=\"_blank\">https://github.com/ippei8jp/renode_my_sample</a></p>\n\n<h2 id=\"リポジトリのクローン\">リポジトリのクローン</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/ippei8jp/renode_my_sample.git\n<span class=\"nb\">cd </span>renode_my_sample\n</code></pre></div></div>\n<h3 id=\"ソース構成\">ソース構成</h3>\n<p>srcディレクトリ下がプログラムソースです。</p>\n\n<h4 id=\"mainc\">main.c</h4>\n<p>メインルーチンと割り込みハンドラなど。</p>\n\n<h4 id=\"syscallsc\">syscalls.c</h4>\n<p>printf/scanfなどを使用するためのsyscallルーチンを定義。<br />\nコンソール入出力のための最低限の処理だけを定義しています。</p>\n\n<h4 id=\"startup_stm32f40_41xxxs\">startup_stm32f40_41xxx.s</h4>\n<p>bootルーチン、ベクタテーブル、デフォルト割り込みハンドラなど。</p>\n\n<h4 id=\"system_stm32f4xxc\">system_stm32f4xx.c</h4>\n<p>初期化処理(C言語部)</p>\n\n<h4 id=\"cmakeliststxt\">CMakeLists.txt</h4>\n<p>cmake処理定義ファイル。<br />\nソースファイルを追加したときなどはここに追加していく。</p>\n\n<h3 id=\"ビルド実行\">ビルド&実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake ..\nmake\n<span class=\"nb\">cd</span> ..\nrenode script/renode-config.resc\n</code></pre></div></div>\n\n<h3 id=\"ブラウザで接続\">ブラウザで接続</h3>\n<p>GUI部品を表示するため、ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページにLEDとスイッチが表示されます。</p>\n\n<h3 id=\"ターゲットプログラム実行\">ターゲットプログラム実行</h3>\n<p>renodeターミナルで<code class=\"language-plaintext highlighter-rouge\">start</code>コマンドを実行するとターゲットプログラムが実行されます。</p>\n\n<h3 id=\"ブラウザの表示\">ブラウザの表示</h3>\n<p>ターゲットプログラムの動作に応じてLEDが順次点灯/消灯していきます。\nスイッチをクリックするとON/OFFがトグルします。<br />\nこのスイッチの情報はターゲットプログラムのメインループで表示されます。<br />\nまたON時は割り込みハンドラが起動され、UARTコンソールに割り込みメッセージが表示されます。</p>\n\n<h3 id=\"renode終了\">Renode終了</h3>\n<p>renodeターミナルで<code class=\"language-plaintext highlighter-rouge\">quit</code>コマンドを実行して Renodeを終了します。</p>\n\n<h2 id=\"vscodeでデバッグ-1\">VScodeでデバッグ</h2>\n\n<p>VScodeでデバッグする前にbuildディレクトリを削除しておいてください。</p>\n\n<h3 id=\"vscodeでcloneしたディレクトリを開く\">VScodeでcloneしたディレクトリを開く</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>code <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"ビルド\">ビルド</h3>\n<p>VSCodeで</p>\n<ul>\n  <li>cmakeサイドパネルを開く\n    <ul>\n      <li>「構成」右側のアイコンをクリックし、「GCC XX.X.X arm-noen-eabi」選択\n        <ul>\n          <li>cmakeが実行される</li>\n        </ul>\n      </li>\n      <li>「ビルド」右側のアイコンをクリックしbuid実行\n        <ul>\n          <li>makeが実行される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>実行とデバッグサイドパネルを開く\n    <ul>\n      <li>Debug application in Renode を選んで実行</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ブラウザで接続-1\">ブラウザで接続</h3>\n<p>GUI部品を表示するため、ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページにLEDとスイッチが表示されます。</p>\n\n<h3 id=\"ブラウザの表示-1\">ブラウザの表示</h3>\n<p>ターゲットプログラムの動作に応じてLEDが順次点灯/消灯していきます。\nスイッチをクリックするとON/OFFがトグルします。<br />\nこのスイッチの情報はターゲットプログラムのメインループで表示されます。<br />\nまたON時は割り込みハンドラが起動され、UARTコンソールに割り込みメッセージが表示されます。</p>\n\n<h3 id=\"デバッグ\">デバッグ</h3>\n<p>デバッグは他の環境と同じなので、ここでは何も書きません。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>TkEasyGUIを使ってみる</title>\n  </head>\n  <body>\n    <header>\n      <h1>TkEasyGUIを使ってみる</h1>\n      <p>pythonでGUIを簡単に作れる TkEasyGUI を使ってみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでGUIを作るにはtkinterを使うが、とっても分かり難い。<br />\nそこで、簡単にGUIが作れるとウワサの TkEasyGUI を使ってみた。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/TkEasyGUI/0.1.4/\" target=\"_blank\">PyPI</a></li>\n  <li><a href=\"https://github.com/kujirahand/tkeasygui-python\" target=\"_blank\">GitHub</a></li>\n  <li><a href=\"https://note.com/sirodon_256/n/na73d3fdac68d?fbclid=IwY2xjawHpgzhleHRuA2FlbQIxMQABHWBZ650bkpcT7-r0B3xAXpeUoIWsjSZJjZ4lqPUtBrxxQp3mlsCzFtM7tA_aem_lSSEVGhwq5SisJRckTFZcw\" target=\"_blank\">TkEasyGUIライブラリの基本とサンプルコード解説</a></li>\n</ul>\n\n<h1 id=\"使ってみる\">使ってみる</h1>\n<p>使ってみようと思ってはみたものの 何を作れば良いか思いつかなかったので、\n以前にtkinterで作ったプログラムを TkEasyGUI を使って書き直して見ることにした。</p>\n\n<p>元にしたのは、\n<a href=\"https://gist.github.com/ippei8jp/b8af596718e357dce185b5279b3533b8\" target=\"_blank\">ketsuatsu_GUI.py</a><br />\nこれの <code class=\"language-plaintext highlighter-rouge\">ketsuatsu_GUI.py</code>だけを書き換えてみる。<br />\n(<code class=\"language-plaintext highlighter-rouge\">ketsuatsu_csv2xls.py</code>はそのまま使用)</p>\n\n<h1 id=\"作ってみた\">作ってみた</h1>\n<p>ということで、書き直してみた。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>TkEasyGUI のインストールは以下を実行するだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>TkEasyGUI\n</code></pre></div></div>\n<p>TkEasyGUI と pyperclip がインストールされる。</p>\n\n<p>全体を実行するには、上の元ソースのREADMEを参照。</p>\n\n<h2 id=\"ソース\">ソース</h2>\n<p>ということで、作ってみたソースがこちら。<br />\n元のソースと比べても行数で半分以下になった。<br />\nまた、イベントによる実行がイベントハンドラで登録するのから\nイベントループでイベントを監視するように変更されたので、プログラムの見通しがよくなった。</p>\n\n<p>これを</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ketsuatsu_easyGUI.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">dont_write_bytecode</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>      <span class=\"c1\"># pycacheを作成しない\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">TkEasyGUI</span> <span class=\"k\">as</span> <span class=\"n\">eg</span>\n\n<span class=\"c1\"># CSV→エクセル変換処理\n</span><span class=\"kn\">from</span> <span class=\"nn\">ketsuatsu_csv2xls</span> <span class=\"kn\">import</span> <span class=\"n\">ketsuatsu_csv2xls</span>\n\n<span class=\"c1\"># フォント\n# FONT_NAME1 = \"MS ゴシック\"\n</span><span class=\"n\">FONT_NAME1</span> <span class=\"o\">=</span> <span class=\"s\">\"BIZ UDゴシック\"</span>\n<span class=\"n\">FONT_NAME2</span> <span class=\"o\">=</span> <span class=\"s\">\"Noto Sans CJK JP\"</span>\n\n<span class=\"n\">FONT_SIZE</span> <span class=\"o\">=</span> <span class=\"mi\">12</span>\n\n\n<span class=\"c1\"># レイアウト\n</span><span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Text</span><span class=\"p\">(</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"CSV file  \"</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Input</span><span class=\"p\">(</span>       <span class=\"s\">\"\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"s\">\"-csvfilepath-\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span> \n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">FileBrowse</span><span class=\"p\">(</span>  <span class=\"n\">button_text</span> <span class=\"o\">=</span> <span class=\"s\">\"Browse...\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"CSV file\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">file_types</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"s\">'CSV file'</span><span class=\"p\">,</span> <span class=\"s\">'*.csv'</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"s\">'all'</span><span class=\"p\">,</span> <span class=\"s\">'*.*'</span><span class=\"p\">)),</span>\n                     <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Text</span><span class=\"p\">(</span>        <span class=\"s\">\"Excel file\"</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Input</span><span class=\"p\">(</span>       <span class=\"s\">\"\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"s\">\"-excelfilepath-\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span> \n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">FileBrowse</span><span class=\"p\">(</span>  <span class=\"n\">button_text</span> <span class=\"o\">=</span> <span class=\"s\">\"Browse...\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">title</span> <span class=\"o\">=</span> <span class=\"s\">\"Excel file\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">file_types</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"s\">'Excel file'</span><span class=\"p\">,</span> <span class=\"s\">'*.xlsx'</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"s\">'all'</span><span class=\"p\">,</span> <span class=\"s\">'*.*'</span><span class=\"p\">)),</span>\n                        <span class=\"n\">save_as</span> <span class=\"o\">=</span> <span class=\"bp\">True</span><span class=\"p\">,</span>\n                     <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Column</span><span class=\"p\">(</span>\n            <span class=\"n\">layout</span><span class=\"o\">=</span><span class=\"p\">[</span>\n                      <span class=\"p\">[</span>\n                        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Button</span><span class=\"p\">(</span>  <span class=\"s\">\"Convert\"</span><span class=\"p\">,</span>\n                                    <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">),</span>\n                                 <span class=\"p\">),</span> \n                        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Button</span><span class=\"p\">(</span>  <span class=\"s\">\"Exit\"</span><span class=\"p\">,</span>\n                                    <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">),</span>\n                                 <span class=\"p\">),</span>\n                      <span class=\"p\">]</span>\n                    <span class=\"p\">],</span>\n            <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n            <span class=\"n\">expand_y</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n            <span class=\"n\">text_align</span><span class=\"o\">=</span><span class=\"s\">\"right\"</span><span class=\"p\">,</span>\n            <span class=\"n\">vertical_alignment</span><span class=\"o\">=</span><span class=\"s\">\"bottom\"</span><span class=\"p\">,</span>\n        <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n<span class=\"p\">]</span>\n\n\n<span class=\"c1\"># CSVファイルからexcelファイルへの変換処理をコールする\n</span><span class=\"k\">def</span> <span class=\"nf\">convert_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">):</span>\n    <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n\n    <span class=\"c1\"># パラメータエラーチェック\n</span>    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ファイルが指定されていない\n</span>        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"入力ファイルを指定してください\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># filedialog.askopenfilename()は存在するファイルしか選択できないが\n</span>    <span class=\"c1\"># エディットボックスを直接編集した場合のためにチェック\n</span>    <span class=\"k\">elif</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"入力ファイルを指定してください\"</span><span class=\"p\">,</span>  <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">output_filename</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ファイルが指定されていない\n</span>        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"出力ファイルを指定してください\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># この判定はfiledialog.asksaveasfilename()内で行うが\n</span>    <span class=\"c1\"># エディットボックスを直接編集した場合のためにチェック\n</span>    <span class=\"k\">elif</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">output_filename</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">ret</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup_ok_cancel</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"出力ファイルが存在します</span><span class=\"se\">\\n</span><span class=\"s\">上書きしますか?\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"確認\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span> <span class=\"k\">if</span> <span class=\"n\">ret</span> <span class=\"o\">==</span> <span class=\"s\">'OK'</span> <span class=\"k\">else</span> <span class=\"bp\">False</span>\n    <span class=\"k\">if</span> <span class=\"n\">execute_flag</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 変換処理\n</span>        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"c1\"># CSVファイルからエクセルファイルを作成\n</span>            <span class=\"n\">ketsuatsu_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">)</span>\n            <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"変換終了\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"終了\"</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"nb\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">e</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n\n    <span class=\"c1\"># 使用するフォントの設定\n</span>    <span class=\"n\">fonts</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">get_font_list</span><span class=\"p\">()</span>\n    <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n    <span class=\"n\">target_font_size</span> <span class=\"o\">=</span> <span class=\"n\">FONT_SIZE</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">FONT_NAME1</span> <span class=\"ow\">in</span> <span class=\"n\">fonts</span> <span class=\"p\">:</span>\n        <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"n\">FONT_NAME1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">FONT_NAME2</span> <span class=\"ow\">in</span> <span class=\"n\">fonts</span> <span class=\"p\">:</span>\n        <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"n\">FONT_NAME2</span>\n\n\n    <span class=\"c1\"># window create\n</span>    <span class=\"n\">window</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Window</span><span class=\"p\">(</span><span class=\"s\">'血圧 CSV->excel'</span><span class=\"p\">,</span> \n                        <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">600</span><span class=\"p\">,</span> <span class=\"mi\">150</span><span class=\"p\">),</span>\n                        <span class=\"n\">font</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">target_font_name</span><span class=\"p\">,</span> <span class=\"n\">target_font_size</span><span class=\"p\">),</span>\n                        <span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"n\">layout</span>\n                    <span class=\"p\">)</span>\n\n    <span class=\"c1\"># event loop\n</span>    <span class=\"k\">while</span> <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">is_alive</span><span class=\"p\">():</span>\n        <span class=\"n\">event</span><span class=\"p\">,</span> <span class=\"n\">values</span> <span class=\"o\">=</span> <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#\"</span><span class=\"p\">,</span> <span class=\"n\">event</span><span class=\"p\">,</span> <span class=\"n\">values</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">event</span> <span class=\"o\">==</span> <span class=\"s\">\"Exit\"</span> <span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">event</span> <span class=\"o\">==</span> <span class=\"s\">\"Convert\"</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># print(values)\n</span>            <span class=\"n\">input_filename</span>  <span class=\"o\">=</span> <span class=\"n\">values</span><span class=\"p\">[</span><span class=\"s\">'-csvfilepath-'</span><span class=\"p\">]</span>\n            <span class=\"n\">output_filename</span> <span class=\"o\">=</span> <span class=\"n\">values</span><span class=\"p\">[</span><span class=\"s\">'-excelfilepath-'</span><span class=\"p\">]</span>\n            <span class=\"n\">convert_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 終了\n</span>    <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n\n\n<span class=\"c1\"># ======================================================\n</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">main</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"未対応項目\">未対応項目</h1>\n<h2 id=\"ドラッグアンドドロップ\">ドラッグアンドドロップ</h2>\n<p>TkEasyGUI は ドラッグアンドドロップに対応していないので、作成したプログラムも未対応。<br />\nissueはあがっていて、作者さんも「It seems we could easily support」と言っているので、近いうちにサポートされるかも。</p>\n<ul>\n  <li><a href=\"https://github.com/kujirahand/tkeasygui-python/issues/7\" target=\"_blank\">Drag & Drop files #7</a></li>\n</ul>\n\n<h2 id=\"テーマの使用\">テーマの使用</h2>\n<p>TkEasyGUI は ttkの使用に対応しているが、使い方によってはうまく動かない。<br />\n(今回は <code class=\"language-plaintext highlighter-rouge\">eg.Column</code> の中の <code class=\"language-plaintext highlighter-rouge\">eg.Button</code> で  <code class=\"language-plaintext highlighter-rouge\">use_ttk_buttons=True</code>を指定したらエラーになった。<br />\nなにか条件があるのかもしれんが。)<br />\nとりあえず「お手軽にGUI」が目的なので、テーマで見た目に凝らなくてもいいか、と対応はあきらめた。</p>\n\n<h1 id=\"まとめ\">まとめ</h1>\n<p>さらっと触っただけだけど、tkinterをそのまま使うよりかなり分かりやすい。<br />\nが、ちょっと凝ったことをやろうとすると、できなかったりすることも。<br />\nその辺は必須かどうか見極めて、あきらめるか、tkinterで泥沼にハマってでも実現するかを決めるしかないか。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openpyxlのバグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>openpyxlのバグ</h1>\n      <p>openpyxl(3.1.5)のバグ(ではないけど、あえてそう書いておく)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"内容\">内容</h1>\n<p>openpyxl(3.1.2)でExcelのグラフを作成するスクリプトを使っていたが、\nopenpyxlを現時点での最新版(3.1.5)にアップデートしたところ、表示されるグラフの見た目が変わってしまった。</p>\n\n<h1 id=\"原因\">原因</h1>\n<p>検索してみたところ、teratailに\n『<a href=\"https://teratail.com/questions/5q9cujzlc2307x\" target=\"_blank\">python openpyxl グラフ作成 グラフ書式が変わったのを治せない</a>』\nというエントリを見つけた。</p>\n\n<p>どうやら、Excelの仕様に厳密に従ったらExcelのバグに引っかかった ということらしい。<br />\n(バグが他のバグ回避になってた、みたいな感じ)</p>\n\n<h1 id=\"対策\">対策</h1>\n<p>Excelのバグの修正を待っててもしかたないので、なんとか出来る方法を探してみた。<br />\nこの部分は openpyxl の 3.1.4 で仕様変更されたようなので、3.1.3以前を使うというのも手なのだけど、<br />\n最新版を使いたい場合はExcelのバグに引っかかってる部分だけ元にもどしてやれば良い。</p>\n\n<p>ということで、上のページにあった変更点を出力している部分を探して修正してみた。</p>\n\n<p>結論から言うと、以下のパッチをインストールしたライブラリにあててやれば良い。</p>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -urpN openpyxl.org/packaging/extended.py openpyxl/packaging/extended.py\n</span><span class=\"gd\">--- openpyxl.org/packaging/extended.py  2025-01-07 07:23:30.159676700 +0900\n</span><span class=\"gi\">+++ openpyxl/packaging/extended.py      2025-01-07 07:41:28.823592900 +0900\n</span><span class=\"p\">@@ -126,7 +126,8 @@</span> class ExtendedProperties(Serialisable):\n         self.HLinks = None\n         self.HyperlinksChanged = HyperlinksChanged\n         self.DigSig = None\n<span class=\"gd\">-        self.Application = f\"Microsoft Excel Compatible / Openpyxl {__version__}\"\n</span><span class=\"gi\">+        # self.Application = f\"Microsoft Excel Compatible / Openpyxl {__version__}\"\n+        self.Application = f\"Microsoft Excel\"\n</span>         self.AppVersion = \".\".join(__version__.split(\".\")[:-1])\n         self.DocSecurity = DocSecurity\n</code></pre></div></div>\n\n<p>で、試してみたところ うまくグラフが表示されるようになった。<br />\nメデタシメデタシ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MSYS2とgccのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>MSYS2とgccのインストール</h1>\n      <p>WindowsにMSYS2とgccをインストールした時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows環境でLinuxライクな環境を使用できる<a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2</a><br />\ngcc は単体で配布されている <a href=\"https://github.com/niXman/mingw-builds-binaries/releases\" target=\"_blank\">MinGW-W64-binaries</a>を使っていたが、\nMSYS2で管理されているものに切り替えてみた。</p>\n\n<h1 id=\"msys2のインストール\">MSYS2のインストール</h1>\n<p>大体以下の感じでインストールできる。</p>\n<ul>\n  <li><a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2のページ</a> を開く</li>\n  <li>Installation セクションの Download the installer: に書かれているリンクからダウンロード(バージョンアップで更新されるのでここにはリンクを貼らないでおく)</li>\n  <li>ダウンロードしたファイルを実行</li>\n  <li>デフォルトのままNextをクリックして行き、Installをクリック</li>\n  <li>終わったらFinishをクリック</li>\n</ul>\n\n<h1 id=\"msys2の設定\">MSYS2の設定</h1>\n<p>後でWindowsTerminalから使えるようにするからやらなくても良いけど、ま、気持ちの問題なので。</p>\n<ul>\n  <li>msys2を起動(スタート→すべて→MSYS2→MSYS2 UCRT64)し、タイトルバーを右クリックし 「Options…」 を選択\n    <ul>\n      <li>Text の Font の Select.. をクリックしてフォントとサイズを変更</li>\n      <li>Text の Local で ja_JP と UTF8 を選択</li>\n      <li>Window の Default size で ウィンドウサイズが変更できる</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"最新版にアップデート\">最新版にアップデート</h1>\n<p>MSYS2を起動して以下を実行(ubuntuの<code class=\"language-plaintext highlighter-rouge\">apt update && apt upgrade</code>に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -Syuu\n</code></pre></div></div>\n\n<p>何か聞かれたらYを入力<br />\nウィンドウが閉じられたら再度MSYS2を起動<br />\n再度MSYS2を起動したらもう一回 <code class=\"language-plaintext highlighter-rouge\">pacman -Syuu</code> を実行</p>\n\n<h1 id=\"開発ツールのインストール\">開発ツールのインストール</h1>\n<p>MSYS2を起動して以下を実行<br />\n(make、gcc、gdbなどのインストール)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -S base-devel\npacman -S mingw-w64-ucrt-x86_64-gcc\npacman -S mingw-w64-ucrt-x86_64-gdb\n</code></pre></div></div>\n\n<h1 id=\"pathの変更\">PATHの変更</h1>\n<p>MSYS2のbashで実行する際はpathは設定済みだが、\nコマンドプロンプト等で実行するためにWindows側のPATHを変更する。</p>\n\n<ul>\n  <li>設定 → システム → バージョン情報</li>\n  <li>関連リンクの「システムの詳細設定」をクリック</li>\n  <li>開いたウィンドウの下のほうにある「環境変数(N)…」をクリック</li>\n  <li>上側のユーザ環境変数で「Path」を選択して「編集」をクリック</li>\n  <li>「新規」をクリックして以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>c:\\msys64\\ucrt64\\bin\nC:\\msys64\\usr\\bin\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\nc:\\msys64\\ucrt64\\bin にはpythonが入っているので、Windowsでインストールしたpythonを使用したい場合は\nそのPATHより後(下)に設定すること</p>\n    </blockquote>\n  </li>\n</ul>\n\n<p>念のためここでPCを再起動する。<br />\n(PATHの変更が有効にならない場合がある)</p>\n\n<h1 id=\"windowsterminal-にmsys2を登録\">WindowsTerminal にMSYS2を登録</h1>\n<p>MSY2のデフォルトのターミナルはminttyだが、いつも使っているWindowsTerminalで使えるようにする。</p>\n<ul>\n  <li>WindowsTerminalを起動</li>\n  <li>「新しいプロファイルを追加」を選択</li>\n  <li>「新しい空のプロファイル」をクリック\n    <ul>\n      <li>コマンドラインに以下を設定(ucrt64の場合。それ以外は最後のオプションを変更する)\n        <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>C:/msys64/msys2_shell.cmd -defterm -here -no-start -ucrt64\"  \n</code></pre></div>        </div>\n      </li>\n      <li>開始ディレクトリに MSYS2のhomeディレクトリ(<code class=\"language-plaintext highlighter-rouge\">cygpath.exe -w ~</code> で取得可能) を指定</li>\n      <li>アイコンは何でもいいけど、<code class=\"language-plaintext highlighter-rouge\">C:\\\\msys64\\\\ucrt64.ico</code>とかが良いかな</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"vs-codeのターミナルでmsys2のbashを使用する方法\">VS CodeのターミナルでMSYS2のBashを使用する方法</h1>\n<p>VS CodeのターミナルでもMSYS2を使えるようにしておく。<br />\n(別ウィンドウでWindowsTerminalから実行すればいいんだけど)</p>\n\n<ul>\n  <li>VSCodeを起動</li>\n  <li>設定(ファイル→ユーザ設定→設定)を開く</li>\n  <li>機能→ターミナルを選ぶ\n-「integrated > profiles:windows」 を探す(検索すれば良いんだけど)\n    <ul>\n      <li>「setting,jsonで編集」 をクリック\n        <ul>\n          <li>ひな型作って開いてくれる。</li>\n          <li>そこに 以下を追加\n            <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>          \"MSYS2 Bash\": {\n              \"path\": [\n                  \"C:\\\\msys64\\\\msys2_shell.cmd\"\n              ],\n              \"args\": [\n                  \"-defterm\",\n                  \"-here\",\n                  \"-no-start\",\n                  \"-ucrt64\"\n              ]\n          }\n</code></pre></div>            </div>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nファイルは ユーザだと、<code class=\"language-plaintext highlighter-rouge\">%APPDATA%\\code\\User\\settings.json</code><br />\nワークスペースだとワークスペース下の<code class=\"language-plaintext highlighter-rouge\">.vscode\\settings.json</code></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nデフォルトのプロファイルをBashにすると悲しい結果が待ち受けているのでやらない方が良さそう</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Buildozerをお試し</title>\n  </head>\n  <body>\n    <header>\n      <h1>Buildozerをお試し</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerをお試ししたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonプログラムをAndroid アプリ化できる Buildozer を試してみた時のメモ<br />\n(iOSもできるみたいだけど試してないのでわからん)<br />\n参考:<br />\n<a href=\"https://buildozer.readthedocs.io/en/latest/installation.html\" target=\"_blank\">公式サイト</a><br />\n<a href=\"https://qiita.com/kouzimiso/items/1332ab62791ca5d81c5f\" target=\"_blank\">BuildozerでAndroidアプリを作る 2024 WSL2</a><br />\n<a href=\"https://paloma69.hatenablog.com/entry/2022/07/05/195915\" target=\"_blank\">pythonでAndroidの野良アプリを作りたい2 buildozerでコンパイル編</a></p>\n\n<h1 id=\"準備\">準備</h1>\n<p>環境はWSL で Ubuntu 24.04を使用した。<br />\n(公式では20.04 or 22.04 となってるけど、24.04でも動いた)<br />\n以下ディストリビューション情報</p>\n\n<p>Andoridはちょっと古いけど ZenFone Max Pro (M2) Android9<br />\n新しいAndroidでも動くかどうかわからん。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>~<span class=\"nv\">$ </span>lsb_release <span class=\"nt\">-a</span>\nNo LSB modules are available.\nDistributor ID: Ubuntu\nDescription:    Ubuntu 24.04.2 LTS\nRelease:        24.04\nCodename:       noble\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n\n<p><a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a>参照</p>\n\n<h2 id=\"pyenvでpythonインストール\">pyenvでpythonインストール</h2>\n<p>公式では python は 3.8 以降となっているので、3.12を使うこととした。</p>\n\n<blockquote>\n  <p>[!NOTE]\n3.12では<code class=\"language-plaintext highlighter-rouge\">distutils</code>が廃止されているので、<code class=\"language-plaintext highlighter-rouge\">setuptools</code>のインストールが必須。<br />\n参考:<a href=\"https://openillumi.com/python-3-12-distutils-error-fix-guide/\" target=\"_blank\">Python 3.12での「ModuleNotFoundError: distutilsが見つかりません」を解決する方法</a></p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.12.9 \npyenv shell 3.12.9 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\npyenv shell <span class=\"nt\">--unset</span> \n</code></pre></div></div>\n\n<h2 id=\"pyenvで仮想環境構築\">pyenvで仮想環境構築</h2>\n<p>お約束で仮想環境を作っておく。<br />\n(そのまま3.12.xにインストールしてもいいけど)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Buildozer <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Buildozer\npyenv virtualenv 3.12.9 Buildozer\npyenv <span class=\"nb\">local </span>Buildozer \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"必要なツール類のインストール\">必要なツール類のインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>zip unzip openjdk-17-jdk autoconf libtool pkg-config zlib1g-dev cmake libffi-dev libssl-dev\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n公式サイトで指定されているライブラリのうち以下は24.04では存在しない。<br />\n<code class=\"language-plaintext highlighter-rouge\">libncurses5-dev libncursesw5-dev libtinfo5</code><br />\nWSL2のUbuntu24.04ではデフォルトで後継のlibncurses-dev、libtinfo6が入ってるので気にしなくても大丈夫</p>\n</blockquote>\n\n<h2 id=\"buildozer関連のモジュールのインストール\">Buildozer関連のモジュールのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> buildozer\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">Cython</span><span class=\"o\">==</span>0.29.33 virtualenv\n</code></pre></div></div>\n\n<h2 id=\"使用するフォントのインストール\">使用するフォントのインストール</h2>\n<p>どっかからダウンロードしてきてもいいけど、お手軽にaptでインストール<br />\n(あとで作業ディレクトリにコピーする)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n\n<h2 id=\"ubuntu上でアプリ実行するとき必要なライブラリのインストール\">Ubuntu上でアプリ実行するとき必要なライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libmtdev-dev\n</code></pre></div></div>\n\n<h2 id=\"アプリで使うモジュールのインストール\">アプリで使うモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>kivy\n</code></pre></div></div>\n\n<h1 id=\"アプリの作成\">アプリの作成</h1>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n\n<p>どこでも良いけど、先に作ったpyenvの仮想環境<code class=\"language-plaintext highlighter-rouge\">Buildozer</code>が使えるh場所で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /work/Buildozer/app <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Buildozer/app\n</code></pre></div></div>\n\n<h2 id=\"フォントのコピー\">フォントのコピー</h2>\n<p>先ほどインストールしたフォントを作業ディレクトリにコピー</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir assets\ncp /usr/share/fonts/truetype/fonts-japanese-gothic.ttf assets/\n</code></pre></div></div>\n\n<h2 id=\"mainpyを作成\">main.pyを作成</h2>\n\n<p><a href=\"https://qiita.com/kouzimiso/items/1332ab62791ca5d81c5f\" target=\"_blank\">参考にしたサイト</a>\nにあったプログラムを使わせてもらった(ちょっち変更あり)。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  main.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.app</span> <span class=\"kn\">import</span> <span class=\"n\">App</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.button</span> <span class=\"kn\">import</span> <span class=\"n\">Button</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.label</span> <span class=\"kn\">import</span> <span class=\"n\">Label</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.boxlayout</span> <span class=\"kn\">import</span> <span class=\"n\">BoxLayout</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.utils</span> <span class=\"kn\">import</span> <span class=\"n\">platform</span>\n\n<span class=\"c1\"># フォントのパスを指定してフォントを設定する\n</span><span class=\"k\">if</span> <span class=\"n\">platform</span> <span class=\"o\">==</span> <span class=\"s\">'win'</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Windowsの場合はシステムフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">\"C:/Windows/Fonts/YuGothR.ttc\"</span><span class=\"p\">)</span>\n<span class=\"k\">elif</span> <span class=\"n\">platform</span> <span class=\"o\">==</span> <span class=\"s\">'android'</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Androidの場合はassetsフォルダ内のフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'assets/fonts-japanese-gothic.ttf'</span><span class=\"p\">)</span>\n<span class=\"k\">else</span><span class=\"p\">:</span>\n    <span class=\"c1\"># その他のプラットフォームではデフォルトフォントを使用\n</span>    <span class=\"c1\"># LabelBase.register(DEFAULT_FONT, fn_regular='DejaVuSans.ttf')\n</span>    <span class=\"c1\"># その他の場合もassetsフォルダ内のフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'assets/fonts-japanese-gothic.ttf'</span><span class=\"p\">)</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MyApp</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># レイアウトの生成\n</span>        <span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"n\">BoxLayout</span><span class=\"p\">(</span><span class=\"n\">orientation</span><span class=\"o\">=</span><span class=\"s\">'vertical'</span><span class=\"p\">,</span> <span class=\"n\">spacing</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ボタンの生成\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span> <span class=\"o\">=</span> <span class=\"n\">Button</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"o\">=</span><span class=\"s\">'クリックしてください'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ボタンにコールバックを設定\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"n\">on_press</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">on_button_press</span><span class=\"p\">,</span> <span class=\"n\">on_release</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">on_button_release</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ラベルの生成\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">Label</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"o\">=</span><span class=\"s\">'ボタンがクリックされるとここに表示されます'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># layoutにボタンとラベルを配置\n</span>        <span class=\"n\">layout</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span><span class=\"p\">)</span>\n        <span class=\"n\">layout</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">layout</span>\n\n    <span class=\"c1\"># ボタンが押されたたときのコールバック処理\n</span>    <span class=\"k\">def</span> <span class=\"nf\">on_button_press</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">instance</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">'ボタンが押されました!'</span>\n    \n    <span class=\"c1\"># ボタンが離されたたときのコールバック処理\n</span>    <span class=\"k\">def</span> <span class=\"nf\">on_button_release</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">instance</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">'ボタンが離されました!'</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">MyApp</span><span class=\"p\">().</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"とりあえずununtu上で試してみる\">とりあえずUnuntu上で試してみる</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python main.py\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n上半分がボタン、下半分がラベル<br />\nボタンを押す/離すとラベルの表示が変わる<br />\nXボタンで終了</p>\n</blockquote>\n\n<h2 id=\"buildozer初期化\">Buildozer初期化</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n<p>buildozer.spec が生成される</p>\n\n<h2 id=\"buildozerspecファイルの修正\">buildozer.specファイルの修正</h2>\n<p>以下の修正を行う</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- buildozer.spec.org  2025-03-28 11:44:32.382972664 +0900\n</span><span class=\"gi\">+++ buildozer.spec      2025-03-28 11:52:18.977717226 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,ttf\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*.ttf\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n</code></pre></div></div>\n\n<h2 id=\"clean--build\">clean & build</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer android clean     <span class=\"c\"># 初回はやらなくてOK(FileNotFoundErrorになる)</span>\nbuildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee</span> <span class=\"nt\">-a</span> buildozer.log\n</code></pre></div></div>\n\n<p>正常にbuildが終了したら以下のように表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n初回は途中ライセンスに同意を求められるので同意するならyを入力(同意しないと終わっちゃうけど)<br />\n終了まで15分ほどかかった(環境依存なのであまりあてにしないで)<br />\n初回はダウンロードが入るのでもうちょっとかかる</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n<h2 id=\"android側の準備\">Android側の準備</h2>\n<p>adbが接続できるようになんか準備が必要(デバッグモードを有効にするとか?)だった気がするけど\n忘れちゃったので良きに計らってちょ\n(<a href=\"https://developer.android.com/studio/debug/dev-options?hl=ja\" target=\"_blank\">このへん?</a>)</p>\n\n<p>で、PCとUSBで接続しておく。</p>\n\n<h2 id=\"windows用-adbのダウンロード\">Windows用 adbのダウンロード</h2>\n<p><a href=\"https://developer.android.com/tools/releases/platform-tools?hl=ja\" target=\"_blank\">SDK Platform-Tools リリースノート</a><br />\n「ダウンロード」セクションの「SDK Platform-Tools for Windowsをダウンロード」からダウンロードし、適当なディレクトリに展開\n(例:C:\\Android_tools )</p>\n\n<blockquote>\n  <p>[!NOTE]\nPATHを通してもいいけど、AndroidStudio使うときに不安なので通さないでcdしてから実行するようにした</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nAndroidStudioが入っているのであれば、そっちを使っても可。<br />\n その場合、adb.exeは<code class=\"language-plaintext highlighter-rouge\">%LOCALAPPDATA%\\Android\\Sdk\\platform-tools</code>にある。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n公式の情報ではWindowsのadbとUbuntuのadbのバージョンが同じでないとダメと書いてあるが、多少違っても大丈夫っぽい。<br />\n(てか、古いバージョンダウンロードできるんだろか?と思ったら、\n<a href=\"https://qiita.com/azumagoro/items/3a44fad53d88b3b2817b\" target=\"_blank\">Android SDK platform-tools 旧バージョン インストール</a>\nに手順書いてあった。メンドクサイけど…)</p>\n</blockquote>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動するためだと思う)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪上で展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!IMPORTANT]\n最初のadbの実行はWindows側。コマンドプロンプトやpowershellで実行する。</p>\n</blockquote>\n\n<p>以下のように表示されるはず</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>* daemon not running; starting now at tcp:XXXX\n* daemon started successfully\nList of devices attached\n== 接続されているデバイスが表示される ==\n</code></pre></div></div>\n\n<p>ちなみにサーバを停止するには以下</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>adb kill-server\n</code></pre></div></div>\n\n<h2 id=\"ダウンロードと実行\">ダウンロードと実行</h2>\n\n<p>WSL側のターミナルに戻って以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run \n</code></pre></div></div>\n\n<p>これでプログラムがAndroidにダウンロードされて実行される。</p>\n\n<p>logcatを表示したいときは以下</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n上記のコマンドを実行すると内部でadbが実行されるようだ。</p>\n</blockquote>\n\n<h2 id=\"usb接続せずに実行したい場合\">USB接続せずに実行したい場合</h2>\n<p>USB接続せずに実行したい場合は以下のように実行してWebサーバを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer serve\n</code></pre></div></div>\n<p>WEBサーバが立ち上がったら、Androidのchrome等からアクセスし、apkファイルをダウンロードしてインストール<br />\n…できるんだけど、通常firewallが動いていてアクセスが弾かれるのでfirewallの設定変更しないといけない。<br />\n変更方法は<a href=\"https://www.fmworld.net/cs/azbyclub/qanavi/jsp/qacontents.jsp?PID=0111-2966\" target=\"_blank\">このへん</a><br />\n(試してないけど)</p>\n\n<h2 id=\"その他の方法\">その他の方法</h2>\n<p>quickshreを使うとか、USBのファイル転送モードを使えばapkファイルを転送できるので、\nあとはFiles等で表示してapkファイルとタップすればインストールできる。<br />\n(なんか野良アプリのインストール許可とか色々許可しないといけなかった気がする)</p>\n\n<h1 id=\"まとめ\">まとめ</h1>\n<p>とりあえずなんか実行できるものができたけど、実用に堪えるかはビミョー。<br />\nファイルアクセスとかネットワークアクセスとか出来るのかな?<br />\nBluetoothはどうなんだろ?<br />\nアクセス権限とかいろいろメンドクサイ処理が必要だったけど、そこまで対応してるんだろか?<br />\n気が向いたらもうちょっと調べてみるかも…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Buildozerでブロック崩しを作る</title>\n  </head>\n  <body>\n    <header>\n      <h1>Buildozerでブロック崩しを作る</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerでブロック崩しを作ってみたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>では訳も分からずとりあえずbuildして実行してみたが、\n少し何がどうなっているか調べてみたところ、\n実行の実体は<a href=\"https://github.com/kivy/python-for-android\" target=\"_blank\">python for android</a>\nというもので、Buildozerはこのプロジェクトをbuildするためのヘルパーらしい。</p>\n\n<p>で、githubのリポジトリを眺めていると<code class=\"language-plaintext highlighter-rouge\">pythonforandroid/recipes</code>にモジュールをbuildするためのレシピが置いてあるようだ。<br />\nそこに、<code class=\"language-plaintext highlighter-rouge\">pygame</code>というディレクトリがあったので、たぶんゲームを作るためのモジュールなんだろうとあたりをつけて\nぐぐってみた。</p>\n\n<p>で、<a href=\"https://python.joho.info/pygame/pygame-blockout/\" target=\"_blank\">【Pygame】ブロック崩しの作り方とサンプルコード(効果音付き)</a>\nにブロック崩しのプログラムの例があったので拝借してAndroidアプリ化してみることにした。</p>\n\n<p>今回は趣向を変えて、失敗事例も含めて書いてみる。</p>\n\n<p>以下、<a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>での環境構築が終わっているものとして進める。</p>\n\n<h1 id=\"使用したソース\">使用したソース</h1>\n<p><a href=\"https://python.joho.info/pygame/pygame-blockout/\" target=\"_blank\">【Pygame】ブロック崩しの作り方とサンプルコード(効果音付き)</a>\nのソースそのままでは動かなかったので、色々試行錯誤した結果のソースが以下。</p>\n\n<p>画像ファイルとオーディオファイルをプロジェクトフォルダに移動して\nアクセスするためのベースディレクトリを環境変数<code class=\"language-plaintext highlighter-rouge\">ANDROID_APP_PATH</code>から取得するようにした。<br />\n(相対パスだとうまく動かない。実行時のディレクトリがmain.pyがあるディレクトリと異なるため)</p>\n\n<p>あと、全画面表示にするため<code class=\"language-plaintext highlighter-rouge\">pygame.display.set_mode</code>に第2パラメータ<code class=\"language-plaintext highlighter-rouge\">(SCALED | FULLSCREEN)</code>を追加している。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pygame</span>\n<span class=\"kn\">from</span> <span class=\"nn\">pygame.locals</span> <span class=\"kn\">import</span> <span class=\"o\">*</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pygame.mixer</span>\n\n<span class=\"c1\"># ベースディレクトリの設定\n# Androidだとchdirされて相対パスでアクセスできなくなるので\n</span>\n<span class=\"n\">BASE_DIR</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getenv</span><span class=\"p\">(</span><span class=\"s\">'ANDROID_APP_PATH'</span><span class=\"p\">)</span>    <span class=\"c1\"># アプリケーションの格納されているパスを環境変数から取得\n</span><span class=\"k\">if</span> <span class=\"n\">BASE_DIR</span> <span class=\"ow\">is</span> <span class=\"bp\">None</span><span class=\"p\">:</span>\n    <span class=\"n\">BASE_DIR</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getcwd</span><span class=\"p\">()</span>                  <span class=\"c1\"># 設定されていない(Androidでない)→ カレントディレクトリを設定\n</span>\n<span class=\"c1\"># 画面サイズ\n</span><span class=\"n\">WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">400</span>\n<span class=\"n\">HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">400</span>\n<span class=\"n\">SCREEN</span> <span class=\"o\">=</span> <span class=\"n\">Rect</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">WIDTH</span><span class=\"p\">,</span> <span class=\"n\">HEIGHT</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像ファイルのパス\n</span><span class=\"n\">PADDLE_IMG_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'paddle.png'</span><span class=\"p\">)</span>\n<span class=\"n\">BLOCK_IMG_PATH</span>  <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'block.png'</span><span class=\"p\">)</span>\n<span class=\"n\">BALL_IMG_PATH</span>   <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'ball.png'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># オーディオファイルのパス\n</span><span class=\"n\">PADDLE_SOUND_PATH</span>   <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'paddle_sound.mp3'</span><span class=\"p\">)</span>\n<span class=\"n\">BLOCK_SOUND_PATH</span>    <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'block_sound.mp3'</span><span class=\"p\">)</span>\n<span class=\"n\">GAMEOVER_SOUND_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'gameover_sound.mp3'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># バドルのスプライトクラス\n</span><span class=\"k\">class</span> <span class=\"nc\">Paddle</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"c1\"># コンストラクタ\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">-</span> <span class=\"mi\">20</span>          <span class=\"c1\"># パドルのy座標\n</span>\n    <span class=\"k\">def</span> <span class=\"nf\">update</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mouse</span><span class=\"p\">.</span><span class=\"n\">get_pos</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span>  <span class=\"c1\"># マウスのx座標をパドルのx座標に\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">clamp_ip</span><span class=\"p\">(</span><span class=\"n\">SCREEN</span><span class=\"p\">)</span>                     <span class=\"c1\"># ゲーム画面内のみで移動\n</span>\n<span class=\"c1\"># ボールのスプライトクラス\n</span><span class=\"k\">class</span> <span class=\"nc\">Ball</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"c1\"># コンストラクタ\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">paddle</span><span class=\"p\">,</span> <span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">,</span> <span class=\"n\">speed</span><span class=\"p\">,</span> <span class=\"n\">angle_left</span><span class=\"p\">,</span> <span class=\"n\">angle_right</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>  <span class=\"c1\"># ボールの速度\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span> <span class=\"o\">=</span> <span class=\"n\">paddle</span>  <span class=\"c1\"># パドルへの参照\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">blocks</span> <span class=\"o\">=</span> <span class=\"n\">blocks</span>  <span class=\"c1\"># ブロックグループへの参照\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">start</span> <span class=\"c1\"># ゲーム開始状態に更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">score</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 連続でブロックを壊した回数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">=</span> <span class=\"n\">speed</span> <span class=\"c1\"># ボールの初期速度\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_left</span> <span class=\"o\">=</span> <span class=\"n\">angle_left</span> <span class=\"c1\"># パドルの反射方向(左端:135度)\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_right</span> <span class=\"o\">=</span> <span class=\"n\">angle_right</span> <span class=\"c1\"># パドルの反射方向(右端:45度)\n</span>\n    <span class=\"c1\"># ゲーム開始状態(マウスを左クリック時するとボール射出)\n</span>    <span class=\"k\">def</span> <span class=\"nf\">start</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># ボールの初期位置(パドルの上)\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span>\n\n        <span class=\"c1\"># 左クリックでボール射出\n</span>        <span class=\"k\">if</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mouse</span><span class=\"p\">.</span><span class=\"n\">get_pressed</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">move</span>\n\n    <span class=\"c1\"># ボールの挙動\n</span>    <span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">+=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centery</span> <span class=\"o\">+=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n        <span class=\"c1\"># 壁との反射\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span><span class=\"p\">:</span>    <span class=\"c1\"># 左側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>              <span class=\"c1\"># 速度を反転\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">></span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>  <span class=\"c1\"># 右側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">right</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span><span class=\"p\">:</span>      <span class=\"c1\"># 上側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n        <span class=\"c1\"># パドルとの反射(左端:135度方向, 右端:45度方向, それ以外:線形補間)\n</span>        <span class=\"c1\"># 2つのspriteが接触しているかどうかの判定\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">colliderect</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                                <span class=\"c1\"># 連続ヒットを0に戻す\n</span>            <span class=\"p\">(</span><span class=\"n\">x1</span><span class=\"p\">,</span> <span class=\"n\">y1</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">-</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">width</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_left</span><span class=\"p\">)</span>\n            <span class=\"p\">(</span><span class=\"n\">x2</span><span class=\"p\">,</span> <span class=\"n\">y2</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_right</span><span class=\"p\">)</span>\n            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span>                          <span class=\"c1\"># ボールが当たった位置\n</span>            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">y2</span><span class=\"o\">-</span><span class=\"n\">y1</span><span class=\"p\">)</span><span class=\"o\">/</span><span class=\"p\">(</span><span class=\"n\">x2</span><span class=\"o\">-</span><span class=\"n\">x1</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">x1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">y1</span>  <span class=\"c1\"># 線形補間\n</span>            <span class=\"n\">angle</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">radians</span><span class=\"p\">(</span><span class=\"n\">y</span><span class=\"p\">)</span>                     <span class=\"c1\"># 反射角度\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">*</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">cos</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">*</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">sin</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>                    <span class=\"c1\"># 反射音\n</span>\n        <span class=\"c1\"># ボールを落とした場合\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">></span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">start</span>                    <span class=\"c1\"># ボールを初期状態に\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">gameover_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">set_score</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>                               <span class=\"c1\"># スコアを0点にする\n</span>            <span class=\"c1\">#self.score.add_score(-100)                  # スコア減点-100点\n</span>\n        <span class=\"c1\"># ボールと衝突したブロックリストを取得(Groupが格納しているSprite中から、指定したSpriteと接触しているものを探索)\n</span>        <span class=\"n\">blocks_collided</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">spritecollide</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">blocks_collided</span><span class=\"p\">:</span>  <span class=\"c1\"># 衝突ブロックがある場合\n</span>            <span class=\"n\">oldrect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span>\n            <span class=\"k\">for</span> <span class=\"n\">block</span> <span class=\"ow\">in</span> <span class=\"n\">blocks_collided</span><span class=\"p\">:</span>\n                <span class=\"c1\"># ボールが左からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"ow\">and</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n                    \n                <span class=\"c1\"># ボールが右からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"ow\">and</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n\n                <span class=\"c1\"># ボールが上からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"ow\">and</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n                <span class=\"c1\"># ボールが下からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"ow\">and</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">block_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>     <span class=\"c1\"># 効果音を鳴らす\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>               <span class=\"c1\"># 衝突回数をカウント\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">add_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">*</span> <span class=\"mi\">10</span><span class=\"p\">)</span>   <span class=\"c1\"># 衝突回数に応じてスコア加点\n</span>\n<span class=\"c1\"># ブロック\n</span><span class=\"k\">class</span> <span class=\"nc\">Block</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"c1\"># ブロックの左上座標\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">+</span> <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">width</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">+</span> <span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">height</span>\n\n<span class=\"c1\"># スコア\n</span><span class=\"k\">class</span> <span class=\"nc\">Score</span><span class=\"p\">():</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">sysfont</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">font</span><span class=\"p\">.</span><span class=\"n\">SysFont</span><span class=\"p\">(</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"mi\">20</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">draw</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">screen</span><span class=\"p\">):</span>\n        <span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">sysfont</span><span class=\"p\">.</span><span class=\"n\">render</span><span class=\"p\">(</span><span class=\"s\">\"SCORE:\"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">),</span> <span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span><span class=\"mi\">255</span><span class=\"p\">,</span><span class=\"mi\">250</span><span class=\"p\">))</span>\n        <span class=\"n\">screen</span><span class=\"p\">.</span><span class=\"n\">blit</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">))</span>\n    <span class=\"k\">def</span> <span class=\"nf\">add_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">+=</span> <span class=\"n\">x</span>\n    <span class=\"k\">def</span> <span class=\"nf\">set_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">score</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"c1\"># 初期化\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># スクリーンの設定\n</span>    <span class=\"c1\"># screen = pygame.display.set_mode(SCREEN.size)\n</span>    <span class=\"n\">screen</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">display</span><span class=\"p\">.</span><span class=\"n\">set_mode</span><span class=\"p\">(</span><span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">SCALED</span> <span class=\"o\">|</span> <span class=\"n\">FULLSCREEN</span><span class=\"p\">))</span>    <span class=\"c1\"># (SCALED | FULLSCREEN) で前画面に拡大表示できる\n</span>\n    <span class=\"c1\"># オーディオ初期化\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># 各種効果音の設定\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">paddle_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">PADDLE_SOUND_PATH</span><span class=\"p\">)</span>               <span class=\"c1\"># パドルにボールが衝突した時の効果音取得\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">block_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">BLOCK_SOUND_PATH</span><span class=\"p\">)</span>                 <span class=\"c1\"># ブロックにボールが衝突した時の効果音取得\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">gameover_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">GAMEOVER_SOUND_PATH</span><span class=\"p\">)</span>           <span class=\"c1\"># ゲームオーバー時の効果音取得\n</span>    \n    <span class=\"c1\"># 描画用のスプライトグループ\n</span>    <span class=\"n\">group</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">RenderUpdates</span><span class=\"p\">()</span>  \n\n    <span class=\"c1\"># 衝突判定用のスプライトグループ\n</span>    <span class=\"n\">blocks</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Group</span><span class=\"p\">()</span>   \n\n    <span class=\"c1\"># スプライトグループに追加    \n</span>    <span class=\"n\">Paddle</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span>\n    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span>\n    <span class=\"n\">Block</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span><span class=\"p\">,</span> <span class=\"n\">blocks</span>\n\n    <span class=\"c1\"># パドルの作成\n</span>    <span class=\"n\">paddle</span> <span class=\"o\">=</span> <span class=\"n\">Paddle</span><span class=\"p\">(</span><span class=\"n\">PADDLE_IMG_PATH</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ブロックの作成(14*10)\n</span>    <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">15</span><span class=\"p\">):</span>\n        <span class=\"k\">for</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">11</span><span class=\"p\">):</span>\n            <span class=\"n\">Block</span><span class=\"p\">(</span><span class=\"n\">BLOCK_IMG_PATH</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># スコアを画面(10, 10)に表示\n</span>    <span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">Score</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>    \n\n    <span class=\"c1\"># ボールを作成\n</span>    <span class=\"n\">Ball</span><span class=\"p\">(</span><span class=\"n\">BALL_IMG_PATH</span><span class=\"p\">,</span> <span class=\"n\">paddle</span><span class=\"p\">,</span> <span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">135</span><span class=\"p\">,</span> <span class=\"mi\">45</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">clock</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">Clock</span><span class=\"p\">()</span>\n\n    <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>  <span class=\"c1\"># ループ処理の実行を継続するフラグ\n</span>\n    <span class=\"k\">while</span> <span class=\"n\">running</span><span class=\"p\">:</span>\n        <span class=\"n\">clock</span><span class=\"p\">.</span><span class=\"n\">tick</span><span class=\"p\">(</span><span class=\"mi\">60</span><span class=\"p\">)</span>      <span class=\"c1\"># フレームレート(60fps)\n</span>        <span class=\"n\">screen</span><span class=\"p\">.</span><span class=\"n\">fill</span><span class=\"p\">((</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">20</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 全てのスプライトグループを更新\n</span>        <span class=\"n\">group</span><span class=\"p\">.</span><span class=\"n\">update</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 全てのスプライトグループを描画       \n</span>        <span class=\"n\">group</span><span class=\"p\">.</span><span class=\"n\">draw</span><span class=\"p\">(</span><span class=\"n\">screen</span><span class=\"p\">)</span>\n        <span class=\"c1\"># スコアを描画  \n</span>        <span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">draw</span><span class=\"p\">(</span><span class=\"n\">screen</span><span class=\"p\">)</span> \n        <span class=\"c1\"># 画面更新 \n</span>        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">display</span><span class=\"p\">.</span><span class=\"n\">update</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># イベント処理\n</span>        <span class=\"k\">for</span> <span class=\"n\">event</span> <span class=\"ow\">in</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">event</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">():</span>\n            <span class=\"c1\"># 閉じるボタンが押されたら終了\n</span>            <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"nb\">type</span> <span class=\"o\">==</span> <span class=\"n\">QUIT</span><span class=\"p\">:</span> \n                <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"c1\"># キーイベント\n</span>            <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"nb\">type</span> <span class=\"o\">==</span> <span class=\"n\">KEYDOWN</span><span class=\"p\">:</span>\n                <span class=\"c1\"># Escキーが押されたら終了\n</span>                <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"n\">K_ESCAPE</span><span class=\"p\">:</span>   \n                    <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># 終了処理\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">quit</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">main</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>画像ファイルとオーディオファイルは参照元のページにあるリンクからダウンロードして以下のように配置する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── main.py\n├── images\n│   ├── ball.png\n│   ├── block.png\n│   └── paddle.png\n└── sound\n    ├── block_sound.mp3\n    ├── gameover_sound.mp3\n    └── paddle_sound.mp3\n</code></pre></div></div>\n\n<p>とりあえずホスト上で動作するか確認してみる。<br />\n(Android上のpython/pygameとバージョンが違うので厳密な動作確認にはならないけど、大体OKを確認したいだけなのでこれでいく)</p>\n\n<p>pygameのインストールは以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>pygame\n</code></pre></div></div>\n\n<p>WSLではデフォルトでオーディオ再生するためのライブラリ類がインストールされていないので、以下でインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>pulseaudio\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWSLってオーディオ再生できるんだ。<br />\n初めて知った…</p>\n</blockquote>\n\n<p>で実行してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python main.py\n</code></pre></div></div>\n\n<p>全画面表示になるので、終了はESCキー押下で。</p>\n\n<h1 id=\"まずは何も考えずにbuildしてみる失敗\">まずは何も考えずにbuildしてみる(失敗)</h1>\n\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>とりあえず最低限必要な修正だけで試してみる。<br />\nbuildozer.spec を以下の内容で修正。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- block0/buildozer.spec       2025-04-04 07:08:53.520218478 +0900\n</span><span class=\"gi\">+++ block1/buildozer.spec       2025-04-04 06:25:27.858934801 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n</code></pre></div></div>\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<p>しばらくするとエラーで止まる。<br />\nmk.logを確認してみると、以下のようなエラーメッセージがあった。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/Buildozer/biock1/.buildozer/android/platform/build-arm64-v8a_armeabi-v7a/build/other_builds/pygame/arm64-v8a__ndk_target_21/pygame/setup.py:70: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives\n・・・\nsrc_c/_sdl2/sdl2.c:211:12: fatal error: 'longintrepr.h' file not found\n</code></pre></div></div>\n\n<p>どうやらpygameのbuuild中に<code class=\"language-plaintext highlighter-rouge\">longintrepr.h</code>が見つからなくてエラーになっているらしい。<br />\n「longintrepr.h」でぐぐってみると、python 3.10 → 3.11 の変更で削除されたファイルらしい。</p>\n\n<h1 id=\"それならばpygameのバージョンを新しくしてbuildしてみる失敗\">それならばpygameのバージョンを新しくしてbuildしてみる(失敗)</h1>\n\n<p>pygameをpython 3.11に対応しているバージョンに変更して試してみる。<br />\n調べてみると、2.1.3からpython 3.11 に対応しているようである。</p>\n\n<p>作成済みのファイルを削除<br />\n<code class=\"language-plaintext highlighter-rouge\">buildozer android clean</code>でも良さそうだけど、念のため全部消して最初からやってみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> .buildozer bin buildozer.spec mk.log\n</code></pre></div></div>\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>buildozer.spec を以下の内容で修正。<br />\npygameのバージョンを2.1.3指定している。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- block0/buildozer.spec       2025-04-04 07:08:53.520218478 +0900\n</span><span class=\"gi\">+++ block2/buildozer.spec       2025-04-04 09:32:40.050228726 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame==2.1.3\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n</code></pre></div></div>\n\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n<p>しばらく待つと、以下のように表示されたので、buildは成功したようである。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Android packaging done!\n# APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<p>なので、実行してみる。<br />\nWindows側でadbサーバを起動しておき、以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>起動はするが、すぐに落ちてしまう。<br />\nなにやらエラーが発生している模様。ログで何が起こっているか確認する。<br />\n無関係なログも多く含まれているので、python関連のログだけ抜き出してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"nt\">-i</span> python run.log <span class=\"o\">></span> run_python.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code> に以下を追加するとlogcatのフィルタが有効になるので、設定しておくと良いかもしれない。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>android.logcat_filters = *:S python:V pythonutil:V PythonActivity:V\n</code></pre></div>  </div>\n  <p>コマンドラインで指定できると良いのがだが…\nadbを直接起動すればコマンドラインで設定できるけど。</p>\n\n  <p>タグ<code class=\"language-plaintext highlighter-rouge\">python</code>がpythonプログラム内のログ、その他は実行時の制御を行っている部分らしい。<br />\nまた、プログラム内のprintによるメッセージ出力もここに表示される。</p>\n</blockquote>\n\n<p>ログファイルの最後の部分には以下のように出力されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> I python  : Traceback (most recent call last):\n I python  :   File \"/work/Buildozer/block2/.buildozer/android/app/main.py\", line 34, in <module>\n I python  :   File \"/work/Buildozer/block2/.buildozer/android/platform/build-arm64-v8a_armeabi-v7a/build/python-installs/myapp/arm64-v8a/pygame/__init__.py\", line 70, in __getattr__\n I python  : NotImplementedError: sprite module not available (ImportError: dlopen failed: cannot locate symbol \"alphablit_alpha_sse2_argb_surf_alpha\" referenced by \"/data/data/org.test.myapp/files/app/_python_bundle/site-packages/pygame/surface.so\"...)\n I python  : Python for android ended.\n</code></pre></div></div>\n\n<p>どうやらpygameの初期化時に<code class=\"language-plaintext highlighter-rouge\">alphablit_alpha_sse2_argb_surf_alpha</code>が見つからないということらしい。<br />\n単にバージョン変えるだけではダメで、ちゃんとレシピも修正しないといけないらしい。</p>\n\n<h1 id=\"python-for-androidのバージョンを下げてみる成功\">python for androidのバージョンを下げてみる(成功)</h1>\n\n<p>python 3.10以下にして試してみることも考えたが、同様にレシピの変更なしで動くとは思えないので\npython for androidのバージョンを下げて試してみることにする。</p>\n\n<p>作成済みのファイルを削除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> .buildozer bin buildozer.spec mk.log\n</code></pre></div></div>\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>buildozer.spec を以下の内容で修正。<br />\n<code class=\"language-plaintext highlighter-rouge\">p4a.branch = release-2022.12.20</code> と指定してrelease-2022.12.20を使用するように設定している。<br />\nこのバージョンは python 3.9.9 を使用している。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gi\">+++ block3/buildozer.spec       2025-04-04 12:28:23.302885362 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n<span class=\"p\">@@ -321,7 +321,7 @@</span>\n #p4a.fork = kivy\n\n # (str) python-for-android branch to use, defaults to master\n<span class=\"gd\">-#p4a.branch = master\n</span><span class=\"gi\">+p4a.branch = release-2022.12.20\n</span>\n # (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch\n #p4a.commit = HEAD\n</code></pre></div></div>\n\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n<p>しばらく待つと、以下のように表示されたので、buildは成功したようである。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Android packaging done!\n# APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<p>なので、実行してみる。<br />\nWindows側でadbサーバを起動しておき(前のセクションで起動してれば再度実行する必要なし)、以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、動いた。<br />\nメデタシメデタシ。<br />\nログがファイルに格納され続けてしまうので、早めにCTRL+Cで止めておきましょう。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのスクロール可能なラベルのカスタムウィジェット</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのスクロール可能なラベルのカスタムウィジェット</h1>\n      <p>PythonプログラムでGUIを作成するkivyでスクロール可能なラベルのカスタムウィジェットを作ったメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>でお試しプログラムを作っていた時、\nログ出力をスクロール可能にしたい(TeraTermみたいなターミナル表示のイメージ)と思い作ってみたけれど、\n汎用的に使えそうな気がしたのでカスタムウィジェットとしてまとめてみた。</p>\n\n<h1 id=\"解説\">解説</h1>\n<p>解説するほど理解してないけど…<br />\nkivyでは文字列を表示するのにLabelウィジェットを使うらしい(AndroidStudioでいうことろのTextView?)。<br />\nで、表示をスクロールするにはScrollViewウィジェットを使う(AndroidStudioでもScrollView)。<br />\n文字列をスクロールするには、ScrollViewの中にLabelを配置してやれば良いのだけれど、「配置しておしまい」という訳でもなく、\n色々と細々と下処理が必要になる。</p>\n\n<p>まずは、表示をどの程度残すか。TeraTermやWindowsTerminalでもスクロールバッファ行数や履歴のサイズとして指定する項目。<br />\nこれを設定できないと際限なく表示が増えてしまうので。<br />\nこれを実現するため、表示内容をdequeに保存し、新規行を追加した際にあふれた分を自動的に破棄するようにしている。</p>\n\n<p>また、テキストが表示領域からあふれた際に自動的にスクロールするようにするため、ラベルの<code class=\"language-plaintext highlighter-rouge\">texture_size</code>プロパティが変更された際に\nイベントハンドラ<code class=\"language-plaintext highlighter-rouge\">update_label_size</code>がコールされるように設定。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"n\">texture_size</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_label_size</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>ここでラベルのサイズをテクスチャサイズに合わせて変更している。<br />\nまた、このときラベルサイズがスクロールビューのサイズを超えた時、<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>に設定することで\n最下行を表示できるようにしている。<br />\nなお、ラベルサイズがスクロールビューのサイズ以下の時に<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>にしてしまうと下付き表示になってしまうため、\nこの条件では<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">1,0</code>にしている。<br />\nラベルサイズがスクロールビューのサイズ以上の時に常に<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>にすると\n以前の内容を確認するためにスクロールしている状態で新しい行が表示されると最下行までスクロールしてしまうので、\n<code class=\"language-plaintext highlighter-rouge\">0.0</code>に設定するのはスクロールビューのサイズを超えた時だけにしている。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">ScrollLabel</code>クラスをインポートして使ってください。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">scrolllabel</span> <span class=\"kn\">import</span> <span class=\"n\">ScrollLabel</span>\n</code></pre></div></div>\n\n<p>設定できるプロパティは<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>のプロパティに<code class=\"language-plaintext highlighter-rouge\">rows</code>(バッファ行数)を追加しています。<br />\nプロパティに<code class=\"language-plaintext highlighter-rouge\">rows</code>は初期化時にのみ変更可能です。\n初期化後(実際は最初のテキスト出力後)は変更してもバッファ行数に反映されません。</p>\n\n<p>テキストを追加するには<code class=\"language-plaintext highlighter-rouge\">add_text(text)</code>を使用します。\n引数<code class=\"language-plaintext highlighter-rouge\">end</code>を指定することで行末文字を変更できます(デフォルトは<code class=\"language-plaintext highlighter-rouge\">\\n</code>)。  <br />\nテキストを消去するには<code class=\"language-plaintext highlighter-rouge\">clear_text()</code>を使用します。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7.js?file=scrolllabel.py\"></script>\n</dev>\n\n<p>また、gistには実際に使用する際の例(レイアウトに Kv language使用/python使用)も載せてあるのでよろしかったら見てください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>AndroidでpythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>AndroidでpythonでBLE</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerでBLE通信アプリを作ってみたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2025/04/04/Buildozer_2.html\">Buildozerでブロック崩しを作る</a>ではゲームを作ってみたが、次はペリフェラルを使ってみたくなるのが人情というもの。<br />\n<a href=\"https://bleak.readthedocs.io/en/latest/\" target=\"_blank\">Bleak</a>というモジュールがクロスプラットフォームでAndroidでも使えるらしい。<br />\nということで、Bleakを使ってBLEを使用するアプリを作って、それをBuildozerでAndroidアプリ化してみる。</p>\n\n<p>以下、<a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>での環境構築が終わっているものとして進める。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>これまで使用してきたWSL環境だとBluetoothが使用できないので、開発にはRaspberryPi5を使用することにした(Pi3以降なら大丈夫だと思う)。<br />\npyenvで仮想環境作ってkivyとbleakをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<h1 id=\"通信相手の準備\">通信相手の準備</h1>\n<p>通信相手は前に作ったランダム値を送るペリフェラルを使った。<br />\n<a href=\"https://github.com/ippei8jp/MultiBLE/tree/main/micropython\" target=\"_blank\">ここ</a>のble_RandomSensor3.py を\nRascberryPi PICO や ESP32 の micropython で動かしておく。</p>\n\n<p>micropythoの使い方は以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは下の「開く」をクリックすると表示されます。<br />\nダウンロードする場合は<a href=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1\" target=\"_blank\">こちら</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nimportしている<code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>は\n<a href=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7\" target=\"_blank\">ここ</a>\nにあります。</p>\n</blockquote>\n\n<p>用意するファイルはこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── kivy_ble.py\n└── scrolllabel.py\n</code></pre></div></div>\n\n<p>↓をクリックするとソースが開きます。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1.js\"></script>\n</dev>\n\n<h1 id=\"raspberrypiで実行\">RaspberryPiで実行</h1>\n<p>まずはPythonスクリプトが動くことを確認するために、RaspBerryPiで動かしてみる。<br />\n通信相手がいないと動かないので、事前に上の通信相手を実行しておく。</p>\n\n<p>RaspberyPi上でkivy_ble.pyを実行するとウィンドウが開くので、connectボタンをクリックする。<br />\nペリフェラルをスキャンが開始され、最初に見つかったデバイスに接続される。<br />\nさらにDATA1とDATA2のNotifyハンドラが登録され、受信データがウィンドウ右上の表示領域に表示される。<br />\ndisconnectボタンをクリックすると切断される。<br />\nQUITボタンをクリックするとプログラム終了。<br />\nウィンドウ下半分のログ表示領域には情報が表示される。この領域はスクロール可能。</p>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>と同様の手順でAndroidアプリ化していく。</p>\n\n<h2 id=\"ファイルの準備\">ファイルの準備</h2>\n\n<ul>\n  <li>BuidozerがインストールされたWSLの仮想マシンに作業ディレクトリを作成</li>\n  <li>作業ディレクトリに 上で作成した<code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code> <code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>をコピー</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code>を <code class=\"language-plaintext highlighter-rouge\">main.py</code> にリネーム</li>\n  <li>RaspberryPiの≪Bleakインストール先≫>/bleak/backends/p4android/recipes を 作業ディレクトリにコピー(ディレクトリまるごと)\n    <blockquote>\n      <p>[!NOTE]\nBleakのインストール先ディレクトリは以下のコマンドで確認できます</p>\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"bleak \"</span>\n</code></pre></div>      </div>\n    </blockquote>\n  </li>\n</ul>\n\n<p>-または以下でもOK</p>\n<blockquote>\n  <p>[!NOTE]</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> recipes/bleak\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/__init__.py\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/fix_setup.py\n</code></pre></div>  </div>\n</blockquote>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer init</code> を実行して<code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>を生成する</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>に以下の修正を加える</li>\n</ul>\n\n<dev class=\"accordion_head\"></dev>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- buildozer.spec.org  2025-04-09 07:58:44.836709400 +0900\n</span><span class=\"gi\">+++ buildozer.spec      2025-04-17 08:12:06.676451390 +0900\n</span><span class=\"p\">@@ -1,10 +1,10 @@</span>\n [app]\n\n # (str) Title of your application\n<span class=\"gd\">-title = My Application\n</span><span class=\"gi\">+title = BLE Demo\n</span>\n # (str) Package name\n<span class=\"gd\">-package.name = myapp\n</span><span class=\"gi\">+package.name = bledemo\n</span>\n # (str) Package domain (needed for android/ios packaging)\n package.domain = org.test\n<span class=\"p\">@@ -22,7 +22,7 @@</span>\n #source.exclude_exts = spec\n\n # (list) List of directory to exclude (let empty to not exclude anything)\n<span class=\"gd\">-#source.exclude_dirs = tests, bin, venv\n</span><span class=\"gi\">+source.exclude_dirs = tests, bin, venv, recipes\n</span>\n # (list) List of exclusions using pattern matching\n # Do not prefix with './'\n<span class=\"p\">@@ -37,7 +37,13 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements =\n+    python3,\n+    kivy,\n+    bleak,\n+    typing_extensions,\n+    async_to_sync,\n+    async-timeout\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n<span class=\"p\">@@ -95,7 +101,14 @@</span>\n\n # (list) Permissions\n # (See https://python-for-android.readthedocs.io/en/latest/buildoptions/#build-options-1 for all the supported syntaxes and properties)\n<span class=\"gd\">-#android.permissions = android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)\n</span><span class=\"gi\">+android.permissions =\n+    BLUETOOTH,\n+    BLUETOOTH_SCAN,\n+    BLUETOOTH_CONNECT,\n+    BLUETOOTH_ADMIN,\n+    ACCESS_FINE_LOCATION,\n+    ACCESS_COARSE_LOCATION,\n+    ACCESS_BACKGROUND_LOCATION\n</span>\n # (list) features (adds uses-feature -tags to manifest)\n #android.features = android.hardware.usb.host\n<span class=\"p\">@@ -330,7 +343,7 @@</span>\n #p4a.source_dir =\n\n # (str) The directory in which python-for-android should look for your own build recipes (if any)\n<span class=\"gd\">-#p4a.local_recipes =\n</span><span class=\"gi\">+p4a.local_recipes = ./recipes\n</span>\n # (str) Filename to the hook for p4a\n #p4a.hook =\n</code></pre></div></div>\n\n<ul>\n  <li>最終的に作業ディレクトリは以下のようになる\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>≪作業ディレクトリ≫\n├── buildozer.spec\n├── main.py\n├── scrolllabel.py\n└── recipes\n     └── bleak\n         ├── __init__.py\n         └── fix_setup.py\n</code></pre></div>    </div>\n    <h2 id=\"build\">build</h2>\n    <p>以下のコマンドでbuidする</p>\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"インストール実行\">インストール&実行</h2>\n<p>Windows側でadbサーバを起動しておき、以下を実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>connectボタンを最初にクリックした時、「この端末の位置情報へのアクセスをBLE Demoに許可しますか?」と聞かれたら「許可」をクリック\n(Androidのバージョンによって違うかもしれん。ターゲットAPIレベルで決まるんだっけ?)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのButtonの色を変更する</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのButtonの色を変更する</h1>\n      <p>kivyのButtonの色を変更する方法あれこれ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nボタン<code class=\"language-plaintext highlighter-rouge\">Button</code>の色を変更しようとすると、なかなか大変なので色々試してみたメモ。</p>\n\n<h1 id=\"画像ファイルを使用して変更する\">画像ファイルを使用して変更する</h1>\n\n<p>これが通常の方法。<br />\nプロパティ<code class=\"language-plaintext highlighter-rouge\">background_normal</code>、<code class=\"language-plaintext highlighter-rouge\">background_down</code>、<code class=\"language-plaintext highlighter-rouge\">background_disabled_normal</code>、<code class=\"language-plaintext highlighter-rouge\">background_disabled_down</code>に\nそれぞれに表示する画像ファイルを指定する。<br />\n単色で表示するなら1✕1pixelの画像ファイルでかまわない。</p>\n\n<h2 id=\"ソース\">ソース</h2>\n<p>ソースはこんな感じ。<br />\n別途画像ファイル<code class=\"language-plaintext highlighter-rouge\">lightgray.png'</code>、<code class=\"language-plaintext highlighter-rouge\">red.png</code>、<code class=\"language-plaintext highlighter-rouge\">gray.png</code>をカレントディレクトリに用意しておく。</p>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。</p>\n<dev class=\"accordion_head_close\"></dev>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.app</span> <span class=\"kn\">import</span> <span class=\"n\">App</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.button</span> <span class=\"kn\">import</span> <span class=\"n\">Button</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.lang</span> <span class=\"kn\">import</span> <span class=\"n\">Builder</span>\n\n    <span class=\"c1\"># GUIlレイアウト\n</span>    <span class=\"n\">Layout</span> <span class=\"o\">=</span> <span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">'''\n# この中はインデントに意味があるので余計なインデントを入れてはいけない\nBoxLayout:\n    orientation:'horizontal'\n    \n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n    Button:\n        id              : button_test\n        text            : \"TEST\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_test()\n        background_normal: 'lightgray.png'\n        background_down: 'red.png'\n        background_disabled_normal: 'gray.png'\n        background_disabled_down: 'gray.png'\n\n    Button:\n        id              : button_ctrl\n        text            : \"Ena/Dis\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_ctrl()\n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n'''</span>\n    <span class=\"p\">)</span>\n\n    <span class=\"k\">class</span> <span class=\"nc\">MyApp</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n        <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n            <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">__init__</span><span class=\"p\">()</span>\n            \n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span> <span class=\"o\">=</span> <span class=\"n\">Layout</span><span class=\"p\">.</span><span class=\"n\">ids</span><span class=\"p\">.</span><span class=\"n\">button_test</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_ctrl</span> <span class=\"o\">=</span> <span class=\"n\">Layout</span><span class=\"p\">.</span><span class=\"n\">ids</span><span class=\"p\">.</span><span class=\"n\">button_ctrl</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"n\">Layout</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">on_test</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'pressed'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">on_ctrl</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span><span class=\"p\">.</span><span class=\"n\">disabled</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span><span class=\"p\">.</span><span class=\"n\">disabled</span>\n            \n    <span class=\"n\">MyApp</span><span class=\"p\">().</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"動作\">動作</h2>\n\n<p>実行すると、Buttonが2つ表示され、TESTボタンが指定されたファイルのイメージで表示される。<br />\nEna/DisボタンをクリックするとTESTボタンのDisable/Enableが切り替えらる。</p>\n\n<h1 id=\"base64エンコードデータで指定\">Base64エンコードデータで指定</h1>\n\n<p>画像ファイルを使用すると、使用する色の分だけ画像ファイルを用意し、処理を流用する度に\n忘れずにすべてのファイルをコピーしないといけない。<br />\nそこで、画像ファイルをbase64エンコードした文字列をpyファイル(またはkvファイル)に保存する方法を試してみる。</p>\n\n<p>まず、上で用意したpngファイルを以下のコマンドでbase64エンコード(前に特定の文字列を付加)する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"data:image/png;base64,</span><span class=\"sb\">`</span><span class=\"nb\">base64</span> <span class=\"nt\">-w</span> 0 ≪pngファイル≫<span class=\"sb\">`</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n<p>付加されている<code class=\"language-plaintext highlighter-rouge\">data:image/png;base64,</code>は続くデータがpngイメージであることを示している。</p>\n\n<p>出力された文字列を以下のようにファイル名の代わりに記載する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        background_normal           : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2M4fPjwfwAH3wNJzT7giwAAAABJRU5ErkJggg=='\n        background_down             : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAANSURBVBhXY3gro/IfAAVUAi3GPZKdAAAAAElFTkSuQmCC'\n        background_disabled_normal  : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2Oor6//DwAFewJ9z0FqqgAAAABJRU5ErkJggg=='\n        background_disabled_down    : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2Oor6//DwAFewJ9z0FqqgAAAABJRU5ErkJggg=='\n</code></pre></div></div>\n\n<p>これにより、pngファイルを削除しても動作するようになる。</p>\n\n<p>ただし、pyファイル(またはkvファイル)が大きくなってしまうことと、一目で指定されている色が把握できないというデメリットがある。</p>\n\n<h1 id=\"canvasbefor-で指定する\">canvas.befor で指定する</h1>\n\n<p>画像ファイルを用意すること自体面倒なので、RGBA値で指定する方法はないかと考えてみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">Label</code>と同様に<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>で背景色を指定してみることを試してみたが、うまくいかなかった。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    Button:\n        ・・・\n        canvas.before:\n            Color:\n                rgba    : (1,0,0,1)\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n</code></pre></div></div>\n<p>これは<code class=\"language-plaintext highlighter-rouge\">Button</code>が<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>をサポートしていないわけではなく、\nちゃんと指定通りに描画しているが、\nその前面に<code class=\"language-plaintext highlighter-rouge\">Button</code>のBackground_XXXが表示されているためらしい。</p>\n\n<p>それならば、Buttonの表示を透明にしてやれば<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>の表示が見えるはずである。<br />\n以下のように変更して試してみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">background_color : (0, 0, 0, 0)</code>が透明色にしている部分で、<br />\n<code class=\"language-plaintext highlighter-rouge\">background_XXX</code>をヌル文字列にしているのはすべてのピクセルを(255,255,255,255)にするためであるが、\n透明になるのであまり関係ないかもしれない。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    Button:\n        ・・・\n        background_normal           : ''\n        background_down             : ''\n        background_disabled_normal  : ''\n        background_disabled_down    : ''\n        background_color            : (0, 0, 0, 0) # 透明\n        canvas.before:\n            Color:\n                rgba    : (1,0,0,1)\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n</code></pre></div></div>\n<p>これでボタンが赤色になった。<br />\nしかし、これでばボタンを押下した時やDisableにした時に色が変化しない。</p>\n\n<p>そこで、さらに以下のようにして押下した時やDisableにした時に色が変わるようにしてみた。<br />\n<code class=\"language-plaintext highlighter-rouge\">canvas.before.Color.rgba</code>を <code class=\"language-plaintext highlighter-rouge\">self.disabled</code>と<code class=\"language-plaintext highlighter-rouge\">self.state</code>によって変更している。<br />\n下にGUIリソース定義部分全体を記載しておく。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 分かりやすいようにグローバル変数で定義しておく\n#:set BG_COLOR_NORMAL   (0.75, 0.75, 0.75, 1.0)\n#:set BG_COLOR_DOWN     (1.00, 0.00, 0.00, 1.0)\n#:set BG_COLOR_DISABLED (0.50, 0.50, 0.50, 1.0)\n\nBoxLayout:\n    orientation:'horizontal'\n    \n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n    Button:\n        id              : button_test\n        text            : \"TEST\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_test()\n        background_normal           : ''\n        background_down             : ''\n        background_disabled_normal  : ''\n        background_disabled_down    : ''\n        background_color            : (0, 0, 0, 0) # 透明\n        canvas.before:\n            Color:\n                rgba    : BG_COLOR_DISABLED if self.disabled else BG_COLOR_NORMAL if self.state == 'normal' else BG_COLOR_DOWN\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n    Button:\n        id              : button_ctrl\n        text            : \"Ena/Dis\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_ctrl()\n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n</code></pre></div></div>\n\n<h1 id=\"カスタムボタンウィジェットを作成する\">カスタムボタンウィジェットを作成する</h1>\n\n<p>上でとりあえず目的は達成されたが、ボタンを配置する度に上記のような設定を書くのは面倒なので、\nカスタムボタンウィジェットを作成してみる。</p>\n\n<h2 id=\"ソース-1\">ソース</h2>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/98907d88de7106b1c30a0be4b39aa77f\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/98907d88de7106b1c30a0be4b39aa77f.js\"></script>\n</dev>\n\n<h2 id=\"解説\">解説</h2>\n<p>上の「canvas.befor で指定する」の方法をkv言語を使用せずpythonで定義している。<br />\nそれぞれの色を自由に変更できるようにプロパティを用意した。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_normal</code>   通常時の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_down</code>     押下時の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_disabled</code> 無効時の色</li>\n</ul>\n\n<p>また、そのままだとボタンを並べて表示したときに境界が分からなくなるので、枠線を描画するため、以下のプロパティを用意した。<br />\nデフォルトは黒で幅1。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">border_color</code>    枠線の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">border_width</code>    枠線の幅</li>\n</ul>\n\n<p>初期化時にボタン本体の背景を透明にし、<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>に描画命令を追加して背景の描画(背景色と枠線)することと、\n状態、位置、プロパティが変化したときに描画パラメータを再設定する処理をbindしている。<br />\nbindした処理では状態や位置に合わせて<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>の処理のパラメータを変更している。</p>\n\n<p>枠線を描画するための<code class=\"language-plaintext highlighter-rouge\">Line</code>はwidth×2の幅で描画されるようなので、本来の矩形のwidthの半分だけ内側に描画されるようにしている。</p>\n\n<p>GUIレイアウトを定義するときは、通常のButtonと同様のプロパティ設定で配置できる。<br />\nもちろん、上の通常時の色、押下時の色、無効時の色を変更したい場合は追加で指定すれば良い。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのSpinnerをカスタマイズ</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのSpinnerをカスタマイズ</h1>\n      <p>kivyのSpinner(ドロップダウンリスト)をカスタマイズする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nSpinner(ドロップダウンリスト)の項目の表示がすべて同じ色で現在選択されている項目がどれか一目で分からなかったので\n選択されている項目の色が変わるようにカスタマイズしてみた。</p>\n\n<p><a href=\"/memoBlog/2025/04/26/kivy_2.html\">kivyのButtonの色を変更する</a>ではButtonをカスタマイズして\n簡単に背景色を変更できるようにしたので、それを使えばわりとお手軽にできそうな感じ。</p>\n\n<h1 id=\"カスタマイズ内容\">カスタマイズ内容</h1>\n<ul>\n  <li>ドロップダウンの項目の表示色を選択中のものとそれ以外のもので分ける</li>\n  <li>それらの色(背景/文字)はプロパティで指定する</li>\n  <li>ドロップダウンの項目の表示高さをプロパティで指定する</li>\n</ul>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7.js\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyではドロップダウンリスト(クリックすると選択項目がぺろっと出てくるやつ)を表示するのにSpinnerウィジェットを使う。<br />\nで、クリックすると設定された項目が表示されるのだけれど、すべて同じ色(通常時、クリックした時、無効化した時の色はそれぞれ画像で指定できる)\nで表示され、現在どれを選択しているのかが分かり難い。<br />\nそこで、現在選択されている項目の色(画像でなく)を変更できるようにカスタマイズする。</p>\n\n<p>色指定に関して、<code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと項目を表示するための<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスはどちらも<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスを継承しているので、\n<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを同時に継承することで<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスに関連する処理を置き換えられる。</p>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスを作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスは特に追加する処理などはない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinnerOption</span><span class=\"p\">(</span><span class=\"n\">SpinnerOption</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n    <span class=\"k\">pass</span>\n</code></pre></div></div>\n\n<p>次に <code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinner</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinner</span><span class=\"p\">(</span><span class=\"n\">Spinner</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>追加するプロパティ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">item_selected_bg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の背景色\n</span>    <span class=\"n\">item_selected_fg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_unselected_bg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 非選択項目の背景色\n</span>    <span class=\"n\">item_unselected_fg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_height</span>          <span class=\"o\">=</span> <span class=\"n\">NumericProperty</span><span class=\"p\">(</span><span class=\"s\">'48dp'</span><span class=\"p\">)</span>               <span class=\"c1\"># 項目の高さ(デフォルトは48dp)\n</span></code></pre></div></div>\n\n<p>コンストラクタでは<code class=\"language-plaintext highlighter-rouge\">option_cls</code>のデフォルト値を<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>に設定し、基底クラスのコンストラクタを実行。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"s\">'option_cls'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">kwargs</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 項目表示用クラスが指定されていなければCustomSpinnerOptionを指定\n</span>            <span class=\"n\">kwargs</span><span class=\"p\">[</span><span class=\"s\">'option_cls'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">CustomSpinnerOption</span>\n        \n        <span class=\"c1\"># 基底クラスの初期化\n</span>        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">CustomSpinner</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>その後、追加した各プロパティと<code class=\"language-plaintext highlighter-rouge\">text</code>プロパティの変更時の処理をバインドする。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span>\n                    <span class=\"n\">text</span>                <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_bg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_bg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_fg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_fg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_height</span>         <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 項目高さ\n</span>                <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの項目の色などを変更する処理を追加。<br />\nこの処理が各プロパティの変更時の処理としてバインドされる。</p>\n\n<p>項目の一覧は<code class=\"language-plaintext highlighter-rouge\">self._dropdown.container.children</code>か<code class=\"language-plaintext highlighter-rouge\">self._dropdown.children</code>にあるので判断して取得。</p>\n\n<p>選択されている項目か否かは各項目の<code class=\"language-plaintext highlighter-rouge\">text</code>と<code class=\"language-plaintext highlighter-rouge\">self.text</code>が一致しているかどうかで判断できるので、\nこの条件で設定する色を変更。<br />\nまた、項目すべてをループするので、ついでに項目高さ(<code class=\"language-plaintext highlighter-rouge\">height</code>)も変更しておく。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ドロップダウン内の項目の高さ/背景色/文字色を更新\n</span>    <span class=\"k\">def</span> <span class=\"nf\">update_dropdown_background</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">text</span>\n        <span class=\"c1\"># 項目のリストを取得\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        \n        <span class=\"c1\"># 各項目の背景色/文字色を変更\n</span>        <span class=\"k\">for</span> <span class=\"n\">item</span> <span class=\"ow\">in</span> <span class=\"n\">items</span><span class=\"p\">:</span>\n            <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_height</span>                      <span class=\"c1\"># 項目高さ\n</span>            <span class=\"k\">if</span> <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">==</span> <span class=\"n\">text</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_bg</span>    <span class=\"c1\"># 選択中の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_fg</span>    <span class=\"c1\"># 選択中の文字色\n</span>            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_bg</span>  <span class=\"c1\"># 非選択の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_fg</span>  <span class=\"c1\"># 非選択中の文字色\n</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの更新処理をオーバーライド。<br />\nこの処理はドロップダウンの新規作成時や項目追加時にコールされる。<br />\nここに上のドロップダウンの項目の色などを変更する処理のコールを追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">_update_dropdown</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">_update_dropdown</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 項目の背景色等を更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>ついでに項目の追加処理を追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># 項目の追加\n</span>    <span class=\"k\">def</span> <span class=\"nf\">add_item</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">values</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>以上でカスタマイズは終了。</p>\n\n<h1 id=\"動作確認プログラム\">動作確認プログラム</h1>\n<p>このファイルを単体で実行すれば動作確認プログラムが動作する。<br />\n動作確認ではAddボタンをクリックする度にドロップダウンリストの項目が追加されるようになっている。<br />\nSpinnerのボタンをクリックするとドロップダウンリストが表示され、現在選択されている項目が他の色で表示されている。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyで画面遷移</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyで画面遷移</h1>\n      <p>kivyで画面遷移する方法について</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\n実行時に画面を切り替えて使用する方法について試した時のメモ。<br />\nついでにAndroidアプリ化もしてみた。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\n(multi_screenって名前はなんか違う気もするけど、複数画面を制御するってことでヨシとしとこう)</p>\n\n<h2 id=\"メイン処理スクリーンマネージャのソース\">メイン処理/スクリーンマネージャのソース</h2>\n<p>multi_screen.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=multi_screen.py\"></script>\n</dev>\n\n<h2 id=\"第1画面のソース\">第1画面のソース</h2>\n<p>screen1.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen1.py\"></script>\n</dev>\n\n<h2 id=\"第2画面のソース\">第2画面のソース</h2>\n<p>screen2.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen2.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyで画面を切り替えて使用するには、<code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承したクラスを使用し、ここに各画面を登録し、\n<code class=\"language-plaintext highlighter-rouge\">self.current</code>に表示する画面の名前(<code class=\"language-plaintext highlighter-rouge\">name</code>)を設定することで切り替えるらしい。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>今回は日本語を使ってみようと思うので、日本語フォントをインストール。<br />\n有名どころではNotoSansCJKとかTAKAOとか。<br />\nubuntuだと以下でインストールできる。<br />\nNotoSansCJK は Androidでもインストールされていることが多いのかな?(手元のちょっと古いAndroidには入ってた)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n<span class=\"c\"># または</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n<p>あと、テキスト入力も試してみるので、クリップボード操作のためのライブラリをインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>xclip\n</code></pre></div></div>\n\n<h2 id=\"multi_screenpy\">multi_screen.py</h2>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">multi_screen.py</code>の内容について。</p>\n\n<p>今回は日本語を使ってみるので、フォントディレクトリの登録と日本語対応フォントをデフォルトフォントに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">get_system_fonts_dir</span><span class=\"p\">()</span>                                        <span class=\"c1\"># フォントディレクトリにシステムフォントディレクトリを登録\n</span><span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'NotoSansCJK-Regular.ttc'</span><span class=\"p\">)</span>  <span class=\"c1\"># デフォルトフォントを設定\n</span></code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承した<code class=\"language-plaintext highlighter-rouge\">ControlScreenManager</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ControlScreenManager</span><span class=\"p\">(</span><span class=\"n\">ScreenManager</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">ControlScreenManager</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># 画面間で共有する変数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n</code></pre></div></div>\n<p>ネットで検索すると画面間で共有する変数を画面間で直接やりとりする例があったが、\nソースの再利用性などを考えてスクリーンマネージャで管理することにした。<br />\nそのための設定/取得メソッド</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ターゲット文字列の設定\n</span>    <span class=\"k\">def</span> <span class=\"nf\">set_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"n\">text</span>\n    \n    <span class=\"c1\"># ターゲット文字列の取得\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span>\n</code></pre></div></div>\n\n<p>画面切り替え処理<br />\nこれも画面から他の画面に直接遷移している例があるけど、\n一旦スクリーンマネージャでうけとってから\n遷移した方が分かりやすいと思う。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># screen1への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">SlideTransition</span><span class=\"p\">(</span><span class=\"n\">direction</span><span class=\"o\">=</span><span class=\"s\">'left'</span><span class=\"p\">,</span> <span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen1'</span>\n        \n    <span class=\"c1\"># screen2への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen2</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">FadeTransition</span><span class=\"p\">(</span><span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen2'</span>\n</code></pre></div></div>\n\n<p>アプリケーションクラス</p>\n\n<p>アプリケーションクラスのbuildメソッドでは上で定義したスクリーンマネージャのインスタンスに\n各画面のインスタンスを登録し、そのインスタンスをリターンする。</p>\n\n<p>KV言語で書く方法もあるけど、画面切り替えのときに使用する名前をここで定義できるので\nソースの見通しが良くなって好み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ScreenManager1</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># スクリーンマネージャの生成\n</span>        <span class=\"n\">sm</span> <span class=\"o\">=</span> <span class=\"n\">ControlScreenManager</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 画面1を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen1</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen1'</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 画面2を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen2</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen2'</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">sm</span>\n</code></pre></div></div>\n\n<h2 id=\"screen1py\">screen1.py</h2>\n\n<p>レイアウトの定義</p>\n\n<p>kvファイルにレイアウトを書く例が多いけど、こう書くとレイアウトと処理をまとめて書けるので好み。</p>\n\n<blockquote>\n  <p>[!NOTE]\n最近知ったけど、色指定は(rr, gg, bb, aa)(各値は0~1)と書かれている例が多いけど、\n色名(“black”とか”red”とか。指定できる色名は kivyインストールディレクトリの<code class=\"language-plaintext highlighter-rouge\">util.py</code>で定義されている<code class=\"language-plaintext highlighter-rouge\">hex_colormap</code>を参照)\nの他、”#RRGGBBAA”でも指定可能(AAは省略可能)。\nどちらも文字列指定なのでダブルクォーテーションまたはシングルクォーテーションで囲む必要あり。</p>\n\n  <p>また、サイズ類は<code class=\"language-plaintext highlighter-rouge\">dp(36)</code>みたいな書き方もできるけど、文字列で<code class=\"language-plaintext highlighter-rouge\">\"36dp\"</code>と書くこともできる。\nサイズ類は数値で指定すると単位は<code class=\"language-plaintext highlighter-rouge\">px</code>になる。</p>\n</blockquote>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen1>:\n    ・・・・\n            bg_color_normal : \"#585858ff\"       # \"coloe_name\" or \"#RRGGBB\" or \"#RRGGBAA\" or (rr, gg, bb, aa) で指定\n    ・・・・\n            item_height          : '36dp'   # 数値で指定したときの単位はpx\n    ・・・・\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nAndroidアプリ化する場合、テキスト入力が下の方にあるとソフトキーボードが出てきたときに見えなくなるので\n上の方に配置しておく方が無難。<br />\nなんかうまくやる方法があるのかもしれんけど、現状分かってない。</p>\n</blockquote>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>class Screen1(Screen):\n</code></pre></div></div>\n\n<p>あとは<code class=\"language-plaintext highlighter-rouge\">Screen1</code>クラス内で動作を定義していけば良い。<br />\n画面切り替え処理はkv言語で直接スクリーンマネージャの処理をコールすると訳わかめになるので\n一旦このクラス内で受け取ってスクリーンマネージャの処理をコールするようにしている。<br />\nこの辺は好みの問題なので、お好きにどうぞ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'switch_to_screen1'</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">switch_to_screen1</span><span class=\"p\">()</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nスクリーンマネージャはScreen派生クラスの<code class=\"language-plaintext highlighter-rouge\">self.manager</code>で取得できる。</p>\n</blockquote>\n\n<h2 id=\"screen2py\">screen2.py</h2>\n\n<p>こちらも同様にレイアウトを定義しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen2>:\n    ・・・・\n</span></code></pre></div></div>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">Screen2</span><span class=\"p\">(</span><span class=\"n\">Screen</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>画面が切り替わる前にScreen1で設定した文字列を取得したいので、<code class=\"language-plaintext highlighter-rouge\">on_pre_enter()</code>をオーバーライドする。<br />\n文字列をScreen1から直接取ると画面構成変えた時に困るので、スクリーンマネージャ経由で取得するようにしている。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">on_pre_enter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"c1\"># 表示用ラベルを書き換え\n</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">get_target_string</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"NONE\"</span>       <span class=\"c1\"># 空文字が来たらNONEに書き換え\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">text</span><span class=\"si\">}</span><span class=\"s\"> が選択されました'</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">python multi_screen.py</code>で実行。<br />\n一番上のドロップダウンリストで項目を選択し、2番目の「Go to Screen 2」ボタンを押すとScreen2に切り替わる。<br />\nScreen2では画面下側の領域にScreen1のドロップダウンリストで選択した文字列が表示される。\n「Go to Screen 1」ボタンでScreen1に戻る。<br />\nScreen1のテキスト入力欄に文字列を入力し、「ADD」ボタンをクリックするとドロップダウンリストに入力した文字列が追加される。<br />\nもちろん、その文字列を選択してScreen2に切り替えればその文字列が表示される。</p>\n\n<blockquote>\n  <p>[!NOTE]\nLunuxでは日本語入力できないみたい。ただしコピペは可能なので他のところで入力してコピペすればOK。<br />\nAndroidではそのまま日本語も入力できる。</p>\n</blockquote>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>の手順でAndroidアプリ化もできる。<br />\nここの準備が終わっていれば以下のコマンドでOK。</p>\n\n<h2 id=\"multi_screenpyをリネーム\">multi_screen.pyをリネーム</h2>\n<p>python for androidはエントリーポイントがmain.pyに固定らしいので、リネーム</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mv </span>multi_screen.py main.py\n</code></pre></div></div>\n\n<h2 id=\"buildozerspec-の生成\">buildozer.spec の生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>今回は特に編集の必要なし。\n<code class=\"language-plaintext highlighter-rouge\">title</code>、<code class=\"language-plaintext highlighter-rouge\">package.name</code>、<code class=\"language-plaintext highlighter-rouge\">package.domain</code>なんかは必要なら変更してちょ。</p>\n\n<h2 id=\"build実行\">build実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動する)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪SDK Platform-Tools <span class=\"k\">for </span>Windowsを展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>で、実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、Android上で動作した。メデタシメデタシ。<br />\n文字入力もちゃんと動いてるし、改造したボタンやスピナーも動いてる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyでドラッグで並べ替えできるリスト</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyでドラッグで並べ替えできるリスト</h1>\n      <p>kivyでドラッグで並べ替えできるリストを作った時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nドラッグで並べ替えできるリスト(AndroidでよくあるUI、<code class=\"language-plaintext highlighter-rouge\">RecycleView</code>と<code class=\"language-plaintext highlighter-rouge\">ItemTouchHelper</code>で作るんだったかな?)\nを作ってみた時のメモ。<br />\n<a href=\"https://maausa.marurm.com/wp-content/uploads/RecyclerView.gif\" target=\"_blank\">ちょっと違うけど、大体こんな感じ</a></p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nreorderablelist.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=reorderablelist.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>ソースは、表示する項目を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>と\nリスト全体を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>で構成される。<br />\n(あと、単体実行で動作するテストプログラム)<br />\n動作としては、</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>に<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を追加していきリスト化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code> をドラッグすることで並べ替え</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を左右にスワイプすることでハンドラ実行(デフォルトでは右スワイプで項目削除)\nといった感じ。</li>\n</ul>\n\n<p>テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>を<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>で囲んでスクロール可能にしています。\nスクロール不要ならそのまま配置しても可(テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">with_scroll</code>を<code class=\"language-plaintext highlighter-rouge\">False</code>に設定)。</p>\n\n<h2 id=\"reorderablelist\">ReorderableList</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>はリスト全体を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承したクラス。</p>\n\n<h3 id=\"追加したプロパティ\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>item_bg</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>item_fg</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>list_bg</td>\n      <td>リストの背景色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\n(<code class=\"language-plaintext highlighter-rouge\">orientation</code>は<code class=\"language-plaintext highlighter-rouge\">\"vertical\"</code>固定(項目を縦方向に並べるため)、\n<code class=\"language-plaintext highlighter-rouge\">size_hint_y</code>は<code class=\"language-plaintext highlighter-rouge\">None</code>固定(ScrollViewに包むため))\nのほか、<br />\n背景色の設定と、スクロール可能にするためminimum_height変更時の処理のbindを行っている。</p>\n\n<h3 id=\"項目追加処理\">項目追加処理</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">add_item</code>が項目追加処理。<br />\nパラメータは<code class=\"language-plaintext highlighter-rouge\">cls</code>で項目表示に使用するクラス(デフォルトは<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>)と、項目表示クラスの初期化パラメータを受け取る。<br />\nこれは項目に表示する内容を柔軟に切り替えられるよう、項目表示クラスを<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を継承したクラスに切り替えられるようにするため。</p>\n\n<h3 id=\"レイアウト処理\">レイアウト処理</h3>\n<p>kivyでは、レイアウトの変更命令と実際に変更が行われるまでにディレイがある。<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">add_widget(wid)</code> して直後にwid.posを読み出すと実際に追加されたあとの位置が読み出せない。<br />\nこれは、<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>では処理の予約だけ行い、実際に描画が行われるのは別のところ(<code class=\"language-plaintext highlighter-rouge\">mainloop</code>?)で\n他のウィジェットのレイアウト結果を五月雨式に反映していくため、\n描画結果がposに反映されるまでタイムラグが発生するためと思われる。</p>\n\n<p>そこで、<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>のレイアウトが変更され、処理が終了したタイミングで子ウィジェットに\nレイアウト完了を通知できるよう<code class=\"language-plaintext highlighter-rouge\">do_layout()</code>をオーバライドし、基底クラスの処理が完了した後\n各子ウィジェットの<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>をコールしている。</p>\n\n<h2 id=\"reorderableitem\">ReorderableItem</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>はリストに表示する項目を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスと<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承している。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスはドラッグ処理を実現するクラス。<br />\nもう一つの基底クラスを<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>とすることで、派生クラスのレイアウトを柔軟に設定できるようにしている。</p>\n\n<h3 id=\"追加したプロパティ-1\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>text</td>\n      <td>項目に表示する文字列</td>\n    </tr>\n    <tr>\n      <td>bg_color</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>fg_color</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ-1\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\nのほか、<br />\n項目内部の構築(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)、\n背景色の設定と、pos/size変更時にドラッグ範囲を変更する処理のbind、\nインスタンス変数の設定を行っている</p>\n\n<h3 id=\"内部ウィジェットの追加処理add_inner_widget\">内部ウィジェットの追加処理(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)</h3>\n<p>項目の内部の表示を構築する処理。<br />\nデフォルトではLabelを1個追加している。<br />\n項目の表示内容を変更したい場合は、派生クラスでこの処理をオーバライドし、\n必要な内容を追加していく。</p>\n\n<h3 id=\"ドラッグ開始処理on_touch_down\">ドラッグ開始処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_down()</code>)</h3>\n<p>まず、基底クラスのドラッグ開始処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ対象としての処理(インスタンス変数の設定)を行い、<br />\n自身の描画Canvasを親ウィジェット(<code class=\"language-plaintext highlighter-rouge\">self.parent</code>)のcanvasからcanvas.afterに繋ぎかえる。\nこれはドラッグ中の表示が前面に表示されるようにするためである。</p>\n\n<blockquote>\n  <p>[!NOTE]\n通常、add_widget()すると追加されたウィジェットの描画Canvasは親ウィジェットのCanvasに繋がれる。<br />\nこの親ウィジェットのCanvasに繋がれた描画ウィジェットは後から繋がれたものが前面に表示される。<br />\n(縦方向のBoxLayoutの場合下に表示されているウィジェットが前に表示される)<br />\n重ならない表示であれば問題ないが、ドラッグを行うとドラッグ中のウィジェットが背面に表示されることがある。<br />\nそこで、ドラッグ中のウィジェット他のウィジェットより前面に表示するため、CanvasからCanvas.afterに繋ぎかえ、前面に表示されるようにする。<br />\n仕様を読む限り、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index, canvas='after')</code>でadd_widget時にcanvas.afterに接続できるようなのだが、\n実際にはバグ(仕様制限?)により、indexが0のときのみcanvasパラメータが有効になるらしい。<br />\nこれを回避するため、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index)</code>で通常通りウィジェットを追加した後、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">after</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>として描画Canvasを繋ぎかえている。\ncanvas.afterに繋いだ描画Canvasをcanvasに戻す場合は、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">cur_index</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">children</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>    <span class=\"c1\"># canvas.after から canvasへ繋ぎかえるため\n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">remove_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>                 <span class=\"c1\"># 一旦削除して(canvasかcanvas.afterは自動的に判別してくれる) \n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"o\">=</span><span class=\"n\">cur_index</span><span class=\"p\">)</span>   <span class=\"c1\"># 再度同じ場所に挿入\n</span></code></pre></div>  </div>\n  <p>と実行する。  <code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>は描画Canvasがどこに繋がっていても探して削除してくれるので、\nそのまま実行して問題ない。</p>\n</blockquote>\n\n<h3 id=\"ドラッグ中処理on_touch_move\">ドラッグ中処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_move()</code>)</h3>\n<p>まず、基底クラスのドラッグ中処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ中の処理を行う。<br />\n親ウィジェットに繋がっている子ウィジェットをサーチして、自分以外で自分の中心がウィジェットの表示範囲内に入っているウィジェットを探す\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>)<br />\n自分の上端が対象ウィジェットの上端を超えたか、自分の下端が対象ウィジェットの下端を超えた場合は自分と対象ウィジェットを入れ替える。<br />\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>だけで判断すると、自分より高さが高いウィジェットと入れ替えるときに不都合が起こる)<br />\n位置を交換するには、自分を一旦削除(<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>)して、対象ウィジェットの位置(<code class=\"language-plaintext highlighter-rouge\">i</code>)に繋ぐ(<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>)。<br />\nその後、ドラッグを継続するので、ドラッグ開始時と同様に描画Canvasをcanvas.afterに繋ぎかえる。</p>\n\n<h3 id=\"ドラッグ終了処理on_touch_up\">ドラッグ終了処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_up()</code>)</h3>\n\n<p>まず、基底クラスのドラッグ終了処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ終了の処理を行う。<br />\nドラッグ開始/ドラッグ中処理でcanvas.afterに繋ぎかえた描画Canvasをcanvasに戻すために一旦<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>してから\n<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>する(これによりドラッグにより表示が移動していた対象ウィジェットが通常位置に戻る)。<br />\nその後、対象ウィジェットの表示位置がドラッグ開始時と変わっていなく、ドラッグした距離が設定値を超えている場合は\nスワイプ処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>または<code class=\"language-plaintext highlighter-rouge\">do_swipe_left()</code>)を実行する。</p>\n\n<h3 id=\"右へswipeしたときの処理do_swipe_right\">右へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、対象ウィジェットを削除する。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"左へswipeしたときの処理do_swipe_right\">左へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、デバッグ用にログ出力のみ。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"親ウィジェットのレイアウト完了時処理done_parent_layout\">親ウィジェットのレイアウト完了時処理(<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>)</h3>\n<p>親ウィジェットのレイアウト完了時に子ウィジェットすべてのこのメソッドがコールされる。<br />\nドラッグ中であれば必要な処理(現在位置の記憶とドラッグ中位置への移動)を行う。</p>\n\n<h1 id=\"サンプルプルグラム\">サンプルプルグラム</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nサンプルプルグラム</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=test1.py\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSB</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSB</h1>\n      <p>WSLでUSBを使った時のメモ(バージョン 2.5.7.0)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLのバージョンが2.5.7.0でカーネルバージョンが6.6.87.1-1になってカーネルの再ビルドしなくても\n色々なUSBデバイスが使えるようになったので試してみた時のメモ。</p>\n\n<p>参考:<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb\" target=\"_blank\">USB デバイスを接続する</a></p>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"windows側の準備\">windows側の準備</h2>\n<h3 id=\"usbipd-winのインストール\">usbipd-winのインストール</h3>\n<p><a href=\"https://github.com/dorssel/usbipd-win/releases\" target=\"_blank\">usbipd-winのgithub</a>からダウンロード(使用したのは5.10)<br />\nインストールはファイルをダウンロードして実行するだけ。<br />\nWindowsTerminarが開いている場合は一旦すべて閉じる(PATHの変更を有効にするため)</p>\n\n<h2 id=\"ubuntu側の準備\">Ubuntu側の準備</h2>\n<h3 id=\"systemdの有効化\">systemdの有効化</h3>\n\n<p>systemdを有効にするため、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に以下の設定を追加。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<h3 id=\"仮想usbホストコントローラインタフェースのインストール\">仮想USBホストコントローラインタフェースのインストール</h3>\n<p>ネットワーク経由でUSBデバイスを共有することを可能にするため、仮想USBホストコントローラインタフェース(vhci-hcd)をインストール\n(ドライバの組み込み)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/modules-load.d/usb.conf</code> (ファイル名は何でも可)を以下の内容で作成し、WSLの再起動。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vhci-hcd\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nお試しで1回だけ読み込むなら以下。この場合は再起動不要(というか再起動したら消える)。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo modprobe vhci-hcd\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"usbユーティリティのインストール\">USBユーティリティのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">lsusb</code>とか使いたいので、インストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>usbutils\n</code></pre></div></div>\n\n<h3 id=\"仮想マシンの再起動\">仮想マシンの再起動</h3>\n<p>設定を有効にするため、仮想マシンを再起動する。<br />\n開いているすべての仮想マシンを閉じた後、Windwos側で <code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行し、<br />\n<code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>ですべて仮想マシンのSTATEが<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていることを確認し仮想マシンを再度実行。</p>\n\n<h4 id=\"systemdが起動していることを確認する\">systemdが起動していることを確認する</h4>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>systemctl\n</code></pre></div></div>\n<p>起動していればサービス一覧が表示される。<br />\n起動していなければ以下のようなメッセージが表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>System has not been booted with systemd as init system (PID 1). Can't operate.\nFailed to connect to bus: ホストが落ちています\n</code></pre></div></div>\n\n<h4 id=\"vhci-hcdが組み込まれていることを確認する\">vhci-hcdが組み込まれていることを確認する</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsmod\n</code></pre></div></div>\n<p>表示の中に<code class=\"language-plaintext highlighter-rouge\">vhci_hcd</code>があることを確認。<br />\nなければ組み込みの設定を確認。</p>\n\n<h1 id=\"usbカメラを使ってみる\">USBカメラを使ってみる</h1>\n<p>今回は エレコムの UCAM-DLA200HBK を使用。<br />\nかなり古いカメラなのでもう売ってないけど…<br />\nUVC仕様のカメラなら基本的に同じはず。</p>\n\n<h2 id=\"ubuntu側の準備-1\">Ubuntu側の準備</h2>\n<p>今回はカメラなので、自身にvideoグループを追加<br />\n(要 再ログイン、シャットダウンは不要)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> video\n</code></pre></div></div>\n\n<h3 id=\"guvcviewのインストール\">guvcviewのインストール</h3>\n<p>表示ツールは何でもいいけど、とりあえずguvcviewで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>guvcview \n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-1\">Windows側の準備</h2>\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行\">Ubuntu側の実行</h2>\n\n<p>USB機器が割り当てられたことを確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 002: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n</code></pre></div></div>\n\n<p>デバイスノードも確認しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> <span class=\"nt\">-la</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1\n</code></pre></div></div>\n\n<p>実際に表示してみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">LANG</code>が<code class=\"language-plaintext highlighter-rouge\">ja_JP.UTF8</code>とかのままだと文字化けしてしまうので、Cに変更して実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示されるが、何も表示されない\nコンソールには「V4L2_CORE: Could not grab image (select timeout): リソースが一時的に利用できません」と表示され続ける</p>\n\n<p>GuvcviewウィンドウのVideo Controls をクリックし、</p>\n<ul>\n  <li>Frame Rate を15/1 fps</li>\n  <li>Rsolution を 160x120</li>\n  <li>Camera Output を MJPEG<br />\nにすると表示されるけど、あまり実用的ではない…</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nこれらのパラメータが選択できるかは使用するカメラによる。<br />\nPCのスペック等によって、もうちょっと大きいサイズでも表示できることがある。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n日本語で表示するには、例えば以下のように日本語フォントをインストールして\nLANGを指定せずに実行すれば良い。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"windows側の後始末\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n<h2 id=\"ということで\">ということで</h2>\n<p>あまり実用的とは言い難い結果となってしまった。</p>\n\n<h1 id=\"usbカメラをubuntu-pcからエクスポートしてみる\">USBカメラをUbuntu PCからエクスポートしてみる</h1>\n<p>試しに、Ubuntu PCからUSBカメラをエクスポートしてWSLで表示してみる。</p>\n\n<blockquote>\n  <p>[!NOTE]\n「Netive UbuntuあるならWSL使わんでも良いやん」という気もするが…</p>\n</blockquote>\n\n<h2 id=\"navive-ubuntuの準備\">Navive Ubuntuの準備</h2>\n\n<h3 id=\"カメラを接続\">カメラを接続</h3>\n<p>USBカメラを接続し、認識されているか確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 003 Device 006: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>デバイスノードの確認。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ。<br />\nカメラが他にも接続されているので2×2表示されてるけど…<br />\n今回接続されたのは2と3のはず(今はこれを使わないので気にしない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1  /dev/video2  /dev/video3\n</code></pre></div></div>\n\n<p>必要ならguvcviewをインストールして試してみてちょ。</p>\n\n<h3 id=\"linux-toolsのインストール\">linux-toolsのインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div></div>\n<p>usbipを実行してみる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div></div>\n\n<p>※ linux-tools-≪バージョン≫-generic をインストールしろと言われたら従う。例えば</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-6.5.0-41-generic\n</code></pre></div></div>\n\n<h3 id=\"ドライバの組み込みとdaemonの起動\">ドライバの組み込みとdaemonの起動</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbip-host        <span class=\"c\"># ドライバ組み込み</span>\n<span class=\"nb\">sudo </span>usbipd <span class=\"nt\">-D</span>                  <span class=\"c\"># daemon起動</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n起動時に自動で組み込み&実行したいときはsystemdでサービス登録するとできそうだけど、<br />\n本筋じゃないのでやめとく。<br />\n<a href=\"https://github.com/furbrain/systemd-usbip/blob/master/usbipd.service\" target=\"_blank\">ここ</a>\nとか参考になるかも。</p>\n</blockquote>\n\n<h3 id=\"接続されているデバイスを表示\">接続されているデバイスを表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip list <span class=\"nt\">--local</span>         <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<p>こんな感じで表示される</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\n - busid 3-11 (056e:700a)\n   Elecom Co., Ltd : unknown product (056e:700a)\n・・・\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n表示される製品名等が不明確な場合は<code class=\"language-plaintext highlighter-rouge\">lsusb</code>の結果と突き合わせてみると良い。<br />\n(IDはどちらも表示されているので、これを頼りに)</p>\n</blockquote>\n\n<h3 id=\"バインド\">バインド</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip <span class=\"nb\">bind</span> <span class=\"nt\">--busid</span> 3-11    <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<h2 id=\"wsl-ubuntuでの操作\">WSL Ubuntuでの操作</h2>\n\n<h3 id=\"linux-toolsのインストール-1\">linux-toolsのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">usbip</code>はWindows側でインストールしたusbipd-winに含まれているのでインストール不要。<br />\n別途aptでインストールしても使えるけど結構メンドクサイ。<br />\n使いたくなることもあるかもしれんので、手順は残しておく。</p>\n\n<blockquote>\n  <p>[!NOTE]</p>\n\n  <p>usbipが入っているパッケージをインストール</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div>  </div>\n  <p>usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>たぶんこんなメッセージが出る</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>WARNING: usbip not found for kernel 6.6.87.1-microsoft\n\n  You may need to install the following packages for this specific kernel:\n    linux-tools-6.6.87.1-microsoft-standard-WSL2\n    linux-cloud-tools-6.6.87.1-microsoft-standard-WSL2\n\n  You may also want to install one of the following packages to keep up to date:\n    linux-tools-standard-WSL2\n    linux-cloud-tools-standard-WSL2\n</code></pre></div>  </div>\n  <p>しかし、指定されたパッケージをインストールしようとしても「そんなもんはない」と怒られる。<br />\nしかたないのでゴマカシ。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /usr/lib/linux-tools\n\n<span class=\"nb\">ls</span> <span class=\"nt\">-la</span>\n合計 12\ndrwxr-xr-x  3 root root 4096  6月  6 13:11 <span class=\"nb\">.</span>\ndrwxr-xr-x 65 root root 4096  6月  6 13:11 ..\ndrwxr-xr-x  2 root root 4096  6月  6 13:11 6.8.0-60-generic    ← これを覚えておく\n</code></pre></div>  </div>\n  <p>isbipを実行した時のメッセージとlsしたときのディレクトリ名から以下のようなシンボリックリンクを作成する<br />\n(カーネルバージョンが変わると変更しないといけないので注意)</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ln</span> <span class=\"nt\">-s</span> 6.8.0-60-generic 6.6.87.1-microsoft-standard-WSL2\n</code></pre></div>  </div>\n\n  <p>再度usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>USAGEが表示されたらOK。<br />\nまたWARNINGが表示されたらシンボリックリンクの名前が間違っていると思うので、再確認。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nusbipコマンドへのpathを設定してもsudoで実行するときは無効なので、設定せずfullpathで指定する</p>\n</blockquote>\n\n<h3 id=\"アタッチ可能なバス番号を調べる\">アタッチ可能なバス番号を調べる</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip list <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫\n</code></pre></div></div>\n<p>こんな感じで表示される(BUSIDは例。以下同じ)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Exportable USB devices\n======================\n - ≪UbuntuPCのIPアドレス≫\n       3-11: Elecom Co., Ltd : unknown product (056e:700a)\n           : /sys/devices/pci0000:00/0000:00:14.0/usb3/3-11\n           : Miscellaneous Device / ? / Interface Association (ef/02/01)\n</code></pre></div></div>\n<h3 id=\"アタッチする\">アタッチする</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip attach <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫ <span class=\"nt\">--busid</span> 3-11\n</code></pre></div></div>\n\n<h3 id=\"確認\">確認</h3>\n<p>アタッチできたか確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 001 Device 003: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>前と同様にguvcviewを実行してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示され、画像が表示される。<br />\nそれなりに大きなサイズに切り替えても表示できている。</p>\n\n<h3 id=\"後片付け\">後片付け</h3>\n<p>usbipのポートの確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip port\n</code></pre></div></div>\n<p>こんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Imported USB devices\n====================\nPort 00: <Port in Use> at High Speed(480Mbps)\n       Elecom Co., Ltd : unknown product (056e:700a)\n       1-1 -> unknown host, remote port and remote busid\n           -> remote bus/dev 003/006\n</code></pre></div></div>\n<p>ポートは0であることが分かる。</p>\n\n<p>デタッチする</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo /mnt/c/Program\\ Files/usbipd-win/WSL/usbip detach --port 0\n</code></pre></div></div>\n\n<h3 id=\"まとめ\">まとめ</h3>\n<p>ということで、どうも、USBIPD-WINの転送速度が遅いようだ。</p>\n\n<h1 id=\"bluetoothを使ってみる\">Bluetoothを使ってみる</h1>\n<p>カメラはビミョーな結果だったので、今度はBluetoothで試してみる。\n使用したのは Buffalo BSBT4D09BK(4.0+EDR/LEのアダプタ、中身はCSR製)。<br />\nこれも結構古いのでもう売ってない。  中身がCSRのアダプタなら動く可能性高い。<br />\nRealtekのも使えそうだけど、試してないのでなんとも…</p>\n\n<h2 id=\"ubuntu側の準備-2\">Ubuntu側の準備</h2>\n<p>今回はBluetoothなのでBluetooth関連のライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>bluez\n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-2\">Windows側の準備</h2>\n<p>USBipd-win</p>\n\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行-1\">Ubuntu側の実行</h2>\n\n<h3 id=\"usb機器が割り当てられたことを確認する\">USB機器が割り当てられたことを確認する。</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 003: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)\n</code></pre></div></div>\n\n<h3 id=\"動かしてみる\">動かしてみる</h3>\n<p>ローカルデバイスの一覧表示をしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>hcitool dev\n</code></pre></div></div>\n<p>例えばこんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Devices:\n        hci0    XX:XX:XX:XX:XX:XX\n</code></pre></div></div>\n\n<p>スキャンしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bluetoothctl\n</code></pre></div></div>\n<p>bluetoothctlが起動され、プロンプトが<code class=\"language-plaintext highlighter-rouge\">[bluetooth]#</code>になる。<br />\nスキャンしてデバイス一覧を見てみる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>scan on\n≪スキャンされたデバイスが表示される≫\n≪しばらく待つ≫\nscan off\n≪表示が止まる≫\n\nlist\n≪スキャンされたデバイスが表示される≫\n\nexit\n≪終了してshellに戻る≫\n</code></pre></div></div>\n\n<h3 id=\"pythonで動かしてみる\">pythonで動かしてみる。</h3>\n<p>pyenvでpythonをインストールする場合は\n<a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a>\n の注意書きにあるように、コンパイル前に以下を実行しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<p>新しくプログラム作るのは面倒なので以前作った <br />\n<a href=\"/memoBlog/2025/04/21/Buildozer_3.html\" target=\"_blank\">AndroidでpythonでBLE</a> <br />\nを実行してみる。</p>\n\n<p>必要なモジュール類をインストールして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libmtdev-dev\npip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<p>実行</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">python</span> <span class=\"n\">kivy_ble</span><span class=\"p\">.</span><span class=\"n\">py</span>\n</code></pre></div></div>\n\n<p>動いた。メデタシメデタシ。</p>\n\n<h2 id=\"windows側の後始末-1\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n<p>USB接続のSDカードリーダを使えばRaspberryPiのブート用SDカードをWSLにマウントして操作することも可能なはず。<br />\nメンドクサくなってきたので試すのはやめておくけど。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
  ],
  "config": null,
  "data": {
  },
  "pages": [
    "# site変数\n```\nsite = \n{{ site | inspect }}\n```\n\n# site.tags変数\n```\nsite.tags = \n{{ site.tags | inspect }}\n```\n\n# site.tags のキー 一覧\n{% assign tag_keys = \"\" | split: \"|\" %}\n{% for item in site.tags %}\n  {% assign tag_keys = tag_keys | push: item[0] %}\n{% endfor %}\n\n```\n{{ tag_keys  | inspect }}\n```\n\n# site.posts[1]変数\n```\nsite.posts[1] = \n{{ site.posts[1] | inspect }}\n```\n<!-- {% comment %}  HTMLのコメントだけだとLiquidの処理は止まらないので、コメント中にでっかいデータが出力されてしまう\n# site.tags[0]変数\n\n```\n{{ site.tags[\"サンプル\"] | inspect }}\n```\n\n# site.tags.keys変数\n\n```\n{{ site.tags.keys | inspect }}\n```\n\n# site.tags変数\n\n```\n{{ site.tags | inspect }}\n```\n# site.tags[\"サンプル\"]変数\n\n```\n{{ site.tags[\"サンプル\"] | inspect }}\n```\n\n# site.tags[\"サンプル\"][0]変数\n\n```\n{{ site.tags[\"サンプル\"][0] | inspect }}\n```\n# page.tags | array_to_sentence_string\n\n```\n{{ page.tags | array_to_sentence_string }}\n```\n{% endcomment %}-->\n",
    "Dockerコンテナを開発環境として使用する場合にイメージ作成時に設定しておくと便利なことなど。  \n\n以下、特に断りのない限りベースイメージはubuntu。  \nおそらくdebianでも同じだと思う。  \n\n# sudo を使えるようにする  \n\nDockefileに以下を記述  \n```bash\nRUN apt update && apt -y install sudo \\\n    && echo «ユーザ名» ALL=\\(root\\) NOPASSWD:ALL > /etc/sudoers.d/«ユーザ名» \\\n    && chmod 0440 /etc/sudoers.d/«ユーザ名»\n```\n>[!NOTE] \n> exec時に--userオプション付けてrootで入ればいいんだけどね。  \n> 逐一別ウィンドウでexecするのは面倒なので。  \n> あと、sudoをパスワードなしで実行できるようにしておかないと悲しいことになるので注意。  \n\n# bashの補完機能を有効にする  \n\nDockefileに以下を記述  \n```bash\nRUN apt update && apt install bash-completion \\\n    && echo \". /usr/share/bash-completion/bash_completion\" >> /etc/bash.bashrc\n```\n\n# コマンドヒストリのサーチ機能を^p/^nにマッピングする  \n\nDockefileに以下を記述  \n(リダイレクト先はユーザのホームディレクトリの.bashrcでも可)  \n```bash\nRUN echo -e \"\\\nbind '\\\"\\C-n\\\": history-search-forward' \\n\\\nbind '\\\"\\C-p\\\": history-search-backward'\\n\\\n\">> /etc/bash.bashrc\n```\n\nこのままだと、^pを2回押さないと順方向サーチができないので  \nホストの .docker/config.json に以下を記載しておく。  \n```\n{\n    \"detachKeys\": \"ctrl-\\\\\"\n}\n```\n>[!NOTE]\n> コンテナからのデタッチキーが``^\\``に変更される。  \n> 詳細は「Docker detachKeys」で検索。  \n\n\n# 日本語を文字化けしないようにする  \n\nDockefileに以下を記述  \n```bash\nRUN echo -e \"\\\nexport LANG=C.UTF-8\nexport LANGUAGE=en_US:\n\">> /etc/bash.bashrc\n```\n>[!NOTE]\n> LANG=ja_JP.UTF-8 だとダメ。\n\n# Dockerコンテナ内にpingがなかったら\n\nコンテナ作成後に気が付いたら、以下でping他をインストールする。  \n```bash\napt update\napt install iputils-ping  net-tools\n```\n",
    "# git\n\n## checkoutしてブランチを作成する\n```bash\ngit checkout -b «ブランチ名» refs/tags/«タグ名»\n```\n\n## ブランチを切り替える\n```bash\ngit checkout «ブランチ名»\n```\n\n## リモートリポジトリと同期する\n\n必要ならmasterブランチに切り替えてから実行する ``git checkout master``\n\n```bash\ngit pull\n```\n\n## ブランチ間のdiff\n```bash\ngit diff «比較元ブランチ名» «比較先ブランチ名» [ファイル名 | ディレクトリ名]\n```\n\n## 管理対象外のファイルを表示する\n\n管理対象外のファイルをすべて表示する\n\n```bash\ngit ls-files --others\n```\n\n管理対象外のファイルを.gitignoreの無視ファイルを反映して表示する\n\n```bash\ngit ls-files --others --exclude-standard\n```\n\n# こんなページもあるよ\n[VSCodeでのGitの基本操作まとめ](https://qiita.com/y-tsutsu/items/2ba96b16b220fb5913be){:target=\"_blank\"}\n\n",
    "# Googleドライブ上のファイルを直接ダウンロードする\n\nスクリプト上でgoogleドライブの共有ファイルをwget(やcurl)で取得する方法  \n共有リンクをwgetにそのまま渡すとヘッダとか色々くっついて保存されてしまうので。  \n\n## ファイルIDの取得\n以下のいずれかの手順でファイルIDを取得する  \nこの「ほげほげ」の部分がファイルIDを示している。下記2つの「ほげほげ」は同一のハズ。\n\n> googleドライブ上の共有したいファイルを右クリック→共有可能なリンクを取得  \n> クリップボードに 以下のリンクが保存される  \n> ``https://drive.google.com/open?id=ほげほげ ``  \n\n\n> 共有設定で以下のリンクが取得できる  \n> ``https://drive.google.com/file/d/ほげほげ/view?usp=sharing``  \n\n## ファイルのダウンロード\n以下のコマンドで取得できる。  \nFILE_IDとFILE_OUTは1回しか使わないから、コマンドに直接書けばいいんだけど、下のとの整合のために使っておく。  \n```bash\nFILE_ID=ほげほげ\nFILE_OUT=保存ファイル名\nwget \"https://drive.google.com/uc?export=download&id=${FILE_ID}\" -O ${FILE_OUT}\nunset FILE_ID\nunset FILE_OUT\n```\n## 大きなファイルのダウンロード\n大きなファイルの場合、上記の方法でダウンロードしようとすると「ウィルススャンできんけどダウンロードする?」なページが取得されてしまう。  \nで、以下のコマンドで取得する。  \n```bash\nFILE_ID=ほげほげ\nFILE_OUT=保存ファイル名\nwget --load-cookies /tmp/cookies.txt \"https://drive.google.com/uc?export=download&confirm=$(wget --quiet --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate \"https://drive.google.com/uc?export=download&id=${FILE_ID}\" -O - | sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\\1\\n/p')&id=${FILE_ID}\" -O ${FILE_OUT} && rm -rf /tmp/cookies.txt\nunset FILE_ID\nunset FILE_OUT\n```\n>[!NOTE]\n> $()の内側のwgetで一度ダウンロード要求を送って、「ウィルススャンできんけどダウンロードする?」なページを取得。  \n> このときのcookieを保存しておく(--save-cookies オプション)。  \n> 取得したページの実際のファイルのダウンロードへのリンク部分から「confirm=XXXX」の部分を取り出し。  \n> で、その時のcookieとXXXXの部分を使用して外側のwgetでファイルを取得する。  \n> 最後に不要になったcookie保存ファイルを削除。  \n",
    "",
    "# pyenvのインストール\n\n[pyenvのインストール]({{ site.baseurl }}/2019/06/27/pyenv.html)  \n\n## pyenv-virtualenvでベースバージョンにインストールされたパッケージを参照できるようにする\n\n以下のように``--system-site-packages``オプションを指定する。  \n```bash\npyenv virtualenv --system-site-packages «バージョン» «仮想環境名»\n```\n\n\n\n# csvファイルをエクセルファイルに変換する\n\n[csvファイルをエクセルファイルに変換する]({{ site.baseurl }}/2020/06/29/csv2xls.html)  \n\n\n# pipでインストールしたモジュールの依存関係の確認方法\n\npipでインストールしたモジュールの依存関係を知りたいときがたまにある。  \nそんな場合は、以下の手順で。  \n\nまずは必要なモジュールのインストール  \n```bash\npip install pipdeptree\n```\n\n以下を実行  \n```bash\npipdeptree\n```\n参考:[Python: pipdeptree でパッケージの依存関係を調べる](https://blog.amedama.jp/entry/2016/05/29/182402?fbclid=IwAR1HwuEEKG3-lbCYNJeDBpwgBDZsNae3Ww6GYwrMCFjXt7kqo5-iAyaOXNI)\n\nちなみに、依存関係の矛盾がないかだけ確認したいなら、以下のコマンドでも可能。  \nこっちは特にインストールする必要はない。  \n```bash\npip check\n```\n\n# sudo で pyenv環境のpythonを使用する方法\n通常、pyenv環境を設定していてもsudoでroot権限でスクリプトを実行するとsystemのpython(``/usr/bin/python*``)で実行される。  \nsudoでもpyenvで指定したバージョンのpythonで実行するには``/etc/sudoers`` の ``secure_path=``の先頭に以下を追加する  \n```\n«pyenvインストールディレクトリ»/plugins/pyenv-virtualenv/shims:«pyenvインストールディレクトリ»/shims:«pyenvインストールディレクトリ»/bin:\n```\n例えばこんな感じ。  \n```\n/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:\n```\n\n実行の際は ``-E``オプションをつけて環境変数を引き継いで実行する。  \n```\nsudo -E python ~\n```\nこの方法でpyenvコマンドも使えるようになる(``pyenv local``くらいしか使い道はないけど)  \n\n\n",
    "# ダウンロードページ\n[Raspberry Pi OS](https://www.raspberrypi.com/software/operating-systems/){:target=\"_blank\"}  \n<small>ページ構成がコロコロ変わるので、このリンクもいつまで正しいやら...</small>\n\n# ドキュメント\n[Raspberry Pi Documentation](https://www.raspberrypi.com/documentation/computers/){:target=\"_blank\"}  \n\n\n# Raspberry Pi OS(64bit)のインストール\n[Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール]({{ site.baseurl }}/2022/02/25/raspios_64_20220128.html){:target=\"_blank\"}  \n\n# SDカードイメージファイルの作成\n[Raspbian SDカードイメージファイルの作成(改訂版)]({{ site.baseurl }}/2021/07/18/sd_image_2.html){:target=\"_blank\"}  \n\n# Raspbian Busterのインストール【旧バージョン】\n[Raspbian Busterのインストール]({{ site.baseurl }}/2019/08/31/raspbian_buster_1.html){:target=\"_blank\"}  \n[Raspberry Pi OS(May 7th 2021)のインストール]({{ site.baseurl }}/2021/07/17/raspios_20210507.html){:target=\"_blank\"}  \n\n\n# Raspbian Buster Lite版のインストール【旧バージョン】\n[Raspbian Buster Lite版のインストール]({{ site.baseurl }}/2019/09/13/raspbian_buster_2.html){:target=\"_blank\"}  \n\n# モバイル ホットスポットでRaspberryPiをネットに接続\n[モバイル ホットスポットでRaspberryPiをネットに接続]({{ site.baseurl }}/2019/09/12/mobilehotspot.html){:target=\"_blank\"}  \n\n# VNCタイムアウトの変更\nRasPiにWindowsからVNC Viewerでつないでいると、しばらくほったらかしにすると切断されてしまう。  \nこれを防ぐには、  \n\n- RasPi側のタスクバーのVNCのアイコンを右クリック → Options... → Expert   \n- パラメータで「IdleTimeout」を探す\n- 設定値を「0」に変更(デフォルトは3600(=60分)になっている)\n\nこれでタイムアウトで切断されなくなる  \n\n# IPv6の無効化\n- ``/etc/sysctl.conf``に以下を追加する  \n```\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\n```\n- 以下を実行する  \n```bash\nsudo sysctl -p\n```\n\n# Windowsの共有フォルダのマウント\n\n## Windows側の準備\nWindows側でネットワーク共有したいフォルダを共有に出しておく。  \nめんどくさいのでEveryone フルアクセスで共有に出しておく(自宅なら問題ないでしょう)  \n\n## RasberryPi側でのマウント\n```bash\nsudo mount -t cifs «ネットワークパス» «マウントポイント» -o uid=«linuxのユーザ名»,gid=«linuxのグループ名»,user=«Windowsのユーザ名»,password=«Windowsのパスワード»\n```\n\n【注意】  \n- ネットワークパスのマシン名はNetBIOSの名前(MY_PC)ではなく、mDNSで解決できる名前(MY_PC.local)なので注意。もちろん、IPアドレス直接指定でも問題なし。\n- Everyonで共有に出してあってもanonymousでアクセス出来るわけではないらしいので、Windowsのユーザ名とパスワードは必要。\n- uidとgidは指定してないとオーナがrootになってしまうので、フォルダ内のファイルに書き込みたい場合は指定が必要。\n\n\n例えば、こんな感じ。  \n```bash\nmount -t cifs //MY_PC.local/Share1 /mnt -o uid=hoge,gid=hoge,user=fuga,password=fugafuga\n```\n\n参考: <https://qazsedcftf.blogspot.com/2019/12/raspberry-pi_21.html>\n\n# バージョン情報の取得\n\n## ハードウェアの情報\n```bash\ncat /proc/device-tree/model\nRaspberry Pi 4 Model B Rev 1.2\n```\n\n## カーネルバージョン等の情報\n```bash\n~$ uname -a\nLinux Pi4 5.10.17-v7l+ #1421 SMP Thu May 27 14:00:13 BST 2021 armv7l GNU/Linux\n```\n\n## ディストリビューションやバージョンの情報\n```bash\n~$ lsb_release -a\nNo LSB modules are available.\nDistributor ID: Raspbian\nDescription:    Raspbian GNU/Linux 10 (buster)\nRelease:        10\nCodename:       buster\n```\n\n\n\n\n\n\n\n",
    "このページのソース:<https://raw.githubusercontent.com/ippei8jp/memoBlog/master/misc/sample.md>\n\n# 見出し1\n\n## 見出し2\n\n### 見出し3\n\n#### 見出し4\n\n##### 見出し5\n\n###### 見出し6\n\n本文1  \n改行後\n\n本文2\n\nほげ(見出し1の別の書き方)\n=======================\n\nふが(見出し2の別の書き方)\n-----------------------\n\n\n# 番号なしリスト\n\n- リスト1\n    - ネスト リスト1_1\n        - ネスト リスト1_1_1\n        - ネスト リスト1_1_2\n    - ネスト リスト1_2\n- リスト2\n- リスト3\n\n# 番号付きリスト\n\n1. 番号付きリスト1\n    1. 番号付きリスト1_1\n    1. 番号付きリスト1_2\n1. 番号付きリスト2\n1. 番号付きリスト3\n\n# 水平線\n\n---\n\n# 強調\n\n通常 *emで強調* 通常  \n通常 **strongで強調** 通常  \n通常 ***em+strongで強調*** 通常  \n\n通常 ~~取り消し線~~ 通常  \n\n# 表\n\n|項目1|項目2|項目3|\n|:--|:--:|--:|\n|align left|align center|align right|\n|a|b|c|\n|=|=|=|\n|フッター1|フッター2|フッター3|\n\n# ノートブロック\n> [!NOTE]\n> This is a NOTE\n\n> [!WARNING]\n> This is a WARNING\n\n> [!ERROR]\n> This is a ERROR\n\n> [!TIP]\n> This is a TIP\n\n> [!IMPORTANT]\n> This is IMPORTANT\n\n> Other\n> This is other note\n\n> Other\n> This is other note\n>> Other nested\n>> This is other note2\n>\n>> [!TIP]\n>> This is a TIP\n\n\n# コードブロック\n\n```python\n# 言語指定あり\nprint(\"Hello world!\")\n```\n\n```\n# 言語指定なし\nprint(\"Hello world!\")\n```\n\n<!-- ファイル名を付けたいときはこれを指定-->\n{% include filename.html filename=\"hoge.py\" %}\n```python\n# 言語指定あり スクロールバーあり\nprint(\"Hello world!\")\n\"\"\"\n12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n\"\"\"\n```\n\n# コメント\n\nコメント(その1)の上\n{::comment}\nここはコメントなので表示されることはありません。\nHTMLには出力されます。\n{:/comment}\nコメント(その1)の下\n\n\nコメント(その2)の上\n{% comment %}\nここはコメントなので表示されることはありません。\nHTMLにも出力されません。\n{% endcomment %}\nコメント(その2)の下\n\n\n# 参照\n\n[Markdown (kramdown) のリファレンス](http://mae0003.github.io/markdown/2015/06/21/kramdownRefference)\n\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n# 見出し\n",
    "// jekyllで使用するscssファイルには先頭に「---」2行が必要\n\n// ヘッダの色\n$default_color:   #00b300;\n$top_color:       #0d5bee;\n$debug_color:     #ff66a3;\n\n// オリジナルの設定をすこしいじりたかったので、カスタマイズしたscssファイルを使用\n// カスタマイズしたscssファイル はプロジェクトディレクトリの_sassにある。\n// @import \"{{ site.theme }}\";\n@import \"my_theme\";\n\n/* アイコン表示用 */\n.avatar {\n    height: 64px;\n    width: 64px;\n    border-radius: 999em;\n    margin-right: 20px;\n}\n\n/* -------- copy buttonの設定 -------- */\n/* コードの領域(preの親) */\ndiv.highlight {\n    position: relative;\n}\n\n/* コピーボタン(非表示にしておく) */\n.do_copy_button {\n    display: none;\n/*\n    position: absolute;\n    right: 0; top: 0;\n*/\n    position: absolute;\n    top:   0;\n    float: left;\n    margin: -20px 0 0 -50px;\n\n    padding: 3px 6px 1px 6px;\n    font-size: 1.1rem;\n    color: #fff;\n    background: #ff8080;\n    cursor: pointer;\n}\n\n/* コードの領域にマウスオンでコピーボタンを表示 */\ndiv.highlight:hover .do_copy_button {\n    display: inline-block;\n}\n",
    "# ファイル(ファイルマネージャ)のアドレスバーをテキスト形式にする\nファイルマネージャのアドレスバーが気持ち悪いので、見慣れたテキスト形式にしたい場合は以下のコマンドで。  \n```bash\ngsettings set org.gnome.nautilus.preferences always-use-location-entry true\n```\n>[!NOTE]\n> 一時的にテキスト形式にした場合は「CTRL+L」  \n\n\n# これまでに apt でインストールしたパッケージを調べる\n\n\n``apt`` でインストールされたパッケージ一覧は ``apt list --installed ``で取得できるけど、  \n自分で入れたのか関連パッケージで入ったのかがイマイチよくわからないのと、  \n実際にどんなパッケージ名でインストールすれば良いのかが分かりにくいので。  \n\n```bash\nzgrep -1 install `ls -tr /var/log/apt/history.log*`\n```\n\nlsのオプションで``-tr``を指定しているのでタイムスタンプが古いファイルから検索される(つまり``apt``実行の古い順)。  \nコマンドラインの一つ前の行に実行日時、一つ後ろの行に実行者が入っているので、これを目安に必要な情報をピックアップできる。  \n\"install\" をgrepで引っかけているので、たまに余計なのも引っかかるけど、ご愛敬ということで(笑)。  \n\nアンインストールしたのは別途調べないといけないけど…  \nremoveとpurgeで引っかければいけるかな?  \nこんな感じ。  \n\n```bash\nzgrep -1 -e remove -e purge `ls -tr /var/log/apt/history.log*`\n```\n\n> [!NOTE]\n現在インストール済みパッケージを知りたいだけなら以下でも大丈夫。  \n```bash\napt list --installed\n```\n手動でインストールしたものだけ取得したい場合は以下(つまり、関連パッケージとしてインストールされたものを除く)。  \n```bash\napt list --installed | grep -v 自動\n```\n\n# ファイルがどのパッケージに含まれているかを調べる方法\n\nコマンドを実行して○○が見つからないと言われて、どのパッケージをインストールすれば良いのか分からないときに。  \n\n最初に``apt-file``をインストール  \n```bash\nsudo apt install apt-file\n```\n\n実行前に以下でパッケージ情報を更新しておく。そんなに頻繁にやらなくても良い。  \n```bash\nsudo apt-file update \n```\n\nで、以下で検索。  \n```bash\napt-file search ○○\n```\n\n逆にパッケージに含まれるファイル一覧を取得したい場合は以下。  \n```bash\napt-file show <パッケージ名>\n```\n\n# リソースモニタツール netdataのインストール\n\n## ツールのインストール  \n```bash\nsudo apt update\nsudo apt install netdata\n```\n\n## 設定変更\nリモートマシンからブラウズできるように、``/etc/netdata/netdata.conf``の\n``bind socket to IP``の設定値を``0.0.0.0`` に変更する。\n\n## サービスの再起動\n設定を変更したので再起動。  \n```bash\nsudo systemctl restart netdata \n```\n\nあとはブラウザで対象マシンのポート19999 にアクセスすればOK  \n```\nhttp://192.168.XXX.XXX:19999\n```\n\n\n\n# VirtualBox上のUbuntuとclipboardの共有がおかしくなったときの対処方法\n\nVirtualBox上のUbuntuでclipboardの共有の動作がおかしくなることがある。  \nその場合、以下で対応可能。  \n\n- 現状のプロセスを確認\n\n```bash\nps aux | grep 'VBoxClient --clipboard' | grep -v grep\n```\n\n- プロセスが存在することを確認\n\n- プロセスのkill\n\n```bash\npkill -f 'VBoxClient --clipboard'\n```\n\n- プロセスの再起動\n\n```bash\n/usr/bin/VBoxClient --clipboard\n```\n\nこれで正常にclipboardの共有ができるようになるはず。  \n\n\n# ubuntu 18.04 で IPv6を無効にする方法\n\nubuntu 18.04 では IPv6を無効にする方法には、以下の手順で行う。  \n\n- ``/etc/sysctl.d/99-sysctl.conf`` に以下の内容を追加。\n\n```\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\nnet.ipv6.conf.lo.disable_ipv6  =  1\n```\n\n- サービスの再読み込み\n\n```bash\nsudo sysctl -p\n```\n\n- ``/etc/rc.local`` に以下を追記(なければ新規作成)\n\n```\n#!/bin/bash\n/etc/init.d/procps restart\n\nexit 0\n```\n\n- 新規作成した場合は実行属性を追加  \n\n```bash\nsudo chmod 755 /etc/rc.local\n```\n\nこれで起動の度にIPv6は無効になる。  \n\n参考: [Ubuntu 18.04 で ipv6 を無効にする](https://www.rough-and-cheap.jp/ubuntu/ubuntu18_04_howto_diseable_ipv6/?fbclid=IwAR3_ZYqE7IJOg-1FMczHdoJ7zztDrVojHfU8VF-Zbu6e1cRT-6IGg3hVtIA)\n\n\n# lessのオプション\n\nlessのオプションで便利そうなもの一覧。  \n\n- ANSI Color Escape Sequenceを色表示する(-R)\n- 検索ワードの大文字小文字を区別しない(-i)\n    - 検索ワードに大文字を含めると区別するようになる。\n- 画面右端で折り返さない(-S)\n    - 矢印キー(←→) で横スクロールできる。\n- ファイル名、現在の表示位置などを表示する(-M)\n- 行番号表示(-N)\n\nデフォルトのオプションを指定するには ``.bachrc`` に以下のように追加しておけば良い。  \n```bash\nexport LESS=\"-iMR\"\n```\n\nlsやgrepの出力をlessしたときも色付きで表示する方法\n```bash\nls --color=always | less -R\ngrep --color=always if .bashrc | less -R\n```\n\n``.bashrc`` に 以下を設定しておくと便利かと思ったけど...  \nただし、同時にlessのデフォルトオプションに``-R`` を指定しておかないと悲しいことになる。  \nでも、ファイルにリダイレクトしたときに悲しいことになるので、やめておいた方が無難...  \n\n```bash\nexport LS_OPT='--color=always' \nexport GREP_OPT='--color=always' \nalias ls='ls ${LS_OPT}'\nalias grep='grep ${GREP_OPT}'\n```\n# ファイルの\"START\" から \"END\" までを抽出する\n\n```bash\nsed -n \"/START/,/END/p\" «ファイル名»\n```\n\n# bashスクリプトのコメント\n\n## ブロックコメント\n\nブロックコメントそのものは存在しないが、ヒアドキュメントを応用すれば出来る。  \n具体的には、コメント部分を``<<キーワード`` と``キーワード``で囲む。\n\n```bash\n<< キーワード\n~~コメント~~\nキーワード\n```\n\n例えばこんな感じ。  \n\n```bash\n<< __BLOCK_COMMENT__\n~~コメント 1 行目~~\n~~コメント 2 行目~~\n・・・・・・\n~~コメント n 行目~~\n__BLOCK_COMMENT__\n```\n\n## インラインコメント\n\nコマンドの一部を一時的に削除したい場合など、インラインコメントを使用したい場面がある。  \n例えば、C言語で``func(~/* コメントアウト */,~)``とする場面のこと。  \nこれをbashスクリプトで実現するには、コマンド置換を応用する。  \nコマンド置換とは、コマンドを`` ` `` と `` ` `` で囲んでその出力を別のコマンドのパラメータとする方法のこと。  \n具体的には、行コメントをコマンド置換で挿入する。  \n置換されたコマンドはコメントなので結果なにもせずに返ってくるので、その部分は無視される。\n\nただ、この書き方はとても汚いので、一時的使用にとどめておくのがベター。  \n\n\n```bash\ncommand arg1 arg2 `#コメントアウト` arg3 ・・・\n```\n\n例えばこんな感じ。  \n\n```bash\nls  `#-l`  /etc\n```\n\nシェル変数の設定など、コマンドの前にコマンド置換があるとうまく動かない場合は、以下のようにコマンド置換の後ろに``;``を挿入する。  \n\n```bash\n`# comment`;var=hoge\n```\n\n# bashのファイル名補完の区切り文字を追加する方法\n\n#### シチュエーション\nたとえば、``HOGE_PATH=/path/to/hoge``と入力したいとき、途中でファイル名の補完処理ができない。  \n今まで、一旦スペース挟んで入力して、戻ってスペース削除するという手順を踏んでいて、  \nこれが地味にストレス...  \n\n##### ソリューション\n``~/.bashrc`` に以下の1行を追加\n```bash\nIFS='«追加したい文字»'$IFS\n```\n\nシチュエーションのように``=``を区切り文字として追加したい場合は、こんな感じ  \n```bash\nIFS='='$IFS\n```\n\n##### ちなみに\n設定内容を確認するには以下。  \n```bash\necho -n \"$IFS\" | od -c\n```\n\n##### ちなみに2\nデフォルトの設定に戻すには以下。\n先頭に``$``で、シングルクォート``'`` で囲むこと。\n```bash\nIFS=$' \\t\\n'\n```\n\n##### 言い訳の先取\nなんか悪影響出たら元に戻そう。。。  \n\n\n# 端末(ターミナル)ウィンドウの起動方法によって初期処理を変更する\n## 端末(ターミナル)ウィンドウの環境変数を設定してbashを起動するプロファイルを作成する\n\n- まず現在の設定で端末を開く  \n- メニューの<span style=\"border: 1px solid;\">編集</span> → <span style=\"border: 1px solid;\">Preferences</span> を選択  \n- 左側でベースにするプロファイルの右端の▼をクリックして<span style=\"border: 1px solid;\">Clone...</span>を選択  \n- 名前を入力(例えばopenVINO)して<span style=\"border: 1px solid;\">Clone</span> をクリック\n- 作成したプロファイルをクリックして右側上のタブで<span style=\"border: 1px solid;\">コマンド</span>を選択  \n- <span style=\"border: 1px solid;\">□ SHELLの代わりにカスタム・コマンドを実行する(N)</span> にチェックを入れる  \n- <span style=\"border: 1px solid;\">カスタムコマンド</span>に``/usr/bin/env myUseSetting=OPENVINO bash``と入力  \n  ここで、``myUseSetting=OPENVINO`` が設定したい環境変数\n- その他のタブはお好みで変更 \n- <span style=\"border: 1px solid;\">閉じる</span>をクリック  \n\n## 環境変数によって.bashrcの処理を変更する\n\n``~/.bashrc`` に環境変数に応じた処理を追加  \n\n```bash\nif [[ ${«設定した環境変数»} = \"«期待する文字列»\" ]]; then\n    «環境変数に応じた処理»\nfi\n```\n\nたとえば、こんな感じ。  \n```bash\nif [[ ${myUseSetting} = \"OPENVINO\" ]]; then\n    source /opt/intel/openvino/bin/setupvars.sh\n    echo \"========== bash for openINO ==========\"\nfi\n```\n\n試してみる。  \n以下のコマンドを実行。  \n```bash\ngnome-terminal --profile=«作成したプロファイル名»\n```\n\nたとえば、こんな感じ。  \n```bash\ngnome-terminal --profile=openVINO\n```\n\n起動した端末(ターミナル)ウィンドウで追加した初期処理が実行されていることを確認。  \n通常起動の端末(ターミナル)ウィンドウで追加した初期処理が実行されていないことも確認した方がいいかも。  \n\n## キーボードショートカットで作成したプロファイルの端末(ターミナル)を起動する\n\n- 「設定」を開き、左側で<span style=\"border: 1px solid;\">デバイス</span> →<span style=\"border: 1px solid;\">キーボード</span>と選択する  \n- <span style=\"border: 1px solid;\">名前</span>に適当な名前を設定  \n- <span style=\"border: 1px solid;\">コマンド</span>に先ほど試したコマンドを入力  \n- <span style=\"border: 1px solid;\">ショートカットの設定...</span>をクリックし、設定したいキーの組み合わせを押す  \n  - 既に設定済みのキーの組み合わせは使用できない  \n- 右上の<span style=\"border: 1px solid;\">追加</span>をクリックして完了  \n\nデスクトップで設定したキーの組み合わせを押して起動することを確認\n\n## メニューに作成したプロファイルの端末(ターミナル)を起動するアイコンを追加する\n\n以下の手順で新しい``.desktop``ファイルを作成すればよい。  \n\n- 元になる``desktop``ファイルから新しい``desktop``ファイルを作成  \n```bash\nsudo cp gnome-terminal.desktop «新しいdesktopファイル»\n```\n\n- 新しい``desktop``ファイルの設定を変更する\n  - ``Name``に適当な名称(この名称で表示されるので、分かりやすい名前で)を入力  \n  - ``Exec``に前に試したコマンドを入力。  \n    例えば、こんな感じ。  \n    ```diff\n    --- gnome-terminal.desktop\t2018-05-30 22:03:45.000000000 +0900\n    +++ openvino.desktop\t2020-06-17 12:26:37.403276823 +0900\n    @@ -1,9 +1,9 @@\n    [Desktop Entry]\n    -Name=Terminal\n    +Name=bash for openVINO\n    Comment=Use the command line\n    Keywords=shell;prompt;command;commandline;cmd;\n    TryExec=gnome-terminal\n    -Exec=gnome-terminal\n    +Exec=gnome-terminal --profile=openVINO\n    Icon=utilities-terminal\n    Type=Application\n    X-GNOME-DocPath=gnome-terminal/index.html\n    ```\n- アクティビティで``Name``で設定した名前を検索すればアイコンが出てくるのでクリックして起動  \n\n\nちなみに、作成したアイコンをデスクトップに置くことも可能(その他の物でもできるけど)  \n\n- 配置したい``desktop``ファイルを``~/デスクトップ``ディレクトリにコピーして実行属性を付ける\n```bash\ncp /usr/share/applications/openvino.desktop ~/デスクトップ/\nchmod +x ~/デスクトップ/openvino.desktop \n```\n  - 実行属性を付けないと以下のダイアログで<span style=\"border: 1px solid;\">キャンセル</span>しか選べないので注意  \n- デスクトップ上のアイコンをダブルクリック\n  - <span style=\"border: 1px solid;\">信用できないアプリケーションのランチャー</span>ダイアログが出るので、  \n  - <span style=\"border: 1px solid;\">信頼して起動</span>をクリック  \n  - (2回目以降はダブルクリックだけで起動できる)\n\n\n\n# カレントディレクトリ下のファイルの全角文字等を抽出する\n\n```bash\ngrep -r -n -v '^[[:cntrl:][:print:]]*$' .\n```\n\n# GUIで設定した項目の変更キーの確認\n\n設定変更の前後で``dconf``コマンドで値一覧を取得し、その差分を確認することで変更キーが分かる。  \n```bash\ndconf dump / > before.txt\n# 設定変更\ndconf dump / > after.txt\n\ndiff -u before.txt after.txt\n```\n\nキーが分かれば、以後は以下のコマンドで設定変更できる。  \nスクリプトなどに記載する場合に便利。  \n```bash\ngsettings set «キー» «値»\n```\n\n# ディストリビューションのバージョン確認\n\n以下のコマンドで確認できる。  \n\n```bash\nlsb_release -a\n```\n\nこんな感じで表示される  \n\n```bash\nNo LSB modules are available.\nDistributor ID: Ubuntu\nDescription:    Ubuntu 20.04.2 LTS\nRelease:        20.04\nCodename:       focal\n```\n最初の1行は特に気にしなくて良い。  \nLSB(Linux Standard Base)がインストールされていると、もっと細かい情報が表示されるらしい。",
    "# エクスプローラーの右クリックメニューをカスタマイズ\n\n以下のページに詳しい説明がある。  \n- [エクスプローラーの右クリックメニューをカスタマイズする](https://ascii.jp/elem/000/000/953/953807/){:target=\"_blank\"}  \n  - わりと全体的な話    \n- [あなただけの右クリックで、ストレスフリーな開発を](https://qiita.com/NumLocker/items/f8016f1aed7207b850fb){:target=\"_blank\"}  \n  - 詳細な設定項目など  \n  - フォルダの右クリックとかデスクトップの右クリックなんかも記載アリ  \n\n順序を指定したい場合は``position``キーで ``Top``/``Middle``/``Bottom`` を指定することでできるが、あくまで3種類だけ(下のリンクの[ここ](https://qiita.com/NumLocker/items/f8016f1aed7207b850fb#6-7-%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC%E3%81%AE%E8%A1%A8%E7%A4%BA%E4%BD%8D%E7%BD%AE%E3%81%AE%E5%A4%89%E6%9B%B4)){:target=\"_blank\"}。  \n表示順序はshellの下のキーがASCIIコード順(?)になるらしいので、  \n同一ポジション内でさらに順序を指定したい場合は、キーに``1_``、``2_``みたいな接頭辞を付けて表示順を固定できるみたい。  \nでも、このままだと接頭辞がついたままの項目でメニューに表示されるので、``(既定)``キーに表示する文字列を設定しておけばOK。  \n\n# Windowsでメニューを出したままアクティブウィンドウをキャプチャ\n\n以下の手順でメニューを出したままアクティブウィンドウをキャプチャできる\n1. ALTキーを押す\n2. ALTキーを押したままCTRLキーを押す\n3. ALTキーとCTRLキーをを押したままメニューをマウスで操作する\n4. CTRLキーだけ放す\n5. ALTキーを押したままPRINT SCREENを押す\n\n# WindowsでX-serve\n\n- [WindowsでX-serve]({{ site.baseurl }}/2019/11/26/VcXsrv.html)\n\n# モバイル ホットスポット\n\n- [モバイル ホットスポットでRaspberryPiをネットに接続]({{ site.baseurl }}/2019/09/12/mobilehotspot.html)\n\n\n# PC起動時にネットワークドライブの再接続に失敗する場合の自動リカバリ\n\nPCの起動時にネットワークドライブの再接続に失敗する場合、以下の手順で自動でリカバリできる。  \n手順は以下。  \n\n- ```%SystemDrive%\\Scripts\\MapDrives.ps1```を以下の内容で作成    \n{% include filename.html filename=\"c:\\Scripts\\MapDrives.ps1\" %}\n```powershell\n$i=3\nwhile($True){\n    $error.clear()\n    $MappedDrives = Get-SmbMapping |where -property Status -Value Unavailable -EQ | select LocalPath,RemotePath\n    foreach( $MappedDrive in $MappedDrives)\n    {\n        try {\n            New-SmbMapping -LocalPath $MappedDrive.LocalPath -RemotePath $MappedDrive.RemotePath -Persistent $True\n        } catch {\n            Write-Host \"There was an error mapping $MappedDrive.RemotePath to $MappedDrive.LocalPath\"\n        }\n    }\n    $i = $i - 1\n    if($error.Count -eq 0 -Or $i -eq 0) {break}\n\n    Start-Sleep -Seconds 30\n\n}\n```\n- ```%SystemDrive%\\Scripts\\MapDrives.cmd```を以下の内容で作成    \n{% include filename.html filename=\"%SystemDrive%\\Scripts\\MapDrives.cmd\" %}\n```powershell\ndate /T > \"%TEMP%\\MapDrivers.txt\"\ntime /T >> \"%TEMP%\\MapDrivers.txt\"\nPowerShell -Command \"Set-ExecutionPolicy -Scope CurrentUser Unrestricted\" >> \"%TEMP%\\MapDrivers.txt\" 2>&1 \nPowerShell -File \"%SystemDrive%\\Scripts\\MapDrives.ps1\" >> \"%TEMP%\\MapDrivers.txt\" 2>&1\n```\n- スタートアップフォルダに```%SystemDrive%\\Scripts\\MapDrives.cmd```のショートカットを置く    \n- 作成したショートカットのプロパティを開いて「ショートカット」タブの「実行時の大きさ」を「最小化」に変更しておく。    \n\n参考: [Windows 10、バージョン 1809 において、マップされたネットワークドライブの再接続に失敗する場合がある](https://support.microsoft.com/ja-jp/help/4471218/mapped-network-drive-may-fail-to-reconnect-in-windows-10-version-1809?fbclid=IwAR3FHRrLbLXn8rp_qigZW46oeAWs22x6Uqh-0Nu7psOKDA45UlOo7a9wlg0){:target=\"_blank\"}\n\n\n# ファイルをロックしているプログラムを特定する\n\nWindowsでファイル削除しようとしたら、「このファイルはロックされています」と言われてイラっとしたときに\nこれを使うとイッパツ解消(と行かないこともないことはない)。\n\n[ファイルの削除を妨げているアプリを特定、ロックを解除できるアプリ「LockHunter」](https://forest.watch.impress.co.jp/docs/review/1222040.html?fbclid=IwAR133Iw2vfGX_e9fnBhm3soJ3iRdY65YOPh02tRa_IkG_ntVWAxesZuFORQ){:target=\"_blank\"}  \n\n# Windows Terminalをインストールする\n\nWindows Terminalのインストールは Microsoft Store で「Windows Terminal」で検索してインストールするだけでOK。  \n\n## 参考サイト  \n\nTIPS色々    : [Windows Terminal Tips](https://qiita.com/whim0321/items/6a6b11dea54642bd6724){:target=\"_blank\"}  \nNYAGOSを使う: [Windows Terminal で nyagos を使おう](https://zenn.dev/zetamatta/books/5ac80a9ddb35fef9a146/viewer/a3f5c9){:target=\"_blank\"}  \n色々        : [1からマスター! Windows Terminal入門](https://news.mynavi.jp/itsearch/series/hardware/1_windows_terminal.html){:target=\"_blank\"}  \n\n## 設定例\n設定ファイルは以下にある。  \n``C:\\Users\\<<USER>>\\AppData\\Local\\Packages\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\LocalState\\settings.json``  \n\n設定変更例:\n- フォント/フォントサイズ/ウィンドウサイズ変更\n- ShellにNYAGOSを追加\n- デフォルトをNYAGOSに変更\n\n```diff\n--- settings_org.json   2021-01-31 05:45:34.767869400 +0900\n+++ settings.json       2021-01-31 06:46:38.275728600 +0900\n@@ -8,7 +8,11 @@\n {\n     \"$schema\": \"https://aka.ms/terminal-profiles-schema\",\n\n-    \"defaultProfile\": \"{61c54bbd-c2c6-5271-96e7-009a87ff44bf}\",\n+    \"defaultProfile\": \"{19ddaf5e-e045-481a-bf88-37f7ebe66292}\",\n+\n+    // window size\n+    \"initialCols\": 80,\n+    \"initialRows\": 55,\n\n     // You can add more global application settings here.\n     // To learn more about global settings, visit https://aka.ms/terminal-global-settings\n@@ -28,10 +32,22 @@\n         \"defaults\":\n         {\n             // Put settings here that you want to apply to all profiles.\n+            // \"fontFace\": \"源真ゴシック等幅 Regular\",\n+            \"fontFace\": \"BIZ UDゴシック\",\n+            \"fontSize\": 12\n         },\n         \"list\":\n         [\n             {\n+                  \"guid\": \"{19ddaf5e-e045-481a-bf88-37f7ebe66292}\",\n+                  \"hidden\": false,\n+                  \"name\": \"NYAGOS 4.4.9\",\n+                  \"commandline\": \"C:\\\\wintools\\\\nyagos-4.4.9_2\\\\nyagos.exe\",\n+                  \"icon\": \"C:\\\\wintools\\\\nyagos-4.4.9_2\\\\nyagos.png\",\n+                  \"cursorShape\": \"vintage\",\n+                  \"startingDirectory\": \"c:\\\\\"\n+            },\n+            {\n                 // Make changes here to the powershell.exe profile.\n                 \"guid\": \"{61c54bbd-c2c6-5271-96e7-009a87ff44bf}\",\n                 \"name\": \"Windows PowerShell\",\n```\n\n## misc\n### NYAGOSのアイコンが表示されないので、表示されるようにする\n- EXEファイルからアイコンを抽出してpngファイルで保存しておく\n  - アイコン抽出には[Icon Ripper](https://www.vector.co.jp/soft/winnt/amuse/se513590.html){:target=\"_blank\"}が使える(インストール不要)\n- ``settings.json`` に ``\"icon\" : ~ `` でアイコン設定しておく。\n\n# NYAGOSのカスタマイズ\n\nNYAGOSのリポジトリはこちら:<https://github.com/zetamatta/nyagos>  \n\n\n## ヒストリ補完機能を追加する\n\n[nyagosでヒストリ補完する](https://qiita.com/nocd5/items/7cfc2441868442838148) のソースを  \n``nyagos.exe``のあるディレクトリの``nyagos.d``ディレクトリの下に``h_search.lua``として格納しておく。  \n\n参照先がなくなると困るので、ここに再掲しておく。  \n\n{% include filename.html filename=\"h_search.lua\" %}\n```lua\n-- ヒストリ補完機能\nnyagos.bindkey(\"C_N\",\n    function(this)\n        search_history(this, false)\n    end\n)\n\nnyagos.bindkey(\"C_P\",\n    function(this)\n        search_history(this, true)\n    end\n)\n\nfunction search_history(this, is_prev)\n    -- カーソル位置が一番左の場合は通常のnext/prev\n    if this.pos == 1 then\n        if is_prev == true then\n            this:call(\"PREVIOUS_HISTORY\")\n        else\n            this:call(\"NEXT_HISTORY\")\n        end\n        this:call(\"BEGINNING_OF_LINE\")\n        return nil\n    end\n\n    -- 検索キーワード\n    local search_string = this.text:sub(1, this.pos - 1)\n\n    -- 重複を除いたhistoryリストの取得\n    local history_uniq = {}\n    local is_duplicated = false\n    local hist_len = nyagos.gethistory()\n    for i = 1, hist_len do\n        local history\n        -- 新しい履歴がリスト後ろに残るよう末尾からサーチ\n        history = nyagos.gethistory(hist_len - i)\n        for i, e in ipairs(history_uniq) do\n            if history == e or history == search_string then\n                is_duplicated = true\n            end\n        end\n        if is_duplicated == false then\n            if is_prev == true then\n                table.insert(history_uniq, history)\n            else\n                table.insert(history_uniq, 1, history)\n            end\n        end\n        is_duplicated = false\n    end\n\n    -- 入力と完全一致する履歴を探す\n    -- 完全一致する履歴を起点にすることで\n    -- (見かけ上)インクリメンタルな検索にする\n    local hist_pos = 0\n    for i, e in ipairs(history_uniq) do\n        if e == this.text then\n            hist_pos = i\n            break\n        end\n    end\n\n    -- 前方一致する履歴を探す\n    local matched_string = nil\n    for i = hist_pos + 1, #history_uniq do\n        if history_uniq[i]:match('^' .. search_string .. '.*') then\n            matched_string = history_uniq[i]\n            break\n        end\n    end\n\n    -- 見つかった履歴を出力\n    -- 見つからなければ、検索キーワードを出力\n    this:call(\"KILL_WHOLE_LINE\")\n    if (matched_string ~= nil) then\n        this:insert(matched_string)\n    else\n        this:insert(search_string)\n    end\n    this:call(\"BEGINNING_OF_LINE\")\n    for i = 1, this.pos - 1 do\n        this:call(\"FORWARD_CHAR\")\n    end\nend\n```\n"
  ],
  "posts": [
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSB</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSB</h1>\n      <p>WSLでUSBを使った時のメモ(バージョン 2.5.7.0)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLのバージョンが2.5.7.0でカーネルバージョンが6.6.87.1-1になってカーネルの再ビルドしなくても\n色々なUSBデバイスが使えるようになったので試してみた時のメモ。</p>\n\n<p>参考:<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb\" target=\"_blank\">USB デバイスを接続する</a></p>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"windows側の準備\">windows側の準備</h2>\n<h3 id=\"usbipd-winのインストール\">usbipd-winのインストール</h3>\n<p><a href=\"https://github.com/dorssel/usbipd-win/releases\" target=\"_blank\">usbipd-winのgithub</a>からダウンロード(使用したのは5.10)<br />\nインストールはファイルをダウンロードして実行するだけ。<br />\nWindowsTerminarが開いている場合は一旦すべて閉じる(PATHの変更を有効にするため)</p>\n\n<h2 id=\"ubuntu側の準備\">Ubuntu側の準備</h2>\n<h3 id=\"systemdの有効化\">systemdの有効化</h3>\n\n<p>systemdを有効にするため、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に以下の設定を追加。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<h3 id=\"仮想usbホストコントローラインタフェースのインストール\">仮想USBホストコントローラインタフェースのインストール</h3>\n<p>ネットワーク経由でUSBデバイスを共有することを可能にするため、仮想USBホストコントローラインタフェース(vhci-hcd)をインストール\n(ドライバの組み込み)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/modules-load.d/usb.conf</code> (ファイル名は何でも可)を以下の内容で作成し、WSLの再起動。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vhci-hcd\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nお試しで1回だけ読み込むなら以下。この場合は再起動不要(というか再起動したら消える)。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo modprobe vhci-hcd\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"usbユーティリティのインストール\">USBユーティリティのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">lsusb</code>とか使いたいので、インストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>usbutils\n</code></pre></div></div>\n\n<h3 id=\"仮想マシンの再起動\">仮想マシンの再起動</h3>\n<p>設定を有効にするため、仮想マシンを再起動する。<br />\n開いているすべての仮想マシンを閉じた後、Windwos側で <code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行し、<br />\n<code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>ですべて仮想マシンのSTATEが<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていることを確認し仮想マシンを再度実行。</p>\n\n<h4 id=\"systemdが起動していることを確認する\">systemdが起動していることを確認する</h4>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>systemctl\n</code></pre></div></div>\n<p>起動していればサービス一覧が表示される。<br />\n起動していなければ以下のようなメッセージが表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>System has not been booted with systemd as init system (PID 1). Can't operate.\nFailed to connect to bus: ホストが落ちています\n</code></pre></div></div>\n\n<h4 id=\"vhci-hcdが組み込まれていることを確認する\">vhci-hcdが組み込まれていることを確認する</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsmod\n</code></pre></div></div>\n<p>表示の中に<code class=\"language-plaintext highlighter-rouge\">vhci_hcd</code>があることを確認。<br />\nなければ組み込みの設定を確認。</p>\n\n<h1 id=\"usbカメラを使ってみる\">USBカメラを使ってみる</h1>\n<p>今回は エレコムの UCAM-DLA200HBK を使用。<br />\nかなり古いカメラなのでもう売ってないけど…<br />\nUVC仕様のカメラなら基本的に同じはず。</p>\n\n<h2 id=\"ubuntu側の準備-1\">Ubuntu側の準備</h2>\n<p>今回はカメラなので、自身にvideoグループを追加<br />\n(要 再ログイン、シャットダウンは不要)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> video\n</code></pre></div></div>\n\n<h3 id=\"guvcviewのインストール\">guvcviewのインストール</h3>\n<p>表示ツールは何でもいいけど、とりあえずguvcviewで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>guvcview \n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-1\">Windows側の準備</h2>\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行\">Ubuntu側の実行</h2>\n\n<p>USB機器が割り当てられたことを確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 002: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n</code></pre></div></div>\n\n<p>デバイスノードも確認しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> <span class=\"nt\">-la</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1\n</code></pre></div></div>\n\n<p>実際に表示してみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">LANG</code>が<code class=\"language-plaintext highlighter-rouge\">ja_JP.UTF8</code>とかのままだと文字化けしてしまうので、Cに変更して実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示されるが、何も表示されない\nコンソールには「V4L2_CORE: Could not grab image (select timeout): リソースが一時的に利用できません」と表示され続ける</p>\n\n<p>GuvcviewウィンドウのVideo Controls をクリックし、</p>\n<ul>\n  <li>Frame Rate を15/1 fps</li>\n  <li>Rsolution を 160x120</li>\n  <li>Camera Output を MJPEG<br />\nにすると表示されるけど、あまり実用的ではない…</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nこれらのパラメータが選択できるかは使用するカメラによる。<br />\nPCのスペック等によって、もうちょっと大きいサイズでも表示できることがある。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n日本語で表示するには、例えば以下のように日本語フォントをインストールして\nLANGを指定せずに実行すれば良い。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"windows側の後始末\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n<h2 id=\"ということで\">ということで</h2>\n<p>あまり実用的とは言い難い結果となってしまった。</p>\n\n<h1 id=\"usbカメラをubuntu-pcからエクスポートしてみる\">USBカメラをUbuntu PCからエクスポートしてみる</h1>\n<p>試しに、Ubuntu PCからUSBカメラをエクスポートしてWSLで表示してみる。</p>\n\n<blockquote>\n  <p>[!NOTE]\n「Netive UbuntuあるならWSL使わんでも良いやん」という気もするが…</p>\n</blockquote>\n\n<h2 id=\"navive-ubuntuの準備\">Navive Ubuntuの準備</h2>\n\n<h3 id=\"カメラを接続\">カメラを接続</h3>\n<p>USBカメラを接続し、認識されているか確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 003 Device 006: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>デバイスノードの確認。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ。<br />\nカメラが他にも接続されているので2×2表示されてるけど…<br />\n今回接続されたのは2と3のはず(今はこれを使わないので気にしない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1  /dev/video2  /dev/video3\n</code></pre></div></div>\n\n<p>必要ならguvcviewをインストールして試してみてちょ。</p>\n\n<h3 id=\"linux-toolsのインストール\">linux-toolsのインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div></div>\n<p>usbipを実行してみる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div></div>\n\n<p>※ linux-tools-≪バージョン≫-generic をインストールしろと言われたら従う。例えば</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-6.5.0-41-generic\n</code></pre></div></div>\n\n<h3 id=\"ドライバの組み込みとdaemonの起動\">ドライバの組み込みとdaemonの起動</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbip-host        <span class=\"c\"># ドライバ組み込み</span>\n<span class=\"nb\">sudo </span>usbipd <span class=\"nt\">-D</span>                  <span class=\"c\"># daemon起動</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n起動時に自動で組み込み&実行したいときはsystemdでサービス登録するとできそうだけど、<br />\n本筋じゃないのでやめとく。<br />\n<a href=\"https://github.com/furbrain/systemd-usbip/blob/master/usbipd.service\" target=\"_blank\">ここ</a>\nとか参考になるかも。</p>\n</blockquote>\n\n<h3 id=\"接続されているデバイスを表示\">接続されているデバイスを表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip list <span class=\"nt\">--local</span>         <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<p>こんな感じで表示される</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\n - busid 3-11 (056e:700a)\n   Elecom Co., Ltd : unknown product (056e:700a)\n・・・\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n表示される製品名等が不明確な場合は<code class=\"language-plaintext highlighter-rouge\">lsusb</code>の結果と突き合わせてみると良い。<br />\n(IDはどちらも表示されているので、これを頼りに)</p>\n</blockquote>\n\n<h3 id=\"バインド\">バインド</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip <span class=\"nb\">bind</span> <span class=\"nt\">--busid</span> 3-11    <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<h2 id=\"wsl-ubuntuでの操作\">WSL Ubuntuでの操作</h2>\n\n<h3 id=\"linux-toolsのインストール-1\">linux-toolsのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">usbip</code>はWindows側でインストールしたusbipd-winに含まれているのでインストール不要。<br />\n別途aptでインストールしても使えるけど結構メンドクサイ。<br />\n使いたくなることもあるかもしれんので、手順は残しておく。</p>\n\n<blockquote>\n  <p>[!NOTE]</p>\n\n  <p>usbipが入っているパッケージをインストール</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div>  </div>\n  <p>usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>たぶんこんなメッセージが出る</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>WARNING: usbip not found for kernel 6.6.87.1-microsoft\n\n  You may need to install the following packages for this specific kernel:\n    linux-tools-6.6.87.1-microsoft-standard-WSL2\n    linux-cloud-tools-6.6.87.1-microsoft-standard-WSL2\n\n  You may also want to install one of the following packages to keep up to date:\n    linux-tools-standard-WSL2\n    linux-cloud-tools-standard-WSL2\n</code></pre></div>  </div>\n  <p>しかし、指定されたパッケージをインストールしようとしても「そんなもんはない」と怒られる。<br />\nしかたないのでゴマカシ。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /usr/lib/linux-tools\n\n<span class=\"nb\">ls</span> <span class=\"nt\">-la</span>\n合計 12\ndrwxr-xr-x  3 root root 4096  6月  6 13:11 <span class=\"nb\">.</span>\ndrwxr-xr-x 65 root root 4096  6月  6 13:11 ..\ndrwxr-xr-x  2 root root 4096  6月  6 13:11 6.8.0-60-generic    ← これを覚えておく\n</code></pre></div>  </div>\n  <p>isbipを実行した時のメッセージとlsしたときのディレクトリ名から以下のようなシンボリックリンクを作成する<br />\n(カーネルバージョンが変わると変更しないといけないので注意)</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ln</span> <span class=\"nt\">-s</span> 6.8.0-60-generic 6.6.87.1-microsoft-standard-WSL2\n</code></pre></div>  </div>\n\n  <p>再度usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>USAGEが表示されたらOK。<br />\nまたWARNINGが表示されたらシンボリックリンクの名前が間違っていると思うので、再確認。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nusbipコマンドへのpathを設定してもsudoで実行するときは無効なので、設定せずfullpathで指定する</p>\n</blockquote>\n\n<h3 id=\"アタッチ可能なバス番号を調べる\">アタッチ可能なバス番号を調べる</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip list <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫\n</code></pre></div></div>\n<p>こんな感じで表示される(BUSIDは例。以下同じ)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Exportable USB devices\n======================\n - ≪UbuntuPCのIPアドレス≫\n       3-11: Elecom Co., Ltd : unknown product (056e:700a)\n           : /sys/devices/pci0000:00/0000:00:14.0/usb3/3-11\n           : Miscellaneous Device / ? / Interface Association (ef/02/01)\n</code></pre></div></div>\n<h3 id=\"アタッチする\">アタッチする</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip attach <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫ <span class=\"nt\">--busid</span> 3-11\n</code></pre></div></div>\n\n<h3 id=\"確認\">確認</h3>\n<p>アタッチできたか確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 001 Device 003: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>前と同様にguvcviewを実行してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示され、画像が表示される。<br />\nそれなりに大きなサイズに切り替えても表示できている。</p>\n\n<h3 id=\"後片付け\">後片付け</h3>\n<p>usbipのポートの確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip port\n</code></pre></div></div>\n<p>こんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Imported USB devices\n====================\nPort 00: <Port in Use> at High Speed(480Mbps)\n       Elecom Co., Ltd : unknown product (056e:700a)\n       1-1 -> unknown host, remote port and remote busid\n           -> remote bus/dev 003/006\n</code></pre></div></div>\n<p>ポートは0であることが分かる。</p>\n\n<p>デタッチする</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo /mnt/c/Program\\ Files/usbipd-win/WSL/usbip detach --port 0\n</code></pre></div></div>\n\n<h3 id=\"まとめ\">まとめ</h3>\n<p>ということで、どうも、USBIPD-WINの転送速度が遅いようだ。</p>\n\n<h1 id=\"bluetoothを使ってみる\">Bluetoothを使ってみる</h1>\n<p>カメラはビミョーな結果だったので、今度はBluetoothで試してみる。\n使用したのは Buffalo BSBT4D09BK(4.0+EDR/LEのアダプタ、中身はCSR製)。<br />\nこれも結構古いのでもう売ってない。  中身がCSRのアダプタなら動く可能性高い。<br />\nRealtekのも使えそうだけど、試してないのでなんとも…</p>\n\n<h2 id=\"ubuntu側の準備-2\">Ubuntu側の準備</h2>\n<p>今回はBluetoothなのでBluetooth関連のライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>bluez\n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-2\">Windows側の準備</h2>\n<p>USBipd-win</p>\n\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行-1\">Ubuntu側の実行</h2>\n\n<h3 id=\"usb機器が割り当てられたことを確認する\">USB機器が割り当てられたことを確認する。</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 003: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)\n</code></pre></div></div>\n\n<h3 id=\"動かしてみる\">動かしてみる</h3>\n<p>ローカルデバイスの一覧表示をしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>hcitool dev\n</code></pre></div></div>\n<p>例えばこんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Devices:\n        hci0    XX:XX:XX:XX:XX:XX\n</code></pre></div></div>\n\n<p>スキャンしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bluetoothctl\n</code></pre></div></div>\n<p>bluetoothctlが起動され、プロンプトが<code class=\"language-plaintext highlighter-rouge\">[bluetooth]#</code>になる。<br />\nスキャンしてデバイス一覧を見てみる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>scan on\n≪スキャンされたデバイスが表示される≫\n≪しばらく待つ≫\nscan off\n≪表示が止まる≫\n\nlist\n≪スキャンされたデバイスが表示される≫\n\nexit\n≪終了してshellに戻る≫\n</code></pre></div></div>\n\n<h3 id=\"pythonで動かしてみる\">pythonで動かしてみる。</h3>\n<p>pyenvでpythonをインストールする場合は\n<a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a>\n の注意書きにあるように、コンパイル前に以下を実行しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<p>新しくプログラム作るのは面倒なので以前作った <br />\n<a href=\"/memoBlog/2025/04/21/Buildozer_3.html\" target=\"_blank\">AndroidでpythonでBLE</a> <br />\nを実行してみる。</p>\n\n<p>必要なモジュール類をインストールして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libmtdev-dev\npip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<p>実行</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">python</span> <span class=\"n\">kivy_ble</span><span class=\"p\">.</span><span class=\"n\">py</span>\n</code></pre></div></div>\n\n<p>動いた。メデタシメデタシ。</p>\n\n<h2 id=\"windows側の後始末-1\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n<p>USB接続のSDカードリーダを使えばRaspberryPiのブート用SDカードをWSLにマウントして操作することも可能なはず。<br />\nメンドクサくなってきたので試すのはやめておくけど。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyでドラッグで並べ替えできるリスト</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyでドラッグで並べ替えできるリスト</h1>\n      <p>kivyでドラッグで並べ替えできるリストを作った時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nドラッグで並べ替えできるリスト(AndroidでよくあるUI、<code class=\"language-plaintext highlighter-rouge\">RecycleView</code>と<code class=\"language-plaintext highlighter-rouge\">ItemTouchHelper</code>で作るんだったかな?)\nを作ってみた時のメモ。<br />\n<a href=\"https://maausa.marurm.com/wp-content/uploads/RecyclerView.gif\" target=\"_blank\">ちょっと違うけど、大体こんな感じ</a></p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nreorderablelist.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=reorderablelist.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>ソースは、表示する項目を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>と\nリスト全体を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>で構成される。<br />\n(あと、単体実行で動作するテストプログラム)<br />\n動作としては、</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>に<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を追加していきリスト化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code> をドラッグすることで並べ替え</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を左右にスワイプすることでハンドラ実行(デフォルトでは右スワイプで項目削除)\nといった感じ。</li>\n</ul>\n\n<p>テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>を<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>で囲んでスクロール可能にしています。\nスクロール不要ならそのまま配置しても可(テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">with_scroll</code>を<code class=\"language-plaintext highlighter-rouge\">False</code>に設定)。</p>\n\n<h2 id=\"reorderablelist\">ReorderableList</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>はリスト全体を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承したクラス。</p>\n\n<h3 id=\"追加したプロパティ\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>item_bg</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>item_fg</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>list_bg</td>\n      <td>リストの背景色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\n(<code class=\"language-plaintext highlighter-rouge\">orientation</code>は<code class=\"language-plaintext highlighter-rouge\">\"vertical\"</code>固定(項目を縦方向に並べるため)、\n<code class=\"language-plaintext highlighter-rouge\">size_hint_y</code>は<code class=\"language-plaintext highlighter-rouge\">None</code>固定(ScrollViewに包むため))\nのほか、<br />\n背景色の設定と、スクロール可能にするためminimum_height変更時の処理のbindを行っている。</p>\n\n<h3 id=\"項目追加処理\">項目追加処理</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">add_item</code>が項目追加処理。<br />\nパラメータは<code class=\"language-plaintext highlighter-rouge\">cls</code>で項目表示に使用するクラス(デフォルトは<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>)と、項目表示クラスの初期化パラメータを受け取る。<br />\nこれは項目に表示する内容を柔軟に切り替えられるよう、項目表示クラスを<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を継承したクラスに切り替えられるようにするため。</p>\n\n<h3 id=\"レイアウト処理\">レイアウト処理</h3>\n<p>kivyでは、レイアウトの変更命令と実際に変更が行われるまでにディレイがある。<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">add_widget(wid)</code> して直後にwid.posを読み出すと実際に追加されたあとの位置が読み出せない。<br />\nこれは、<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>では処理の予約だけ行い、実際に描画が行われるのは別のところ(<code class=\"language-plaintext highlighter-rouge\">mainloop</code>?)で\n他のウィジェットのレイアウト結果を五月雨式に反映していくため、\n描画結果がposに反映されるまでタイムラグが発生するためと思われる。</p>\n\n<p>そこで、<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>のレイアウトが変更され、処理が終了したタイミングで子ウィジェットに\nレイアウト完了を通知できるよう<code class=\"language-plaintext highlighter-rouge\">do_layout()</code>をオーバライドし、基底クラスの処理が完了した後\n各子ウィジェットの<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>をコールしている。</p>\n\n<h2 id=\"reorderableitem\">ReorderableItem</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>はリストに表示する項目を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスと<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承している。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスはドラッグ処理を実現するクラス。<br />\nもう一つの基底クラスを<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>とすることで、派生クラスのレイアウトを柔軟に設定できるようにしている。</p>\n\n<h3 id=\"追加したプロパティ-1\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>text</td>\n      <td>項目に表示する文字列</td>\n    </tr>\n    <tr>\n      <td>bg_color</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>fg_color</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ-1\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\nのほか、<br />\n項目内部の構築(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)、\n背景色の設定と、pos/size変更時にドラッグ範囲を変更する処理のbind、\nインスタンス変数の設定を行っている</p>\n\n<h3 id=\"内部ウィジェットの追加処理add_inner_widget\">内部ウィジェットの追加処理(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)</h3>\n<p>項目の内部の表示を構築する処理。<br />\nデフォルトではLabelを1個追加している。<br />\n項目の表示内容を変更したい場合は、派生クラスでこの処理をオーバライドし、\n必要な内容を追加していく。</p>\n\n<h3 id=\"ドラッグ開始処理on_touch_down\">ドラッグ開始処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_down()</code>)</h3>\n<p>まず、基底クラスのドラッグ開始処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ対象としての処理(インスタンス変数の設定)を行い、<br />\n自身の描画Canvasを親ウィジェット(<code class=\"language-plaintext highlighter-rouge\">self.parent</code>)のcanvasからcanvas.afterに繋ぎかえる。\nこれはドラッグ中の表示が前面に表示されるようにするためである。</p>\n\n<blockquote>\n  <p>[!NOTE]\n通常、add_widget()すると追加されたウィジェットの描画Canvasは親ウィジェットのCanvasに繋がれる。<br />\nこの親ウィジェットのCanvasに繋がれた描画ウィジェットは後から繋がれたものが前面に表示される。<br />\n(縦方向のBoxLayoutの場合下に表示されているウィジェットが前に表示される)<br />\n重ならない表示であれば問題ないが、ドラッグを行うとドラッグ中のウィジェットが背面に表示されることがある。<br />\nそこで、ドラッグ中のウィジェット他のウィジェットより前面に表示するため、CanvasからCanvas.afterに繋ぎかえ、前面に表示されるようにする。<br />\n仕様を読む限り、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index, canvas='after')</code>でadd_widget時にcanvas.afterに接続できるようなのだが、\n実際にはバグ(仕様制限?)により、indexが0のときのみcanvasパラメータが有効になるらしい。<br />\nこれを回避するため、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index)</code>で通常通りウィジェットを追加した後、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">after</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>として描画Canvasを繋ぎかえている。\ncanvas.afterに繋いだ描画Canvasをcanvasに戻す場合は、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">cur_index</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">children</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>    <span class=\"c1\"># canvas.after から canvasへ繋ぎかえるため\n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">remove_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>                 <span class=\"c1\"># 一旦削除して(canvasかcanvas.afterは自動的に判別してくれる) \n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"o\">=</span><span class=\"n\">cur_index</span><span class=\"p\">)</span>   <span class=\"c1\"># 再度同じ場所に挿入\n</span></code></pre></div>  </div>\n  <p>と実行する。  <code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>は描画Canvasがどこに繋がっていても探して削除してくれるので、\nそのまま実行して問題ない。</p>\n</blockquote>\n\n<h3 id=\"ドラッグ中処理on_touch_move\">ドラッグ中処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_move()</code>)</h3>\n<p>まず、基底クラスのドラッグ中処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ中の処理を行う。<br />\n親ウィジェットに繋がっている子ウィジェットをサーチして、自分以外で自分の中心がウィジェットの表示範囲内に入っているウィジェットを探す\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>)<br />\n自分の上端が対象ウィジェットの上端を超えたか、自分の下端が対象ウィジェットの下端を超えた場合は自分と対象ウィジェットを入れ替える。<br />\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>だけで判断すると、自分より高さが高いウィジェットと入れ替えるときに不都合が起こる)<br />\n位置を交換するには、自分を一旦削除(<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>)して、対象ウィジェットの位置(<code class=\"language-plaintext highlighter-rouge\">i</code>)に繋ぐ(<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>)。<br />\nその後、ドラッグを継続するので、ドラッグ開始時と同様に描画Canvasをcanvas.afterに繋ぎかえる。</p>\n\n<h3 id=\"ドラッグ終了処理on_touch_up\">ドラッグ終了処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_up()</code>)</h3>\n\n<p>まず、基底クラスのドラッグ終了処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ終了の処理を行う。<br />\nドラッグ開始/ドラッグ中処理でcanvas.afterに繋ぎかえた描画Canvasをcanvasに戻すために一旦<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>してから\n<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>する(これによりドラッグにより表示が移動していた対象ウィジェットが通常位置に戻る)。<br />\nその後、対象ウィジェットの表示位置がドラッグ開始時と変わっていなく、ドラッグした距離が設定値を超えている場合は\nスワイプ処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>または<code class=\"language-plaintext highlighter-rouge\">do_swipe_left()</code>)を実行する。</p>\n\n<h3 id=\"右へswipeしたときの処理do_swipe_right\">右へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、対象ウィジェットを削除する。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"左へswipeしたときの処理do_swipe_right\">左へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、デバッグ用にログ出力のみ。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"親ウィジェットのレイアウト完了時処理done_parent_layout\">親ウィジェットのレイアウト完了時処理(<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>)</h3>\n<p>親ウィジェットのレイアウト完了時に子ウィジェットすべてのこのメソッドがコールされる。<br />\nドラッグ中であれば必要な処理(現在位置の記憶とドラッグ中位置への移動)を行う。</p>\n\n<h1 id=\"サンプルプルグラム\">サンプルプルグラム</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nサンプルプルグラム</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=test1.py\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyで画面遷移</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyで画面遷移</h1>\n      <p>kivyで画面遷移する方法について</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\n実行時に画面を切り替えて使用する方法について試した時のメモ。<br />\nついでにAndroidアプリ化もしてみた。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\n(multi_screenって名前はなんか違う気もするけど、複数画面を制御するってことでヨシとしとこう)</p>\n\n<h2 id=\"メイン処理スクリーンマネージャのソース\">メイン処理/スクリーンマネージャのソース</h2>\n<p>multi_screen.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=multi_screen.py\"></script>\n</dev>\n\n<h2 id=\"第1画面のソース\">第1画面のソース</h2>\n<p>screen1.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen1.py\"></script>\n</dev>\n\n<h2 id=\"第2画面のソース\">第2画面のソース</h2>\n<p>screen2.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen2.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyで画面を切り替えて使用するには、<code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承したクラスを使用し、ここに各画面を登録し、\n<code class=\"language-plaintext highlighter-rouge\">self.current</code>に表示する画面の名前(<code class=\"language-plaintext highlighter-rouge\">name</code>)を設定することで切り替えるらしい。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>今回は日本語を使ってみようと思うので、日本語フォントをインストール。<br />\n有名どころではNotoSansCJKとかTAKAOとか。<br />\nubuntuだと以下でインストールできる。<br />\nNotoSansCJK は Androidでもインストールされていることが多いのかな?(手元のちょっと古いAndroidには入ってた)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n<span class=\"c\"># または</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n<p>あと、テキスト入力も試してみるので、クリップボード操作のためのライブラリをインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>xclip\n</code></pre></div></div>\n\n<h2 id=\"multi_screenpy\">multi_screen.py</h2>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">multi_screen.py</code>の内容について。</p>\n\n<p>今回は日本語を使ってみるので、フォントディレクトリの登録と日本語対応フォントをデフォルトフォントに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">get_system_fonts_dir</span><span class=\"p\">()</span>                                        <span class=\"c1\"># フォントディレクトリにシステムフォントディレクトリを登録\n</span><span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'NotoSansCJK-Regular.ttc'</span><span class=\"p\">)</span>  <span class=\"c1\"># デフォルトフォントを設定\n</span></code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承した<code class=\"language-plaintext highlighter-rouge\">ControlScreenManager</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ControlScreenManager</span><span class=\"p\">(</span><span class=\"n\">ScreenManager</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">ControlScreenManager</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># 画面間で共有する変数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n</code></pre></div></div>\n<p>ネットで検索すると画面間で共有する変数を画面間で直接やりとりする例があったが、\nソースの再利用性などを考えてスクリーンマネージャで管理することにした。<br />\nそのための設定/取得メソッド</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ターゲット文字列の設定\n</span>    <span class=\"k\">def</span> <span class=\"nf\">set_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"n\">text</span>\n    \n    <span class=\"c1\"># ターゲット文字列の取得\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span>\n</code></pre></div></div>\n\n<p>画面切り替え処理<br />\nこれも画面から他の画面に直接遷移している例があるけど、\n一旦スクリーンマネージャでうけとってから\n遷移した方が分かりやすいと思う。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># screen1への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">SlideTransition</span><span class=\"p\">(</span><span class=\"n\">direction</span><span class=\"o\">=</span><span class=\"s\">'left'</span><span class=\"p\">,</span> <span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen1'</span>\n        \n    <span class=\"c1\"># screen2への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen2</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">FadeTransition</span><span class=\"p\">(</span><span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen2'</span>\n</code></pre></div></div>\n\n<p>アプリケーションクラス</p>\n\n<p>アプリケーションクラスのbuildメソッドでは上で定義したスクリーンマネージャのインスタンスに\n各画面のインスタンスを登録し、そのインスタンスをリターンする。</p>\n\n<p>KV言語で書く方法もあるけど、画面切り替えのときに使用する名前をここで定義できるので\nソースの見通しが良くなって好み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ScreenManager1</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># スクリーンマネージャの生成\n</span>        <span class=\"n\">sm</span> <span class=\"o\">=</span> <span class=\"n\">ControlScreenManager</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 画面1を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen1</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen1'</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 画面2を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen2</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen2'</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">sm</span>\n</code></pre></div></div>\n\n<h2 id=\"screen1py\">screen1.py</h2>\n\n<p>レイアウトの定義</p>\n\n<p>kvファイルにレイアウトを書く例が多いけど、こう書くとレイアウトと処理をまとめて書けるので好み。</p>\n\n<blockquote>\n  <p>[!NOTE]\n最近知ったけど、色指定は(rr, gg, bb, aa)(各値は0~1)と書かれている例が多いけど、\n色名(“black”とか”red”とか。指定できる色名は kivyインストールディレクトリの<code class=\"language-plaintext highlighter-rouge\">util.py</code>で定義されている<code class=\"language-plaintext highlighter-rouge\">hex_colormap</code>を参照)\nの他、”#RRGGBBAA”でも指定可能(AAは省略可能)。\nどちらも文字列指定なのでダブルクォーテーションまたはシングルクォーテーションで囲む必要あり。</p>\n\n  <p>また、サイズ類は<code class=\"language-plaintext highlighter-rouge\">dp(36)</code>みたいな書き方もできるけど、文字列で<code class=\"language-plaintext highlighter-rouge\">\"36dp\"</code>と書くこともできる。\nサイズ類は数値で指定すると単位は<code class=\"language-plaintext highlighter-rouge\">px</code>になる。</p>\n</blockquote>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen1>:\n    ・・・・\n            bg_color_normal : \"#585858ff\"       # \"coloe_name\" or \"#RRGGBB\" or \"#RRGGBAA\" or (rr, gg, bb, aa) で指定\n    ・・・・\n            item_height          : '36dp'   # 数値で指定したときの単位はpx\n    ・・・・\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nAndroidアプリ化する場合、テキスト入力が下の方にあるとソフトキーボードが出てきたときに見えなくなるので\n上の方に配置しておく方が無難。<br />\nなんかうまくやる方法があるのかもしれんけど、現状分かってない。</p>\n</blockquote>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>class Screen1(Screen):\n</code></pre></div></div>\n\n<p>あとは<code class=\"language-plaintext highlighter-rouge\">Screen1</code>クラス内で動作を定義していけば良い。<br />\n画面切り替え処理はkv言語で直接スクリーンマネージャの処理をコールすると訳わかめになるので\n一旦このクラス内で受け取ってスクリーンマネージャの処理をコールするようにしている。<br />\nこの辺は好みの問題なので、お好きにどうぞ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'switch_to_screen1'</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">switch_to_screen1</span><span class=\"p\">()</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nスクリーンマネージャはScreen派生クラスの<code class=\"language-plaintext highlighter-rouge\">self.manager</code>で取得できる。</p>\n</blockquote>\n\n<h2 id=\"screen2py\">screen2.py</h2>\n\n<p>こちらも同様にレイアウトを定義しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen2>:\n    ・・・・\n</span></code></pre></div></div>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">Screen2</span><span class=\"p\">(</span><span class=\"n\">Screen</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>画面が切り替わる前にScreen1で設定した文字列を取得したいので、<code class=\"language-plaintext highlighter-rouge\">on_pre_enter()</code>をオーバーライドする。<br />\n文字列をScreen1から直接取ると画面構成変えた時に困るので、スクリーンマネージャ経由で取得するようにしている。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">on_pre_enter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"c1\"># 表示用ラベルを書き換え\n</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">get_target_string</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"NONE\"</span>       <span class=\"c1\"># 空文字が来たらNONEに書き換え\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">text</span><span class=\"si\">}</span><span class=\"s\"> が選択されました'</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">python multi_screen.py</code>で実行。<br />\n一番上のドロップダウンリストで項目を選択し、2番目の「Go to Screen 2」ボタンを押すとScreen2に切り替わる。<br />\nScreen2では画面下側の領域にScreen1のドロップダウンリストで選択した文字列が表示される。\n「Go to Screen 1」ボタンでScreen1に戻る。<br />\nScreen1のテキスト入力欄に文字列を入力し、「ADD」ボタンをクリックするとドロップダウンリストに入力した文字列が追加される。<br />\nもちろん、その文字列を選択してScreen2に切り替えればその文字列が表示される。</p>\n\n<blockquote>\n  <p>[!NOTE]\nLunuxでは日本語入力できないみたい。ただしコピペは可能なので他のところで入力してコピペすればOK。<br />\nAndroidではそのまま日本語も入力できる。</p>\n</blockquote>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>の手順でAndroidアプリ化もできる。<br />\nここの準備が終わっていれば以下のコマンドでOK。</p>\n\n<h2 id=\"multi_screenpyをリネーム\">multi_screen.pyをリネーム</h2>\n<p>python for androidはエントリーポイントがmain.pyに固定らしいので、リネーム</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mv </span>multi_screen.py main.py\n</code></pre></div></div>\n\n<h2 id=\"buildozerspec-の生成\">buildozer.spec の生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>今回は特に編集の必要なし。\n<code class=\"language-plaintext highlighter-rouge\">title</code>、<code class=\"language-plaintext highlighter-rouge\">package.name</code>、<code class=\"language-plaintext highlighter-rouge\">package.domain</code>なんかは必要なら変更してちょ。</p>\n\n<h2 id=\"build実行\">build実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動する)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪SDK Platform-Tools <span class=\"k\">for </span>Windowsを展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>で、実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、Android上で動作した。メデタシメデタシ。<br />\n文字入力もちゃんと動いてるし、改造したボタンやスピナーも動いてる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのSpinnerをカスタマイズ</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのSpinnerをカスタマイズ</h1>\n      <p>kivyのSpinner(ドロップダウンリスト)をカスタマイズする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nSpinner(ドロップダウンリスト)の項目の表示がすべて同じ色で現在選択されている項目がどれか一目で分からなかったので\n選択されている項目の色が変わるようにカスタマイズしてみた。</p>\n\n<p><a href=\"/memoBlog/2025/04/26/kivy_2.html\">kivyのButtonの色を変更する</a>ではButtonをカスタマイズして\n簡単に背景色を変更できるようにしたので、それを使えばわりとお手軽にできそうな感じ。</p>\n\n<h1 id=\"カスタマイズ内容\">カスタマイズ内容</h1>\n<ul>\n  <li>ドロップダウンの項目の表示色を選択中のものとそれ以外のもので分ける</li>\n  <li>それらの色(背景/文字)はプロパティで指定する</li>\n  <li>ドロップダウンの項目の表示高さをプロパティで指定する</li>\n</ul>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7.js\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyではドロップダウンリスト(クリックすると選択項目がぺろっと出てくるやつ)を表示するのにSpinnerウィジェットを使う。<br />\nで、クリックすると設定された項目が表示されるのだけれど、すべて同じ色(通常時、クリックした時、無効化した時の色はそれぞれ画像で指定できる)\nで表示され、現在どれを選択しているのかが分かり難い。<br />\nそこで、現在選択されている項目の色(画像でなく)を変更できるようにカスタマイズする。</p>\n\n<p>色指定に関して、<code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと項目を表示するための<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスはどちらも<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスを継承しているので、\n<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを同時に継承することで<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスに関連する処理を置き換えられる。</p>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスを作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスは特に追加する処理などはない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinnerOption</span><span class=\"p\">(</span><span class=\"n\">SpinnerOption</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n    <span class=\"k\">pass</span>\n</code></pre></div></div>\n\n<p>次に <code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinner</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinner</span><span class=\"p\">(</span><span class=\"n\">Spinner</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>追加するプロパティ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">item_selected_bg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の背景色\n</span>    <span class=\"n\">item_selected_fg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_unselected_bg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 非選択項目の背景色\n</span>    <span class=\"n\">item_unselected_fg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_height</span>          <span class=\"o\">=</span> <span class=\"n\">NumericProperty</span><span class=\"p\">(</span><span class=\"s\">'48dp'</span><span class=\"p\">)</span>               <span class=\"c1\"># 項目の高さ(デフォルトは48dp)\n</span></code></pre></div></div>\n\n<p>コンストラクタでは<code class=\"language-plaintext highlighter-rouge\">option_cls</code>のデフォルト値を<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>に設定し、基底クラスのコンストラクタを実行。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"s\">'option_cls'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">kwargs</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 項目表示用クラスが指定されていなければCustomSpinnerOptionを指定\n</span>            <span class=\"n\">kwargs</span><span class=\"p\">[</span><span class=\"s\">'option_cls'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">CustomSpinnerOption</span>\n        \n        <span class=\"c1\"># 基底クラスの初期化\n</span>        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">CustomSpinner</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>その後、追加した各プロパティと<code class=\"language-plaintext highlighter-rouge\">text</code>プロパティの変更時の処理をバインドする。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span>\n                    <span class=\"n\">text</span>                <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_bg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_bg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_fg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_fg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_height</span>         <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 項目高さ\n</span>                <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの項目の色などを変更する処理を追加。<br />\nこの処理が各プロパティの変更時の処理としてバインドされる。</p>\n\n<p>項目の一覧は<code class=\"language-plaintext highlighter-rouge\">self._dropdown.container.children</code>か<code class=\"language-plaintext highlighter-rouge\">self._dropdown.children</code>にあるので判断して取得。</p>\n\n<p>選択されている項目か否かは各項目の<code class=\"language-plaintext highlighter-rouge\">text</code>と<code class=\"language-plaintext highlighter-rouge\">self.text</code>が一致しているかどうかで判断できるので、\nこの条件で設定する色を変更。<br />\nまた、項目すべてをループするので、ついでに項目高さ(<code class=\"language-plaintext highlighter-rouge\">height</code>)も変更しておく。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ドロップダウン内の項目の高さ/背景色/文字色を更新\n</span>    <span class=\"k\">def</span> <span class=\"nf\">update_dropdown_background</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">text</span>\n        <span class=\"c1\"># 項目のリストを取得\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        \n        <span class=\"c1\"># 各項目の背景色/文字色を変更\n</span>        <span class=\"k\">for</span> <span class=\"n\">item</span> <span class=\"ow\">in</span> <span class=\"n\">items</span><span class=\"p\">:</span>\n            <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_height</span>                      <span class=\"c1\"># 項目高さ\n</span>            <span class=\"k\">if</span> <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">==</span> <span class=\"n\">text</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_bg</span>    <span class=\"c1\"># 選択中の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_fg</span>    <span class=\"c1\"># 選択中の文字色\n</span>            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_bg</span>  <span class=\"c1\"># 非選択の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_fg</span>  <span class=\"c1\"># 非選択中の文字色\n</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの更新処理をオーバーライド。<br />\nこの処理はドロップダウンの新規作成時や項目追加時にコールされる。<br />\nここに上のドロップダウンの項目の色などを変更する処理のコールを追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">_update_dropdown</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">_update_dropdown</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 項目の背景色等を更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>ついでに項目の追加処理を追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># 項目の追加\n</span>    <span class=\"k\">def</span> <span class=\"nf\">add_item</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">values</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>以上でカスタマイズは終了。</p>\n\n<h1 id=\"動作確認プログラム\">動作確認プログラム</h1>\n<p>このファイルを単体で実行すれば動作確認プログラムが動作する。<br />\n動作確認ではAddボタンをクリックする度にドロップダウンリストの項目が追加されるようになっている。<br />\nSpinnerのボタンをクリックするとドロップダウンリストが表示され、現在選択されている項目が他の色で表示されている。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのButtonの色を変更する</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのButtonの色を変更する</h1>\n      <p>kivyのButtonの色を変更する方法あれこれ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nボタン<code class=\"language-plaintext highlighter-rouge\">Button</code>の色を変更しようとすると、なかなか大変なので色々試してみたメモ。</p>\n\n<h1 id=\"画像ファイルを使用して変更する\">画像ファイルを使用して変更する</h1>\n\n<p>これが通常の方法。<br />\nプロパティ<code class=\"language-plaintext highlighter-rouge\">background_normal</code>、<code class=\"language-plaintext highlighter-rouge\">background_down</code>、<code class=\"language-plaintext highlighter-rouge\">background_disabled_normal</code>、<code class=\"language-plaintext highlighter-rouge\">background_disabled_down</code>に\nそれぞれに表示する画像ファイルを指定する。<br />\n単色で表示するなら1✕1pixelの画像ファイルでかまわない。</p>\n\n<h2 id=\"ソース\">ソース</h2>\n<p>ソースはこんな感じ。<br />\n別途画像ファイル<code class=\"language-plaintext highlighter-rouge\">lightgray.png'</code>、<code class=\"language-plaintext highlighter-rouge\">red.png</code>、<code class=\"language-plaintext highlighter-rouge\">gray.png</code>をカレントディレクトリに用意しておく。</p>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。</p>\n<dev class=\"accordion_head_close\"></dev>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.app</span> <span class=\"kn\">import</span> <span class=\"n\">App</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.button</span> <span class=\"kn\">import</span> <span class=\"n\">Button</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.lang</span> <span class=\"kn\">import</span> <span class=\"n\">Builder</span>\n\n    <span class=\"c1\"># GUIlレイアウト\n</span>    <span class=\"n\">Layout</span> <span class=\"o\">=</span> <span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">'''\n# この中はインデントに意味があるので余計なインデントを入れてはいけない\nBoxLayout:\n    orientation:'horizontal'\n    \n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n    Button:\n        id              : button_test\n        text            : \"TEST\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_test()\n        background_normal: 'lightgray.png'\n        background_down: 'red.png'\n        background_disabled_normal: 'gray.png'\n        background_disabled_down: 'gray.png'\n\n    Button:\n        id              : button_ctrl\n        text            : \"Ena/Dis\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_ctrl()\n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n'''</span>\n    <span class=\"p\">)</span>\n\n    <span class=\"k\">class</span> <span class=\"nc\">MyApp</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n        <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n            <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">__init__</span><span class=\"p\">()</span>\n            \n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span> <span class=\"o\">=</span> <span class=\"n\">Layout</span><span class=\"p\">.</span><span class=\"n\">ids</span><span class=\"p\">.</span><span class=\"n\">button_test</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_ctrl</span> <span class=\"o\">=</span> <span class=\"n\">Layout</span><span class=\"p\">.</span><span class=\"n\">ids</span><span class=\"p\">.</span><span class=\"n\">button_ctrl</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"n\">Layout</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">on_test</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'pressed'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">on_ctrl</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span><span class=\"p\">.</span><span class=\"n\">disabled</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span><span class=\"p\">.</span><span class=\"n\">disabled</span>\n            \n    <span class=\"n\">MyApp</span><span class=\"p\">().</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"動作\">動作</h2>\n\n<p>実行すると、Buttonが2つ表示され、TESTボタンが指定されたファイルのイメージで表示される。<br />\nEna/DisボタンをクリックするとTESTボタンのDisable/Enableが切り替えらる。</p>\n\n<h1 id=\"base64エンコードデータで指定\">Base64エンコードデータで指定</h1>\n\n<p>画像ファイルを使用すると、使用する色の分だけ画像ファイルを用意し、処理を流用する度に\n忘れずにすべてのファイルをコピーしないといけない。<br />\nそこで、画像ファイルをbase64エンコードした文字列をpyファイル(またはkvファイル)に保存する方法を試してみる。</p>\n\n<p>まず、上で用意したpngファイルを以下のコマンドでbase64エンコード(前に特定の文字列を付加)する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"data:image/png;base64,</span><span class=\"sb\">`</span><span class=\"nb\">base64</span> <span class=\"nt\">-w</span> 0 ≪pngファイル≫<span class=\"sb\">`</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n<p>付加されている<code class=\"language-plaintext highlighter-rouge\">data:image/png;base64,</code>は続くデータがpngイメージであることを示している。</p>\n\n<p>出力された文字列を以下のようにファイル名の代わりに記載する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        background_normal           : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2M4fPjwfwAH3wNJzT7giwAAAABJRU5ErkJggg=='\n        background_down             : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAANSURBVBhXY3gro/IfAAVUAi3GPZKdAAAAAElFTkSuQmCC'\n        background_disabled_normal  : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2Oor6//DwAFewJ9z0FqqgAAAABJRU5ErkJggg=='\n        background_disabled_down    : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2Oor6//DwAFewJ9z0FqqgAAAABJRU5ErkJggg=='\n</code></pre></div></div>\n\n<p>これにより、pngファイルを削除しても動作するようになる。</p>\n\n<p>ただし、pyファイル(またはkvファイル)が大きくなってしまうことと、一目で指定されている色が把握できないというデメリットがある。</p>\n\n<h1 id=\"canvasbefor-で指定する\">canvas.befor で指定する</h1>\n\n<p>画像ファイルを用意すること自体面倒なので、RGBA値で指定する方法はないかと考えてみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">Label</code>と同様に<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>で背景色を指定してみることを試してみたが、うまくいかなかった。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    Button:\n        ・・・\n        canvas.before:\n            Color:\n                rgba    : (1,0,0,1)\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n</code></pre></div></div>\n<p>これは<code class=\"language-plaintext highlighter-rouge\">Button</code>が<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>をサポートしていないわけではなく、\nちゃんと指定通りに描画しているが、\nその前面に<code class=\"language-plaintext highlighter-rouge\">Button</code>のBackground_XXXが表示されているためらしい。</p>\n\n<p>それならば、Buttonの表示を透明にしてやれば<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>の表示が見えるはずである。<br />\n以下のように変更して試してみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">background_color : (0, 0, 0, 0)</code>が透明色にしている部分で、<br />\n<code class=\"language-plaintext highlighter-rouge\">background_XXX</code>をヌル文字列にしているのはすべてのピクセルを(255,255,255,255)にするためであるが、\n透明になるのであまり関係ないかもしれない。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    Button:\n        ・・・\n        background_normal           : ''\n        background_down             : ''\n        background_disabled_normal  : ''\n        background_disabled_down    : ''\n        background_color            : (0, 0, 0, 0) # 透明\n        canvas.before:\n            Color:\n                rgba    : (1,0,0,1)\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n</code></pre></div></div>\n<p>これでボタンが赤色になった。<br />\nしかし、これでばボタンを押下した時やDisableにした時に色が変化しない。</p>\n\n<p>そこで、さらに以下のようにして押下した時やDisableにした時に色が変わるようにしてみた。<br />\n<code class=\"language-plaintext highlighter-rouge\">canvas.before.Color.rgba</code>を <code class=\"language-plaintext highlighter-rouge\">self.disabled</code>と<code class=\"language-plaintext highlighter-rouge\">self.state</code>によって変更している。<br />\n下にGUIリソース定義部分全体を記載しておく。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 分かりやすいようにグローバル変数で定義しておく\n#:set BG_COLOR_NORMAL   (0.75, 0.75, 0.75, 1.0)\n#:set BG_COLOR_DOWN     (1.00, 0.00, 0.00, 1.0)\n#:set BG_COLOR_DISABLED (0.50, 0.50, 0.50, 1.0)\n\nBoxLayout:\n    orientation:'horizontal'\n    \n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n    Button:\n        id              : button_test\n        text            : \"TEST\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_test()\n        background_normal           : ''\n        background_down             : ''\n        background_disabled_normal  : ''\n        background_disabled_down    : ''\n        background_color            : (0, 0, 0, 0) # 透明\n        canvas.before:\n            Color:\n                rgba    : BG_COLOR_DISABLED if self.disabled else BG_COLOR_NORMAL if self.state == 'normal' else BG_COLOR_DOWN\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n    Button:\n        id              : button_ctrl\n        text            : \"Ena/Dis\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_ctrl()\n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n</code></pre></div></div>\n\n<h1 id=\"カスタムボタンウィジェットを作成する\">カスタムボタンウィジェットを作成する</h1>\n\n<p>上でとりあえず目的は達成されたが、ボタンを配置する度に上記のような設定を書くのは面倒なので、\nカスタムボタンウィジェットを作成してみる。</p>\n\n<h2 id=\"ソース-1\">ソース</h2>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/98907d88de7106b1c30a0be4b39aa77f\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/98907d88de7106b1c30a0be4b39aa77f.js\"></script>\n</dev>\n\n<h2 id=\"解説\">解説</h2>\n<p>上の「canvas.befor で指定する」の方法をkv言語を使用せずpythonで定義している。<br />\nそれぞれの色を自由に変更できるようにプロパティを用意した。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_normal</code>   通常時の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_down</code>     押下時の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_disabled</code> 無効時の色</li>\n</ul>\n\n<p>また、そのままだとボタンを並べて表示したときに境界が分からなくなるので、枠線を描画するため、以下のプロパティを用意した。<br />\nデフォルトは黒で幅1。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">border_color</code>    枠線の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">border_width</code>    枠線の幅</li>\n</ul>\n\n<p>初期化時にボタン本体の背景を透明にし、<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>に描画命令を追加して背景の描画(背景色と枠線)することと、\n状態、位置、プロパティが変化したときに描画パラメータを再設定する処理をbindしている。<br />\nbindした処理では状態や位置に合わせて<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>の処理のパラメータを変更している。</p>\n\n<p>枠線を描画するための<code class=\"language-plaintext highlighter-rouge\">Line</code>はwidth×2の幅で描画されるようなので、本来の矩形のwidthの半分だけ内側に描画されるようにしている。</p>\n\n<p>GUIレイアウトを定義するときは、通常のButtonと同様のプロパティ設定で配置できる。<br />\nもちろん、上の通常時の色、押下時の色、無効時の色を変更したい場合は追加で指定すれば良い。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>AndroidでpythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>AndroidでpythonでBLE</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerでBLE通信アプリを作ってみたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2025/04/04/Buildozer_2.html\">Buildozerでブロック崩しを作る</a>ではゲームを作ってみたが、次はペリフェラルを使ってみたくなるのが人情というもの。<br />\n<a href=\"https://bleak.readthedocs.io/en/latest/\" target=\"_blank\">Bleak</a>というモジュールがクロスプラットフォームでAndroidでも使えるらしい。<br />\nということで、Bleakを使ってBLEを使用するアプリを作って、それをBuildozerでAndroidアプリ化してみる。</p>\n\n<p>以下、<a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>での環境構築が終わっているものとして進める。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>これまで使用してきたWSL環境だとBluetoothが使用できないので、開発にはRaspberryPi5を使用することにした(Pi3以降なら大丈夫だと思う)。<br />\npyenvで仮想環境作ってkivyとbleakをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<h1 id=\"通信相手の準備\">通信相手の準備</h1>\n<p>通信相手は前に作ったランダム値を送るペリフェラルを使った。<br />\n<a href=\"https://github.com/ippei8jp/MultiBLE/tree/main/micropython\" target=\"_blank\">ここ</a>のble_RandomSensor3.py を\nRascberryPi PICO や ESP32 の micropython で動かしておく。</p>\n\n<p>micropythoの使い方は以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは下の「開く」をクリックすると表示されます。<br />\nダウンロードする場合は<a href=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1\" target=\"_blank\">こちら</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nimportしている<code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>は\n<a href=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7\" target=\"_blank\">ここ</a>\nにあります。</p>\n</blockquote>\n\n<p>用意するファイルはこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── kivy_ble.py\n└── scrolllabel.py\n</code></pre></div></div>\n\n<p>↓をクリックするとソースが開きます。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1.js\"></script>\n</dev>\n\n<h1 id=\"raspberrypiで実行\">RaspberryPiで実行</h1>\n<p>まずはPythonスクリプトが動くことを確認するために、RaspBerryPiで動かしてみる。<br />\n通信相手がいないと動かないので、事前に上の通信相手を実行しておく。</p>\n\n<p>RaspberyPi上でkivy_ble.pyを実行するとウィンドウが開くので、connectボタンをクリックする。<br />\nペリフェラルをスキャンが開始され、最初に見つかったデバイスに接続される。<br />\nさらにDATA1とDATA2のNotifyハンドラが登録され、受信データがウィンドウ右上の表示領域に表示される。<br />\ndisconnectボタンをクリックすると切断される。<br />\nQUITボタンをクリックするとプログラム終了。<br />\nウィンドウ下半分のログ表示領域には情報が表示される。この領域はスクロール可能。</p>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>と同様の手順でAndroidアプリ化していく。</p>\n\n<h2 id=\"ファイルの準備\">ファイルの準備</h2>\n\n<ul>\n  <li>BuidozerがインストールされたWSLの仮想マシンに作業ディレクトリを作成</li>\n  <li>作業ディレクトリに 上で作成した<code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code> <code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>をコピー</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code>を <code class=\"language-plaintext highlighter-rouge\">main.py</code> にリネーム</li>\n  <li>RaspberryPiの≪Bleakインストール先≫>/bleak/backends/p4android/recipes を 作業ディレクトリにコピー(ディレクトリまるごと)\n    <blockquote>\n      <p>[!NOTE]\nBleakのインストール先ディレクトリは以下のコマンドで確認できます</p>\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"bleak \"</span>\n</code></pre></div>      </div>\n    </blockquote>\n  </li>\n</ul>\n\n<p>-または以下でもOK</p>\n<blockquote>\n  <p>[!NOTE]</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> recipes/bleak\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/__init__.py\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/fix_setup.py\n</code></pre></div>  </div>\n</blockquote>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer init</code> を実行して<code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>を生成する</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>に以下の修正を加える</li>\n</ul>\n\n<dev class=\"accordion_head\"></dev>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- buildozer.spec.org  2025-04-09 07:58:44.836709400 +0900\n</span><span class=\"gi\">+++ buildozer.spec      2025-04-17 08:12:06.676451390 +0900\n</span><span class=\"p\">@@ -1,10 +1,10 @@</span>\n [app]\n\n # (str) Title of your application\n<span class=\"gd\">-title = My Application\n</span><span class=\"gi\">+title = BLE Demo\n</span>\n # (str) Package name\n<span class=\"gd\">-package.name = myapp\n</span><span class=\"gi\">+package.name = bledemo\n</span>\n # (str) Package domain (needed for android/ios packaging)\n package.domain = org.test\n<span class=\"p\">@@ -22,7 +22,7 @@</span>\n #source.exclude_exts = spec\n\n # (list) List of directory to exclude (let empty to not exclude anything)\n<span class=\"gd\">-#source.exclude_dirs = tests, bin, venv\n</span><span class=\"gi\">+source.exclude_dirs = tests, bin, venv, recipes\n</span>\n # (list) List of exclusions using pattern matching\n # Do not prefix with './'\n<span class=\"p\">@@ -37,7 +37,13 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements =\n+    python3,\n+    kivy,\n+    bleak,\n+    typing_extensions,\n+    async_to_sync,\n+    async-timeout\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n<span class=\"p\">@@ -95,7 +101,14 @@</span>\n\n # (list) Permissions\n # (See https://python-for-android.readthedocs.io/en/latest/buildoptions/#build-options-1 for all the supported syntaxes and properties)\n<span class=\"gd\">-#android.permissions = android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)\n</span><span class=\"gi\">+android.permissions =\n+    BLUETOOTH,\n+    BLUETOOTH_SCAN,\n+    BLUETOOTH_CONNECT,\n+    BLUETOOTH_ADMIN,\n+    ACCESS_FINE_LOCATION,\n+    ACCESS_COARSE_LOCATION,\n+    ACCESS_BACKGROUND_LOCATION\n</span>\n # (list) features (adds uses-feature -tags to manifest)\n #android.features = android.hardware.usb.host\n<span class=\"p\">@@ -330,7 +343,7 @@</span>\n #p4a.source_dir =\n\n # (str) The directory in which python-for-android should look for your own build recipes (if any)\n<span class=\"gd\">-#p4a.local_recipes =\n</span><span class=\"gi\">+p4a.local_recipes = ./recipes\n</span>\n # (str) Filename to the hook for p4a\n #p4a.hook =\n</code></pre></div></div>\n\n<ul>\n  <li>最終的に作業ディレクトリは以下のようになる\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>≪作業ディレクトリ≫\n├── buildozer.spec\n├── main.py\n├── scrolllabel.py\n└── recipes\n     └── bleak\n         ├── __init__.py\n         └── fix_setup.py\n</code></pre></div>    </div>\n    <h2 id=\"build\">build</h2>\n    <p>以下のコマンドでbuidする</p>\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"インストール実行\">インストール&実行</h2>\n<p>Windows側でadbサーバを起動しておき、以下を実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>connectボタンを最初にクリックした時、「この端末の位置情報へのアクセスをBLE Demoに許可しますか?」と聞かれたら「許可」をクリック\n(Androidのバージョンによって違うかもしれん。ターゲットAPIレベルで決まるんだっけ?)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのスクロール可能なラベルのカスタムウィジェット</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのスクロール可能なラベルのカスタムウィジェット</h1>\n      <p>PythonプログラムでGUIを作成するkivyでスクロール可能なラベルのカスタムウィジェットを作ったメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>でお試しプログラムを作っていた時、\nログ出力をスクロール可能にしたい(TeraTermみたいなターミナル表示のイメージ)と思い作ってみたけれど、\n汎用的に使えそうな気がしたのでカスタムウィジェットとしてまとめてみた。</p>\n\n<h1 id=\"解説\">解説</h1>\n<p>解説するほど理解してないけど…<br />\nkivyでは文字列を表示するのにLabelウィジェットを使うらしい(AndroidStudioでいうことろのTextView?)。<br />\nで、表示をスクロールするにはScrollViewウィジェットを使う(AndroidStudioでもScrollView)。<br />\n文字列をスクロールするには、ScrollViewの中にLabelを配置してやれば良いのだけれど、「配置しておしまい」という訳でもなく、\n色々と細々と下処理が必要になる。</p>\n\n<p>まずは、表示をどの程度残すか。TeraTermやWindowsTerminalでもスクロールバッファ行数や履歴のサイズとして指定する項目。<br />\nこれを設定できないと際限なく表示が増えてしまうので。<br />\nこれを実現するため、表示内容をdequeに保存し、新規行を追加した際にあふれた分を自動的に破棄するようにしている。</p>\n\n<p>また、テキストが表示領域からあふれた際に自動的にスクロールするようにするため、ラベルの<code class=\"language-plaintext highlighter-rouge\">texture_size</code>プロパティが変更された際に\nイベントハンドラ<code class=\"language-plaintext highlighter-rouge\">update_label_size</code>がコールされるように設定。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"n\">texture_size</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_label_size</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>ここでラベルのサイズをテクスチャサイズに合わせて変更している。<br />\nまた、このときラベルサイズがスクロールビューのサイズを超えた時、<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>に設定することで\n最下行を表示できるようにしている。<br />\nなお、ラベルサイズがスクロールビューのサイズ以下の時に<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>にしてしまうと下付き表示になってしまうため、\nこの条件では<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">1,0</code>にしている。<br />\nラベルサイズがスクロールビューのサイズ以上の時に常に<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>にすると\n以前の内容を確認するためにスクロールしている状態で新しい行が表示されると最下行までスクロールしてしまうので、\n<code class=\"language-plaintext highlighter-rouge\">0.0</code>に設定するのはスクロールビューのサイズを超えた時だけにしている。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">ScrollLabel</code>クラスをインポートして使ってください。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">scrolllabel</span> <span class=\"kn\">import</span> <span class=\"n\">ScrollLabel</span>\n</code></pre></div></div>\n\n<p>設定できるプロパティは<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>のプロパティに<code class=\"language-plaintext highlighter-rouge\">rows</code>(バッファ行数)を追加しています。<br />\nプロパティに<code class=\"language-plaintext highlighter-rouge\">rows</code>は初期化時にのみ変更可能です。\n初期化後(実際は最初のテキスト出力後)は変更してもバッファ行数に反映されません。</p>\n\n<p>テキストを追加するには<code class=\"language-plaintext highlighter-rouge\">add_text(text)</code>を使用します。\n引数<code class=\"language-plaintext highlighter-rouge\">end</code>を指定することで行末文字を変更できます(デフォルトは<code class=\"language-plaintext highlighter-rouge\">\\n</code>)。  <br />\nテキストを消去するには<code class=\"language-plaintext highlighter-rouge\">clear_text()</code>を使用します。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7.js?file=scrolllabel.py\"></script>\n</dev>\n\n<p>また、gistには実際に使用する際の例(レイアウトに Kv language使用/python使用)も載せてあるのでよろしかったら見てください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Buildozerでブロック崩しを作る</title>\n  </head>\n  <body>\n    <header>\n      <h1>Buildozerでブロック崩しを作る</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerでブロック崩しを作ってみたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>では訳も分からずとりあえずbuildして実行してみたが、\n少し何がどうなっているか調べてみたところ、\n実行の実体は<a href=\"https://github.com/kivy/python-for-android\" target=\"_blank\">python for android</a>\nというもので、Buildozerはこのプロジェクトをbuildするためのヘルパーらしい。</p>\n\n<p>で、githubのリポジトリを眺めていると<code class=\"language-plaintext highlighter-rouge\">pythonforandroid/recipes</code>にモジュールをbuildするためのレシピが置いてあるようだ。<br />\nそこに、<code class=\"language-plaintext highlighter-rouge\">pygame</code>というディレクトリがあったので、たぶんゲームを作るためのモジュールなんだろうとあたりをつけて\nぐぐってみた。</p>\n\n<p>で、<a href=\"https://python.joho.info/pygame/pygame-blockout/\" target=\"_blank\">【Pygame】ブロック崩しの作り方とサンプルコード(効果音付き)</a>\nにブロック崩しのプログラムの例があったので拝借してAndroidアプリ化してみることにした。</p>\n\n<p>今回は趣向を変えて、失敗事例も含めて書いてみる。</p>\n\n<p>以下、<a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>での環境構築が終わっているものとして進める。</p>\n\n<h1 id=\"使用したソース\">使用したソース</h1>\n<p><a href=\"https://python.joho.info/pygame/pygame-blockout/\" target=\"_blank\">【Pygame】ブロック崩しの作り方とサンプルコード(効果音付き)</a>\nのソースそのままでは動かなかったので、色々試行錯誤した結果のソースが以下。</p>\n\n<p>画像ファイルとオーディオファイルをプロジェクトフォルダに移動して\nアクセスするためのベースディレクトリを環境変数<code class=\"language-plaintext highlighter-rouge\">ANDROID_APP_PATH</code>から取得するようにした。<br />\n(相対パスだとうまく動かない。実行時のディレクトリがmain.pyがあるディレクトリと異なるため)</p>\n\n<p>あと、全画面表示にするため<code class=\"language-plaintext highlighter-rouge\">pygame.display.set_mode</code>に第2パラメータ<code class=\"language-plaintext highlighter-rouge\">(SCALED | FULLSCREEN)</code>を追加している。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pygame</span>\n<span class=\"kn\">from</span> <span class=\"nn\">pygame.locals</span> <span class=\"kn\">import</span> <span class=\"o\">*</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pygame.mixer</span>\n\n<span class=\"c1\"># ベースディレクトリの設定\n# Androidだとchdirされて相対パスでアクセスできなくなるので\n</span>\n<span class=\"n\">BASE_DIR</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getenv</span><span class=\"p\">(</span><span class=\"s\">'ANDROID_APP_PATH'</span><span class=\"p\">)</span>    <span class=\"c1\"># アプリケーションの格納されているパスを環境変数から取得\n</span><span class=\"k\">if</span> <span class=\"n\">BASE_DIR</span> <span class=\"ow\">is</span> <span class=\"bp\">None</span><span class=\"p\">:</span>\n    <span class=\"n\">BASE_DIR</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getcwd</span><span class=\"p\">()</span>                  <span class=\"c1\"># 設定されていない(Androidでない)→ カレントディレクトリを設定\n</span>\n<span class=\"c1\"># 画面サイズ\n</span><span class=\"n\">WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">400</span>\n<span class=\"n\">HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">400</span>\n<span class=\"n\">SCREEN</span> <span class=\"o\">=</span> <span class=\"n\">Rect</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">WIDTH</span><span class=\"p\">,</span> <span class=\"n\">HEIGHT</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像ファイルのパス\n</span><span class=\"n\">PADDLE_IMG_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'paddle.png'</span><span class=\"p\">)</span>\n<span class=\"n\">BLOCK_IMG_PATH</span>  <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'block.png'</span><span class=\"p\">)</span>\n<span class=\"n\">BALL_IMG_PATH</span>   <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'ball.png'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># オーディオファイルのパス\n</span><span class=\"n\">PADDLE_SOUND_PATH</span>   <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'paddle_sound.mp3'</span><span class=\"p\">)</span>\n<span class=\"n\">BLOCK_SOUND_PATH</span>    <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'block_sound.mp3'</span><span class=\"p\">)</span>\n<span class=\"n\">GAMEOVER_SOUND_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'gameover_sound.mp3'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># バドルのスプライトクラス\n</span><span class=\"k\">class</span> <span class=\"nc\">Paddle</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"c1\"># コンストラクタ\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">-</span> <span class=\"mi\">20</span>          <span class=\"c1\"># パドルのy座標\n</span>\n    <span class=\"k\">def</span> <span class=\"nf\">update</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mouse</span><span class=\"p\">.</span><span class=\"n\">get_pos</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span>  <span class=\"c1\"># マウスのx座標をパドルのx座標に\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">clamp_ip</span><span class=\"p\">(</span><span class=\"n\">SCREEN</span><span class=\"p\">)</span>                     <span class=\"c1\"># ゲーム画面内のみで移動\n</span>\n<span class=\"c1\"># ボールのスプライトクラス\n</span><span class=\"k\">class</span> <span class=\"nc\">Ball</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"c1\"># コンストラクタ\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">paddle</span><span class=\"p\">,</span> <span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">,</span> <span class=\"n\">speed</span><span class=\"p\">,</span> <span class=\"n\">angle_left</span><span class=\"p\">,</span> <span class=\"n\">angle_right</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>  <span class=\"c1\"># ボールの速度\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span> <span class=\"o\">=</span> <span class=\"n\">paddle</span>  <span class=\"c1\"># パドルへの参照\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">blocks</span> <span class=\"o\">=</span> <span class=\"n\">blocks</span>  <span class=\"c1\"># ブロックグループへの参照\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">start</span> <span class=\"c1\"># ゲーム開始状態に更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">score</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 連続でブロックを壊した回数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">=</span> <span class=\"n\">speed</span> <span class=\"c1\"># ボールの初期速度\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_left</span> <span class=\"o\">=</span> <span class=\"n\">angle_left</span> <span class=\"c1\"># パドルの反射方向(左端:135度)\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_right</span> <span class=\"o\">=</span> <span class=\"n\">angle_right</span> <span class=\"c1\"># パドルの反射方向(右端:45度)\n</span>\n    <span class=\"c1\"># ゲーム開始状態(マウスを左クリック時するとボール射出)\n</span>    <span class=\"k\">def</span> <span class=\"nf\">start</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># ボールの初期位置(パドルの上)\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span>\n\n        <span class=\"c1\"># 左クリックでボール射出\n</span>        <span class=\"k\">if</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mouse</span><span class=\"p\">.</span><span class=\"n\">get_pressed</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">move</span>\n\n    <span class=\"c1\"># ボールの挙動\n</span>    <span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">+=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centery</span> <span class=\"o\">+=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n        <span class=\"c1\"># 壁との反射\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span><span class=\"p\">:</span>    <span class=\"c1\"># 左側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>              <span class=\"c1\"># 速度を反転\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">></span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>  <span class=\"c1\"># 右側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">right</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span><span class=\"p\">:</span>      <span class=\"c1\"># 上側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n        <span class=\"c1\"># パドルとの反射(左端:135度方向, 右端:45度方向, それ以外:線形補間)\n</span>        <span class=\"c1\"># 2つのspriteが接触しているかどうかの判定\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">colliderect</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                                <span class=\"c1\"># 連続ヒットを0に戻す\n</span>            <span class=\"p\">(</span><span class=\"n\">x1</span><span class=\"p\">,</span> <span class=\"n\">y1</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">-</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">width</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_left</span><span class=\"p\">)</span>\n            <span class=\"p\">(</span><span class=\"n\">x2</span><span class=\"p\">,</span> <span class=\"n\">y2</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_right</span><span class=\"p\">)</span>\n            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span>                          <span class=\"c1\"># ボールが当たった位置\n</span>            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">y2</span><span class=\"o\">-</span><span class=\"n\">y1</span><span class=\"p\">)</span><span class=\"o\">/</span><span class=\"p\">(</span><span class=\"n\">x2</span><span class=\"o\">-</span><span class=\"n\">x1</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">x1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">y1</span>  <span class=\"c1\"># 線形補間\n</span>            <span class=\"n\">angle</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">radians</span><span class=\"p\">(</span><span class=\"n\">y</span><span class=\"p\">)</span>                     <span class=\"c1\"># 反射角度\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">*</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">cos</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">*</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">sin</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>                    <span class=\"c1\"># 反射音\n</span>\n        <span class=\"c1\"># ボールを落とした場合\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">></span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">start</span>                    <span class=\"c1\"># ボールを初期状態に\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">gameover_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">set_score</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>                               <span class=\"c1\"># スコアを0点にする\n</span>            <span class=\"c1\">#self.score.add_score(-100)                  # スコア減点-100点\n</span>\n        <span class=\"c1\"># ボールと衝突したブロックリストを取得(Groupが格納しているSprite中から、指定したSpriteと接触しているものを探索)\n</span>        <span class=\"n\">blocks_collided</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">spritecollide</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">blocks_collided</span><span class=\"p\">:</span>  <span class=\"c1\"># 衝突ブロックがある場合\n</span>            <span class=\"n\">oldrect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span>\n            <span class=\"k\">for</span> <span class=\"n\">block</span> <span class=\"ow\">in</span> <span class=\"n\">blocks_collided</span><span class=\"p\">:</span>\n                <span class=\"c1\"># ボールが左からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"ow\">and</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n                    \n                <span class=\"c1\"># ボールが右からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"ow\">and</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n\n                <span class=\"c1\"># ボールが上からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"ow\">and</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n                <span class=\"c1\"># ボールが下からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"ow\">and</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">block_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>     <span class=\"c1\"># 効果音を鳴らす\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>               <span class=\"c1\"># 衝突回数をカウント\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">add_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">*</span> <span class=\"mi\">10</span><span class=\"p\">)</span>   <span class=\"c1\"># 衝突回数に応じてスコア加点\n</span>\n<span class=\"c1\"># ブロック\n</span><span class=\"k\">class</span> <span class=\"nc\">Block</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"c1\"># ブロックの左上座標\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">+</span> <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">width</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">+</span> <span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">height</span>\n\n<span class=\"c1\"># スコア\n</span><span class=\"k\">class</span> <span class=\"nc\">Score</span><span class=\"p\">():</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">sysfont</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">font</span><span class=\"p\">.</span><span class=\"n\">SysFont</span><span class=\"p\">(</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"mi\">20</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">draw</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">screen</span><span class=\"p\">):</span>\n        <span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">sysfont</span><span class=\"p\">.</span><span class=\"n\">render</span><span class=\"p\">(</span><span class=\"s\">\"SCORE:\"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">),</span> <span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span><span class=\"mi\">255</span><span class=\"p\">,</span><span class=\"mi\">250</span><span class=\"p\">))</span>\n        <span class=\"n\">screen</span><span class=\"p\">.</span><span class=\"n\">blit</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">))</span>\n    <span class=\"k\">def</span> <span class=\"nf\">add_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">+=</span> <span class=\"n\">x</span>\n    <span class=\"k\">def</span> <span class=\"nf\">set_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">score</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"c1\"># 初期化\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># スクリーンの設定\n</span>    <span class=\"c1\"># screen = pygame.display.set_mode(SCREEN.size)\n</span>    <span class=\"n\">screen</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">display</span><span class=\"p\">.</span><span class=\"n\">set_mode</span><span class=\"p\">(</span><span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">SCALED</span> <span class=\"o\">|</span> <span class=\"n\">FULLSCREEN</span><span class=\"p\">))</span>    <span class=\"c1\"># (SCALED | FULLSCREEN) で前画面に拡大表示できる\n</span>\n    <span class=\"c1\"># オーディオ初期化\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># 各種効果音の設定\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">paddle_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">PADDLE_SOUND_PATH</span><span class=\"p\">)</span>               <span class=\"c1\"># パドルにボールが衝突した時の効果音取得\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">block_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">BLOCK_SOUND_PATH</span><span class=\"p\">)</span>                 <span class=\"c1\"># ブロックにボールが衝突した時の効果音取得\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">gameover_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">GAMEOVER_SOUND_PATH</span><span class=\"p\">)</span>           <span class=\"c1\"># ゲームオーバー時の効果音取得\n</span>    \n    <span class=\"c1\"># 描画用のスプライトグループ\n</span>    <span class=\"n\">group</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">RenderUpdates</span><span class=\"p\">()</span>  \n\n    <span class=\"c1\"># 衝突判定用のスプライトグループ\n</span>    <span class=\"n\">blocks</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Group</span><span class=\"p\">()</span>   \n\n    <span class=\"c1\"># スプライトグループに追加    \n</span>    <span class=\"n\">Paddle</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span>\n    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span>\n    <span class=\"n\">Block</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span><span class=\"p\">,</span> <span class=\"n\">blocks</span>\n\n    <span class=\"c1\"># パドルの作成\n</span>    <span class=\"n\">paddle</span> <span class=\"o\">=</span> <span class=\"n\">Paddle</span><span class=\"p\">(</span><span class=\"n\">PADDLE_IMG_PATH</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ブロックの作成(14*10)\n</span>    <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">15</span><span class=\"p\">):</span>\n        <span class=\"k\">for</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">11</span><span class=\"p\">):</span>\n            <span class=\"n\">Block</span><span class=\"p\">(</span><span class=\"n\">BLOCK_IMG_PATH</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># スコアを画面(10, 10)に表示\n</span>    <span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">Score</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>    \n\n    <span class=\"c1\"># ボールを作成\n</span>    <span class=\"n\">Ball</span><span class=\"p\">(</span><span class=\"n\">BALL_IMG_PATH</span><span class=\"p\">,</span> <span class=\"n\">paddle</span><span class=\"p\">,</span> <span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">135</span><span class=\"p\">,</span> <span class=\"mi\">45</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">clock</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">Clock</span><span class=\"p\">()</span>\n\n    <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>  <span class=\"c1\"># ループ処理の実行を継続するフラグ\n</span>\n    <span class=\"k\">while</span> <span class=\"n\">running</span><span class=\"p\">:</span>\n        <span class=\"n\">clock</span><span class=\"p\">.</span><span class=\"n\">tick</span><span class=\"p\">(</span><span class=\"mi\">60</span><span class=\"p\">)</span>      <span class=\"c1\"># フレームレート(60fps)\n</span>        <span class=\"n\">screen</span><span class=\"p\">.</span><span class=\"n\">fill</span><span class=\"p\">((</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">20</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 全てのスプライトグループを更新\n</span>        <span class=\"n\">group</span><span class=\"p\">.</span><span class=\"n\">update</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 全てのスプライトグループを描画       \n</span>        <span class=\"n\">group</span><span class=\"p\">.</span><span class=\"n\">draw</span><span class=\"p\">(</span><span class=\"n\">screen</span><span class=\"p\">)</span>\n        <span class=\"c1\"># スコアを描画  \n</span>        <span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">draw</span><span class=\"p\">(</span><span class=\"n\">screen</span><span class=\"p\">)</span> \n        <span class=\"c1\"># 画面更新 \n</span>        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">display</span><span class=\"p\">.</span><span class=\"n\">update</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># イベント処理\n</span>        <span class=\"k\">for</span> <span class=\"n\">event</span> <span class=\"ow\">in</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">event</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">():</span>\n            <span class=\"c1\"># 閉じるボタンが押されたら終了\n</span>            <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"nb\">type</span> <span class=\"o\">==</span> <span class=\"n\">QUIT</span><span class=\"p\">:</span> \n                <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"c1\"># キーイベント\n</span>            <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"nb\">type</span> <span class=\"o\">==</span> <span class=\"n\">KEYDOWN</span><span class=\"p\">:</span>\n                <span class=\"c1\"># Escキーが押されたら終了\n</span>                <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"n\">K_ESCAPE</span><span class=\"p\">:</span>   \n                    <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># 終了処理\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">quit</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">main</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>画像ファイルとオーディオファイルは参照元のページにあるリンクからダウンロードして以下のように配置する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── main.py\n├── images\n│   ├── ball.png\n│   ├── block.png\n│   └── paddle.png\n└── sound\n    ├── block_sound.mp3\n    ├── gameover_sound.mp3\n    └── paddle_sound.mp3\n</code></pre></div></div>\n\n<p>とりあえずホスト上で動作するか確認してみる。<br />\n(Android上のpython/pygameとバージョンが違うので厳密な動作確認にはならないけど、大体OKを確認したいだけなのでこれでいく)</p>\n\n<p>pygameのインストールは以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>pygame\n</code></pre></div></div>\n\n<p>WSLではデフォルトでオーディオ再生するためのライブラリ類がインストールされていないので、以下でインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>pulseaudio\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWSLってオーディオ再生できるんだ。<br />\n初めて知った…</p>\n</blockquote>\n\n<p>で実行してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python main.py\n</code></pre></div></div>\n\n<p>全画面表示になるので、終了はESCキー押下で。</p>\n\n<h1 id=\"まずは何も考えずにbuildしてみる失敗\">まずは何も考えずにbuildしてみる(失敗)</h1>\n\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>とりあえず最低限必要な修正だけで試してみる。<br />\nbuildozer.spec を以下の内容で修正。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- block0/buildozer.spec       2025-04-04 07:08:53.520218478 +0900\n</span><span class=\"gi\">+++ block1/buildozer.spec       2025-04-04 06:25:27.858934801 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n</code></pre></div></div>\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<p>しばらくするとエラーで止まる。<br />\nmk.logを確認してみると、以下のようなエラーメッセージがあった。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/Buildozer/biock1/.buildozer/android/platform/build-arm64-v8a_armeabi-v7a/build/other_builds/pygame/arm64-v8a__ndk_target_21/pygame/setup.py:70: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives\n・・・\nsrc_c/_sdl2/sdl2.c:211:12: fatal error: 'longintrepr.h' file not found\n</code></pre></div></div>\n\n<p>どうやらpygameのbuuild中に<code class=\"language-plaintext highlighter-rouge\">longintrepr.h</code>が見つからなくてエラーになっているらしい。<br />\n「longintrepr.h」でぐぐってみると、python 3.10 → 3.11 の変更で削除されたファイルらしい。</p>\n\n<h1 id=\"それならばpygameのバージョンを新しくしてbuildしてみる失敗\">それならばpygameのバージョンを新しくしてbuildしてみる(失敗)</h1>\n\n<p>pygameをpython 3.11に対応しているバージョンに変更して試してみる。<br />\n調べてみると、2.1.3からpython 3.11 に対応しているようである。</p>\n\n<p>作成済みのファイルを削除<br />\n<code class=\"language-plaintext highlighter-rouge\">buildozer android clean</code>でも良さそうだけど、念のため全部消して最初からやってみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> .buildozer bin buildozer.spec mk.log\n</code></pre></div></div>\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>buildozer.spec を以下の内容で修正。<br />\npygameのバージョンを2.1.3指定している。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- block0/buildozer.spec       2025-04-04 07:08:53.520218478 +0900\n</span><span class=\"gi\">+++ block2/buildozer.spec       2025-04-04 09:32:40.050228726 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame==2.1.3\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n</code></pre></div></div>\n\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n<p>しばらく待つと、以下のように表示されたので、buildは成功したようである。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Android packaging done!\n# APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<p>なので、実行してみる。<br />\nWindows側でadbサーバを起動しておき、以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>起動はするが、すぐに落ちてしまう。<br />\nなにやらエラーが発生している模様。ログで何が起こっているか確認する。<br />\n無関係なログも多く含まれているので、python関連のログだけ抜き出してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"nt\">-i</span> python run.log <span class=\"o\">></span> run_python.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code> に以下を追加するとlogcatのフィルタが有効になるので、設定しておくと良いかもしれない。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>android.logcat_filters = *:S python:V pythonutil:V PythonActivity:V\n</code></pre></div>  </div>\n  <p>コマンドラインで指定できると良いのがだが…\nadbを直接起動すればコマンドラインで設定できるけど。</p>\n\n  <p>タグ<code class=\"language-plaintext highlighter-rouge\">python</code>がpythonプログラム内のログ、その他は実行時の制御を行っている部分らしい。<br />\nまた、プログラム内のprintによるメッセージ出力もここに表示される。</p>\n</blockquote>\n\n<p>ログファイルの最後の部分には以下のように出力されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> I python  : Traceback (most recent call last):\n I python  :   File \"/work/Buildozer/block2/.buildozer/android/app/main.py\", line 34, in <module>\n I python  :   File \"/work/Buildozer/block2/.buildozer/android/platform/build-arm64-v8a_armeabi-v7a/build/python-installs/myapp/arm64-v8a/pygame/__init__.py\", line 70, in __getattr__\n I python  : NotImplementedError: sprite module not available (ImportError: dlopen failed: cannot locate symbol \"alphablit_alpha_sse2_argb_surf_alpha\" referenced by \"/data/data/org.test.myapp/files/app/_python_bundle/site-packages/pygame/surface.so\"...)\n I python  : Python for android ended.\n</code></pre></div></div>\n\n<p>どうやらpygameの初期化時に<code class=\"language-plaintext highlighter-rouge\">alphablit_alpha_sse2_argb_surf_alpha</code>が見つからないということらしい。<br />\n単にバージョン変えるだけではダメで、ちゃんとレシピも修正しないといけないらしい。</p>\n\n<h1 id=\"python-for-androidのバージョンを下げてみる成功\">python for androidのバージョンを下げてみる(成功)</h1>\n\n<p>python 3.10以下にして試してみることも考えたが、同様にレシピの変更なしで動くとは思えないので\npython for androidのバージョンを下げて試してみることにする。</p>\n\n<p>作成済みのファイルを削除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> .buildozer bin buildozer.spec mk.log\n</code></pre></div></div>\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>buildozer.spec を以下の内容で修正。<br />\n<code class=\"language-plaintext highlighter-rouge\">p4a.branch = release-2022.12.20</code> と指定してrelease-2022.12.20を使用するように設定している。<br />\nこのバージョンは python 3.9.9 を使用している。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gi\">+++ block3/buildozer.spec       2025-04-04 12:28:23.302885362 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n<span class=\"p\">@@ -321,7 +321,7 @@</span>\n #p4a.fork = kivy\n\n # (str) python-for-android branch to use, defaults to master\n<span class=\"gd\">-#p4a.branch = master\n</span><span class=\"gi\">+p4a.branch = release-2022.12.20\n</span>\n # (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch\n #p4a.commit = HEAD\n</code></pre></div></div>\n\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n<p>しばらく待つと、以下のように表示されたので、buildは成功したようである。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Android packaging done!\n# APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<p>なので、実行してみる。<br />\nWindows側でadbサーバを起動しておき(前のセクションで起動してれば再度実行する必要なし)、以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、動いた。<br />\nメデタシメデタシ。<br />\nログがファイルに格納され続けてしまうので、早めにCTRL+Cで止めておきましょう。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Buildozerをお試し</title>\n  </head>\n  <body>\n    <header>\n      <h1>Buildozerをお試し</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerをお試ししたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonプログラムをAndroid アプリ化できる Buildozer を試してみた時のメモ<br />\n(iOSもできるみたいだけど試してないのでわからん)<br />\n参考:<br />\n<a href=\"https://buildozer.readthedocs.io/en/latest/installation.html\" target=\"_blank\">公式サイト</a><br />\n<a href=\"https://qiita.com/kouzimiso/items/1332ab62791ca5d81c5f\" target=\"_blank\">BuildozerでAndroidアプリを作る 2024 WSL2</a><br />\n<a href=\"https://paloma69.hatenablog.com/entry/2022/07/05/195915\" target=\"_blank\">pythonでAndroidの野良アプリを作りたい2 buildozerでコンパイル編</a></p>\n\n<h1 id=\"準備\">準備</h1>\n<p>環境はWSL で Ubuntu 24.04を使用した。<br />\n(公式では20.04 or 22.04 となってるけど、24.04でも動いた)<br />\n以下ディストリビューション情報</p>\n\n<p>Andoridはちょっと古いけど ZenFone Max Pro (M2) Android9<br />\n新しいAndroidでも動くかどうかわからん。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>~<span class=\"nv\">$ </span>lsb_release <span class=\"nt\">-a</span>\nNo LSB modules are available.\nDistributor ID: Ubuntu\nDescription:    Ubuntu 24.04.2 LTS\nRelease:        24.04\nCodename:       noble\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n\n<p><a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a>参照</p>\n\n<h2 id=\"pyenvでpythonインストール\">pyenvでpythonインストール</h2>\n<p>公式では python は 3.8 以降となっているので、3.12を使うこととした。</p>\n\n<blockquote>\n  <p>[!NOTE]\n3.12では<code class=\"language-plaintext highlighter-rouge\">distutils</code>が廃止されているので、<code class=\"language-plaintext highlighter-rouge\">setuptools</code>のインストールが必須。<br />\n参考:<a href=\"https://openillumi.com/python-3-12-distutils-error-fix-guide/\" target=\"_blank\">Python 3.12での「ModuleNotFoundError: distutilsが見つかりません」を解決する方法</a></p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.12.9 \npyenv shell 3.12.9 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\npyenv shell <span class=\"nt\">--unset</span> \n</code></pre></div></div>\n\n<h2 id=\"pyenvで仮想環境構築\">pyenvで仮想環境構築</h2>\n<p>お約束で仮想環境を作っておく。<br />\n(そのまま3.12.xにインストールしてもいいけど)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Buildozer <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Buildozer\npyenv virtualenv 3.12.9 Buildozer\npyenv <span class=\"nb\">local </span>Buildozer \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"必要なツール類のインストール\">必要なツール類のインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>zip unzip openjdk-17-jdk autoconf libtool pkg-config zlib1g-dev cmake libffi-dev libssl-dev\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n公式サイトで指定されているライブラリのうち以下は24.04では存在しない。<br />\n<code class=\"language-plaintext highlighter-rouge\">libncurses5-dev libncursesw5-dev libtinfo5</code><br />\nWSL2のUbuntu24.04ではデフォルトで後継のlibncurses-dev、libtinfo6が入ってるので気にしなくても大丈夫</p>\n</blockquote>\n\n<h2 id=\"buildozer関連のモジュールのインストール\">Buildozer関連のモジュールのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> buildozer\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">Cython</span><span class=\"o\">==</span>0.29.33 virtualenv\n</code></pre></div></div>\n\n<h2 id=\"使用するフォントのインストール\">使用するフォントのインストール</h2>\n<p>どっかからダウンロードしてきてもいいけど、お手軽にaptでインストール<br />\n(あとで作業ディレクトリにコピーする)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n\n<h2 id=\"ubuntu上でアプリ実行するとき必要なライブラリのインストール\">Ubuntu上でアプリ実行するとき必要なライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libmtdev-dev\n</code></pre></div></div>\n\n<h2 id=\"アプリで使うモジュールのインストール\">アプリで使うモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>kivy\n</code></pre></div></div>\n\n<h1 id=\"アプリの作成\">アプリの作成</h1>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n\n<p>どこでも良いけど、先に作ったpyenvの仮想環境<code class=\"language-plaintext highlighter-rouge\">Buildozer</code>が使えるh場所で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /work/Buildozer/app <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Buildozer/app\n</code></pre></div></div>\n\n<h2 id=\"フォントのコピー\">フォントのコピー</h2>\n<p>先ほどインストールしたフォントを作業ディレクトリにコピー</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir assets\ncp /usr/share/fonts/truetype/fonts-japanese-gothic.ttf assets/\n</code></pre></div></div>\n\n<h2 id=\"mainpyを作成\">main.pyを作成</h2>\n\n<p><a href=\"https://qiita.com/kouzimiso/items/1332ab62791ca5d81c5f\" target=\"_blank\">参考にしたサイト</a>\nにあったプログラムを使わせてもらった(ちょっち変更あり)。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  main.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.app</span> <span class=\"kn\">import</span> <span class=\"n\">App</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.button</span> <span class=\"kn\">import</span> <span class=\"n\">Button</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.label</span> <span class=\"kn\">import</span> <span class=\"n\">Label</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.boxlayout</span> <span class=\"kn\">import</span> <span class=\"n\">BoxLayout</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.utils</span> <span class=\"kn\">import</span> <span class=\"n\">platform</span>\n\n<span class=\"c1\"># フォントのパスを指定してフォントを設定する\n</span><span class=\"k\">if</span> <span class=\"n\">platform</span> <span class=\"o\">==</span> <span class=\"s\">'win'</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Windowsの場合はシステムフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">\"C:/Windows/Fonts/YuGothR.ttc\"</span><span class=\"p\">)</span>\n<span class=\"k\">elif</span> <span class=\"n\">platform</span> <span class=\"o\">==</span> <span class=\"s\">'android'</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Androidの場合はassetsフォルダ内のフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'assets/fonts-japanese-gothic.ttf'</span><span class=\"p\">)</span>\n<span class=\"k\">else</span><span class=\"p\">:</span>\n    <span class=\"c1\"># その他のプラットフォームではデフォルトフォントを使用\n</span>    <span class=\"c1\"># LabelBase.register(DEFAULT_FONT, fn_regular='DejaVuSans.ttf')\n</span>    <span class=\"c1\"># その他の場合もassetsフォルダ内のフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'assets/fonts-japanese-gothic.ttf'</span><span class=\"p\">)</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MyApp</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># レイアウトの生成\n</span>        <span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"n\">BoxLayout</span><span class=\"p\">(</span><span class=\"n\">orientation</span><span class=\"o\">=</span><span class=\"s\">'vertical'</span><span class=\"p\">,</span> <span class=\"n\">spacing</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ボタンの生成\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span> <span class=\"o\">=</span> <span class=\"n\">Button</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"o\">=</span><span class=\"s\">'クリックしてください'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ボタンにコールバックを設定\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"n\">on_press</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">on_button_press</span><span class=\"p\">,</span> <span class=\"n\">on_release</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">on_button_release</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ラベルの生成\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">Label</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"o\">=</span><span class=\"s\">'ボタンがクリックされるとここに表示されます'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># layoutにボタンとラベルを配置\n</span>        <span class=\"n\">layout</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span><span class=\"p\">)</span>\n        <span class=\"n\">layout</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">layout</span>\n\n    <span class=\"c1\"># ボタンが押されたたときのコールバック処理\n</span>    <span class=\"k\">def</span> <span class=\"nf\">on_button_press</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">instance</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">'ボタンが押されました!'</span>\n    \n    <span class=\"c1\"># ボタンが離されたたときのコールバック処理\n</span>    <span class=\"k\">def</span> <span class=\"nf\">on_button_release</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">instance</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">'ボタンが離されました!'</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">MyApp</span><span class=\"p\">().</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"とりあえずununtu上で試してみる\">とりあえずUnuntu上で試してみる</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python main.py\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n上半分がボタン、下半分がラベル<br />\nボタンを押す/離すとラベルの表示が変わる<br />\nXボタンで終了</p>\n</blockquote>\n\n<h2 id=\"buildozer初期化\">Buildozer初期化</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n<p>buildozer.spec が生成される</p>\n\n<h2 id=\"buildozerspecファイルの修正\">buildozer.specファイルの修正</h2>\n<p>以下の修正を行う</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- buildozer.spec.org  2025-03-28 11:44:32.382972664 +0900\n</span><span class=\"gi\">+++ buildozer.spec      2025-03-28 11:52:18.977717226 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,ttf\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*.ttf\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n</code></pre></div></div>\n\n<h2 id=\"clean--build\">clean & build</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer android clean     <span class=\"c\"># 初回はやらなくてOK(FileNotFoundErrorになる)</span>\nbuildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee</span> <span class=\"nt\">-a</span> buildozer.log\n</code></pre></div></div>\n\n<p>正常にbuildが終了したら以下のように表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n初回は途中ライセンスに同意を求められるので同意するならyを入力(同意しないと終わっちゃうけど)<br />\n終了まで15分ほどかかった(環境依存なのであまりあてにしないで)<br />\n初回はダウンロードが入るのでもうちょっとかかる</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n<h2 id=\"android側の準備\">Android側の準備</h2>\n<p>adbが接続できるようになんか準備が必要(デバッグモードを有効にするとか?)だった気がするけど\n忘れちゃったので良きに計らってちょ\n(<a href=\"https://developer.android.com/studio/debug/dev-options?hl=ja\" target=\"_blank\">このへん?</a>)</p>\n\n<p>で、PCとUSBで接続しておく。</p>\n\n<h2 id=\"windows用-adbのダウンロード\">Windows用 adbのダウンロード</h2>\n<p><a href=\"https://developer.android.com/tools/releases/platform-tools?hl=ja\" target=\"_blank\">SDK Platform-Tools リリースノート</a><br />\n「ダウンロード」セクションの「SDK Platform-Tools for Windowsをダウンロード」からダウンロードし、適当なディレクトリに展開\n(例:C:\\Android_tools )</p>\n\n<blockquote>\n  <p>[!NOTE]\nPATHを通してもいいけど、AndroidStudio使うときに不安なので通さないでcdしてから実行するようにした</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nAndroidStudioが入っているのであれば、そっちを使っても可。<br />\n その場合、adb.exeは<code class=\"language-plaintext highlighter-rouge\">%LOCALAPPDATA%\\Android\\Sdk\\platform-tools</code>にある。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n公式の情報ではWindowsのadbとUbuntuのadbのバージョンが同じでないとダメと書いてあるが、多少違っても大丈夫っぽい。<br />\n(てか、古いバージョンダウンロードできるんだろか?と思ったら、\n<a href=\"https://qiita.com/azumagoro/items/3a44fad53d88b3b2817b\" target=\"_blank\">Android SDK platform-tools 旧バージョン インストール</a>\nに手順書いてあった。メンドクサイけど…)</p>\n</blockquote>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動するためだと思う)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪上で展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!IMPORTANT]\n最初のadbの実行はWindows側。コマンドプロンプトやpowershellで実行する。</p>\n</blockquote>\n\n<p>以下のように表示されるはず</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>* daemon not running; starting now at tcp:XXXX\n* daemon started successfully\nList of devices attached\n== 接続されているデバイスが表示される ==\n</code></pre></div></div>\n\n<p>ちなみにサーバを停止するには以下</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>adb kill-server\n</code></pre></div></div>\n\n<h2 id=\"ダウンロードと実行\">ダウンロードと実行</h2>\n\n<p>WSL側のターミナルに戻って以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run \n</code></pre></div></div>\n\n<p>これでプログラムがAndroidにダウンロードされて実行される。</p>\n\n<p>logcatを表示したいときは以下</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n上記のコマンドを実行すると内部でadbが実行されるようだ。</p>\n</blockquote>\n\n<h2 id=\"usb接続せずに実行したい場合\">USB接続せずに実行したい場合</h2>\n<p>USB接続せずに実行したい場合は以下のように実行してWebサーバを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer serve\n</code></pre></div></div>\n<p>WEBサーバが立ち上がったら、Androidのchrome等からアクセスし、apkファイルをダウンロードしてインストール<br />\n…できるんだけど、通常firewallが動いていてアクセスが弾かれるのでfirewallの設定変更しないといけない。<br />\n変更方法は<a href=\"https://www.fmworld.net/cs/azbyclub/qanavi/jsp/qacontents.jsp?PID=0111-2966\" target=\"_blank\">このへん</a><br />\n(試してないけど)</p>\n\n<h2 id=\"その他の方法\">その他の方法</h2>\n<p>quickshreを使うとか、USBのファイル転送モードを使えばapkファイルを転送できるので、\nあとはFiles等で表示してapkファイルとタップすればインストールできる。<br />\n(なんか野良アプリのインストール許可とか色々許可しないといけなかった気がする)</p>\n\n<h1 id=\"まとめ\">まとめ</h1>\n<p>とりあえずなんか実行できるものができたけど、実用に堪えるかはビミョー。<br />\nファイルアクセスとかネットワークアクセスとか出来るのかな?<br />\nBluetoothはどうなんだろ?<br />\nアクセス権限とかいろいろメンドクサイ処理が必要だったけど、そこまで対応してるんだろか?<br />\n気が向いたらもうちょっと調べてみるかも…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MSYS2とgccのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>MSYS2とgccのインストール</h1>\n      <p>WindowsにMSYS2とgccをインストールした時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows環境でLinuxライクな環境を使用できる<a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2</a><br />\ngcc は単体で配布されている <a href=\"https://github.com/niXman/mingw-builds-binaries/releases\" target=\"_blank\">MinGW-W64-binaries</a>を使っていたが、\nMSYS2で管理されているものに切り替えてみた。</p>\n\n<h1 id=\"msys2のインストール\">MSYS2のインストール</h1>\n<p>大体以下の感じでインストールできる。</p>\n<ul>\n  <li><a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2のページ</a> を開く</li>\n  <li>Installation セクションの Download the installer: に書かれているリンクからダウンロード(バージョンアップで更新されるのでここにはリンクを貼らないでおく)</li>\n  <li>ダウンロードしたファイルを実行</li>\n  <li>デフォルトのままNextをクリックして行き、Installをクリック</li>\n  <li>終わったらFinishをクリック</li>\n</ul>\n\n<h1 id=\"msys2の設定\">MSYS2の設定</h1>\n<p>後でWindowsTerminalから使えるようにするからやらなくても良いけど、ま、気持ちの問題なので。</p>\n<ul>\n  <li>msys2を起動(スタート→すべて→MSYS2→MSYS2 UCRT64)し、タイトルバーを右クリックし 「Options…」 を選択\n    <ul>\n      <li>Text の Font の Select.. をクリックしてフォントとサイズを変更</li>\n      <li>Text の Local で ja_JP と UTF8 を選択</li>\n      <li>Window の Default size で ウィンドウサイズが変更できる</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"最新版にアップデート\">最新版にアップデート</h1>\n<p>MSYS2を起動して以下を実行(ubuntuの<code class=\"language-plaintext highlighter-rouge\">apt update && apt upgrade</code>に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -Syuu\n</code></pre></div></div>\n\n<p>何か聞かれたらYを入力<br />\nウィンドウが閉じられたら再度MSYS2を起動<br />\n再度MSYS2を起動したらもう一回 <code class=\"language-plaintext highlighter-rouge\">pacman -Syuu</code> を実行</p>\n\n<h1 id=\"開発ツールのインストール\">開発ツールのインストール</h1>\n<p>MSYS2を起動して以下を実行<br />\n(make、gcc、gdbなどのインストール)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -S base-devel\npacman -S mingw-w64-ucrt-x86_64-gcc\npacman -S mingw-w64-ucrt-x86_64-gdb\n</code></pre></div></div>\n\n<h1 id=\"pathの変更\">PATHの変更</h1>\n<p>MSYS2のbashで実行する際はpathは設定済みだが、\nコマンドプロンプト等で実行するためにWindows側のPATHを変更する。</p>\n\n<ul>\n  <li>設定 → システム → バージョン情報</li>\n  <li>関連リンクの「システムの詳細設定」をクリック</li>\n  <li>開いたウィンドウの下のほうにある「環境変数(N)…」をクリック</li>\n  <li>上側のユーザ環境変数で「Path」を選択して「編集」をクリック</li>\n  <li>「新規」をクリックして以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>c:\\msys64\\ucrt64\\bin\nC:\\msys64\\usr\\bin\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\nc:\\msys64\\ucrt64\\bin にはpythonが入っているので、Windowsでインストールしたpythonを使用したい場合は\nそのPATHより後(下)に設定すること</p>\n    </blockquote>\n  </li>\n</ul>\n\n<p>念のためここでPCを再起動する。<br />\n(PATHの変更が有効にならない場合がある)</p>\n\n<h1 id=\"windowsterminal-にmsys2を登録\">WindowsTerminal にMSYS2を登録</h1>\n<p>MSY2のデフォルトのターミナルはminttyだが、いつも使っているWindowsTerminalで使えるようにする。</p>\n<ul>\n  <li>WindowsTerminalを起動</li>\n  <li>「新しいプロファイルを追加」を選択</li>\n  <li>「新しい空のプロファイル」をクリック\n    <ul>\n      <li>コマンドラインに以下を設定(ucrt64の場合。それ以外は最後のオプションを変更する)\n        <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>C:/msys64/msys2_shell.cmd -defterm -here -no-start -ucrt64\"  \n</code></pre></div>        </div>\n      </li>\n      <li>開始ディレクトリに MSYS2のhomeディレクトリ(<code class=\"language-plaintext highlighter-rouge\">cygpath.exe -w ~</code> で取得可能) を指定</li>\n      <li>アイコンは何でもいいけど、<code class=\"language-plaintext highlighter-rouge\">C:\\\\msys64\\\\ucrt64.ico</code>とかが良いかな</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"vs-codeのターミナルでmsys2のbashを使用する方法\">VS CodeのターミナルでMSYS2のBashを使用する方法</h1>\n<p>VS CodeのターミナルでもMSYS2を使えるようにしておく。<br />\n(別ウィンドウでWindowsTerminalから実行すればいいんだけど)</p>\n\n<ul>\n  <li>VSCodeを起動</li>\n  <li>設定(ファイル→ユーザ設定→設定)を開く</li>\n  <li>機能→ターミナルを選ぶ\n-「integrated > profiles:windows」 を探す(検索すれば良いんだけど)\n    <ul>\n      <li>「setting,jsonで編集」 をクリック\n        <ul>\n          <li>ひな型作って開いてくれる。</li>\n          <li>そこに 以下を追加\n            <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>          \"MSYS2 Bash\": {\n              \"path\": [\n                  \"C:\\\\msys64\\\\msys2_shell.cmd\"\n              ],\n              \"args\": [\n                  \"-defterm\",\n                  \"-here\",\n                  \"-no-start\",\n                  \"-ucrt64\"\n              ]\n          }\n</code></pre></div>            </div>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nファイルは ユーザだと、<code class=\"language-plaintext highlighter-rouge\">%APPDATA%\\code\\User\\settings.json</code><br />\nワークスペースだとワークスペース下の<code class=\"language-plaintext highlighter-rouge\">.vscode\\settings.json</code></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nデフォルトのプロファイルをBashにすると悲しい結果が待ち受けているのでやらない方が良さそう</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openpyxlのバグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>openpyxlのバグ</h1>\n      <p>openpyxl(3.1.5)のバグ(ではないけど、あえてそう書いておく)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"内容\">内容</h1>\n<p>openpyxl(3.1.2)でExcelのグラフを作成するスクリプトを使っていたが、\nopenpyxlを現時点での最新版(3.1.5)にアップデートしたところ、表示されるグラフの見た目が変わってしまった。</p>\n\n<h1 id=\"原因\">原因</h1>\n<p>検索してみたところ、teratailに\n『<a href=\"https://teratail.com/questions/5q9cujzlc2307x\" target=\"_blank\">python openpyxl グラフ作成 グラフ書式が変わったのを治せない</a>』\nというエントリを見つけた。</p>\n\n<p>どうやら、Excelの仕様に厳密に従ったらExcelのバグに引っかかった ということらしい。<br />\n(バグが他のバグ回避になってた、みたいな感じ)</p>\n\n<h1 id=\"対策\">対策</h1>\n<p>Excelのバグの修正を待っててもしかたないので、なんとか出来る方法を探してみた。<br />\nこの部分は openpyxl の 3.1.4 で仕様変更されたようなので、3.1.3以前を使うというのも手なのだけど、<br />\n最新版を使いたい場合はExcelのバグに引っかかってる部分だけ元にもどしてやれば良い。</p>\n\n<p>ということで、上のページにあった変更点を出力している部分を探して修正してみた。</p>\n\n<p>結論から言うと、以下のパッチをインストールしたライブラリにあててやれば良い。</p>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -urpN openpyxl.org/packaging/extended.py openpyxl/packaging/extended.py\n</span><span class=\"gd\">--- openpyxl.org/packaging/extended.py  2025-01-07 07:23:30.159676700 +0900\n</span><span class=\"gi\">+++ openpyxl/packaging/extended.py      2025-01-07 07:41:28.823592900 +0900\n</span><span class=\"p\">@@ -126,7 +126,8 @@</span> class ExtendedProperties(Serialisable):\n         self.HLinks = None\n         self.HyperlinksChanged = HyperlinksChanged\n         self.DigSig = None\n<span class=\"gd\">-        self.Application = f\"Microsoft Excel Compatible / Openpyxl {__version__}\"\n</span><span class=\"gi\">+        # self.Application = f\"Microsoft Excel Compatible / Openpyxl {__version__}\"\n+        self.Application = f\"Microsoft Excel\"\n</span>         self.AppVersion = \".\".join(__version__.split(\".\")[:-1])\n         self.DocSecurity = DocSecurity\n</code></pre></div></div>\n\n<p>で、試してみたところ うまくグラフが表示されるようになった。<br />\nメデタシメデタシ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>TkEasyGUIを使ってみる</title>\n  </head>\n  <body>\n    <header>\n      <h1>TkEasyGUIを使ってみる</h1>\n      <p>pythonでGUIを簡単に作れる TkEasyGUI を使ってみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでGUIを作るにはtkinterを使うが、とっても分かり難い。<br />\nそこで、簡単にGUIが作れるとウワサの TkEasyGUI を使ってみた。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/TkEasyGUI/0.1.4/\" target=\"_blank\">PyPI</a></li>\n  <li><a href=\"https://github.com/kujirahand/tkeasygui-python\" target=\"_blank\">GitHub</a></li>\n  <li><a href=\"https://note.com/sirodon_256/n/na73d3fdac68d?fbclid=IwY2xjawHpgzhleHRuA2FlbQIxMQABHWBZ650bkpcT7-r0B3xAXpeUoIWsjSZJjZ4lqPUtBrxxQp3mlsCzFtM7tA_aem_lSSEVGhwq5SisJRckTFZcw\" target=\"_blank\">TkEasyGUIライブラリの基本とサンプルコード解説</a></li>\n</ul>\n\n<h1 id=\"使ってみる\">使ってみる</h1>\n<p>使ってみようと思ってはみたものの 何を作れば良いか思いつかなかったので、\n以前にtkinterで作ったプログラムを TkEasyGUI を使って書き直して見ることにした。</p>\n\n<p>元にしたのは、\n<a href=\"https://gist.github.com/ippei8jp/b8af596718e357dce185b5279b3533b8\" target=\"_blank\">ketsuatsu_GUI.py</a><br />\nこれの <code class=\"language-plaintext highlighter-rouge\">ketsuatsu_GUI.py</code>だけを書き換えてみる。<br />\n(<code class=\"language-plaintext highlighter-rouge\">ketsuatsu_csv2xls.py</code>はそのまま使用)</p>\n\n<h1 id=\"作ってみた\">作ってみた</h1>\n<p>ということで、書き直してみた。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>TkEasyGUI のインストールは以下を実行するだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>TkEasyGUI\n</code></pre></div></div>\n<p>TkEasyGUI と pyperclip がインストールされる。</p>\n\n<p>全体を実行するには、上の元ソースのREADMEを参照。</p>\n\n<h2 id=\"ソース\">ソース</h2>\n<p>ということで、作ってみたソースがこちら。<br />\n元のソースと比べても行数で半分以下になった。<br />\nまた、イベントによる実行がイベントハンドラで登録するのから\nイベントループでイベントを監視するように変更されたので、プログラムの見通しがよくなった。</p>\n\n<p>これを</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ketsuatsu_easyGUI.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">dont_write_bytecode</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>      <span class=\"c1\"># pycacheを作成しない\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">TkEasyGUI</span> <span class=\"k\">as</span> <span class=\"n\">eg</span>\n\n<span class=\"c1\"># CSV→エクセル変換処理\n</span><span class=\"kn\">from</span> <span class=\"nn\">ketsuatsu_csv2xls</span> <span class=\"kn\">import</span> <span class=\"n\">ketsuatsu_csv2xls</span>\n\n<span class=\"c1\"># フォント\n# FONT_NAME1 = \"MS ゴシック\"\n</span><span class=\"n\">FONT_NAME1</span> <span class=\"o\">=</span> <span class=\"s\">\"BIZ UDゴシック\"</span>\n<span class=\"n\">FONT_NAME2</span> <span class=\"o\">=</span> <span class=\"s\">\"Noto Sans CJK JP\"</span>\n\n<span class=\"n\">FONT_SIZE</span> <span class=\"o\">=</span> <span class=\"mi\">12</span>\n\n\n<span class=\"c1\"># レイアウト\n</span><span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Text</span><span class=\"p\">(</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"CSV file  \"</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Input</span><span class=\"p\">(</span>       <span class=\"s\">\"\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"s\">\"-csvfilepath-\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span> \n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">FileBrowse</span><span class=\"p\">(</span>  <span class=\"n\">button_text</span> <span class=\"o\">=</span> <span class=\"s\">\"Browse...\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"CSV file\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">file_types</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"s\">'CSV file'</span><span class=\"p\">,</span> <span class=\"s\">'*.csv'</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"s\">'all'</span><span class=\"p\">,</span> <span class=\"s\">'*.*'</span><span class=\"p\">)),</span>\n                     <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Text</span><span class=\"p\">(</span>        <span class=\"s\">\"Excel file\"</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Input</span><span class=\"p\">(</span>       <span class=\"s\">\"\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"s\">\"-excelfilepath-\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span> \n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">FileBrowse</span><span class=\"p\">(</span>  <span class=\"n\">button_text</span> <span class=\"o\">=</span> <span class=\"s\">\"Browse...\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">title</span> <span class=\"o\">=</span> <span class=\"s\">\"Excel file\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">file_types</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"s\">'Excel file'</span><span class=\"p\">,</span> <span class=\"s\">'*.xlsx'</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"s\">'all'</span><span class=\"p\">,</span> <span class=\"s\">'*.*'</span><span class=\"p\">)),</span>\n                        <span class=\"n\">save_as</span> <span class=\"o\">=</span> <span class=\"bp\">True</span><span class=\"p\">,</span>\n                     <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Column</span><span class=\"p\">(</span>\n            <span class=\"n\">layout</span><span class=\"o\">=</span><span class=\"p\">[</span>\n                      <span class=\"p\">[</span>\n                        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Button</span><span class=\"p\">(</span>  <span class=\"s\">\"Convert\"</span><span class=\"p\">,</span>\n                                    <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">),</span>\n                                 <span class=\"p\">),</span> \n                        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Button</span><span class=\"p\">(</span>  <span class=\"s\">\"Exit\"</span><span class=\"p\">,</span>\n                                    <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">),</span>\n                                 <span class=\"p\">),</span>\n                      <span class=\"p\">]</span>\n                    <span class=\"p\">],</span>\n            <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n            <span class=\"n\">expand_y</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n            <span class=\"n\">text_align</span><span class=\"o\">=</span><span class=\"s\">\"right\"</span><span class=\"p\">,</span>\n            <span class=\"n\">vertical_alignment</span><span class=\"o\">=</span><span class=\"s\">\"bottom\"</span><span class=\"p\">,</span>\n        <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n<span class=\"p\">]</span>\n\n\n<span class=\"c1\"># CSVファイルからexcelファイルへの変換処理をコールする\n</span><span class=\"k\">def</span> <span class=\"nf\">convert_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">):</span>\n    <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n\n    <span class=\"c1\"># パラメータエラーチェック\n</span>    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ファイルが指定されていない\n</span>        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"入力ファイルを指定してください\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># filedialog.askopenfilename()は存在するファイルしか選択できないが\n</span>    <span class=\"c1\"># エディットボックスを直接編集した場合のためにチェック\n</span>    <span class=\"k\">elif</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"入力ファイルを指定してください\"</span><span class=\"p\">,</span>  <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">output_filename</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ファイルが指定されていない\n</span>        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"出力ファイルを指定してください\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># この判定はfiledialog.asksaveasfilename()内で行うが\n</span>    <span class=\"c1\"># エディットボックスを直接編集した場合のためにチェック\n</span>    <span class=\"k\">elif</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">output_filename</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">ret</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup_ok_cancel</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"出力ファイルが存在します</span><span class=\"se\">\\n</span><span class=\"s\">上書きしますか?\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"確認\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span> <span class=\"k\">if</span> <span class=\"n\">ret</span> <span class=\"o\">==</span> <span class=\"s\">'OK'</span> <span class=\"k\">else</span> <span class=\"bp\">False</span>\n    <span class=\"k\">if</span> <span class=\"n\">execute_flag</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 変換処理\n</span>        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"c1\"># CSVファイルからエクセルファイルを作成\n</span>            <span class=\"n\">ketsuatsu_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">)</span>\n            <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"変換終了\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"終了\"</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"nb\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">e</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n\n    <span class=\"c1\"># 使用するフォントの設定\n</span>    <span class=\"n\">fonts</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">get_font_list</span><span class=\"p\">()</span>\n    <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n    <span class=\"n\">target_font_size</span> <span class=\"o\">=</span> <span class=\"n\">FONT_SIZE</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">FONT_NAME1</span> <span class=\"ow\">in</span> <span class=\"n\">fonts</span> <span class=\"p\">:</span>\n        <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"n\">FONT_NAME1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">FONT_NAME2</span> <span class=\"ow\">in</span> <span class=\"n\">fonts</span> <span class=\"p\">:</span>\n        <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"n\">FONT_NAME2</span>\n\n\n    <span class=\"c1\"># window create\n</span>    <span class=\"n\">window</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Window</span><span class=\"p\">(</span><span class=\"s\">'血圧 CSV->excel'</span><span class=\"p\">,</span> \n                        <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">600</span><span class=\"p\">,</span> <span class=\"mi\">150</span><span class=\"p\">),</span>\n                        <span class=\"n\">font</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">target_font_name</span><span class=\"p\">,</span> <span class=\"n\">target_font_size</span><span class=\"p\">),</span>\n                        <span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"n\">layout</span>\n                    <span class=\"p\">)</span>\n\n    <span class=\"c1\"># event loop\n</span>    <span class=\"k\">while</span> <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">is_alive</span><span class=\"p\">():</span>\n        <span class=\"n\">event</span><span class=\"p\">,</span> <span class=\"n\">values</span> <span class=\"o\">=</span> <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#\"</span><span class=\"p\">,</span> <span class=\"n\">event</span><span class=\"p\">,</span> <span class=\"n\">values</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">event</span> <span class=\"o\">==</span> <span class=\"s\">\"Exit\"</span> <span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">event</span> <span class=\"o\">==</span> <span class=\"s\">\"Convert\"</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># print(values)\n</span>            <span class=\"n\">input_filename</span>  <span class=\"o\">=</span> <span class=\"n\">values</span><span class=\"p\">[</span><span class=\"s\">'-csvfilepath-'</span><span class=\"p\">]</span>\n            <span class=\"n\">output_filename</span> <span class=\"o\">=</span> <span class=\"n\">values</span><span class=\"p\">[</span><span class=\"s\">'-excelfilepath-'</span><span class=\"p\">]</span>\n            <span class=\"n\">convert_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 終了\n</span>    <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n\n\n<span class=\"c1\"># ======================================================\n</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">main</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"未対応項目\">未対応項目</h1>\n<h2 id=\"ドラッグアンドドロップ\">ドラッグアンドドロップ</h2>\n<p>TkEasyGUI は ドラッグアンドドロップに対応していないので、作成したプログラムも未対応。<br />\nissueはあがっていて、作者さんも「It seems we could easily support」と言っているので、近いうちにサポートされるかも。</p>\n<ul>\n  <li><a href=\"https://github.com/kujirahand/tkeasygui-python/issues/7\" target=\"_blank\">Drag & Drop files #7</a></li>\n</ul>\n\n<h2 id=\"テーマの使用\">テーマの使用</h2>\n<p>TkEasyGUI は ttkの使用に対応しているが、使い方によってはうまく動かない。<br />\n(今回は <code class=\"language-plaintext highlighter-rouge\">eg.Column</code> の中の <code class=\"language-plaintext highlighter-rouge\">eg.Button</code> で  <code class=\"language-plaintext highlighter-rouge\">use_ttk_buttons=True</code>を指定したらエラーになった。<br />\nなにか条件があるのかもしれんが。)<br />\nとりあえず「お手軽にGUI」が目的なので、テーマで見た目に凝らなくてもいいか、と対応はあきらめた。</p>\n\n<h1 id=\"まとめ\">まとめ</h1>\n<p>さらっと触っただけだけど、tkinterをそのまま使うよりかなり分かりやすい。<br />\nが、ちょっと凝ったことをやろうとすると、できなかったりすることも。<br />\nその辺は必須かどうか見極めて、あきらめるか、tkinterで泥沼にハマってでも実現するかを決めるしかないか。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Renodeお試し</title>\n  </head>\n  <body>\n    <header>\n      <h1>Renodeお試し</h1>\n      <p>シミュレータ Renode を試してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>おいそれと評価ボードを買えないボンビーの味方、シミュレータ(エミュレータ)。<br />\n<a href=\"https://www.qemu.org/\" target=\"_blank\">QEMU</a>が有名だけど、\n最近は<a href=\"https://renode.io/\" target=\"_blank\">Renode</a>というのもあるらしい。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://wokwi.com/\" target=\"_blank\">wokwi</a>というのもある。<br />\n見た目がきれいで惹かれるけど、VScodeで実行する環境のライセンスが\nよく分からんかった(30日は無料らしいけど、その後無料で更新できるのか、有料になるのか読み取れなかった)<br />\n至れり尽くせりなのはイヤだという天邪鬼気質もあるけど…</p>\n</blockquote>\n\n<p>ということで、Renodeをちらっと試してみた時のメモ。</p>\n\n<p>Renodeのドキュメントは<a href=\"https://renode.readthedocs.io/en/latest/\" target=\"_blank\">https://renode.readthedocs.io/en/latest/</a>にあります<br />\nソースやリリースバイナリは<a href=\"https://github.com/renode/renode\" target=\"_blank\">Github</a>にあります。</p>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"環境\">環境</h2>\n<p>今回はWindows11上のWSLのUbuntu 22.04で試してみます。</p>\n\n<h2 id=\"renodeのインストール\">Renodeのインストール</h2>\n<p>インストール用バイナリは<a href=\"https://github.com/renode/renode/releases\" target=\"_blank\">github</a>\nや<a href=\"https://builds.renode.io\" target=\"_blank\">https://builds.renode.io</a>にあります。</p>\n\n<p>プラットフォームはmono版と.NET版がありますが、ここではmono版を使います。<br />\ndebファイルがあるので、aptでもインストールできますが、ここではポータブル版を使います。</p>\n\n<p>以下のように実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /proj\nwget https://builds.renode.io/renode-latest.linux-portable.tar.gz\n<span class=\"nb\">mkdir </span>renode_portable\n<span class=\"nb\">tar </span>xvf  renode-latest.linux-portable.tar.gz <span class=\"nt\">-C</span> renode_portable <span class=\"nt\">--strip-components</span><span class=\"o\">=</span>1\n</code></pre></div></div>\n\n<p>これで <code class=\"language-plaintext highlighter-rouge\">/proj/renode_portable</code> に必要なファイルが展開されます。<br />\nここにPATHを通すため、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># renodeのインストール先をpathに追加</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span>/proj/renode_portable:<span class=\"nv\">$PATH</span>\n</code></pre></div></div>\n\n<h2 id=\"renodeの依存パッケージのインストール\">renodeの依存パッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mono-devel policykit-1 libgtk2.0-0 screen uml-utilities gtk-sharp2 libc6-dev libicu-dev gcc python3 python3-pip\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nmonoのリポジトリを追加してインストールする情報が散見されるが、ubuntu22.04のaptリポジトリにはmono-develも入っているらしい。<br />\nなので、普通に<code class=\"language-plaintext highlighter-rouge\">apt install</code>だけでインストールできる。<br />\nただし、最新版が欲しい場合は以下でインストールする。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ca-certificates gnupg\n<span class=\"nb\">sudo </span>gpg <span class=\"nt\">--homedir</span> /tmp <span class=\"nt\">--no-default-keyring</span> <span class=\"nt\">--keyring</span> /usr/share/keyrings/mono-official-archive-keyring.gpg <span class=\"nt\">--keyserver</span> hkp://keyserver.ubuntu.com:80 <span class=\"nt\">--recv-keys</span> 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF\n<span class=\"nb\">echo</span> <span class=\"s2\">\"deb [signed-by=/usr/share/keyrings/mono-official-archive-keyring.gpg] https://download.mono-project.com/repo/ubuntu stable-focal main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/mono-official-stable.list\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mono-devel\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"gccのインストール\">gccのインストール</h2>\n<p>Renodeの実行自体にコンパイラは不要ですが、実行するバイナリを作成するのに必要なので、gccをインストールします。</p>\n\n<p>ダウンロードサイト:<a href=\"https://developer.arm.com/downloads/-/gnu-rm\" target=\"_blank\">ARM Developer GNU Arm Embedded Toolchain Downloads</a></p>\n\n<p>以下の手順でインストールします(ファイル名/ディレクトリ名はダウンロードしたバージョンに合わせて変更)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /proj\nwget https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz\n<span class=\"nb\">tar </span>xvf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz \n\n<span class=\"c\"># 依存パッケージのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libncursesw5\n</code></pre></div></div>\n\n<p>PATHを通すため、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># arm-gccのインストール先をpathに追加</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span>/proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin:<span class=\"nv\">$PATH</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンパイラだけなら<code class=\"language-plaintext highlighter-rouge\">apt install gcc-arm-none-eabi</code>でインストールできますが、\ngdbが入ってないので上のサイトからダウンロードして使用します。</p>\n</blockquote>\n\n<h2 id=\"その他インストール\">その他インストール</h2>\n<p>ターゲットプログラムのbuild時にcmakeも使用するのでインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n</code></pre></div></div>\n\n<h1 id=\"デモの実行\">デモの実行</h1>\n<p>ドキュメントの<a href=\"https://renode.readthedocs.io/en/latest/introduction/demo.html\" target=\"_blank\">Running your first demo</a>\nにしたがって実行してみます。</p>\n\n<p>renodeを起動します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode\n</code></pre></div></div>\n\n<p>renodeウィンドウが開くのでそこで以下を入力</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>s @scripts/single-node/stm32f4_discovery.resc\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i @scripts/single-node/stm32f4_discovery.resc\ns\n</code></pre></div>  </div>\n  <p>と実行しても可。<br />\n<code class=\"language-plaintext highlighter-rouge\">i</code>は<code class=\"language-plaintext highlighter-rouge\">include</code>のalias<br />\n<code class=\"language-plaintext highlighter-rouge\">s</code>は<code class=\"language-plaintext highlighter-rouge\">start</code>のalias</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nrenode起動時に以下のようにパラメータとしてrescファイルを指定することもできます。<br />\nこれはincludeコマンドを実行するのと同義(というか起動時にincludeコマンドが実行されている)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode /proj/renode_portable/scripts/single-node/stm32f4_discovery.resc\n</code></pre></div>  </div>\n  <p>rescファイルのパスは絶対パス/カレントディレクトリからの相対パスで指定可能。<br />\n<code class=\"language-plaintext highlighter-rouge\">@</code>を使ったrenodeインストールディレクトリからの相対パスは指定不可。</p>\n</blockquote>\n\n<p>プログラムが実行されると uart4ウィンドウが開いてなにやら色々表示されます。</p>\n\n<p>renodeウィンドウで<code class=\"language-plaintext highlighter-rouge\">quit</code>と入力する(CTRL+Dでも可)と終了します。</p>\n\n<h2 id=\"おまけ\">おまけ</h2>\n<h3 id=\"その1\">その1</h3>\n<p>renodeウィンドウが見難かったら以下のように<code class=\"language-plaintext highlighter-rouge\">-P</code>オプションでポート番号を指定して実行し、</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode <span class=\"nt\">-P</span> 1234\n</code></pre></div></div>\n\n<p>他のターミナルから以下のように実行すると普段使っているターミナルから制御できます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>telnet localhost 1234\n</code></pre></div></div>\n\n<h3 id=\"その2\">その2</h3>\n<p>renode起動時に<code class=\"language-plaintext highlighter-rouge\">--console</code> オプションを指定すると、起動したターミナルがコンソールになります。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode <span class=\"nt\">--cnsole</span>\n</code></pre></div></div>\n<p>ログが同じターミナルに表示されるので見難くなったりするかもしれんけど</p>\n\n<h1 id=\"vscodeでデバッグ\">VScodeでデバッグ</h1>\n\n<p><a href=\"https://renode.readthedocs.io/en/latest/debugging/vscode.html\" target=\"_blank\">ドキュメント</a>\nの説明は分かり難いので、解説記事\n<a href=\"https://medium.com/@pc0is0me/getting-started-with-stm32f4-emulation-using-renode-f6cb158d27d1\" target=\"_blank\">Getting Started with STM32F4 Emulation using Renode</a>\nの手順を試してみます。</p>\n\n<h2 id=\"サンプルのリポジトリをclone\">サンプルのリポジトリをclone</h2>\n\n<p>まずはリポジトリをcloneします。<br />\n適当なディレクトリで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/PhanCuong91/data.git\n</code></pre></div></div>\n\n<h2 id=\"とりあえず動作確認\">とりあえず動作確認</h2>\n\n<p>VScodeでデバッグする前にターゲットプログラムのbuildが行えるか、\nbuildしたバイナリが実行できるか確認しておきます。<br />\nプログラムのbuildは以下のコマンドで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>data/renode\nbash build.bat\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nbatファイルなので、Windowsのバッチファイルですが、\n中身はLinuxでもそのまま実行できる内容なので、\nそのままシェルスクリプトとして実行します。</p>\n</blockquote>\n\n<p>こんな感じでbuildが実行されます。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Release build.\n-- The C compiler identification is GNU 13.3.1\n-- The CXX compiler identification is GNU 13.3.1\n-- The ASM compiler identification is GNU\n-- Found assembler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc\n-- Detecting C compiler ABI info\n-- Detecting C compiler ABI info - done\n-- Check for working C compiler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc - skipped\n-- Detecting C compile features\n-- Detecting C compile features - done\n-- Detecting CXX compiler ABI info\n-- Detecting CXX compiler ABI info - done\n-- Check for working CXX compiler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-g++ - skipped\n-- Detecting CXX compile features\n-- Detecting CXX compile features - done\n-- Configuring done\n-- Generating done\n-- Build files have been written to: /work/data/renode/build\n</code></pre></div></div>\n\n<p>正常にbuildできていれば<code class=\"language-plaintext highlighter-rouge\">build/src/STM32F4Template.elf</code>が出来ています。</p>\n\n<p>renodeを実行し、renodeターミナルで以下のように入力し、プログラムを実行します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mach create\nmachine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl\nsysbus LoadELF @/work/data/renode/build/src/STM32F4Template.elf \nshowAnalyzer sysbus.usart2\nstart\n</code></pre></div></div>\n\n<p>UART2ウィンドウに以下のように表示されればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Hello World!\n</code></pre></div></div>\n\n<p>確認したらrenodeを終了します。</p>\n\n<p>次の作業に備えて、buildディレクトリを削除(またはrename)しておきます。</p>\n\n<h2 id=\"vscodeでのデバッグ\">VScodeでのデバッグ</h2>\n\n<h3 id=\"rescファイルの修正\">rescファイルの修正</h3>\n<p>フルパスで記述されている部分を修正します。</p>\n\n<p>修正内容は以下。<br />\n<code class=\"language-plaintext highlighter-rouge\">$ORIGIN</code>を使用してrescファイルからの相対パス指定に変更。<br />\nこれにより、ダブルクォーテーションで囲む必要はなくなる。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/renode/renode-config.resc b/renode/renode-config.resc\nindex 2729cd1..fcb4f34 100644\n</span><span class=\"gd\">--- a/renode/renode-config.resc\n</span><span class=\"gi\">+++ b/renode/renode-config.resc\n</span><span class=\"p\">@@ -2,8 +2,8 @@</span>\n :description: This script runs the usart_printf example on stm32f4 discovery\n\n $name?=\"STM32F4_Discovery\"\n<span class=\"gd\">-$cmm_repl?=\"C:\\working\\data\\renode\\add-ccm.repl\"\n-$bin_path?=\"C:\\working\\data\\renode\\build\\src\\STM32F4Template.elf\"\n</span><span class=\"gi\">+$cmm_repl?=$ORIGIN/add-ccm.repl\n+$bin_path?=$ORIGIN/build/src/STM32F4Template.elf\n</span>\n # create Socket Terminal for UART\n emulation CreateServerSocketTerminal 3456 \"term\" false\n</code></pre></div></div>\n\n<h3 id=\"buildスクリプトに実行属性を付与\">buildスクリプトに実行属性を付与</h3>\n<p>元がwindows用なので、linuxで実行できるように実行属性を付与します。<br />\n中身はそのまま。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod</span> +x build-debug.bat\n</code></pre></div></div>\n\n<h3 id=\"vscodeを起動\">VScodeを起動</h3>\n<p>ホストOS側のVScodeを起動します。<br />\nWSLなので、ターミナルから以下のコマンドで起動してカレントディレクトリを開きます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>code <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"vscodeの拡張機能のインストール\">VScodeの拡張機能のインストール</h3>\n<p>VScodeの拡張機能で</p>\n<ul>\n  <li>C/C++ Extension Pack をインストールします</li>\n  <li>念のため、CMakeを無効化しておきます</li>\n</ul>\n\n<h3 id=\"実行\">実行</h3>\n\n<p>エクスプローラサイドパネルから<code class=\"language-plaintext highlighter-rouge\">src/main.c</code>を開き、<code class=\"language-plaintext highlighter-rouge\">main()</code> のどこかにブレークポイントを設定。<br />\nデバッグサイドパネルで 「Debug application in Renode」 を選んで実行。<br />\nRenoteターミナルとUART2ウィンドウが開き、設定したブレークポイントで停止するはず。<br />\n実行を再開すると、UART2ウィンドウに<code class=\"language-plaintext highlighter-rouge\">Hello World!</code>と表示され、無限ループに入る。</p>\n\n<h1 id=\"renode-interactive-visualization-example\">Renode interactive visualization example</h1>\n<p>組み込みプログラムなので、ターゲットボードの動作を目で見たくなるのが人情…<br />\nということで、Renode interactive visualization exampleを実行してみます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nWSLのネットワークモードは mirrored にしておきます\n(ほかのモードでも動くかもしれんけど、試してないので)</p>\n</blockquote>\n\n<p><a href=\"https://github.com/antmicro/renode-board-visualization\" target=\"_blank\">github</a>\nからソースを取得します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/antmicro/renode-board-visualization.git\n<span class=\"nb\">cd </span>renode-board-visualization/\n</code></pre></div></div>\n\n<p>Renodeを実行します。<br />\n(バイナリファイルがあるのでbuildは不要。というよりソースファイルはない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode scripts/blinky.resc\n</code></pre></div></div>\n\n<p>rescファイルに<code class=\"language-plaintext highlighter-rouge\">start</code>コマンドが書いてあるので、\n起動と同時にターゲットプログラムが実行されます。</p>\n\n<p>renodeを起動したターミナルにはGPIOアクセスのログが以下のように表示されます。<br />\n(ログが表示されるか否かはPeripheralのエミュレーションプログラムによるので、\nどのCPUても表示されるわけではありません)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>11:28:31.6894 [NOISY] gpio0: Setting pin 24 output to False\n11:28:32.6891 [NOISY] gpio0: Setting pin 24 output to True\n11:28:33.6891 [NOISY] gpio0: Setting pin 24 output to False\n11:28:34.6892 [NOISY] gpio0: Setting pin 24 output to True\n11:28:35.6892 [NOISY] gpio0: Setting pin 24 output to False\n</code></pre></div></div>\n\n<p>renodeコンソールで以下のコマンドを実行します。<br />\nこれによりWebサーバが起動します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>serveVisualization 8000\n</code></pre></div></div>\n\n<p>ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページが表示され、ボード左上のLED(赤色)が点滅しているのが確認できます。</p>\n\n<p>Webサーバを停止するため、renodeコンソールで以下のコマンドを実行します。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>stopVisualization\n</code></pre></div></div>\n\n<p>Renodeを終了します。</p>\n<blockquote>\n  <p>[!NOTE]\nWebサーバを停止せずにRenodeを終了しても構いません。<br />\n停止せずに終了すると終了時に python で たくさんEXCEPTIONが起こるので\n気持ち悪い人はWebサーバを停止してから終了しましょう。</p>\n</blockquote>\n\n<h1 id=\"自分の環境を作ってみた\">自分の環境を作ってみた</h1>\n\n<p>以上を踏まえて、一通り作ってみました。<br />\n(公式サンプルにはターゲットプログラムのソースがないので、\nソースからビルドする部分も含めて試してみたかった)</p>\n\n<p>作った環境はgithubに登録しておきました。<br />\n<a href=\"https://github.com/ippei8jp/renode_my_sample\" target=\"_blank\">https://github.com/ippei8jp/renode_my_sample</a></p>\n\n<h2 id=\"リポジトリのクローン\">リポジトリのクローン</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/ippei8jp/renode_my_sample.git\n<span class=\"nb\">cd </span>renode_my_sample\n</code></pre></div></div>\n<h3 id=\"ソース構成\">ソース構成</h3>\n<p>srcディレクトリ下がプログラムソースです。</p>\n\n<h4 id=\"mainc\">main.c</h4>\n<p>メインルーチンと割り込みハンドラなど。</p>\n\n<h4 id=\"syscallsc\">syscalls.c</h4>\n<p>printf/scanfなどを使用するためのsyscallルーチンを定義。<br />\nコンソール入出力のための最低限の処理だけを定義しています。</p>\n\n<h4 id=\"startup_stm32f40_41xxxs\">startup_stm32f40_41xxx.s</h4>\n<p>bootルーチン、ベクタテーブル、デフォルト割り込みハンドラなど。</p>\n\n<h4 id=\"system_stm32f4xxc\">system_stm32f4xx.c</h4>\n<p>初期化処理(C言語部)</p>\n\n<h4 id=\"cmakeliststxt\">CMakeLists.txt</h4>\n<p>cmake処理定義ファイル。<br />\nソースファイルを追加したときなどはここに追加していく。</p>\n\n<h3 id=\"ビルド実行\">ビルド&実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake ..\nmake\n<span class=\"nb\">cd</span> ..\nrenode script/renode-config.resc\n</code></pre></div></div>\n\n<h3 id=\"ブラウザで接続\">ブラウザで接続</h3>\n<p>GUI部品を表示するため、ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページにLEDとスイッチが表示されます。</p>\n\n<h3 id=\"ターゲットプログラム実行\">ターゲットプログラム実行</h3>\n<p>renodeターミナルで<code class=\"language-plaintext highlighter-rouge\">start</code>コマンドを実行するとターゲットプログラムが実行されます。</p>\n\n<h3 id=\"ブラウザの表示\">ブラウザの表示</h3>\n<p>ターゲットプログラムの動作に応じてLEDが順次点灯/消灯していきます。\nスイッチをクリックするとON/OFFがトグルします。<br />\nこのスイッチの情報はターゲットプログラムのメインループで表示されます。<br />\nまたON時は割り込みハンドラが起動され、UARTコンソールに割り込みメッセージが表示されます。</p>\n\n<h3 id=\"renode終了\">Renode終了</h3>\n<p>renodeターミナルで<code class=\"language-plaintext highlighter-rouge\">quit</code>コマンドを実行して Renodeを終了します。</p>\n\n<h2 id=\"vscodeでデバッグ-1\">VScodeでデバッグ</h2>\n\n<p>VScodeでデバッグする前にbuildディレクトリを削除しておいてください。</p>\n\n<h3 id=\"vscodeでcloneしたディレクトリを開く\">VScodeでcloneしたディレクトリを開く</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>code <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"ビルド\">ビルド</h3>\n<p>VSCodeで</p>\n<ul>\n  <li>cmakeサイドパネルを開く\n    <ul>\n      <li>「構成」右側のアイコンをクリックし、「GCC XX.X.X arm-noen-eabi」選択\n        <ul>\n          <li>cmakeが実行される</li>\n        </ul>\n      </li>\n      <li>「ビルド」右側のアイコンをクリックしbuid実行\n        <ul>\n          <li>makeが実行される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>実行とデバッグサイドパネルを開く\n    <ul>\n      <li>Debug application in Renode を選んで実行</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ブラウザで接続-1\">ブラウザで接続</h3>\n<p>GUI部品を表示するため、ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページにLEDとスイッチが表示されます。</p>\n\n<h3 id=\"ブラウザの表示-1\">ブラウザの表示</h3>\n<p>ターゲットプログラムの動作に応じてLEDが順次点灯/消灯していきます。\nスイッチをクリックするとON/OFFがトグルします。<br />\nこのスイッチの情報はターゲットプログラムのメインループで表示されます。<br />\nまたON時は割り込みハンドラが起動され、UARTコンソールに割り込みメッセージが表示されます。</p>\n\n<h3 id=\"デバッグ\">デバッグ</h3>\n<p>デバッグは他の環境と同じなので、ここでは何も書きません。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tkinter で スクロール可能なcanvasを作る</title>\n  </head>\n  <body>\n    <header>\n      <h1>tkinter で スクロール可能なcanvasを作る</h1>\n      <p>tkinter で スクロール可能なcanvasを作る</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>tkinterでスクロール可能なcanvasのクラス<code class=\"language-plaintext highlighter-rouge\">ScrollableCanvas</code>を作ってみました。<br />\nぶっちゃけ、あちこちにその手の記事はあるのですが、なんか自分のコーディングスタイルとあってないの気がしたので\n微妙に書き換えてみました。</p>\n\n<h1 id=\"サンプルプログラム\">サンプルプログラム</h1>\n\n<p>さっそくサンプルプログラムを貼りつけておきます。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/0ccd48b5cec72ad363d7eaa452972b1f.js\"></script>\n</dev>\n\n<h2 id=\"解説のようなもの\">解説のようなもの</h2>\n\n<h3 id=\"canvas-を継承した-scrollablecanvas-クラス\">canvas を継承した ScrollableCanvas クラス</h3>\n<p>ネット上にある例では、Frameクラスを継承してその下にcanvasを貼り付けているものが多いですが、\nなんとなく余分なウィジェットを作りたくない気分だったのでCanvasクラスを継承するようにしてみました。<br />\nまた、コンストラクタ中でpackしている例が多かったですが、配置の自由度を上げるため上位側に任せるようにしました。</p>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>今回は縦スクロールのみ対応なので、canvasの幅はあらかじめ指定しておくようにしてあります。<br />\nまた、表示するウィジェットを配置するためのフレーム(<code class=\"language-plaintext highlighter-rouge\">child_frame</code>)は幅を自由に設定できるようにすると\n親ウィジェットであるcanvasの幅まで大きくなりますが、これだとスクロールバーが見えなくなります。<br />\nそこで、<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の幅はcanvasの幅からスクロールバーの幅を差し引いたサイズを設定しています。</p>\n\n<blockquote>\n  <p>[!NOTE]\n縦横スクロール可能にした場合は このあたり見直さないといけないかもしれない。</p>\n</blockquote>\n\n<p>また、マウスドラッグによるスクロールをスムーズにするため、スクロール量(<code class=\"language-plaintext highlighter-rouge\">yscrollincrement</code>)のデフォルトを1に設定しています。\nこれはScrollableCanvasクラスのインスタンスを生成する際に変更することができます。</p>\n\n<h3 id=\"ウィンドウイベント\">ウィンドウイベント</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">\"<Configure>\"</code> イベントをbindすることで、ウィンドウが移動されたり、リサイズされたりしたときに実行する処理を割り当てています。<br />\n<code class=\"language-plaintext highlighter-rouge\">\"<Configure>\"</code> イベントはウィンドウのリサイズ等だけでなく、pack()等でFrameのサイズが変更されたときも通知されます。</p>\n\n<p>ここではスクロール範囲の再設定を行っています。</p>\n\n<h3 id=\"マウスイベント\">マウスイベント</h3>\n\n<p>マウスイベントのbindは\n<a href=\"/memoBlog/2024/09/14/tkinter_event_1.html\" target=\"_blank\">tkinter で 低層のウィジェットでイベントを検出する</a>\nの方法を使用しています。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>操作</th>\n      <th>処理</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>左クリック</td>\n      <td>ドラッグ開始位置の設定</td>\n    </tr>\n    <tr>\n      <td>左クリック→マウス移動</td>\n      <td>縦方向の移動量に応じたスクロール</td>\n    </tr>\n    <tr>\n      <td>左ダブルクリック</td>\n      <td>子ウィジェットの追加</td>\n    </tr>\n    <tr>\n      <td>ホイール</td>\n      <td>縦方向スクロール</td>\n    </tr>\n    <tr>\n      <td>右クリック</td>\n      <td>子ウィジェットの全削除</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"実は\">実は…</h3>\n\n<p>右クリックで子ウィジェットを全削除した際、<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の高さは削除前の高さのままになっています。<br />\nつまり、なにもないフレームをスクロールできる状態になっています。<br />\n次に左ダブルクリックでウィジェットを追加したときに1ジェット1個分の高さに変更されます。<br />\nこの仕様が気持ち悪くて色々試したのですが、うまくいきませんでした。<br />\nそこで、「cleard」と表示して<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の高さを変更して誤魔化しています。<br />\n子ウィジェットの差し替えしかしないのであれば特に気にしなくても良い部分だと思います。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tkinter で 低層のウィジェットでイベントを検出する</title>\n  </head>\n  <body>\n    <header>\n      <h1>tkinter で 低層のウィジェットでイベントを検出する</h1>\n      <p>tkinter で 低層のウィジェットでイベントを検出する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>tkinterでイベントを検出する際、対象のウィジェットの手前に別のウィジェットがあるとイベントを検出できません。<br />\nそれを回避し、手前にウィジェットが存在してもイベントが検出できるサンプルプログラムを書いてみました。</p>\n\n<h1 id=\"サンプルプログラム\">サンプルプログラム</h1>\n\n<p>さっそくサンプルプログラムを貼りつけておきます。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/59faf9f974e22d34a8e988954a32518b.js\"></script>\n</dev>\n\n<h2 id=\"解説のようなもの\">解説のようなもの</h2>\n\n<h3 id=\"canvasにバインドしたイベントハンドラ\">canvasにバインドしたイベントハンドラ</h3>\n\n<p>以下の部分が普通にcanvasにマウスクリックイベントをバインドしている部分です。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">test_canvas</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"s\">'<ButtonPress-1>'</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_on_click_canvas</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>canvas上(水色の部分)でクリックすると<code class=\"language-plaintext highlighter-rouge\">_on_click_canvas</code>が実行され、\n<code class=\"language-plaintext highlighter-rouge\">_on_click_canvas : click on canvas</code>と表示されます。<br />\nしかし、その上に配置されたラベル(labex_1x)上でクリックしたときは表示されません。</p>\n\n<p>labelもcanvasの一部なので、ここでもクリック処理が動いてほしいことはよくあると思います。</p>\n\n<h3 id=\"rootにバインドしたイベントハンドラ\">rootにバインドしたイベントハンドラ</h3>\n\n<p>そこで、以下の部分でrootにマウスクリックイベントをバインドします。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">winfo_toplevel</span><span class=\"p\">().</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"s\">'<ButtonPress-1>'</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_on_click</span><span class=\"p\">,</span> <span class=\"s\">\"+\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>これはrootにバインドされたイベントですから、当然canvas以外の部分でも処理が動きます。<br />\nそこで、イベントハンドラでマウス座標を取得し、canvasの範囲内かを確認し、\nそうであればクリック処理(ここでは<code class=\"language-plaintext highlighter-rouge\">_on_click : click on canvas</code>を表示)を実行します。<br />\nパラメータの最後の<code class=\"language-plaintext highlighter-rouge\">\"+\"</code>は、既にバインドされているハンドラがあった時、上書きせずに追加することを指定しています。<br />\n(つまり、以前にバインドしたハンドラと今回のハンドラ両方が実行されます)</p>\n\n<p>こちらの処理はcanvas上(水色の部分)でクリックしたときも\nその上に配置されたラベル(labex_1x)上でクリックしたときもクリック処理が実行されます。</p>\n\n<p>なお、イベントハンドラに渡されるパラメータ<code class=\"language-plaintext highlighter-rouge\">event</code>の<code class=\"language-plaintext highlighter-rouge\">event.x</code>、<code class=\"language-plaintext highlighter-rouge\">event.y</code>はウィジェット内の相対座標なので\n比較には<code class=\"language-plaintext highlighter-rouge\">event.x_root</code>、<code class=\"language-plaintext highlighter-rouge\">event.y_root</code>を使用して画面上の座標を使用します。<br />\n当然比較するcanvasの座標も<code class=\"language-plaintext highlighter-rouge\">widget.winfo_rootx()</code>、<code class=\"language-plaintext highlighter-rouge\">widget.winfo_rooty()</code>で画面上の座標を使用しなければなりません。</p>\n\n<h3 id=\"おまけ\">おまけ</h3>\n\n<p>おまけとして、ダブルクリックした位置に存在するウィジェットの一覧を表示する処理を入れておきました(<code class=\"language-plaintext highlighter-rouge\">_on_doubleclick</code>) 。<br />\nダブルクリックに意味はなく、クリックは既に使っていたのでダブルクリックにしただけです。</p>\n\n<blockquote>\n  <p>おーちゃくせずに別のプログラム書けよ > 自分</p>\n</blockquote>\n\n<h3 id=\"ふと思ったこと\">ふと思ったこと</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">event.widget</code> から 順に <code class=\"language-plaintext highlighter-rouge\">master</code> をたどって行き、対象のウィジェットが見つかるかで判断する方法もあるなぁ…<br />\nrootの <code class=\"language-plaintext highlighter-rouge\">master</code> は <code class=\"language-plaintext highlighter-rouge\">None</code> なのでそこでサーチ終了。<br />\nどっちが簡単かな…</p>\n\n<h3 id=\"ふと思ったこと-その2\">ふと思ったこと その2</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">bind</code>するときに、.winfo_children() を再帰的にサーチしてすべての子ウィジェットにbindしていく、という手もあるなぁ。<br />\nいっぱいウィジェット配置してるとえらいことになるかもしれんけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) でI2C Slave その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) でI2C Slave その2</h1>\n      <p>Raspberry Pi Pico W の SDK を使用してI2C Slaveプログラムを作成する(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/10/28/RasPiPico_i2c_slave.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) でI2C Slave</a>\nでI2Cスレーブのプログラムを載せましたが、ちょっと特殊な構成のデバイスをエミュレートしていたので\n一般的なレジスタアクセスをエミュレートするプログラムを作ってみました。</p>\n\n<blockquote>\n  <p>[!NOTE]\n公式サンプル<code class=\"language-plaintext highlighter-rouge\">pico-examples/i2c/slave_mem_i2c</code>をちょこっと修正しただけですが。</p>\n</blockquote>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"i2cの結線\">I2Cの結線</h2>\n\n<p>以下のように結線します。<br />\nPico側はソース中の割り当て端子を変更すれば別の端子でもOKです。<br />\n今回はI2C0とI2C1を使うので、両方結線します。<br />\npull-up抵抗はPi3についているのでここでは付けません。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>Pi3</th>\n      <th>Pico</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>SDA1(pin3)</td>\n      <td>I2C0_SDA/GP16(Pin21) I2C1_SDA/GP18(Pin24)</td>\n    </tr>\n    <tr>\n      <td>SCL1(pin5)</td>\n      <td>I2C0_SCL/GP17(Pin22) I2C1_SCL/GP19(Pin25)</td>\n    </tr>\n  </tbody>\n</table>\n\n<blockquote>\n  <p>[!NOTE]\n別に2ch使わなくても良いのですが、8bitアクセスと16bitアクセスを作りたかったので。<br />\nそれぞれ別のプログラムにすると動作確認が面倒だったのでまとめちゃいました。</p>\n</blockquote>\n\n<p>その他の準備は\n<a href=\"/memoBlog/2023/10/28/RasPiPico_i2c_slave.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) でI2C Slave</a>\nを参照してください。</p>\n\n<h1 id=\"picoのプログラム\">Picoのプログラム</h1>\n\n<h2 id=\"プロジェクト生成\">プロジェクト生成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">pico_project</code>でプロジェクトを生成します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">pico_project</code>については、\n<a href=\"/memoBlog/2023/10/23/RasPiPico_3.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</a>\nの「自作プロジェクトの作成」を参照してください)</p>\n</blockquote>\n\n<p>設定内容は以下の通りです</p>\n\n<ul>\n  <li>Project Name に プロジェクト名(例:i2c_slave_2ch)</li>\n  <li>Location に プロジェクトを作成するディレクトリ</li>\n  <li>Board Type で「pico_w」を選択</li>\n  <li>Library Options で「I2C interface」を選択</li>\n  <li>Pico wireless Options で「PicoW onboard LED」を選択</li>\n  <li>Console Options では必要な方式をチェック(両方でも可)</li>\n  <li>IDE Options で「Create VSCode Project」にチェック、「Debugger」は「SWD」を選択</li>\n</ul>\n\n<h2 id=\"プログラムの作成\">プログラムの作成</h2>\n<p>作成したプログラムを以下に示します。</p>\n\n<h3 id=\"メインルーチン\">メインルーチン</h3>\n\n<p>メインルーチンはI2Cを初期化したあと無限ループします。<br />\nループ内ではI2Cに関する処理はなく、生存確認用のLチカと\nキー入力監視して入力に応じて処理を行っています。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_2ch.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/stdlib.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"hardware/i2c.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/cyw43_arch.h\"</span><span class=\"cp\">\n</span>\n<span class=\"c1\">// プロトタイプ宣言</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n\n\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n\n\n<span class=\"kt\">int64_t</span> <span class=\"nf\">alarm_callback</span><span class=\"p\">(</span><span class=\"n\">alarm_id_t</span> <span class=\"n\">id</span><span class=\"p\">,</span> <span class=\"kt\">void</span> <span class=\"o\">*</span><span class=\"n\">user_data</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// Put your timeout handler code in here</span>\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"kt\">int</span> <span class=\"nf\">main</span><span class=\"p\">()</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">stdio_init_all</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// STDIOがUSBのとき、USB認識されないことがあるのでstdio初期化の後、ちょっと待つ</span>\n    <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">3000</span><span class=\"p\">);</span>\n\n    <span class=\"n\">puts</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">I2C slave 2ch\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// LEDを使うためにwifi初期化</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">cyw43_arch_init</span><span class=\"p\">())</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"Wi-Fi init failed\"</span><span class=\"p\">);</span>\n        <span class=\"k\">return</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\">// I2Cスレーブ 初期化</span>\n    <span class=\"n\">setup_i2c_slave0</span><span class=\"p\">();</span>\n    <span class=\"n\">setup_i2c_slave1</span><span class=\"p\">();</span>\n    \n\n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// ==== 生存確認用にLチカ ====</span>\n        <span class=\"c1\">// 現在の出力値取得</span>\n        <span class=\"n\">bool</span> <span class=\"n\">led_out</span> <span class=\"o\">=</span> <span class=\"n\">cyw43_arch_gpio_get</span> <span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">);</span>\n        <span class=\"c1\">// 出力反転</span>\n        <span class=\"n\">cyw43_arch_gpio_put</span><span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">,</span> <span class=\"o\">!</span><span class=\"n\">led_out</span><span class=\"p\">);</span>\n\n        <span class=\"c1\">// キー入力監視</span>\n        <span class=\"kt\">int</span> <span class=\"n\">key_in</span> <span class=\"o\">=</span>  <span class=\"n\">getchar_timeout_us</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'D'</span><span class=\"p\">)</span> <span class=\"o\">||</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'d'</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// 表示モード反転</span>\n            <span class=\"n\">DISP_flag</span> <span class=\"o\">=</span> <span class=\"o\">!</span><span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"**** DISP on ****</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"**** DISP off ****</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'0'</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// slave0データ表示</span>\n            <span class=\"n\">disp_data_slave0</span><span class=\"p\">();</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'1'</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// slave1データ表示</span>\n            <span class=\"n\">disp_data_slave1</span><span class=\"p\">();</span>\n        <span class=\"p\">}</span>\n\n\n        <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">1000</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"i2c0処理\">I2C0処理</h3>\n\n<h4 id=\"初期化\">初期化</h4>\n<p>I2C0の初期化は<code class=\"language-plaintext highlighter-rouge\">setup_i2c_slave0</code>です。<br />\n主に端子の初期化とI2C0の初期化、\nI2Cスレーブの初期化(I2C割り込みハンドラからのコールバックの登録)を行っています。</p>\n\n<p>読み書きするデータは1アドレスあたり8bitとしています。</p>\n\n<h4 id=\"処理本体\">処理本体</h4>\n<p>I2C0処理本体は<code class=\"language-plaintext highlighter-rouge\">i2c_slave0_handler()</code>です。</p>\n\n<p>これはI2C割り込みハンドラからのコールバック処理です。<br />\nなので、できるだけ速やかにリターンする必要があります。\nprintfなどの時間のかかる処理は行わないほうが良いのですが、\nデバッグ用途に送受信データを表示したいのでprintfで表示しています。<br />\nprintfをなくして高速に応答できるように、フラグを使用してprintfの有効/無効化を行っています。<br />\nフラグはメインルーチンでコンソールからのキー入力で切り替えています。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave0.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/rand.h></span><span class=\"c1\">      // 乱数</span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"k\">extern</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">16</span><span class=\"p\">;</span>  <span class=\"c1\">//GP16(Pin21)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">17</span><span class=\"p\">;</span>  <span class=\"c1\">//GP17(Pin22)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">256</span><span class=\"p\">];</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>\n    <span class=\"n\">bool</span> <span class=\"n\">mem_address_written</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"== ch0 ==  addr : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"mh\">0xff</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">+=</span><span class=\"mh\">0x10</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"%02x : %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">14</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">get_rand_32</span><span class=\"p\">();</span>        <span class=\"c1\">// 乱数で初期化</span>\n    <span class=\"p\">}</span>\n    <span class=\"c1\">// アドレス初期化</span>\n    <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではないけど使っちゃお...</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave0_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// STOP/RESTART後の最初の書き込みはアドレス更新</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 set memory address : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// メモリ内容書き換え</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 write memory : %02x : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// メモリから1バイト送信する</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">];</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 read memory : %02x : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// 次の書き込みはアドレス更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 STOP/RESTART condition</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch0</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave0_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch0 done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"i2c1処理\">I2C1処理</h3>\n\n<p>I2C1は読み書きするデータが1アドレスあたり16bitとしていることを除けばI2C0と同じです。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave1.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/rand.h></span><span class=\"c1\">      // 乱数</span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"k\">extern</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x32</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">18</span><span class=\"p\">;</span>  <span class=\"c1\">//GP18(Pin24)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">19</span><span class=\"p\">;</span>  <span class=\"c1\">//GP19(Pin25)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">512</span><span class=\"p\">];</span>\n    <span class=\"kt\">uint16_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>\n    <span class=\"n\">bool</span> <span class=\"n\">mem_address_written</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"== ch1 ==  addr : %02x  %s</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">);</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"mh\">0x200</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">+=</span><span class=\"mh\">0x10</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"%03x : %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">14</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">get_rand_32</span><span class=\"p\">();</span>        <span class=\"c1\">// 乱数で初期化</span>\n    <span class=\"p\">}</span>\n    <span class=\"c1\">// アドレス初期化</span>\n    <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではないけど使っちゃお...</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave1_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// STOP/RESTART後の最初の書き込みはアドレス更新</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint16_t</span><span class=\"p\">)</span><span class=\"n\">addr</span> <span class=\"o\">*</span> <span class=\"mi\">2</span><span class=\"p\">;</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 set memory address : %02x(%03x)</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// メモリ内容書き換え</span>\n            <span class=\"kt\">uint16_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n            <span class=\"p\">}</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 write memory : %02x %s : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span>  <span class=\"n\">addr</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// メモリから1バイト送信する</span>\n        <span class=\"kt\">uint16_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"p\">}</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">];</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 read memory : %02x %s : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span>  <span class=\"n\">addr</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// 次の書き込みはアドレス更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 STOP/RESTART condition</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch1</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c1</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c1</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE1_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave1_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch1 done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n</code></pre></div></div>\n\n<h3 id=\"cmake設定ファイル\">cmake設定ファイル</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>の\n<code class=\"language-plaintext highlighter-rouge\">add_executable</code> に <code class=\"language-plaintext highlighter-rouge\">i2c_slave0.c</code>と<code class=\"language-plaintext highlighter-rouge\">i2c_slave1.c</code>(追加したファイル名)を追加します。<br />\n<code class=\"language-plaintext highlighter-rouge\">target_link_libraries</code> に <code class=\"language-plaintext highlighter-rouge\">pico_i2c_slave</code>(I2Cスレーブを使用)と<code class=\"language-plaintext highlighter-rouge\">pico_rand</code>(乱数を使用)を追加します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  CMakeLists.txt\n</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># Generated Cmake Pico project file</span>\n\n<span class=\"nb\">cmake_minimum_required</span><span class=\"p\">(</span>VERSION 3.13<span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_C_STANDARD 11<span class=\"p\">)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_CXX_STANDARD 17<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise pico_sdk from installed location</span>\n<span class=\"c1\"># (note this can come from environment, CMake cache etc)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_SDK_PATH <span class=\"s2\">\"/work/pico/pico-sdk\"</span><span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_BOARD pico_w CACHE STRING <span class=\"s2\">\"Board type\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># Pull in Raspberry Pi Pico SDK (must be before project)</span>\n<span class=\"nb\">include</span><span class=\"p\">(</span>pico_sdk_import.cmake<span class=\"p\">)</span>\n\n<span class=\"nb\">if</span> <span class=\"p\">(</span>PICO_SDK_VERSION_STRING VERSION_LESS <span class=\"s2\">\"1.4.0\"</span><span class=\"p\">)</span>\n  <span class=\"nb\">message</span><span class=\"p\">(</span>FATAL_ERROR <span class=\"s2\">\"Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is </span><span class=\"si\">${</span><span class=\"nv\">PICO_SDK_VERSION_STRING</span><span class=\"si\">}</span><span class=\"s2\">\"</span><span class=\"p\">)</span>\n<span class=\"nb\">endif</span><span class=\"p\">()</span>\n\n<span class=\"nb\">project</span><span class=\"p\">(</span>i2c_slave_2ch C CXX ASM<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise the Raspberry Pi Pico SDK</span>\n<span class=\"nf\">pico_sdk_init</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># Add executable. Default name is the project name, version 0.1</span>\n\n<span class=\"nb\">add_executable</span><span class=\"p\">(</span>i2c_slave_2ch \n                i2c_slave_2ch.c\n                i2c_slave0.c\n                i2c_slave1.c\n                <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_set_program_name</span><span class=\"p\">(</span>i2c_slave_2ch <span class=\"s2\">\"i2c_slave_2ch\"</span><span class=\"p\">)</span>\n<span class=\"nf\">pico_set_program_version</span><span class=\"p\">(</span>i2c_slave_2ch <span class=\"s2\">\"0.1\"</span><span class=\"p\">)</span>\n\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>i2c_slave_2ch 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>i2c_slave_2ch 0<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard library to the build</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_2ch\n        pico_stdlib<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard include files to the build</span>\n<span class=\"nb\">target_include_directories</span><span class=\"p\">(</span>i2c_slave_2ch PRIVATE\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>/.. <span class=\"c1\"># for our common lwipopts or any other standard includes, if required</span>\n<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add any user requested libraries</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_2ch \n        hardware_i2c\n        pico_cyw43_arch_none\n        pico_i2c_slave\n        pico_rand\n        <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_add_extra_outputs</span><span class=\"p\">(</span>i2c_slave_2ch<span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>あとはビルドしてRaspberry Pi Picoに書き込みます。</p>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認です。<br />\nここからはRaspberry Pi3 での作業です。</p>\n\n<h2 id=\"i2cdetect\">i2cdetect</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdetect</code> で I2Cバス上でデバイスが検出されるか確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n\n<p>Picoのプログラムで設定したスレーブアドレス(<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>と<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE1_ADDRESS</code>の設定値。上のプログラムだと0x17と0x32)\nが表示されていればOKです。<br />\n表示されていない場合はPicoのプログラムやボードの結線を見直してください。</p>\n\n<h2 id=\"i2cdump\">i2cdump</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdump</code> で レジスタダンプしてみます。</p>\n\n<h3 id=\"i2c0\">I2C0</h3>\n<p>I2C0のレジスタをダンプしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdump <span class=\"nt\">-y</span> 1 0x17\n</code></pre></div></div>\n<p>RaspberryPiPICOのコンソールで<code class=\"language-plaintext highlighter-rouge\">0</code>を入力し、Slave0のレジスタをダンプした内容と比較して\n内容が同じであることを確認します。</p>\n\n<h3 id=\"i2c1\">I2C1</h3>\n<p>I2C1のレジスタをダンプしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdump <span class=\"nt\">-y</span> 1 0x32 w\n</code></pre></div></div>\n<p>RaspberryPiPICOのコンソールで<code class=\"language-plaintext highlighter-rouge\">1</code>を入力し、Slave1のレジスタをダンプした内容と比較して\n内容が同じであることを確認します。</p>\n\n<h2 id=\"その他\">その他</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cset</code>や<code class=\"language-plaintext highlighter-rouge\">i2cget</code>で色々読み書きしてみてください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Web Bluetooth APIを試す</title>\n  </head>\n  <body>\n    <header>\n      <h1>Web Bluetooth APIを試す</h1>\n      <p>Web bluetooth APIを試した時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>ブラウザからBluetoothにアクセスできる<a href=\"https://developer.mozilla.org/ja/docs/Web/API/Web_Bluetooth_API\" target=\"_blank\">Web Bluetooth API</a>\nを試してみた時に作ったプログラムを貼っておきます。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"ペリフェラル機器\">ペリフェラル機器</h2>\n\n<p>BLEは通信なので、通信相手が必要です。<br />\n市販機器を使うと仕様を調べるのが大変なので、エイヤッと自分で作っりました。<br />\nといっても Raspberry Pi Pico W にmicropythonのF/Wを書き込んでプログラム実行するだけ。<br />\n(使用したmicropython F/Wは「MicroPython v1.23.0 on 2024-06-02」です)</p>\n\n<p>以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。 と言ってもWi-Fiとか要らないからパクり先のリンク貼ってあるだけだけど。</p>\n\n<p>ということで、以下のソースを Raspberry Pi Pico で実行しておきます。<br />\n(特にH/W依存なことはしてないので、ESP32でも動くかも)</p>\n\n<p>BLEの処理については「micropython aioble」とかでググってください。<br />\nでも、公式のサンプル動かした例ばっかりであんまりないんだよなぁ…</p>\n\n<p>==懺悔==<br />\nUUIDはどっかのサンプルの値をちょこっといじったものです。<br />\n(調べたら温度計用のUUIDでした)<br />\n本来ならUUIDをちゃんと生成しないといけません。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=ble_peripheral.py\"></script>\n</dev>\n\n<h2 id=\"webサーバ\">Webサーバ</h2>\n<p>Web Bluetooth APIを使用するのは、HTMLファイルをHTTPSサーバからロードしなければならない仕様のようです。\n(httpやfileでは不可)<br />\nファイル1個だけなので、どこかのサーバの片隅に置くとかでも良いと思います。<br />\nローカルでサーバを立てるならApacheとかnginxとかで立ててください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsでApacheを使うなら<a href=\"https://nanbu.marune205.net/2022/01/windows10-apache-ssl.html?m=1\" target=\"_blank\">WindowsのApacheサーバーでSSL</a>\nあたりが参考になりました。<br />\nただし、仮の証明書を作るバッチファイルで、Apacheのインストール先がc:¥Apache24 以外の場合は\n以下の設定を追加しておく必要があります。</p>\n  <div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SET</span><span class=\"w\"> </span><span class=\"nx\">OPENSSL_CONF</span><span class=\"o\">=</span><span class=\"err\">≪</span><span class=\"n\">Apache</span><span class=\"err\">のインストール先≫</span><span class=\"nx\">\\conf\\openssl.cnf</span><span class=\"w\">\n</span></code></pre></div>  </div>\n  <p>インストール先を<code class=\"language-plaintext highlighter-rouge\">m:\\Apache24</code>にした場合の変更例はこんな感じ。</p>\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- aaa.txt     2024-07-29 06:58:34.154735900 +0900\n</span><span class=\"gi\">+++ make-snakeoil-cert.bat      2024-07-26 05:09:37.394502700 +0900\n</span><span class=\"p\">@@ -1,8 +1,11 @@</span>\n REM openssl.exe\n<span class=\"gd\">-SET OPENSSL=c:\\Apache24\\bin\\openssl.exe\n</span><span class=\"gi\">+SET OPENSSL=m:\\Apache24\\bin\\openssl.exe\n+\n+REM openssl.cnf\n+SET OPENSSL_CONF=m:\\Apache24\\conf\\openssl.cnf\n</span>\n REM 証明書用データの出力場所\n<span class=\"gd\">-SET ROOTDIR=c:\\Apache24\\certs\n</span><span class=\"gi\">+SET ROOTDIR=m:\\Apache24\\certs\n</span>\n REM サーバーのドメインまたはIPアドレス\n SET IPADDRESS=localhost\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h1 id=\"htmlファイル\">HTMLファイル</h1>\n\n<p>Web Bluetooth API のサンプルプログラムを以下に示します。<br />\nこれをHTTPSサーバに置いておきます</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=BLE_sample.html\"></script>\n</dev>\n\n<h1 id=\"実験\">実験</h1>\n\n<p>ペリフェラルプログラムを動作させておき、\nブラウザで上記HTMLファイルを開きます。</p>\n\n<p>アクセスするPCやスマホはBLE対応のBluetoothが搭載されている必要があります。<br />\nブラウザはChromeかEdge(は試してないけど)で。(firefox不可)</p>\n\n<p>WindowsPCとAndroidスマホのChromeは動作確認しました。<br />\nmacとiPhoneは持ってないので試してません。</p>\n\n<p>次に「接続」ボタンをクリック、「XXXXXがペア接続を要求しています」ダイアログが出るので\n「mpy-sensor」を選択し、「ペア設定」をクリックします。</p>\n\n<p>接続されると DATA1 に受信したデータを表示します。<br />\nDATA1はNotificationありのデータ読み取りです。<br />\nNotificationイベントを受けてデータを読み取ります。<br />\n上は1行を常に書き換えるタイプ。<br />\n下は過去分を含め10行程度表示(それ以前は削除)するタイプです。<br />\n受診自体は1回でページの書き換え処理を2通り行っています。</p>\n\n<p>DATA2はNotificationなしのデータ読み取りです。<br />\nREADボタンをクリックすると読み取った値を表示します。</p>\n\n<p>測定間隔のテキストボックスに数値を入力し、「WRITE」をクリックすると\nDATA1の取得間隔を変更できます。<br />\n値は100~5000が有効で、範囲外の値が設定されると範囲内の値に補正されます(補正はペリフェラル川で行っています)。</p>\n\n<p>接続を終了するには「切断」をクリックします。</p>\n\n<h1 id=\"操作例\">操作例</h1>\n\n<p><a href=\"/memoBlog/misc/WEB_BT_API_2024-07-29_075522.mp4\" target=\"_blank\">操作例の動画</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>HTMLで疑似トースト表示</title>\n  </head>\n  <body>\n    <header>\n      <h1>HTMLで疑似トースト表示</h1>\n      <p>HTMLで疑似(なんちゃって)トースト表示するサンプル</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Javascriptでスクリプト書いていて、alert表示するとOKボタン押すまで戻ってこなくて使い勝手が悪いので、\n一定時間表示して勝手に消えるトースト表示みたいな表示ができないかと作ってみた。<br />\nあくまで簡易的なものなので、ウィンドウ作ったりとかはしてない。</p>\n\n<p>妙なこだわりで、消えるときはふわと消える(フェードアウト)にしてみた。<br />\n<code class=\"language-plaintext highlighter-rouge\">fadetime</code>を0にしたらぱっと消える。<br />\nま、ぱっと出てぱっと消えるなら<code class=\"language-plaintext highlighter-rouge\">style.visibility =\"visible\"</code>と<code class=\"language-plaintext highlighter-rouge\">style.visibility =\"hidden\"</code>でいいけど。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>以下のソースを適当に保存して、ブラウザで開いてちょ。<br />\nローカルファイル(file://)で開いてもOK。</p>\n\n<p>説明するほどのことはないので省略。</p>\n\n<p>ページの先頭に固定なので、スクロールしたら消えちゃうけど、\n表示領域の固定(position: fixed など)を使えばなんとかなりそう。</p>\n\n<p>表示が消える前に次の表示を始めたらうまくいかないかも…</p>\n\n<div class=\"language-html highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\"><!DOCTYPE HTML></span>\n<span class=\"nt\"><html</span> <span class=\"na\">lang=</span><span class=\"s\">\"ja\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><head></span>\n<span class=\"nt\"><meta</span> <span class=\"na\">charset=</span><span class=\"s\">\"UTF-8\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><title></span>疑似トースト表示<span class=\"nt\"></title></span>\n<span class=\"nt\"><script></span>\n<span class=\"c1\">// msgをdisptime(msec)表示後、fadetime(msec)でフェードアウトする</span>\n<span class=\"kd\">function</span> <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"nx\">msg</span><span class=\"p\">,</span> <span class=\"nx\">disptime</span><span class=\"o\">=</span><span class=\"mi\">2000</span><span class=\"p\">,</span> <span class=\"nx\">fadetime</span><span class=\"o\">=</span><span class=\"mi\">2000</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"kd\">let</span> <span class=\"nx\">elm</span> <span class=\"o\">=</span> <span class=\"nb\">document</span><span class=\"p\">.</span><span class=\"nx\">getElementById</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">toast</span><span class=\"dl\">\"</span><span class=\"p\">)</span>\n  <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">innerText</span> <span class=\"o\">=</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>            <span class=\"c1\">// 表示メッセージの変更</span>\n  <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">style</span><span class=\"p\">.</span><span class=\"nx\">animation</span> <span class=\"o\">=</span> <span class=\"dl\">\"</span><span class=\"s2\">none</span><span class=\"dl\">\"</span><span class=\"p\">;</span>   <span class=\"c1\">// アニメーションをキャンセルして表示する</span>\n  <span class=\"nx\">setTimeout</span><span class=\"p\">(()</span> <span class=\"o\">=></span> <span class=\"p\">{</span>              <span class=\"c1\">// disptime経過後、アニメーションを開始する。</span>\n    <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">style</span><span class=\"p\">.</span><span class=\"nx\">animation</span> <span class=\"o\">=</span> <span class=\"s2\">`fadeOut </span><span class=\"p\">${</span><span class=\"nx\">fadetime</span><span class=\"p\">}</span><span class=\"s2\">ms forwards`</span><span class=\"p\">;</span>\n  <span class=\"p\">},</span> <span class=\"nx\">disptime</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// ボタンクリック時にコールされる関数</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message1</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ1</span><span class=\"dl\">\"</span><span class=\"p\">,</span><span class=\"mi\">1000</span><span class=\"p\">,</span> <span class=\"mi\">4000</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message2</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ2</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"mi\">3000</span><span class=\"p\">,</span> <span class=\"mi\">1000</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message3</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ3</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message4</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ4</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"mi\">3000</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"nt\"></script></span>\n<span class=\"nt\"></head></span>\n\n<span class=\"nt\"><style></span>\n<span class=\"c\">/* フェードアウトのキーフレーム */</span>\n<span class=\"k\">@keyframes</span> <span class=\"n\">fadeOut</span> <span class=\"p\">{</span>\n  <span class=\"err\">0</span><span class=\"o\">%</span> <span class=\"p\">{</span>\n    <span class=\"nl\">opacity</span><span class=\"p\">:</span> <span class=\"m\">1</span><span class=\"p\">;</span>\n  <span class=\"p\">}</span>\n  <span class=\"err\">100</span><span class=\"o\">%</span> <span class=\"p\">{</span>\n    <span class=\"nl\">opacity</span><span class=\"p\">:</span> <span class=\"m\">0</span><span class=\"p\">;</span>\n  <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c\">/* トースト表示領域 */</span>\n<span class=\"nf\">#toast</span><span class=\"p\">{</span>\n  <span class=\"c\">/* 背景色 */</span>\n  <span class=\"nl\">background-color</span><span class=\"p\">:</span> <span class=\"nb\">rgb</span><span class=\"p\">(</span><span class=\"m\">128</span><span class=\"p\">,</span><span class=\"m\">256</span><span class=\"p\">,</span><span class=\"m\">128</span><span class=\"p\">);</span>\n  <span class=\"c\">/* 0secでアニメーションして表示を消しておく */</span>\n  <span class=\"nl\">animation</span><span class=\"p\">:</span> <span class=\"n\">fadeOut</span> <span class=\"m\">0s</span> <span class=\"n\">forwards</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n<span class=\"c\">/* ボタンを大きくしたいので */</span>\n<span class=\"nc\">.font-large</span><span class=\"p\">{</span>\n    <span class=\"nl\">font-size</span><span class=\"p\">:</span> <span class=\"m\">130%</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n<span class=\"nt\"></style></span>\n\n<span class=\"nt\"><body></span>\n<span class=\"nt\"><font</span> <span class=\"na\">size=</span><span class=\"s\">\"5\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><div></span>\n  <span class=\"nt\"><H3></span>疑似トースト表示<span class=\"nt\"></H3></span>\n  <span class=\"c\"><!-- トースト表示領域 --></span>\n  <span class=\"nt\"><div</span> <span class=\"na\">id=</span><span class=\"s\">\"toast\"</span><span class=\"nt\">></span>\n    メッセージ領域\n  <span class=\"nt\"></div></span>\n  \n  <span class=\"c\"><!-- テスト用ボタン --></span>\n  <span class=\"nt\"><div></span>\n    <span class=\"nt\"><p></span>\n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ1\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message1();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ2\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message2();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ3\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message3();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ4\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message4();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n    <span class=\"nt\"></p></span>\n  <span class=\"nt\"><div></span>\n<span class=\"nt\"></div></span>\n<span class=\"nt\"></font></span>\n<span class=\"nt\"></body></span>\n<span class=\"nt\"></html></span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2 メモ(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2 メモ(改訂版)</h1>\n      <p>WSL2のディストリビューションインストール~初期設定に関するメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"インストール\">インストール</h1>\n<p>WSL自体はインストール済みとします。<br />\n(インストール方法はぐぐってちょ)</p>\n\n<p>ディストリビューションのインストールはコマンドプロンプト等で行います。</p>\n\n<h2 id=\"インストール可能なディストリビューション\">インストール可能なディストリビューション</h2>\n<p>オンラインでインストールできるディストリビューションの一覧は以下で表示できます。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--online</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"新しいディストリビューションのインストール\">新しいディストリビューションのインストール</h2>\n<p>表示されたディストリビューションからインストールしたいディストリビューションを選んでインストールします。<br />\n以下は Ubuntu-24.04 をインストールする例。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--install</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>インストールが終了したら自動的にディストリビューションが起動してユーザアカウントとパスワードの設定が行われますので、\n使用したいユーザ名とパスワードを設定してください。</p>\n\n<h1 id=\"セットアップ\">セットアップ</h1>\n\n<p>引き続きセットアップを行います。</p>\n\n<h2 id=\"アップデート\">アップデート</h2>\n<p>まずはアップデート</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nubuntu 24.04以降なら<code class=\"language-plaintext highlighter-rouge\">sudo apt -U upgrade</code> でもOK。</p>\n</blockquote>\n\n<h2 id=\"日本語化\">日本語化</h2>\n<p>日本語化のため、以下のインストール/設定を行います。</p>\n\n<ul>\n  <li>日本語ランゲージパックのインストール</li>\n  <li>ロケールの設定</li>\n  <li>日本語manページのインストール</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>language-pack-ja <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>update-locale <span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF8 <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>manpages-ja manpages-ja-dev \n</code></pre></div></div>\n\n<h2 id=\"クローンしたあとのデフォルトユーザを設定\">クローンしたあとのデフォルトユーザを設定</h2>\n\n<p>クローンした環境ではデフォルトでrootでログインしてしまうので、<br />\n現在のユーザをデフォルトユーザに設定しておきます。<br />\n(マスタで設定しておけば、クローンする毎に設定しなくて済むので)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span>  /etc/wsl.conf <span class=\"o\"><<</span> <span class=\"no\">__EOF__</span><span class=\"sh\">\n\n[user]\ndefault=</span><span class=\"nv\">$USER</span><span class=\"sh\">\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nPATHにWindowsのPATHを引き継がせない設定<br />\n仮想マシン起動語、PATHにWindows環境のPATHが引き継がれます。<br />\nWindows環境のPATHを引き継がせないようにすることもできます。</p>\n\n  <p>設定方法は <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に 以下の設定を追加します。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>interop]\nappendWindowsPath <span class=\"o\">=</span> <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n\n  <p>参考: <a href=\"https://zenn.dev/o2z/articles/zenn-20210524-01\" target=\"_blank\">WSL2でWindowsのPATH設定が引き継がれるのを解除する</a></p>\n\n  <p>なお、下の .bashrcの設定 ではWindowsのPATHを引き継いだうえで、\nWINDOWSディレクトリ下、VS Code格納ディレクトリ下以外のPATHを削除して不要なPATHを残さないようにしています。</p>\n</blockquote>\n\n<h2 id=\"ミニミニスクリプト\">ミニミニスクリプト</h2>\n<p>ちょっとした不便を解消するミニミニスクリプトを作成しておきます。</p>\n\n<p>以下はExplorerと秀丸をシンボリックリンクでも実体を追いかけて開いてくれるスクリプト</p>\n\n<blockquote>\n  <p>[!NOTE]\nたとえば、<code class=\"language-plaintext highlighter-rouge\">explorer.exe /lib</code>と実行するとエクスプローラでは<code class=\"language-plaintext highlighter-rouge\">/lib</code>を開けません。<br />\n以下のスクリプトを作成した後、<code class=\"language-plaintext highlighter-rouge\">explorer /lib</code>と実行すると\n<code class=\"language-plaintext highlighter-rouge\">/lib</code>の実体である<code class=\"language-plaintext highlighter-rouge\">/usr/lib</code>が開かれます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">~/bin</code>にpathを通すには、作成後再ログイン必要。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/bin\n\n<span class=\"nb\">tee</span> <span class=\"nt\">-a</span>  ~/bin/explorer <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n#!/usr/bin/env bash\n/mnt/c/WINDOWS/explorer.exe </span><span class=\"si\">$(</span>wslpath <span class=\"nt\">-w</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"sh\">\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">tee</span> <span class=\"nt\">-a</span>  ~/bin/hidemaru <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n#!/usr/bin/env bash\nEDITOR=\"/mnt/c/Program Files (x86)/Hidemaru/Hidemaru.exe\"\n\"</span><span class=\"k\">${</span><span class=\"nv\">EDITOR</span><span class=\"k\">}</span><span class=\"sh\">\" </span><span class=\"si\">$(</span>wslpath <span class=\"nt\">-w</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"sh\">&\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">chmod</span> +x ~/bin/<span class=\"k\">*</span>\n</code></pre></div></div>\n\n<h2 id=\"bashrcの設定\">.bashrcの設定</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に必要な変更/追加を行います。<br />\n以下は私の好みの設定なので、好みに合わせて変更してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.bashrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n\n# プロンプトの設定\n# PS1=\"</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\nPS1=\"</span><span class=\"se\">\\[\\e</span><span class=\"sh\">[36m</span><span class=\"se\">\\]</span><span class=\"nv\">$WSL_DISTRO_NAME</span><span class=\"se\">\\[\\e</span><span class=\"sh\">[0m</span><span class=\"se\">\\]</span><span class=\"sh\">:</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\n\n# キーバインドの設定\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-n\": history-search-forward'\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-p\": history-search-backward'\n\n# ディレクトリスタックの表示改善\nfunction pushd() {\n    command pushd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction popd() {\n    command popd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction dirs() {\n    command dirs -v\n}\n\n# 表示色変更\nexport LS_COLORS='di=01;32:ln=01;36:ex=01;31:'\nexport GREP_COLORS='mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'\n\n# lessのオプション\nexport LESS=\"-iMRq\"\n\n# grepのオプション指定(GREP_OPTIONS)は廃止されたのでaliasで設定\n# export GREP_OPTIONS=\"--exclude-dir .git\"\nalias grep='grep --exclude-dir .git'\n\n# WindowsのPATHのうち、\"WINDOWS\"を含むディレクトリ、\"VS Code\"を含むディレクトリ以外を削除\nexport PATH=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$PATH</span> | python3 <span class=\"nt\">-c</span> <span class=\"s1\">'import re,sys;PPP=sys.stdin.readline();print(\":\".join([a for a in PPP.split(\":\") if re.match(r\"^(?!\\/mnt)\", a) or re.match(r\"(^/mnt.*WINDOWS.*$|^/mnt.*VS Code.*$)\", a)]))'</span><span class=\"si\">)</span><span class=\"sh\">\n\n# for pyenv\nexport PYENV_ROOT=/proj/.pyenv    #環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    # 仮想環境名をプロンプトに表示しない場合は以下を有効化\n    # export VIRTUAL_ENV_DISABLE_PROMPT=1\n    eval \"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"sh\">\"          # pyenv 2.0以降で必要\n    eval \"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"sh\">\"\n    eval \"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"sh\">\"\n    export PYTHON_CONFIGURE_OPTS=\"</span><span class=\"se\">\\</span><span class=\"sh\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"sh\">\n    \"\nfi\n\n# for nodenv\nexport NODENV_ROOT=/proj/.nodenv    # 環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    eval \"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"sh\">\"\nfi\n\n# __pycache__ディレクトリの生成を抑制する\nexport PYTHONDONTWRITEBYTECODE=1\n\n<< '__COMMENT__'\n# この部分はミラーモードでは使えないし、WSLgサポートされたので特に必要ないのでコメントアウト\n# NATモードでは使えるが、hostコマンドインストール必要。(sudo apt install bind9-host)\n# HOSTのIPアドレス取得\n# export HOST_IP_ADDR=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span><span class=\"si\">)</span><span class=\"sh\">\n# HOSTのIPアドレス取得(アドレスが2つ以上返ってきたときは1個目だけ取り出す)\nexport HOST_IP_ADDR=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-n</span> 1p<span class=\"si\">)</span><span class=\"sh\">\n\n# DISPLAY変数が未定義(SSHログイン等)ならDISPLAYを設定する\nif [ -v </span><span class=\"nv\">$DISPLAY</span><span class=\"sh\"> ]; then\n    export DISPLAY=</span><span class=\"k\">${</span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"k\">}</span><span class=\"sh\">:0.0\nfi\necho DISPLAY=\"</span><span class=\"nv\">$DISPLAY</span><span class=\"sh\">\"\n__COMMENT__\n\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<p>変更した内容を有効にするには、再ログインするか、<code class=\"language-plaintext highlighter-rouge\">source ~/.bashrc</code>してください。</p>\n\n<h2 id=\"readlinebash等の設定\">readline(bash等)の設定</h2>\n\n<ul>\n  <li>beepを鳴らさない設定</li>\n  <li>ブラケットペーストモードを無効化する設定(コメントアウト)<br />\n無効化したければ<code class=\"language-plaintext highlighter-rouge\">enable-bracketed-paste</code> の行を有効にします</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalではブラケットペーストモードを無効にすると確認ダイアログでチェックできるようになりますが、\nブラケットペーストモードを有効にすると確認ダイアログは出ず入力欄で確認できるようになります。<br />\nTeraterm のように二重チェックにならないので有効にしてもストレスは少ないと思い無効にしていません。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span>  /etc/inputrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\nset bell-style visible\n# set enable-bracketed-paste off\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalの場合、beepを鳴らさない設定は <br />\n設定→各仮想環境の設定画面→詳細設定→ベル通知スタイル<br />\nからも変更できる。</p>\n</blockquote>\n\n<h2 id=\"vimの設定\">vimの設定</h2>\n\n<p>私はシンプルな1色表示が好きなのでsyntax highlightを無効にしておきます。<br />\nまた、<code class=\"language-plaintext highlighter-rouge\">sudo vi</code>実行時にも同じように動作するように、<code class=\"language-plaintext highlighter-rouge\">/root</code>にもコピーしておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">/etc/vim/vimrc</code>または<code class=\"language-plaintext highlighter-rouge\">/etc/vim/vimrc.local</code>に記述するとシステム全体で有効なはずですが、\nなぜかうまくいかないので自分とrootの設定を書き換えておきます。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.vimrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\nsyntax off\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">sudo cp</span> ~/.vimrc /root/\n\n</code></pre></div></div>\n\n<h2 id=\"一旦リブート\">一旦リブート</h2>\n\n<p>ここまでの設定を反映するため、念のためリブートしておきます。</p>\n\n<p>まず、ディストリビューションを停止します。<br />\n<code class=\"language-plaintext highlighter-rouge\">exit</code>コマンドやCTRL-Dでシェルを終了します。<br />\nこれだけではディストリビューションは終了していません。<br />\n(<code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>で「Running」になっている)<br />\nコマンドプロンプト等から以下のコマンドでディストリビューションを終了します。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>で「Stopped」になっていることを確認し、再度ディストリビューションを起動します。<br />\nこのとき、既に実行中のWindowsTerminalのドロップダウンメニューには新しいディストリビューションは表示されません。<br />\nあたらしくWindowsTerminalを開くとそのウィンドウのドロップダウンメニューには表示されますので、そこから実行します。</p>\n\n<p>引き続きセットアップを行います。</p>\n\n<h2 id=\"ワークディレクトリの作成\">ワークディレクトリの作成</h2>\n\n<p>ホームに色々置くのが嫌いなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span> /proj /work\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshをbashに変更\">デフォルトshをbashに変更</h2>\n\n<p>なんとなくいつも変更してるので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /usr/bin <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<h2 id=\"ツール類インストール\">ツール類インストール</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ifconfig</code>とか<code class=\"language-plaintext highlighter-rouge\">route</code>とかを使いたいので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n\n<h3 id=\"必要なツール類をインストール\">必要なツール類をインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev <span class=\"se\">\\</span>\n                    libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\n                    xz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div></div>\n\n<h3 id=\"pyenvのインストール-1\">pyenvのインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv  <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<p>pyenvを有効にするため、再ログイン(.bashrcに必要な処理は記載済み)。</p>\n\n<h3 id=\"pythonのインストール\">pythonのインストール</h3>\n\n<p>使いたいpythonのバージョンはそのシチュエーションで変わるので、<br />\nインストールするのはマスタからクローンした環境で行う方がいいかも。</p>\n\n<h4 id=\"インストール可能なバージョンを確認\">インストール可能なバージョンを確認</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span> | less\n</code></pre></div></div>\n\n<h4 id=\"インストール-1\">インストール</h4>\n\n<p>インストールが終わったらpip他をアップデートしておく。<br />\n(「pip 古いでぇ~」とうるさいので言われる前にやっとく)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.12.4\npyenv shell 3.12.4\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h1 id=\"仮想環境の複製\">仮想環境の複製</h1>\n\n<p>それまでの状態を保持した状態で新しい仮想環境を作成できます。<br />\n今までは一旦tarファイルにエクスポートしてからインポートしていましたが、\nvhdxファイルから直接インポートできるようになりました。</p>\n\n<h2 id=\"仮想hddファイルvhdxを探す\">仮想HDDファイル(.vhdx)を探す</h2>\n<p>インストールしたディストリビューションを含む各仮想環境の名前とパスの一覧は\n以下をコマンドプロンプト等で実行すると表示できる。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">reg</span><span class=\"w\"> </span><span class=\"nx\">query</span><span class=\"w\"> </span><span class=\"nx\">HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Lxss</span><span class=\"w\"> </span><span class=\"nx\">/s</span><span class=\"w\"> </span><span class=\"err\">^</span><span class=\"w\">\n</span><span class=\"o\">|</span><span class=\"w\"> </span><span class=\"n\">findstr</span><span class=\"w\"> </span><span class=\"s2\">\"BasePath DistributionName HKEY_CURRENT_USER\"</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n1行目末の<code class=\"language-plaintext highlighter-rouge\">^</code>は次行に続くことを示す。linuxの<code class=\"language-plaintext highlighter-rouge\">\\</code>と同じ</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">HKEY_CURRENT_USER</code>を検索しているのは区切り位置を見やすくするため</p>\n</blockquote>\n\n<h2 id=\"仮想環境をクローンする\">仮想環境をクローンする</h2>\n\n<p>クローンする仮想環境を停止する</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>確認(Stoppedになっていることを確認)</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\"> </span><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">-l</span><span class=\"w\"> </span><span class=\"nt\">-v</span><span class=\"w\">\n</span><span class=\"err\">・・・・・</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"仮想環境をクローンする-1\">仮想環境をクローンする</h2>\n<p>クローン先に移動しておく</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">cd</span><span class=\"w\"> </span><span class=\"nx\">F:\\WSL_VMs</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>クローンを作成するには以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"err\">≪クローンの名前≫</span><span class=\"w\"> </span><span class=\"err\">≪クローンの保存先≫</span><span class=\"w\"> </span><span class=\"err\">≪クローン元の</span><span class=\"nx\">vhdx</span><span class=\"err\">ファイル≫</span><span class=\"w\"> </span><span class=\"nt\">--vhd</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>例えば、</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04-temp1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">\\Ubuntu-24.04-temp1</span><span class=\"w\"> </span><span class=\"o\">%</span><span class=\"nx\">LOCALAPPDATA</span><span class=\"o\">%</span><span class=\"nx\">\\Packages\\CanonicalGroupLimited.Ubuntu24.04LTS_79rhkp1fndgsc\\LocalState\\\\ext4.vhdx</span><span class=\"w\"> </span><span class=\"nt\">--vhd</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>クローンが完了したらクローンした仮想環境を実行します。</p>\n\n<h3 id=\"削除\">削除</h3>\n<p>不要になった仮想環境は削除する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"err\">«削除する仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04-2</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h1 id=\"wsl2上のサーバプログラムへのアクセス\">WSL2上のサーバプログラムへのアクセス</h1>\n<p>参考:<a href=\"https://www.atmarkit.co.jp/ait/articles/1909/09/news020.html\" target=\"_blank\">Linuxがほぼそのまま動くようになった「WSL2」のネットワーク機能</a></p>\n\n<table>\n  <thead>\n    <tr>\n      <th>向き</th>\n      <th>可否</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>HOST → WSL2</td>\n      <td>localhost でアクセスできる</td>\n    </tr>\n    <tr>\n      <td>WSL2 → HOST</td>\n      <td>localhost でアクセスできない。<br /> IPアドレス指定ならアクセスできる。</td>\n    </tr>\n  </tbody>\n</table>\n\n<p>Windows11の場合は、ネットワークをミラーモードに設定するとどちらもlocalhostでアクセスできます。<br />\nそれどころか、外部PCからWSLの仮想環境内に直接アクセスできます。<br />\nただし、ポート番号はWindows、各仮想環境で共通で使用されるので、\n他で使用していないポート番号を使用しなければなりません。<br />\nミラーモードに設定するには、<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%\\.wslconfig</code> に以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[wsl2]\nnetworkingMode=mirrored\n</code></pre></div></div>\n<p>参考:<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/networking#mirrored-mode-networking\" target=\"_blank\">WSL を使用したネットワーク アプリケーションへのアクセス/ミラー モードのネットワーク</a></p>\n\n<h1 id=\"virtualboxとの共存\">Virtualboxとの共存</h1>\n\n<p>参考:<a href=\"https://zenn.dev/yuni_hutsuka/articles/46923a0b345619\" target=\"_blank\">【REPORT】Ubuntu Desktop on VirtualBox と wsl2 の共存</a></p>\n\n<p>要は「Windows ハイパーバイザープラットフォームを有効化する」だけど、設定箇所にたどり着くのがメンドクサイので\n上の参考サイトを見てね。</p>\n\n<h1 id=\"なんかのときに使うかも\">なんかのときに使うかも</h1>\n\n<h2 id=\"仮想ディスクが肥大化した場合の対処方法\">仮想ディスクが肥大化した場合の対処方法</h2>\n<p><del><a href=\"https://qiita.com/386jp/items/e469333c5a74789db46d\" target=\"_blank\">WSL2を使っているパソコンのディスク容量が枯渇したときにやってみるべきこと</a></del><br />\nこっちの方が分かりやすかった。<br />\n<a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1271vhdexpcmd/vhdexpcmd.html\" target=\"_blank\">仮想ディスクをコマンドラインから拡大/縮小する</a></p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>PS: XXXX> diskpart                                                 ← コマンド起動\n\nMicrosoft DiskPart バージョン 10.0.19041.964\n\nCopyright (C) Microsoft Corporation.\nコンピューター: XXXXXX\n\nDISKPART> select vdisk file=\"f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\" ← 圧縮したいvhdxファイル\n\nDiskPart により、仮想ディスク ファイルが選択されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   20 GB\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART> compact vdisk                                            ← 縮小の実行\n\n  100% 完了しました                       ← ちょっと時間がかかる\n\nDiskPart により、仮想ディスク ファイルは正常に圧縮されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   12 GB                      ← 小さくなった\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART>exit                                                      ← 終了\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 24.04のVirtualBoxへのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 24.04のVirtualBoxへのインストール</h1>\n      <p>Ubuntu 24.04のVirtualBoxへのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 24.04のVirtualBoxへのインストール手順をまとめてみた。<br />\n今回は 極力コマンドコピペで実行できるように書いてみた。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2404-インストール媒体の入手\">Ubuntu 24.04 インストール媒体の入手</h2>\n<p>24.04は日本語Remixがリリースされないので(<a href=\"https://www.ubuntulinux.jp/News/ubuntu2404-ja-remix\" target=\"_blank\">ニュース</a>)、\n<a href=\"https://jp.ubuntu.com/download\" target=\"_blank\">本家</a>\nからダウンロードする必要がありますが、海外にあるサーバなのでとっても遅いです。<br />\n国内のミラーサーバの一覧が<a href=\"https://www.ubuntulinux.jp/ubuntu/mirrors#imagemirror\" target=\"_blank\">ここ</a>\nにあるので、お好きなところからダウンロードしてください。<br />\n(私がダウンロードしたときはKDDI研究所が速かった)</p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、CPU数2個以上、メインメモリーを4096MB以上に設定しておくこと</strong></p>\n<blockquote>\n  <p>[!NOTE]\n推奨環境が2 GHzデュアルコアプロセッサ以上、4GBシステムメモリなので。</p>\n</blockquote>\n\n<p>普通にインストール媒体からインストール。<br />\n以下の説明が図付きで分かりやすい:<br />\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a></p>\n\n<blockquote>\n  <p>[!TIP]\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a>では、「仮想マシンの作成」の「ハードウェア」で「EFIを有効化・・・チェックを入れます。」となっているが、\n入れなくて可(入れて試してないので入れて動くのか未確認。図でもチェック入ってないし)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nインストーラにアップデートがある場合は「今すぐアップデート」をクリックしてアップデートし、\n完了したら一旦インストーラを閉じる。<br />\nデスクトップにインストーラアイコンが出来ているので、そこから再度インストーラを起動し、\n最初から設定を行う(これまでの入力は覚えているっぽい)<br />\n参照:<a href=\"https://pc.watch.impress.co.jp/docs/column/ubuntu/1590461.html\" target=\"_blank\">Ubuntu24.04 LTSの新インストーラを徹底解説</a>\nの「インストーラにアップデートがあった場合」</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a>では、「アプリケーション」での「拡張選択」を選択とあるが、\n余計なアプリを入れたくないので「既定の選択」のままにしておく。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n</blockquote>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<blockquote>\n  <p>[!NOTE]\n設定アプリ等のGUIで設定を変更した内容をスクリプト化したいとき、どのパスを変更すれば良いか調べるには、ターミナルで</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf watch /\n</code></pre></div>  </div>\n  <p>と実行しておくと、変更される度にパスと設定値が表示される。<br />\nこれを <code class=\"language-plaintext highlighter-rouge\">dconf write</code> で書き込めばGUIで設定した内容をコマンドラインで再現できる。<br />\n参考:<a href=\"https://qiita.com/liqsuq/items/2c7aa741caa94508050b\" target=\"_blank\">デスクトップで変えた設定をCUIでやりたい!(gnome限定)</a><br />\nその関係で前回まで<code class=\"language-plaintext highlighter-rouge\">gsettings</code>コマンドでの設定手順を載せていたが、今回は<code class=\"language-plaintext highlighter-rouge\">dconf</code>コマンドに変更した。</p>\n\n</blockquote>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<p>まだGuestAdditionをインストールしてないからコピペできないけど、BashのTab補完が効くので、\nちょろっと入力してあとは補完に頼れば大丈夫。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">dconf</code>だと変更済みのパスしか補完対象にならないらしく入力が面倒なので、\nここは補完が効く<code class=\"language-plaintext highlighter-rouge\">gsettings</code>コマンドで。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">dconf</code>だとこんな感じ。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ndconf write /org/gnome/desktop/session/idle-delay 0\n\n<span class=\"c\"># 自動画面ロック OFF</span>\ndconf write /org/gnome/desktop/screensaver/lock-enabled <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\n設定 → Privacy & Security → Screen Lock → 自動画面ロックを off に</p>\n\n  <p>==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\n設定 → Privacy & Security → Screen Lock → Blank Screen Delay を「しない」に</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>裏でソフトウェアの更新が動いていると、ロックファイルがロックされてしばらく適用できないので、<br />\nそうなっちゃったらお茶でも飲んでしばらくお待ちください。<br />\nソフトウェアの更新による自動更新を止める方法は後ほど。</p>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">upgrade</code> や <code class=\"language-plaintext highlighter-rouge\">install</code> 時にオプション <code class=\"language-plaintext highlighter-rouge\">-U</code> (<code class=\"language-plaintext highlighter-rouge\">--update</code>)をつけると\n<code class=\"language-plaintext highlighter-rouge\">update</code>も一緒に実行してくれるので命令ひとつで済む。<br />\n(ubuntu 24.04に搭載された2.7.14以降)</p>\n</blockquote>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools dconf-editor gnome-tweaks \n</code></pre></div></div>\n\n<h3 id=\"一旦リブート\">一旦リブート</h3>\n<p>念のため一旦リブートしておく。</p>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>以前にマウントしたものが残ってたらアンマウントしておくこと(インストール後初めてなのでマウントされてることはないけれど)。<br />\nVirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<blockquote>\n  <p>[!TIPS]\nプログラムが自動で始まらない場合は、CDROMのマウント先(たぶん、<code class=\"language-plaintext highlighter-rouge\">/media/${USER}/VBox_GAs_x.x.xx/</code>)に移動して<code class=\"language-plaintext highlighter-rouge\">sudo ./VBoxLinuxAdditions.run</code>を実行すれば良い。</p>\n</blockquote>\n\n<h3 id=\"再度リブート\">再度リブート</h3>\n<p>GuestAdditionによる更新適用のため、もう一度リブート。<br />\n(再ログインだけでもよさそうな感じではあるが、念のため)</p>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから<br />\n「デバイス」→「クリップボードの共有」→「双方向」 を選択。<br />\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<p>また、デスクトップサイズの変更(仮想マシンのウィンドウのサイズ変更)にも対応できる。</p>\n\n<h3 id=\"使わないアプリのアンインストール\">使わないアプリのアンインストール</h3>\n<p>「アプリケーション」で「既定の選択」を選んでいれば要らないアプリは入っていないハズ。</p>\n\n<h2 id=\"お好みで\">お好みで</h2>\n\n<h3 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h3>\n\n<p>bashでクリップボードからペーストするとペーストした文字が反転表示になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n以前の動作が良い場合は<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>に設定を追加するため、以下を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/inputrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n# disable bracked-paste mode\nset enable-bracketed-paste off\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<blockquote>\n  <p>[!NOTE]\nteraterm使ってるときはteratermが確認ダイアログ出すので邪魔なんだけど、<br />\ngnome-terminalだと誤ペースト防止にそのままが良いかも。</p>\n</blockquote>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>以下のコマンドで~/.bashrcに設定を追加。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.bashrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n# プロンプトの設定\nPS1=\"</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\n\n# キーバインドの設定\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-n\": history-search-forward'\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-p\": history-search-backward'\n\n# ディレクトリスタックの表示改善\nfunction pushd() {\n    command pushd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction popd() {\n    command popd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction dirs() {\n    command dirs -v\n}\n\n# 表示色変更\nexport LS_COLORS='di=01;32:ln=01;36:ex=01;31:'\nexport GREP_COLORS='mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'\n\n# lessのオプション\nexport LESS=\"-iMR\"\n\n# grepのオプション指定(GREP_OPTIONS)は廃止されたのでaliasで設定\n# export GREP_OPTIONS=\"--exclude-dir .git\"\nalias grep='grep --exclude-dir .git'\n\n# for pyenv\nexport PYENV_ROOT=/proj/.pyenv    #環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    # 仮想環境名をプロンプトに表示しない場合は以下を有効化\n    # export VIRTUAL_ENV_DISABLE_PROMPT=1\n    eval \"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"sh\">\"          # pyenv 2.0以降で必要\n    eval \"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"sh\">\"\n    eval \"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"sh\">\"\n    export PYTHON_CONFIGURE_OPTS=\"</span><span class=\"se\">\\</span><span class=\"sh\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"sh\">\n    \"\nfi\n\n# for nodenv\nexport NODENV_ROOT=/proj/.nodenv    # 環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    eval \"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"sh\">\"\nfi\n\n# x11からのログイン以外ならDISPLAYを設定する\n# Ubuntu22.04/24.04だとwaylandになるらしい\nif [ \"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"sh\">\" != \"x11\" ] && [ \"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"sh\">\" != \"wayland\" ]; then\n    export DISPLAY=192.168.78.200:0.0\nfi\necho DISPLAY=\"</span><span class=\"nv\">$DISPLAY</span><span class=\"sh\">\"\n\n# direnv 設定\nif type direnv > /dev/null 2>&1; then\n    export EDITOR=vi\n    eval \"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"sh\">\"\n    \n    # # venvの仮想環境名を表示するための設定\n    # show_virtual_env() {\n    #   if [ -n \"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"sh\">\" ]; then\n    #     echo \"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"sh\">)\"\n    #   fi\n    # }\n    # PS1='</span><span class=\"si\">$(</span>show_virtual_env<span class=\"si\">)</span><span class=\"sh\">'</span><span class=\"nv\">$PS1</span><span class=\"sh\">\nfi\n\n# __pycache__ディレクトリの生成を抑制する\nexport PYTHONDONTWRITEBYTECODE=1\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nヒアドキュメント内での変数展開やコマンド置換を抑止するには、\nヒアドキュメント開始文字列(上記では__EOF__)をシングルクォートで囲む。<br />\n参考:<a href=\"https://qiita.com/take4s5i/items/e207cee4fb04385a9952#%E5%A4%89%E6%95%B0%E5%B1%95%E9%96%8B%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E7%BD%AE%E6%8F%9B\" target=\"_blank\">bashのヒアドキュメントを活用する/変数展開・コマンド置換</a></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npython でimportする度に<code class=\"language-plaintext highlighter-rouge\">__pycache__</code>ディレクトリ<code class=\"language-plaintext highlighter-rouge\">*.pyc</code>ファイルが作成されるのが\n鬱陶しかったので、<code class=\"language-plaintext highlighter-rouge\">PYTHONDONTWRITEBYTECODE</code>に1を設定している。<br />\n2回目以降、若干実行時間が延びるかもしれないが、気にするほどでもないので。<br />\n通常の動作がよければ削除してください。</p>\n</blockquote>\n\n<h3 id=\"ubuntu-japanese-teamのパッケージリポジトリを追加\">Ubuntu Japanese Teamのパッケージリポジトリを追加</h3>\n\n<p>日本語特有のパッケージをインストールするため、Ubuntu Japanese Teamのパッケージリポジトリを追加します。<br />\n参考:<a href=\"https://www.ubuntulinux.jp/News/ubuntu2404-ja-remix\" target=\"_blank\">Ubuntu 24.04 LTSの日本語Remixについて</a>\nの最後の部分</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>wget https://www.ubuntulinux.jp/sources.list.d/noble.sources <span class=\"nt\">-O</span> /etc/apt/sources.list.d/ubuntu-ja.sources <span class=\"o\">&&</span><span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade <span class=\"o\">&&</span><span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ubuntu-defaults-ja\n</code></pre></div></div>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">/usr/share/fonts</code>の下(自分専用なら<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>の下)にコピるだけ。<br />\n下では全部コピってる(移動だけど)けど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp/ <span class=\"o\">&&</span> <span class=\"se\">\\</span>\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.3.1/UDEVGothic_v1.3.1.zip <span class=\"o\">&&</span> <span class=\"se\">\\</span>\nunzip UDEVGothic_v1.3.1.zip <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo mv </span>UDEVGothic_v1.3.1 /usr/share/fonts/truetype/ <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<p>設定を反映するため、開いている端末をすべて閉じで、再度起動します。<br />\n開いたままだと設定が中途半端に反映されてしまいます。<br />\nまた、一つでも端末が残っていると新しく開いた端末にも正常な反映がされません。</p>\n\n<blockquote>\n  <p>[!NOTE]\nCLIで設定するならこちら….なんだけど、UUIDが同じとは限らないので参考まで。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/use-system-font    <span class=\"nb\">false\n</span>dconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/font               <span class=\"s2\">\"'UDEV Gothic JPDOC 12'\"</span>\ndconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/default-size-rows  40\n</code></pre></div>  </div>\n\n  <p>すべてのプロファイルに適用するならこんな感じでもできるかな。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">for </span>prof <span class=\"k\">in</span> <span class=\"si\">$(</span>dconf list /org/gnome/terminal/legacy/profiles:/<span class=\"si\">)</span> <span class=\"p\">;</span> <span class=\"k\">do\n    </span>dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>use-system-font    <span class=\"nb\">false</span>                       <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n    dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>font               <span class=\"s2\">\"'UDEV Gothic JPDOC 12'\"</span>    <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n    dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>default-size-rows  40\n<span class=\"k\">done</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h3>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /NFSROOT <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span> /proj /work /NFSROOT\n</code></pre></div></div>\n\n<h3 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h3>\n\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく<br />\n(CLIでも「どこにインストールする?」と聞かれて「どこだっけ?」となるのでその予防)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<p>設定が正常に行われたか確認するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<p>正常に設定されていれば、以下のような結果が出力される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>0 /dev/sda\n</code></pre></div></div>\n<h3 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h3>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gnome-extensions disable tiling-assistant@ubuntu.com <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/mutter/edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/desktop/wm/preferences/focus-mode        <span class=\"s2\">\"'sloppy'\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/desktop/wm/preferences/auto-raise        <span class=\"nb\">false</span>      <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/desktop/wm/preferences/raise-on-click    <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。<br />\nと書いてあったけど、同じ動き(フォーカスがはずれる)に見える….</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/ding/show-home  <span class=\"nb\">false</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/shell/extensions/ding/show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/desktop/interface/cursor-size 48\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nGUIで設定する場合は「設定」→「アクセシビリティ」→「Seeing」→「Cursor Size」で選択<br />\n(数値ではなく画像で選択)</p>\n</blockquote>\n\n<h3 id=\"ファイルnautilusの設定変更\">ファイル(nautilus)の設定変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<h4 id=\"ロケーションバーをデフォルトにする\">ロケーションバーをデフォルトにする</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/nautilus/preferences/always-use-location-entry <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h4 id=\"詳細表示をデフォルトに\">詳細表示をデフォルトに</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/nautilus/preferences/default-folder-viewer <span class=\"s2\">\"'list-view'\"</span> \n</code></pre></div></div>\n\n<h4 id=\"隠しファイルを表示する\">隠しファイルを表示する</h4>\n<p>隠しファイルの表示はちょっと場所が違う</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gtk/gtk4/settings/file-chooser/show-hidden <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n\n<h4 id=\"ゴミ箱削除\">ゴミ箱削除</h4>\n\n<p>私はゴミ箱使わないので消しときます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n<h4 id=\"dockバーを画面下に表示\">Dockバーを画面下に表示</h4>\n\n<p>Windows7っぽく下に移動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/dock-position <span class=\"s2\">\"'BOTTOM'\"</span>\n</code></pre></div></div>\n\n<h4 id=\"アプリケーションをdockバーの上または左に表示\">アプリケーションをDockバーの上(または左)に表示</h4>\n\n<p>Windows7のスタートボタンっぽく左に移動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/show-apps-at-top <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h4 id=\"アイコンサイズの変更\">アイコンサイズの変更</h4>\n\n<p>最後の数字が大きさなので、お好みの大きさにしてください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/dash-max-icon-size 20\n</code></pre></div></div>\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアとアップデート(software-properties-gtk)を起動\n    <ul>\n      <li>アップデートタブを選択</li>\n      <li>アップデートの自動確認を「なし」に変更</li>\n      <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n      <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n      <li>閉じるをクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a></p>\n\n<p>tewaksを使用する<br />\n<a href=\"https://yassan.hatenablog.jp/entry/2024/05/01/Ubuntu_Bdgie%E3%83%A1%E3%83%A2%EF%BC%9A_Tweeks%E3%81%A7Caps%E3%81%A8Ctrl%E3%81%AESwap\" target=\"_blank\">Ubuntu Bdgieメモ: TweeksでCapsとCtrlのSwap</a><br />\nというのもある。 お好きな方で。</p>\n\n<p>Native環境にインストールしてないので未確認だけど…</p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下のように「quiet splash」を削除。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h2 id=\"ネットワークアダプタの追加\">ネットワークアダプタの追加</h2>\n<p>ホストのWindowsや外部マシンからアクセスできるようにデフォルトのNAT以外にネットワークアダプタを追加します。<br />\n仮想マシンの設定を変更する必要があるので、一旦仮想マシンをシャットダウンしてください。</p>\n\n<h3 id=\"ネットワークアダプタ追加設定\">ネットワークアダプタ追加設定</h3>\n<ul>\n  <li>Virtualboxマネージャ で対象の仮想マシンを選択し、設定ボタンをクリック。</li>\n  <li>開いたウィンドウの左側で「ネットワーク」を選択</li>\n  <li>右側のウィンドウで「アダプタ2」をクリック\n    <ul>\n      <li>「ネットワークアダプタを有効化」にチェックを入れる</li>\n      <li>「割り当て」で「ホストオンリーアダプター」を選択</li>\n    </ul>\n  </li>\n  <li>右側のウィンドウで「アダプタ3」をクリック\n    <ul>\n      <li>「ネットワークアダプタを有効化」にチェックを入れる</li>\n      <li>「割り当て」で「ブリッジアダプター」を選択</li>\n      <li>「名前」で割り当てる物理的なネットワークアダプタを選択</li>\n    </ul>\n  </li>\n  <li>OKをクリック</li>\n</ul>\n\n<p>設定が終わったら仮想マシンを起動します。</p>\n\n<blockquote>\n  <p>[!NOTE]\nNATも削除してブリッジアダプターだけでも大丈夫な気もするが、ネットワーク不調になっても\nホストOS(Windows)からアクセスできるようにホストオンリーアダプターも追加しておく。<br />\nまた、ホストオンリーアダプターも不調になったときでも\nWebアクセスなど最低限のアクセスができるようNATも残しておく。<br />\n要らないと思ったら上記の設定の「ネットワークアダプタを有効化」のチェックをはずせば良い。</p>\n</blockquote>\n\n<h3 id=\"ネットワークのコネクション名の変更\">ネットワークのコネクション名の変更</h3>\n\n<p>ネットワークコントローラを追加したので、ネットワークマネージャのコネクション一覧を見てみます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection \n</code></pre></div></div>\n\n<p>結果はこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>NAME            UUID                                  TYPE      DEVICE \nnetplan-enp0s3  1eef7e45-3b9d-3043-bee3-fc5925c90273  ethernet  enp0s3 \n有線接続 1      eef7ccb4-2a33-336f-bb48-701058d5e6ce  ethernet  enp0s8 \n有線接続 2      eff49436-1aac-36eb-b1f6-2a32cc246b83  ethernet  enp0s9 \nlo              d30bde24-f5dd-458d-86b0-b5c8870f4485  loopback  lo     \n</code></pre></div></div>\n<p>「有線接続 1」と「有線接続 2」がさきほど追加したホストオンリーアダプターとブリッジアダプターなのですが、\nどっちがどっちか判別できません。<br />\nそこで判別できるような名前に変更しておきます。<br />\n(192.168.xx.xxのものだけ変更。NATとloはそのまま)<br />\n変更後のコネクション名はネットワークとの対応が分かりやすくなるよう、\n≪IPアドレスの3桁目≫_LINE としています。<br />\nお好みの名前に変更してください。<br />\n(現在、日本語だと文字化けするバグがあるようです。そのうち直ると思いますが)</p>\n\n<p>手動で設定するのは面倒なので、以下のスクリプトファイルを作成して実行してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># すべてのコネクション名を改行区切りで配列に取得</span>\n<span class=\"nv\">ORG_IFS</span><span class=\"o\">=</span><span class=\"nv\">$IFS</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"s1\">$'</span><span class=\"se\">\\n</span><span class=\"s1\">'</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span>nmcli  <span class=\"nt\">-t</span> <span class=\"nt\">-f</span> NAME connection<span class=\"si\">)</span><span class=\"o\">)</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"nv\">$ORG_IFS</span>        <span class=\"c\"># 元に戻す</span>\n\n<span class=\"k\">for </span>i <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"p\">!connections[@]</span><span class=\"k\">}</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各コネクションについて</span>\n    <span class=\"c\"># 直接取り出すとうまくいかないのでインデックス取り出して内容取得</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[</span><span class=\"nv\">$i</span><span class=\"p\">]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n\n    <span class=\"c\"># 現在設定されているIPv4アドレスを取得</span>\n    <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.ADDRESS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n    <span class=\"c\"># 結果⇒ 「IP4.ADDRESS[1]: 192.168.78.215/24」</span>\n    \n    <span class=\"c\"># IPアドスの各桁とサブネットマスクを空白区切りで取得し、配列に代入</span>\n    <span class=\"c\"># 1個目のsed ⇒ 192.168.78.215/24</span>\n    <span class=\"c\"># 2個目のsed ⇒ 192 168 78 215 24</span>\n    <span class=\"nv\">ipv4octet</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/[</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]/ /g\"</span><span class=\"si\">)</span><span class=\"o\">)</span>\n\n    <span class=\"c\"># echo ${str}</span>\n    <span class=\"c\"># echo ${ipv4octet[0]}  ${ipv4octet[1]}  ${ipv4octet[2]}  ${ipv4octet[3]}  ${ipv4octet[4]}</span>\n    \n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 192 <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 168 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n        <span class=\"c\"># 192.168.XX.XX のコネクション</span>\n        <span class=\"c\"># echo \"**** ${str} ****\"</span>\n\n        <span class=\"c\"># コネクション名を\"≪IPアドレスの3桁目≫_LINE\"変更する</span>\n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> connection.id </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[2]</span><span class=\"k\">}</span><span class=\"s2\">_LINE</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone\n\n</span><span class=\"nb\">echo</span> <span class=\"o\">==</span><span class=\"nv\">RESULT</span><span class=\"o\">==</span>\nnmcli  connection\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)→<br />\n左側のネットワークを選択し、対象のNICの設定ボタン(歯車アイコン)をクリック→<br />\n開いたウィンドウで「identity」タブをクリック→<br />\n「名前」に設定する名前を設定→<br />\n「適用」をクリック</p>\n</blockquote>\n\n<h3 id=\"sambaのインストール\">sambaのインストール</h3>\n\n<h4 id=\"ツール本体のインストール\">ツール本体のインストール</h4>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<h4 id=\"etcsambasmbconf-の設定を変更\">/etc/samba/smb.conf の設定を変更</h4>\n\n<p>以下のコマンドを実行します。<br />\n変更内容は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code>をバックアップ</li>\n  <li>[homes]セクションを有効化</li>\n  <li>[homes]セクションの「read only」を「no」に設定</li>\n  <li>[global]セクションに「map archive = no」を追加</li>\n  <li>ファイル末尾に[proj][work][NFSROOT]セクションを追加<br />\n他にも追加したいセクション(ディレクトリの設定)があったら追加してください。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /etc/samba/smb.conf /etc/samba/smb.conf.org     <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'/\\[homes\\]/s/;//g'</span> /etc/samba/smb.conf     <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'/\\[homes\\]/,/\\[/ {s/^;[^\\[]//g}'</span> /etc/samba/smb.conf   <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"/</span><span class=\"se\">\\[</span><span class=\"s2\">homes</span><span class=\"se\">\\]</span><span class=\"s2\">/,/^</span><span class=\"se\">\\[\\|</span><span class=\"s2\">^;</span><span class=\"se\">\\s</span><span class=\"s2\">*</span><span class=\"se\">\\[</span><span class=\"s2\">/ s/read only = .*/read only = no/1\"</span> /etc/samba/smb.conf <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'s/\\(^\\[global\\].*\\)/\\1\\n\\n    map archive = no/'</span> /etc/samba/smb.conf   <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/samba/smb.conf <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n</span><span class=\"no\">\n__EOF__\n</span></code></pre></div></div>\n\n<h4 id=\"ユーザの追加\">ユーザの追加</h4>\n\n<p>sambaのためのユーザを追加します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>pdbedit <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n</code></pre></div></div>\n\n<p>新しいパスワードを聞かれるので入力</p>\n\n<blockquote>\n  <p>[!NOTE]\n以前は<code class=\"language-plaintext highlighter-rouge\">sudo smbpasswd -a $USER</code> だったけど、最近は上のコマンドが正式らしい。<br />\n(まだ <code class=\"language-plaintext highlighter-rouge\">smbpasswd</code>も使えるけど)</p>\n</blockquote>\n\n<h4 id=\"sambaの再起動\">sambaの再起動</h4>\n\n<p>設定を反映するため、sambaを再起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl reload  smbd.service <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>systemctl restart smbd.service\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">Warning: The unit file, source configuration file or drop-ins of smbd.service changed on disk. Run 'systemctl daemon-reload' to reload units.</code>\nと言われたときは、<code class=\"language-plaintext highlighter-rouge\">sudo systemctl daemon-reload</code>を実行</p>\n</blockquote>\n\n<h3 id=\"nfsのインストール\">NFSのインストール</h3>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<h4 id=\"インストール-1\">インストール</h4>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<h4 id=\"設定ファイルの変更\">設定ファイルの変更</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">/NFSROOT</code>をエクスポートするため、<code class=\"language-plaintext highlighter-rouge\">/etc/exports</code>を修正。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/exports <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<h4 id=\"再起動\">再起動</h4>\n\n<p>変更した設定を反映するため、NFSを再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl restart nfs-server.service \n</code></pre></div></div>\n\n<h4 id=\"確認\">確認</h4>\n\n<h5 id=\"exportできているか確認\">exportできているか確認</h5>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>こんな感じで表示されればOK</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT      \t192.168.0.0/255.255.0.0\n</code></pre></div></div>\n\n<h5 id=\"別のマシンからマウントしてみる\">別のマシンからマウントしてみる</h5>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n\n<p>別のマシンから以下のコマンドを実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">abc</code>の下に今インストールしているPCの<code class=\"language-plaintext highlighter-rouge\">/NFSROOT</code>ディレクトリのファイルが見えたらOK</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<p>マスタイメージを残しておいて、色々な環境をお試しするには仮想マシンをクローンして使うのがおススメ。</p>\n<ul>\n  <li>VirtualBoxのメインウィンドウでマスタイメージの仮想マシンを右クリック→クローンを選択。</li>\n  <li>名前とパスを設定し、MACアドレスのポリシーは「すべてのネットワークアダプタでMACアドレスを生成」を選択。</li>\n  <li>「次へ」をクリック</li>\n  <li>すべてをクローンにチェックが入っていることを確認し、「完了」をクリック\nクローンが終了するまで待つ。</li>\n</ul>\n\n<p>クローンした仮想マシンを起動し、必要な変更を加える。</p>\n\n<h2 id=\"ネットワーク設定の変更\">ネットワーク設定の変更</h2>\n\n<p>マシン名とか同じ名前だと色々不都合があるので、変更しておく。<br />\n他のクローン仮想環境と同時に使わないならそのままでも良いけど。<br />\nIPアドレスも固定で割り振っておくと名前が引けない時にさくっと分かってなにかと便利…\nなんだけど、最近はWindowsもUbuntuもRaspberryPiもmDNSがサポートされてるから自動割り当てのままでもそんなに不便はないかも。</p>\n\n<p>ポリシー</p>\n<ul>\n  <li>IPアドレスの最終桁を決める(numberとする)。</li>\n  <li>ホスト名をskull≪number≫とする</li>\n  <li>ホストオンリーアダプタ/ブリッジアダプタの設定変更\n    <ul>\n      <li>IPv4アドレスを手動設定にする</li>\n      <li>IPv4アドレスの1桁目~3桁目、サブネットマスクを現在のIPアドレスと同じにする</li>\n      <li>IPv4アドレスの最終桁をnumberにする</li>\n      <li>GW、DNSが設定されていれば同じアドレスを設定する</li>\n    </ul>\n  </li>\n</ul>\n\n<p>以下の内容でスクリプトファイルを作成し、実行する。<br />\nホスト名などは適宜変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/usr/bin/env bash</span>\n\n<span class=\"c\"># 設定する数値の入力</span>\n<span class=\"nb\">read</span> <span class=\"nt\">-p</span> <span class=\"s2\">\"数値を入力してください: \"</span> number \n\n<span class=\"c\"># echo ${number}</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[[</span> <span class=\"o\">!</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">=</span>~ ^[0-9]+<span class=\"nv\">$ </span><span class=\"o\">]]</span><span class=\"p\">;</span> <span class=\"k\">then\n  </span><span class=\"nb\">echo</span> <span class=\"s1\">'数値ではありません'</span>\n  <span class=\"nb\">exit </span>1\n<span class=\"k\">fi\n\nif</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"nt\">-lt</span> 2 <span class=\"o\">]</span> <span class=\"o\">||</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"nt\">-gt</span> 254 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n  </span><span class=\"nb\">echo</span> <span class=\"s1\">'数値は2~254でなければなりません'</span>\n  <span class=\"nb\">exit </span>1\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># ホスト名の変更</span>\n<span class=\"nv\">old_name</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">hostname</span><span class=\"si\">)</span>\n<span class=\"nv\">new_name</span><span class=\"o\">=</span><span class=\"s2\">\"skull</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo nmcli general hostname </span><span class=\"k\">${</span><span class=\"nv\">new_name</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n<span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo sed -i -e \"</span>s/<span class=\"k\">${</span><span class=\"nv\">old_name</span><span class=\"k\">}</span>/<span class=\"k\">${</span><span class=\"nv\">new_name</span><span class=\"k\">}</span>/<span class=\"s2\">\" /etc/hosts\"</span>\n<span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n<span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n\n<span class=\"c\"># すべてのコネクション名を改行区切りで配列に取得</span>\n<span class=\"nv\">ORG_IFS</span><span class=\"o\">=</span><span class=\"nv\">$IFS</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"s1\">$'</span><span class=\"se\">\\n</span><span class=\"s1\">'</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span>nmcli  <span class=\"nt\">-t</span> <span class=\"nt\">-f</span> NAME connection<span class=\"si\">)</span><span class=\"o\">)</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"nv\">$ORG_IFS</span>        <span class=\"c\"># 元に戻す</span>\n\n<span class=\"k\">for </span>i <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"p\">!connections[@]</span><span class=\"k\">}</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各コネクションについて</span>\n    <span class=\"c\"># 直接取り出すとうまくいかないのでインデックス取り出して内容取得</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[</span><span class=\"nv\">$i</span><span class=\"p\">]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># 現在設定されているIPv4アドレスを取得</span>\n    <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.ADDRESS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n    <span class=\"c\"># 結果⇒ 「IP4.ADDRESS[1]: 192.168.78.215/24」</span>\n    \n    <span class=\"c\"># IPアドスの各桁とサブネットマスクを空白区切りで取得し、配列に代入</span>\n    <span class=\"c\"># 1個目のsed ⇒ 192.168.78.215/24</span>\n    <span class=\"c\"># 2個目のsed ⇒ 192 168 78 215 24</span>\n    <span class=\"nv\">ipv4octet</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/[</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]/ /g\"</span><span class=\"si\">)</span><span class=\"o\">)</span>\n    \n    <span class=\"c\"># echo ${str}</span>\n    <span class=\"c\"># echo ${ipv4octet[0]}  ${ipv4octet[1]}  ${ipv4octet[2]}  ${ipv4octet[3]}  ${ipv4octet[4]}</span>\n    \n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 192 <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 168 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n        <span class=\"c\"># 192.168.XX.XX のコネクション</span>\n        <span class=\"c\"># echo \"**** ${str} ****\"</span>\n        \n        <span class=\"c\"># 現在設定されているIPv4GWアドレスを取得</span>\n        <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.GATEWAY\"</span> <span class=\"si\">)</span>\n        <span class=\"c\"># 結果⇒ 「IP4.GATEWAY: 192.168.78.1」</span>\n        \n        <span class=\"c\"># IPv4GWアドレスを抽出(未定義では--なので-も抽出対象)</span>\n        <span class=\"nv\">gwaddr</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.</span><span class=\"s2\">-]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span><span class=\"si\">)</span>\n        <span class=\"c\"># \"--\" だったら空文字にする</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">=</span> <span class=\"s2\">\"--\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then </span><span class=\"nv\">gwaddr</span><span class=\"o\">=</span><span class=\"s2\">\"\"</span><span class=\"p\">;</span> <span class=\"k\">fi</span>\n        \n        <span class=\"c\"># 現在設定されているIPv4DNSアドレスを取得(未定義ならこのエントリがない)</span>\n        <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.DNS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n        <span class=\"c\"># 結果⇒ 「IP4.DNS[1]: 192.168.78.1」</span>\n        \n        <span class=\"c\"># IPv4DNSアドレスを抽出</span>\n        <span class=\"nv\">dnsaddr</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span><span class=\"si\">)</span>\n        \n        <span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"ipv4.method manual ipv4.addresses </span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[2]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[4]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n            </span><span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\"> ipv4.gateway </span><span class=\"k\">${</span><span class=\"nv\">gwaddr</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">fi\n        if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n            </span><span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\"> ipv4.dns </span><span class=\"k\">${</span><span class=\"nv\">dnsaddr</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">fi</span>\n        \n        <span class=\"c\"># echo ipv4.method manual ${set_str}</span>\n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n        \n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection down   </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n        \n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection up     </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone\n\n</span><span class=\"nb\">echo</span> <span class=\"o\">==</span><span class=\"nv\">DONE</span><span class=\"o\">==</span>\n</code></pre></div></div>\n\n<p>実行後、<br />\n<code class=\"language-plaintext highlighter-rouge\">ip address</code>や<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPアドレスが変更されていること、<br />\n<code class=\"language-plaintext highlighter-rouge\">hostname</code>でホスト名が変更されていること、<br />\n<code class=\"language-plaintext highlighter-rouge\">cat /etc/hosts</code>でhostsが変更されていること、\nをそれぞれ確認する。</p>\n\n<blockquote>\n  <p>[!TIP]\nIPアドレスの変更をGUIで行うには以下。<br />\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nこのスクリプトをマスタイメージのどこか(例えば<code class=\"language-plaintext highlighter-rouge\">~/bin</code>とか)に保存しておけば、\nクローンする度にスクリプトを実行すればIPアドレスとホスト名の変更をイッパツで完了できる。</p>\n</blockquote>\n\n<h2 id=\"あとはお約束\">あとはお約束</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade\n</code></pre></div></div>\n\n<p>VirtalBoxのバージョンが変更されているときは、GuestAdditionのバージョンアップも忘れずに。<br />\nまた、マスタイメージは定期的に<code class=\"language-plaintext highlighter-rouge\">sudo apt -U upgrade</code>しておくと\nクローン時のアップデート時間が短くて済む。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSBデバイスを使う(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSBデバイスを使う(その3)</h1>\n      <p>WSLでUSBデバイスを使う(その3:USBカメラ編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>で\nWSLカーネル v6.6.36.3 をビルドしたのでもうv5.15.153は使わなくて良くなったのですが、\nやっぱりカーネル入れ替えずにUSBカメラ使いたい衝動にかられ、手順をまとめてみました。<br />\n(その2でUSBストレージ編を書こうと思っていたので、その2は欠番、その3になりました)</p>\n\n<p>参考:<br />\n<a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a><br />\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a></p>\n\n<h1 id=\"開発環境の準備\">開発環境の準備</h1>\n<p>開発環境の準備については、\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>\nの「Linuxカーネルのビルド環境の構築」を参照してください。</p>\n\n<h1 id=\"カーネルモジュールのビルド\">カーネルモジュールのビルド</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<p>たとえば、以下。 どこでも良いけど、以下の手順はこのディレクトリで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /proj/wsl_kernel <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /proj/wsl_kernel\n</code></pre></div></div>\n\n<h2 id=\"カーネルソースの取得\">カーネルソースの取得</h2>\n<p>作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)にカーネルソースをダウンロードします。<br />\ngitリポジトリをcloneするか、リリースソースをダウンロードして展開します。</p>\n\n<h3 id=\"gitでcloneする場合\">gitでcloneする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/microsoft/WSL2-Linux-Kernel.git\n\n<span class=\"c\"># 目的のタグをチェックアウト</span>\ngit <span class=\"nt\">-C</span> WSL2-Linux-Kernel checkout <span class=\"nt\">-b</span> WSL-5.15.153.1 refs/tags/linux-msft-wsl-5.15.153.1\n\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> WSL2-Linux-Kernel linux\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nclone済みなら念のため<code class=\"language-plaintext highlighter-rouge\">git pull</code>して最新状態にしておく</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nブランチ作る必要ないけど、念のため。</p>\n</blockquote>\n\n<h3 id=\"リリースソースzipをダウンロードする場合\">リリースソース(zip)をダウンロードする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-5.15.153.1.zip\nunzip linux-msft-wsl-5.15.153.1.zip\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> linux-msft-wsl-5.15.153.1 linux\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nunzipはデフォルトではインストールされていないのでインストール必要。</p>\n</blockquote>\n\n<h2 id=\"スクリプトdockerfileの入手\">スクリプト&Dockerfileの入手</h2>\n<blockquote>\n  <p>[!NOTE]\nGistに必要なスクリプト&<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>を置いておいたので以下のページの<code class=\"language-plaintext highlighter-rouge\">DownloadZIP</code>ボタンからダウンロードして\n作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)に展開してください。<br />\n<a href=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021\" target=\"_blank\">Gist:WSLカーネルビルド環境</a></p>\n\n  <p>または以下のコマンドで取得できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021/archive/main.zip\nunzip <span class=\"nt\">-j</span> main.zip\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージを作成起動確認\">Dockerイメージを作成~起動確認</h2>\n<p>Dockerイメージを作成~起動確認は\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>\nのDockerイメージを作成~起動確認 を参照してください。<br />\n作成済みならスキップしてください。</p>\n\n<h2 id=\"カーネルモジュールのビルド-1\">カーネルモジュールのビルド</h2>\n\n<p>カーネルソースの取得、Dockeイメージのビルドが終わったら、以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_multimedia.sh\n</code></pre></div></div>\n\n<p>実行には数十分~1時間程度かかります(PCのスペックによる)。</p>\n\n<p>実行完了後、<code class=\"language-plaintext highlighter-rouge\">out</code>ディレクトリに<code class=\"language-plaintext highlighter-rouge\">linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb</code>ができます。<br />\nこれを使用するディストリビューションから見えるフォルダ(ディストリビューション内でなくWindowsのディレクトリでも可)にコピーします。</p>\n\n<h3 id=\"カーネルビルド用スクリプト\">カーネルビルド用スクリプト</h3>\n\n<p>用意したスクリプトの概要は以下の通りです。</p>\n\n<h4 id=\"build_functionssh\">build_functions.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_functions.sh</code>はビルドに関わる処理を関数化したものをまとめたファイルです。<br />\n以下のスクリプトからインクルードして使用します。</p>\n\n<p>Dockerコンテナを使用するので、あらかじめDockerイメージを作成しておく必要があります。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_functions.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_multimediash\">build_wsl_multimedia.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_multimedia.sh</code>はマルチメディア関連のカーネルモジュールのビルドを行います。<br />\n<code class=\"language-plaintext highlighter-rouge\">build_wsl_usb-storage.sh</code>の<code class=\"language-plaintext highlighter-rouge\">ADD_CONFIG</code>変数の設定値を変更しただけです。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_multimedia.sh\"></script>\n</dev>\n\n<p>その他は<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>を参照してください。</p>\n\n<h1 id=\"実行環境の準備\">実行環境の準備</h1>\n<p>実行環境の準備は <a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a>\nと同じです。<br />\n使用するUSBデバイスがUSBカメラに変わるだけです。</p>\n\n<h2 id=\"実行ディストリビューションの準備\">実行ディストリビューションの準備</h2>\n\n<p>デフォルト状態ではカーネルモジュールのインストール先(<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/</code>)が書き込みできないので、\noverlayfsで書き込みできるファイルシステムをマウントします。</p>\n\n<p>まず、マウントする(実際に書き込むための)ディレクトリを用意します。<br />\nupperとworkの2つが必要です。workにはなにも書き込まないでください。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> /modules_overlay/upper/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> /modules_overlay/work/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n</code></pre></div></div>\n\n<p>次にお試しマウントしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> overlay overlay <span class=\"nt\">-o</span> <span class=\"se\">\\</span>\n    <span class=\"nv\">lowerdir</span><span class=\"o\">=</span>/usr/lib/modules/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>,<span class=\"se\">\\</span>\n    <span class=\"nv\">upperdir</span><span class=\"o\">=</span>/modules_overlay/upper/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>,<span class=\"se\">\\</span>\n    <span class=\"nv\">workdir</span><span class=\"o\">=</span>/modules_overlay/work/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span> <span class=\"se\">\\</span>\n    /usr/lib/modules/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n</code></pre></div></div>\n\n<p>マウントできたか確認するため、ファイルを作成してみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo </span>hogehoge | <span class=\"nb\">sudo tee</span> /usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt</code>が出来ていること(内容が正しいこと)と、\n<code class=\"language-plaintext highlighter-rouge\">/modules_overlay/upper/5.15.153.1-microsoft-standard-WSL2/test.txt</code>に同じファイルがあることを確認します。</p>\n\n<p>終わったら削除しておきましょう。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo rm</span> /usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt\n</code></pre></div></div>\n\n<p>再起動したときに自動的にマウントされるように、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に先ほどのマウントコマンドを\n<code class=\"language-plaintext highlighter-rouge\">command=</code>に指定します。<br />\n以下は書き込んだ後の<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>の例。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\ncommand=mount -t overlay overlay -o \\\n    lowerdir=/usr/lib/modules/$(uname -r),\\\n    upperdir=/modules_overlay/upper/$(uname -r),\\\n    workdir=/modules_overlay/work/$(uname -r) \\\n    /usr/lib/modules/$(uname -r)\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>が正常に変更できたか確認するにはWSLの再起動が必要です(ウィンドウ閉じただけではダメ)。</p>\n\n<h2 id=\"カーネルモジュールのインストール\">カーネルモジュールのインストール</h2>\n\n<p>先ほど作成した<code class=\"language-plaintext highlighter-rouge\">linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb</code>を使用して\n以下のように実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb\n</code></pre></div></div>\n\n<h1 id=\"usbカメラを繋いでみる\">USBカメラを繋いでみる</h1>\n\n<p>実行手順は\n実行環境の準備は <a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a>\nの「USB-Serialデバイスを接続」を参照してください。</p>\n\n<p>USBカメラのを接続したときのログはこんな感じ</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[22183.171276] vhci_hcd vhci_hcd.0: pdev(0) rhport(0) sockfd(3)\n[22183.171281] vhci_hcd vhci_hcd.0: devid(196610) speed(3) speed_str(high-speed)\n[22183.171334] vhci_hcd vhci_hcd.0: Device attached\n[22183.550422] usb 1-1: new high-speed USB device number 3 using vhci_hcd\n[22183.700457] usb 1-1: SetAddress Request (3) to port 0\n[22183.786408] usb 1-1: New USB device found, idVendor=056e, idProduct=700a, bcdDevice= 1.00\n[22183.786412] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0\n[22183.786414] usb 1-1: Product: Venus USB2.0 Camera\n[22183.786416] usb 1-1: Manufacturer: Vimicro Corp.\n[22183.799190] usb 1-1: Found UVC 1.00 device Venus USB2.0 Camera (056e:700a)\n[22183.844401] input: Venus USB2.0 Camera: Venus USB2 as /devices/platform/vhci_hcd.0/usb1/1-1/1-1:1.0/input/input1\n</code></pre></div></div>\n\n<h2 id=\"画出し確認\">画出し確認</h2>\n\n<p>pythonのopwnCVでもguvcviewでもお好きな方でどうぞ。</p>\n\n<p>データ転送帯域が足りなくて画像が表示できない場合は、解像度を落としたり、\nフォーマットをYUYV等からMKPEGに変更したりしてデータ量を少なくして試してみてください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLのカーネルをビルドする</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLのカーネルをビルドする</h1>\n      <p>WSLのカーネルをビルドする手順(Docker使用)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLでUSBストレージ(USBメモリなど)を使う方法を書こうと手順をまとめている間に、カーネル v6.6.36.3 がリリースされてしまいました。<br />\nこのバージョンは自前でビルドしなくてもUSBストレージ関連のドライバが入っています(Builtinモジュールではなくロードモジュールとして)。<br />\nで、バイナリリリースされてしまえば何もしなくてもUSBストレージが使えるようになる(ハズ)ですが、\n今日の段階はまだバイナリリリースされてないので自前でビルドしてみることにしました。<br />\n以下はその時のメモ。<br />\nで、手順は以下のサイトのDockerを使用して開発環境を構築する方法を <del>パクった</del>  参考にしました。<br />\n(もともとカーネル差し替えずにドライバ組み込む手順を調べてて参考にしたサイト)</p>\n\n<p>参照:<a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">カーネルモジュールのビルドと使用</a></p>\n\n<h1 id=\"準備の準備\">準備の準備</h1>\n\n<h2 id=\"wslディストリビューションでsystemdの有効化\">WSLディストリビューションでsystemdの有効化</h2>\n\n<p>systemdの方がDockerのサービスの操作とかやりやすい(情報が多い?)のでsystemdを有効化しておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストールしたタイミングによっては既に有効化されているかも。</p>\n</blockquote>\n\n<p> \n使用するディストリビューションを起動し、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下の設定を行います。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdを有効にするか否かはディストリビューション毎の設定</p>\n</blockquote>\n\n<p>設定後、WSLをシャットダウン(コマンドプロンプト等から<code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行)し、<br />\n再度ディストリビューションを起動します。</p>\n\n<p>参考:<a href=\"https://qiita.com/curacao/items/fb9adaf1c097b1acd6a8\" target=\"_blank\">WSL2でsystemctlを使う方法</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdが動作しているか確認するには、<code class=\"language-plaintext highlighter-rouge\">systemctl is-system-running</code> を実行します。<br />\n<code class=\"language-plaintext highlighter-rouge\">running</code>(起動中) <code class=\"language-plaintext highlighter-rouge\">degraded</code>(起動中だが失敗したサービスなどが存在) と表示されれば動作しています。<br />\n<code class=\"language-plaintext highlighter-rouge\">offline</code> と表示されれば起動していません。<br />\nその他使い方についてはぐぐってちょ。</p>\n</blockquote>\n\n<h1 id=\"linuxカーネルのビルド環境の構築\">Linuxカーネルのビルド環境の構築</h1>\n\n<h2 id=\"dockerの準備\">Dockerの準備</h2>\n\n<p>コンパイル環境はDockerコンテナを使用するので、Dockerをインストールします。<br />\nWindows上で使用できるDocker Desktop for Windowsでも良いのですが、ディストリビューション上にDockerをインストールすることにします。</p>\n\n<blockquote>\n  <p>[!NOTE]\nDocker Desktop for Windows を使用する場合は「WSL統合」でDockerを統合したディストリビューションで作業することになるようです。<br />\n試してないから分からんけど….</p>\n</blockquote>\n\n<p>インストール方法は先人の知恵を拝借→<a href=\"https://zenn.dev/thyt_lab/articles/fee07c278fcaa8\" target=\"_blank\">WSL(Ubuntu)にDocker環境を構築する</a><br />\nこのページの通りに実行すればDockerがインストールできます。</p>\n\n<p>また、Dockerをsudoなしで実行できるように、dockerグループを追加しておきます。<br />\n追加しなくてもsudoで実行できますが、作成されたファイルのオーナーがrootになってしまって面倒なのでおススメしません。</p>\n\n<p>以下、私が実際に行ったコマンドです。上記サイトの手順ほとんどそのままです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># apt keyring ファイル格納ディレクトリを作成</span>\n<span class=\"nb\">sudo install</span> <span class=\"nt\">-m</span> 0755 <span class=\"nt\">-d</span> /etc/apt/keyrings\n\n<span class=\"c\"># 鍵ファイルの作成&リード属性付与</span>\ncurl <span class=\"nt\">-fsSL</span> https://download.docker.com/linux/ubuntu/gpg | <span class=\"nb\">sudo </span>gpg <span class=\"nt\">--dearmor</span> <span class=\"nt\">-o</span> /etc/apt/keyrings/docker.gpg\n<span class=\"nb\">sudo chmod </span>a+r /etc/apt/keyrings/docker.gpg\n\n<span class=\"c\"># aptリポジトリの追加</span>\n<span class=\"nb\">echo</span>   <span class=\"s2\">\"deb [arch=\"</span><span class=\"si\">$(</span>dpkg <span class=\"nt\">--print-architecture</span><span class=\"si\">)</span><span class=\"s2\">\" signed-by=/etc/apt/keyrings/docker.gpg] </span><span class=\"se\">\\</span><span class=\"s2\">\n        https://download.docker.com/linux/ubuntu </span><span class=\"se\">\\</span><span class=\"s2\">\n        \"</span><span class=\"si\">$(</span><span class=\"nb\">.</span> /etc/os-release <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"s2\">\"</span><span class=\"nv\">$VERSION_CODENAME</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"s2\">\" stable\"</span> <span class=\"se\">\\</span>\n        | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/docker.list\n\n<span class=\"c\"># 追加したリポジトリも含めてaptデータベースの更新</span>\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># Dockerのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n\n<span class=\"c\"># 自身にdockerグループを追加</span>\n<span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> docker\n</code></pre></div></div>\n\n<p>dockerグループの追加を有効にするため、<strong>ここで一旦ログアウトして再ログイン</strong></p>\n\n<p>dockerグループが追加されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">groups</span>\n</code></pre></div></div>\n\n<p>以下のようにdockerグループが追加されていればOK。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XXXX adm cdrom <span class=\"nb\">sudo </span>dip plugdev lxd docker\n</code></pre></div></div>\n\n<h3 id=\"dockerのテスト\">Dockerのテスト</h3>\n\n<p>Dockerが正常にインストールできたか確認するため、hello-worldを実行します。<br />\n実行後、コンテナを削除するように<code class=\"language-plaintext highlighter-rouge\">--rm</code>オプションを指定。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">--rm</span> hello-world\n</code></pre></div></div>\n\n<p>以下のように表示されればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・・\nHello from Docker!\nThis message shows that your installation appears to be working correctly.\n・・・・\n</code></pre></div></div>\n\n<p>使用したhello-worldイメージはもう使わないので削除しておきます。</p>\n\n<p>まずコンテナが残ってないか確認します。<br />\n<code class=\"language-plaintext highlighter-rouge\">-a</code>をつけるのを忘れずに!</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n\n<p>以下のようにヘッダ行だけ表示されればコンテナは残っていません(OKです)。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nもしコンテナが残っていたら(rmオプション付け忘れなど)以下のように表示されます。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES\nae8523f06af4   hello-world   \"/hello\"   13 seconds ago   Exited (0) 10 seconds ago             romantic_booth\n</code></pre></div>  </div>\n  <p>この場合は以下のコマンドで削除します(CONTAINER IDやNAMEは上で表示されたものを使用)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CONTAINER ID で指定</span>\ndocker <span class=\"nb\">rm </span>ae8523f06af4\n<span class=\"c\"># または NAME で指定</span>\ndocker <span class=\"nb\">rm </span>romantic_booth\n</code></pre></div>  </div>\n</blockquote>\n\n<p>イメージを確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<p>結果はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>REPOSITORY    TAG       IMAGE ID       CREATED         SIZE\nhello-world   latest    d2c94e258dcb   14 months ago   13.3kB\n</code></pre></div></div>\n\n<p>イメージを削除します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image <span class=\"nb\">rm </span>hello-world\n</code></pre></div></div>\n\n<p>結果はこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Untagged: hello-world:latest\nUntagged: hello-world@sha256:94323f3e5e09a8b9515d74337010375a456c909543e1ff1538f5116d38ab3989\nDeleted: sha256:d2c94e258dcb3c5ac2798d32e1249e42ef01cba4841c2234249495f87264ac5a\nDeleted: sha256:ac28800ec8bb38d5c35b49d45a6ac4777544941199075dff8c4eb63e093aa81e\n</code></pre></div></div>\n\n<p>削除されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<p>結果はこんな感じでヘッダ行だけ表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>REPOSITORY   TAG       IMAGE ID   CREATED   SIZE\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nカーネル入れ替えたり、なんやかんやしてるうちにDockerが起動しなくなることがありました。<br />\nそのときは <code class=\"language-plaintext highlighter-rouge\">systemctl status docker</code> を実行して <code class=\"language-plaintext highlighter-rouge\">Active</code>の表示を確認します。\n<code class=\"language-plaintext highlighter-rouge\">failed</code>になっていたら起動に失敗しています。<br />\n原因の調査方法はいろいろありますが、私が遭遇したパターンでは\n<code class=\"language-plaintext highlighter-rouge\">sudo dockerd --debug</code> を実行してエラーメッセージを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">networks have same bridge name</code> と出ている場合は\n<code class=\"language-plaintext highlighter-rouge\">/var/lib/docker/network</code>ディレクトリを消して(不安ならリネームして)、\n<code class=\"language-plaintext highlighter-rouge\">sudo systemctl start docker</code> を実行します。<br />\nこの後、 <code class=\"language-plaintext highlighter-rouge\">systemctl status docker</code> を実行して \n<code class=\"language-plaintext highlighter-rouge\">Active</code>の表示が<code class=\"language-plaintext highlighter-rouge\">active (running)</code>になっていればOKのはず。</p>\n\n</blockquote>\n\n<h1 id=\"カーネルのビルド\">カーネルのビルド</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<p>たとえば、以下。 どこでも良いけど、以下の手順はこのディレクトリで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /proj/wsl_kernel <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /proj/wsl_kernel\n</code></pre></div></div>\n\n<h2 id=\"カーネルソースの取得\">カーネルソースの取得</h2>\n<p>作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)にカーネルソースをダウンロードします。<br />\ngitリポジトリをcloneするか、リリースソースをダウンロードして展開します。</p>\n\n<h3 id=\"gitでcloneする場合\">gitでcloneする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/microsoft/WSL2-Linux-Kernel.git\n\n<span class=\"c\"># 目的のタグをチェックアウト</span>\ngit <span class=\"nt\">-C</span> WSL2-Linux-Kernel checkout <span class=\"nt\">-b</span> WSL-6.6.36.3 refs/tags/linux-msft-wsl-6.6.36.3\n\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> WSL2-Linux-Kernel linux\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nclone済みなら念のため<code class=\"language-plaintext highlighter-rouge\">git pull</code>して最新状態にしておく</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nブランチ作る必要ないけど、念のため。</p>\n</blockquote>\n\n<h3 id=\"リリースソースzipをダウンロードする場合\">リリースソース(zip)をダウンロードする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-6.6.36.3.zip\nunzip linux-msft-wsl-6.6.36.3.zip\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> linux-msft-wsl-6.6.36.3 linux\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nunzipはデフォルトではインストールされていないのでインストール必要。</p>\n</blockquote>\n\n<h2 id=\"スクリプトdockerfileの入手\">スクリプト&Dockerfileの入手</h2>\n<blockquote>\n  <p>[!NOTE]\nGistに必要なスクリプト&<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>を置いておいたので以下のページの<code class=\"language-plaintext highlighter-rouge\">DownloadZIP</code>ボタンからダウンロードして\n作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)に展開してください。<br />\n<a href=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021\" target=\"_blank\">Gist:WSLカーネルビルド環境</a></p>\n\n  <p>または以下のコマンドで取得できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021/archive/main.zip\nunzip <span class=\"nt\">-j</span> main.zip\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージを作成\">Dockerイメージを作成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>は上のサイトからダウンロードしてください。<br />\n<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>があるディレクトリで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker build <span class=\"nt\">-t</span> wslkernelbuilder:2.0 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<p>Dockerfileの内容は以下の通り。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=Dockerfile\"></script>\n</dev>\n\n<h2 id=\"dockerコンテナの起動確認\">Dockerコンテナの起動確認</h2>\n<p>上で作成したDockerイメージでコンテナを起動できることを確認します。<br />\nこのスクリプトは上のDockerイメージでDockerコンテナを起動し、シェルを実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_interactive.sh\n</code></pre></div></div>\n<p>プロンプトが以下のように変わればOKです(最後のディレクトリはlinuxのリンク先の実体のディレクトリ名になります)。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>builder [ /usr/src/WSL2-Linux-Kernel ]$\n</code></pre></div></div>\n<p>適当なコマンドを入力して遊んでみてください(カレントディレクトリのファイルは消さないように)。<br />\n最後は<code class=\"language-plaintext highlighter-rouge\">exit</code>で終了します。<br />\n起動時に<code class=\"language-plaintext highlighter-rouge\">--rm</code>しているので、終了時コンテナは削除されます。<br />\nなので、<code class=\"language-plaintext highlighter-rouge\">/usr/src</code>ディレクトリ以外にファイルを作っても終了後はなくなります。<br />\nもちろん<code class=\"language-plaintext highlighter-rouge\">tdnf install</code>(marinerなのでaptではない)でインストールしたアプリケーションもきれいさっぱりなくなります。<br />\n<code class=\"language-plaintext highlighter-rouge\">/usr/src</code>ディレクトリはスクリプトを起動したディレクトリをマウントしていますので、\nここに作成したファイルはコンテナ終了後も残ります(逆に削除するとホストからも削除されます)。</p>\n\n<h2 id=\"カーネルのビルド-1\">カーネルのビルド</h2>\n\n<p>カーネルソースの取得、Dockeイメージのビルドが終わったら、以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_kernel.sh\n</code></pre></div></div>\n\n<p>実行には1時間とか2時間とかのオーダーの時間がかかりますので、お茶でも飲んで気長に待ってください。</p>\n\n<p>実行完了後、<code class=\"language-plaintext highlighter-rouge\">out</code>ディレクトリに<code class=\"language-plaintext highlighter-rouge\">bzImage</code>と<code class=\"language-plaintext highlighter-rouge\">linux-module-6.6.36.3-microsoft-standard-wsl2_6.6.36.3-3_amd64.deb</code>ができます。<br />\nこれらを使用するPCのWindowsから見えるフォルダ(例えば、<code class=\"language-plaintext highlighter-rouge\">c:\\WSL_KERNEL\\</code>)にコピーします。</p>\n\n<h3 id=\"カーネルビルド用スクリプト\">カーネルビルド用スクリプト</h3>\n\n<p>用意したスクリプトの概要は以下の通りです。</p>\n\n<h4 id=\"build_functionssh\">build_functions.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_functions.sh</code>はビルドに関わる処理を関数化したものをまとめたファイルです。<br />\n以下のスクリプトからインクルードして使用します。</p>\n\n<p>Dockerコンテナを使用するので、あらかじめDockerイメージを作成しておく必要があります。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_functions.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_kernelsh\">build_wsl_kernel.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_kernel.sh</code>はカーネルのビルドを行います。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_kernel.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_interactivesh\">build_wsl_interactive.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_interactive.sh</code>はコンテナ内でインタラクティブにビルド操作をしたい場合に使用します。<br />\nたとえば、新しくモジュールを有効化したいとき、<code class=\"language-plaintext highlighter-rouge\">make menuconfig</code>して<code class=\"language-plaintext highlighter-rouge\">make</code>するような場合です。<br />\n実行するとコンテナ内のシェルが起動するので、実行したいコマンドを実行してください。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_interactive.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_usb-storagesh\">build_wsl_usb-storage.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_usb-storage.sh</code>はUSBストレージのカーネルモジュールのビルドを行います。<br />\nバージョン6.6.<em>ではすでに有効になっているので、使用しません。<br />\nバージョン5.15.</em>で標準カーネルのままカーネルモジュールをビルドして使用するときに使用します。<br />\n6.6.*でも他のモジュールを有効化するときに参考になるかもと残しています。</p>\n\n<p><a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">参照先</a>\nの処理を少し書き換えただけです。</p>\n\n<p>outディレクトリに作成された<code class=\"language-plaintext highlighter-rouge\">linux-module-usb-storage-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64</code>を使用するディストリビューションにコピーし、\n以下のように実行しますが、インストール先の<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/</code>が書き込み禁止のため\nあらかじめここにoverlayfsをマウントしておく必要があります。<br />\nマウント方法やその他使用方法は\n<a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">参照先</a>\nを参照してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> linux-module-usb-storage-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64\n</code></pre></div></div>\n<p>標準カーネルを使用することを前提にしているので、カーネルの差し替えは必要ありません。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_usb-storage.sh\"></script>\n</dev>\n\n<blockquote>\n  <p>[!NOTE]\nこのスクリプトは使用するWSLカーネルで実行されているディストリビューションで実行してください。<br />\nそうしないとBTFの確認(<code class=\"language-plaintext highlighter-rouge\">check_btf</code>関数)が失敗します。</p>\n</blockquote>\n\n<h1 id=\"差し替えたカーネルで実行\">差し替えたカーネルで実行</h1>\n\n<h2 id=\"wslの停止\">WSLの停止</h2>\n<p>WSL実行中の場合はすべてのウィンドウを閉じます。<br />\nさらにWSLを完全に終了するために以下のコマンドを実行します。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--shutdown</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>念のため、すべて停止していることを確認を確認)</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>結果はこんな感じで<code class=\"language-plaintext highlighter-rouge\">STATE</code>がすべて<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  NAME              STATE           VERSION\n* Ubuntu-20.04-1    Stopped         2\n  ubuntu-22.04-2    Stopped         2\n  test_6_6          Stopped         2\n</code></pre></div></div>\n\n<h2 id=\"差し替えカーネルの設定\">差し替えカーネルの設定</h2>\n\n<p>差し替えカーネルを設定するため、<code class=\"language-plaintext highlighter-rouge\">%USERPROFILE%\\.wslconfig</code> に以下を追記(なければ新規作成)します。<br />\nここで指定しているのは先にコピーしたbzImageファイルのパスです。<br />\nただし、フォルダ区切りの<code class=\"language-plaintext highlighter-rouge\">\\</code>は<code class=\"language-plaintext highlighter-rouge\">\\\\</code>に置き換える必要があります。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[wsl2]\nkernel=c:\\\\WSL_KERNEL\\\\bzImage\n</code></pre></div></div>\n\n<h2 id=\"差し替えカーネルでの起動\">差し替えカーネルでの起動</h2>\n<p>通常通り、ディストリビューションを起動します。<br />\n起動後、ディストリビューション内のシェルで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">uname</span> <span class=\"nt\">-r</span>\n</code></pre></div></div>\n<p>結果が<code class=\"language-plaintext highlighter-rouge\">6.6.36.3-microsoft-standard-WSL2</code>と差し替えたカーネルのバージョンになっていることを確認します。</p>\n\n<h2 id=\"カーネルモジュールのインストール\">カーネルモジュールのインストール</h2>\n\n<p>次に先ほどコピーしたカーネルモジュールをインストールします。</p>\n<blockquote>\n  <p>[!NOTE]\nカーネルモジュールのインストールはカーネル差し替え後に行ってください。<br />\n差し替え前が標準カーネルだった場合、インストール先がリードオンリーのため、インストールに失敗します。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> /mnt/c/WSL_KERNEL/linux-module-6.6.36.3-microsoft-standard-wsl2_6.6.36.3-3_amd64.deb\n</code></pre></div></div>\n\n<p>インストールされると、<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/6.6.36.3-microsoft-standard-WSL2/</code>以下に各種ファイルが作成されます。</p>\n\n<p>インストールしたモジュールを読み込むため、ディストリビューションを再起動します。<br />\nWSLを完全に終了するために以下のコマンドを実行します。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--shutdown</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>念のため、すべて停止していることを確認(<code class=\"language-plaintext highlighter-rouge\">STATE</code>が<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていることを確認)</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  NAME              STATE           VERSION\n* Ubuntu-20.04-1    Stopped         2\n  ubuntu-22.04-2    Stopped         2\n  test_6_6          Stopped         2\n</code></pre></div></div>\n\n<p>再度カーネルモジュールをインストールしたディストリビューションを起動し、\n起動したディストリビューションでモジュールが読み込まれていることを確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsmod\n</code></pre></div></div>\n<p>以下のように、いくつかのモジュールが読み込まれていることを確認します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Module                  Size  Used by\nintel_rapl_msr         16384  0\nintel_rapl_common      36864  1 intel_rapl_msr\ncrc32c_intel           16384  0\nconfigfs               61440  0\nip_tables              32768  0\nautofs4                53248  0\n</code></pre></div></div>\n\n<h1 id=\"おわり\">おわり</h1>\n<p>この状態でカーネルの差し替えは完了です。<br />\nusbipd-win を使用すれば、USBシリアルやUSBストレージ、USBカメラも使えるようになります。\nただし、モジュールvhci-hcd(USB 仮想ホストコントローラインターフェース)が読み込まれていないので、\n以下のコマンドで読み込んでおく必要があります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe vhci-hcd\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n起動時にモジュールを読み込むには、通常<code class=\"language-plaintext highlighter-rouge\">/etc/modules</code>に設定しておけば良いのですが、\n試してみましたがうまくいきませんでした。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下のように記述しておくとうまくいくかもしれません。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\ncommand=modprobe vhci-hcd\n</code></pre></div>  </div>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSBデバイスを使う(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSBデバイスを使う(その1)</h1>\n      <p>WSLでUSBデバイスを使う(その1:準備&USB-Serial編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLでUSBを使う方法。あちこちに情報があるけど、なんとなく自分なりにまとめておく。<br />\n<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb\" target=\"_blank\">本家の説明</a></p>\n\n<p>ますは、準備とLinuxカーネルのビルドが必要ないUSB-Serialデバイスから。</p>\n\n<h1 id=\"wsl側の準備\">WSL側の準備</h1>\n\n<h2 id=\"wslのバージョン\">WSLのバージョン</h2>\n<p>使用したWSLのバージョンは以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wsl <span class=\"nt\">--version</span>\n\nWSL バージョン: 2.2.4.0\nカーネル バージョン: 5.15.153.1-2\nWSLg バージョン: 1.0.61\nMSRDC バージョン: 1.2.5326\nDirect3D バージョン: 1.611.1-81528511\nDXCore バージョン: 10.0.26091.1-240325-1447.ge-release\nWindows バージョン: 10.0.19045.4529\n</code></pre></div></div>\n\n<p>使用したディストリビューションは「Ubuntu 22.04 LTS」</p>\n\n<h2 id=\"wslディストリビューションでsystemdの有効化\">WSLディストリビューションでsystemdの有効化</h2>\n\n<blockquote>\n  <p>[!NOTE]\nインストールしたタイミングによっては既に有効化されているかも。</p>\n</blockquote>\n\n<p>USBのホットプラグ処理は systemd + udev がよしなに行ってくれるみたいなので、systemdを有効化しておく。<br />\n使用するディストリビューションを起動し、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下の設定を行う。</p>\n\n<p>デフォルト(古いデフォルト?)のSystemVinitだとバカチョンで動かなかった…udevサービス再起動とかやったら動いたけど。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdを有効にするか否かはディストリビューション毎の設定</p>\n</blockquote>\n\n<p>設定後、WSLをシャットダウン(コマンドプロンプト等から<code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行)し、<br />\n再度ディストリビューションを起動する。</p>\n\n<p>参考:<a href=\"https://qiita.com/curacao/items/fb9adaf1c097b1acd6a8\" target=\"_blank\">WSL2でsystemctlを使う方法</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdが動作しているか確認するには、<code class=\"language-plaintext highlighter-rouge\">systemctl is-system-running</code> を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">running</code>(起動中) <code class=\"language-plaintext highlighter-rouge\">degraded</code>(起動中だが失敗したサービスなどが存在) と表示されれば動作している。<br />\n<code class=\"language-plaintext highlighter-rouge\">offline</code> と表示されれば起動していない。<br />\nその他使い方についてはぐぐってちょ。</p>\n</blockquote>\n\n<h2 id=\"必要なパッケージをインストール\">必要なパッケージをインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic hwdata\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nlinux-tools-generic : usbipコマンド等が入る<br />\nhwdata : USB ID等のデータベースが入る<br />\nlinux-tools-generic インストールしたら自動でhwdata入るけど….<br />\n参考にしたサイトにこう書いてあったので。<br />\nlinux-tools-virtualと書いてあるサイトもあるけど、ubuntu 22.04だとchangelogとcopyrightしか違わないみたい。<br />\n </p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /usr/lib/linux-tools\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> 5.15.0-113-generic <span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあちこちに<code class=\"language-plaintext highlighter-rouge\">sudo update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20</code>\nでコマンドのバージョン管理を行う例が書かれているけど、なんとなくシンボリックリンクを張る方がしっくりするのでこっちにした。</p>\n\n  <p>本来、usbipを実行すると <code class=\"language-plaintext highlighter-rouge\">/usr/bin/usbip</code> が <code class=\"language-plaintext highlighter-rouge\">/usr/lib/linux-tools/≪カーネルバージョン≫/usbip</code><br />\nを起動してくれるらしいのだけど、WSL環境では≪カーネルバージョン≫がカスタマイズバージョンでうまく働かないので<br />\n/usr/lib/linux-tools/≪カーネルバージョン≫をインストールされているバージョンに飛ばしてやればいい。<br />\nカーネルバージョンが変更されたら動かなくなるけど、そのときは、新しいカーネルバージョン名のシンボリックリンクを作ってやればよい。<br />\nもちろん、linux-tools-genericのアップデートが必要か判断して、必要ならアップデートする。</p>\n</blockquote>\n\n<h1 id=\"windows側の準備\">windows側の準備</h1>\n<h2 id=\"usbipd-win-のインストール\">usbipd-win のインストール</h2>\n<p>まずはUSBをTCP/IP経由で接続させるためのツール、usbipd-win をwindowsにインストールする。<br />\nインストールするには、<a href=\"https://github.com/dorssel/usbipd-win/releases\" target=\"_blank\">ダウンロードページ</a>  から\n最新版(以下の手順で使用したのは4.2.0)のmsiファイルをダウンロードして実行するだけ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストール時PATHが変更されるので、既に開いているコマンドプロンプトorPowerShellは一旦閉じて再実行する。</p>\n</blockquote>\n\n<h1 id=\"usbデバイスの操作\">USBデバイスの操作</h1>\n<p>WSLで使用したいUSBデバイスはあらかじめPCに接続しておく。</p>\n\n<p>以下の処理はコマンドプロンプトorPowerShellで行う。<br />\nただし、bind/unbindサブコマンドは管理者権限が必要なので、管理者として開いたコマンドプロンプトorPowerShellで実行する。</p>\n\n<h2 id=\"接続したいデバイスのbusidを調べる\">接続したいデバイスのBusIDを調べる</h2>\n\n<p>以下のコマンドを実行する。<br />\n結果は例。今回は3-4のUSB Serial Converter を使う。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">list</span><span class=\"w\">\n</span><span class=\"err\">≪結果≫</span><span class=\"w\">\n</span><span class=\"n\">Connected:</span><span class=\"w\">\n</span><span class=\"nx\">BUSID</span><span class=\"w\">  </span><span class=\"nx\">VID:PID</span><span class=\"w\">    </span><span class=\"nx\">DEVICE</span><span class=\"w\">                                                        </span><span class=\"nx\">STATE</span><span class=\"w\">\n</span><span class=\"mi\">2</span><span class=\"nt\">-1</span><span class=\"w\">    </span><span class=\"mi\">1</span><span class=\"n\">f75:0918</span><span class=\"w\">  </span><span class=\"nx\">USB</span><span class=\"w\"> </span><span class=\"err\">大容量記憶装置</span><span class=\"w\">                                            </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span><span class=\"mi\">2</span><span class=\"nt\">-2</span><span class=\"w\">    </span><span class=\"mi\">056</span><span class=\"n\">e:700a</span><span class=\"w\">  </span><span class=\"nx\">Venus</span><span class=\"w\"> </span><span class=\"nx\">USB2.0</span><span class=\"w\"> </span><span class=\"nx\">Camera</span><span class=\"w\">                                           </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span><span class=\"mi\">3</span><span class=\"nt\">-4</span><span class=\"w\">    </span><span class=\"mi\">0403</span><span class=\"p\">:</span><span class=\"mi\">6001</span><span class=\"w\">  </span><span class=\"n\">USB</span><span class=\"w\"> </span><span class=\"nx\">Serial</span><span class=\"w\"> </span><span class=\"nx\">Converter</span><span class=\"w\">                                          </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>ここで表示されたWSLで使用したいUSBデバイスのBUSID(例えば3-4)を覚えておく。</p>\n\n<h2 id=\"デバイスを共有設定する\">デバイスを共有設定する</h2>\n\n<p>管理者として開いたコマンドプロンプトorPowerShellで以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">bind</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">        </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">usbipd: warning: USB filter 'USBPcap' is known to be incompatible with this software; 'bind --force' will be required.</code><br />\nと出た時は、一旦unbindして、–forceオプションを追加して実行<br />\n(うちのPCはWiresharkインストールしてUSBPcap入ってるからだろうなぁ…)</p>\n</blockquote>\n\n<p>実行後、<code class=\"language-plaintext highlighter-rouge\">usbipd list</code>を実行すると、対象デバイスのステータスが Shared または Shared (forced) になっている</p>\n\n<h2 id=\"ディストリビューションの起動\">ディストリビューションの起動</h2>\n\n<p>接続するためのWSLのディストリビューションを起動しておく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n起動してないと<code class=\"language-plaintext highlighter-rouge\">usbipd: error: There is no WSL 2 distribution running; keep a command prompt to a WSL 2 distribution open to leave it running.</code>とエラーになる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nこのとき、複数のディストリビューションが起動していると変なことが起こりそうなので(未確認)\n対象のディストリビューションだけ起動しておくのが良いと思う。</p>\n</blockquote>\n\n<h2 id=\"デバイスを接続する\">デバイスを接続する</h2>\n\n<p>bindしただけではまだWSL側からはUSBデバイスは見えない。</p>\n\n<h3 id=\"windows側から接続する場合\">Windows側から接続する場合</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">attach</span><span class=\"w\"> </span><span class=\"nt\">--wsl</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">             </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"linux側から接続する場合\">linux側から接続する場合</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip attach <span class=\"nt\">-r</span> 172.20.160.1 <span class=\"nt\">-b</span> 3-4    <span class=\"c\"># 172.20.160.1 はWindows側のIPアドレス</span>\n                                            <span class=\"c\"># 3-4は接続するデバイスのBusID</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWindows側のIPアドレスはコマンドプロンプトorPowerShellから<code class=\"language-plaintext highlighter-rouge\">ipconfig</code>コマンドを実行し、<br />\n<code class=\"language-plaintext highlighter-rouge\">Ethernet adapter vEthernet (WSL):</code> に表示されているIPアドレスを使用する。<br />\nでもWSLがミラーネットワークモードになってたらどうなるんだろう???</p>\n</blockquote>\n\n<h2 id=\"デバイス接続を確認する\">デバイス接続を確認する</h2>\n<p>linux側で以下を実行し、接続されたデバイスが表示されていることを確認する。 \n以下のように接続したデバイスが表示されていればOK<br />\n(以下では2行目のFT232 Serial (UART) IC)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n≪結果≫\nBus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub\nBus 001 Device 003: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial <span class=\"o\">(</span>UART<span class=\"o\">)</span> IC\nBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub<span class=\"sb\">```</span>\n</code></pre></div></div>\n\n<h1 id=\"usb-serialデバイスを接続\">USB-Serialデバイスを接続</h1>\n<p>上記操作で接続したUSBデバイスがUSB-Serialデバイス(上記の例では FT232 Serial (UART) IC) であれば、\n<code class=\"language-plaintext highlighter-rouge\">/dev/ttyUSBx</code>(xは数字。通常0から順に割り当てられる)に割り当てられる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> <span class=\"nt\">-la</span> /dev/ttyUSB<span class=\"k\">*</span>\n≪結果≫\ncrw-rw---- 1 root dialout 188, 0  7月  3 11:02 /dev/ttyUSB0\n</code></pre></div></div>\n\n<p>一応、ログを確認してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dmesg\n≪結果≫\n・・・・・・\n<span class=\"o\">[</span>  189.418189] vhci_hcd vhci_hcd.0: pdev<span class=\"o\">(</span>0<span class=\"o\">)</span> rhport<span class=\"o\">(</span>0<span class=\"o\">)</span> sockfd<span class=\"o\">(</span>3<span class=\"o\">)</span>\n<span class=\"o\">[</span>  189.418196] vhci_hcd vhci_hcd.0: devid<span class=\"o\">(</span>196612<span class=\"o\">)</span> speed<span class=\"o\">(</span>2<span class=\"o\">)</span> speed_str<span class=\"o\">(</span>full-speed<span class=\"o\">)</span>\n<span class=\"o\">[</span>  189.418249] vhci_hcd vhci_hcd.0: Device attached\n<span class=\"o\">[</span>  189.690366] vhci_hcd: vhci_device speed not <span class=\"nb\">set</span>\n<span class=\"o\">[</span>  189.760405] usb 1-1: new full-speed USB device number 2 using vhci_hcd\n<span class=\"o\">[</span>  189.840475] vhci_hcd: vhci_device speed not <span class=\"nb\">set</span>\n<span class=\"o\">[</span>  189.910358] usb 1-1: SetAddress Request <span class=\"o\">(</span>2<span class=\"o\">)</span> to port 0\n<span class=\"o\">[</span>  190.135906] usb 1-1: New USB device found, <span class=\"nv\">idVendor</span><span class=\"o\">=</span>0403, <span class=\"nv\">idProduct</span><span class=\"o\">=</span>6001, <span class=\"nv\">bcdDevice</span><span class=\"o\">=</span> 6.00\n<span class=\"o\">[</span>  190.135918] usb 1-1: New USB device strings: <span class=\"nv\">Mfr</span><span class=\"o\">=</span>1, <span class=\"nv\">Product</span><span class=\"o\">=</span>2, <span class=\"nv\">SerialNumber</span><span class=\"o\">=</span>3\n<span class=\"o\">[</span>  190.135921] usb 1-1: Product: FT232R USB UART\n<span class=\"o\">[</span>  190.135923] usb 1-1: Manufacturer: FTDI\n<span class=\"o\">[</span>  190.135924] usb 1-1: SerialNumber: A50285BI\n<span class=\"o\">[</span>  190.511832] usbcore: registered new interface driver ftdi_sio\n<span class=\"o\">[</span>  190.511852] usbserial: USB Serial support registered <span class=\"k\">for </span>FTDI USB Serial Device\n<span class=\"o\">[</span>  190.511881] ftdi_sio 1-1:1.0: FTDI USB Serial Device converter detected\n<span class=\"o\">[</span>  190.511904] usb 1-1: Detected FT232RL\n<span class=\"o\">[</span>  190.521353] usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB0       ← /dev/ttyUSB0が割り当てられたことが分かる\n</code></pre></div></div>\n\n<p>デフォルトで使用できるUSB-Serialデバイスは、\nSilicon Labs社製 CP210x、FTDI社製シリアルコンバータ(FT232)、CH34x(安い中国製Arduinoで使われているらしい)らしい。</p>\n\n<p>/dev/ttyUSBxが割り当てられていない場合は、対応しているUSB-Serialデバイスか、systemdが有効になっているか、等を確認してください。</p>\n\n<blockquote>\n  <p>[!NOTE]\n参考:<a href=\"https://another.maple4ever.net/archives/3221/?fbclid=IwZXh0bgNhZW0CMTAAAR2mnOe2c5FmYg3ig1IQbB1r4Y3t43MLJyqvzAx6tyjuiWCjETjj_x9Rkd0_aem_EpK6sQQOwszToANXZLsfiQ\" target=\"_blank\">Windows WSL2 の Ubuntu 22.04 上から USB-UART 経由で M5Stack に書き込みする</a><br />\n上記サイトではudevルールをplatform.ioのサイトから拝借してきているが、上記の製品なら持ってこなくても可。<br />\n互換品とかでうまく認識しないときは試してみると動くかも(試してないので無責任発言)。</p>\n</blockquote>\n\n<h2 id=\"シリアルポートを使ってみる\">シリアルポートを使ってみる</h2>\n\n<p>シリアルポートを使うツールは色々あると思うけど、とりあえず動いているか確認するならこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>pyserial-miniterm <span class=\"nt\">--parity</span> N /dev/ttyUSB0 115200\n</code></pre></div></div>\n\n<p>終了するにはCTRL+]を入力する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nsudoなしで実行するには、自分のアカウントにdialoutグループを追加すればよい。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> dialout\n</code></pre></div>  </div>\n  <p>一旦ログアウトして再ログイン必要。</p>\n</blockquote>\n\n<h2 id=\"デバイスを接続解除する\">デバイスを接続解除する</h2>\n\n<p>WSLをシャットダウンしたら(ディストリビューションのシャットダウンではなくWSL全体)接続解除されるけど、\n手動で接続解除するには以下のコマンドを実行する。</p>\n\n<h3 id=\"windows側から接続解除する場合\">Windows側から接続解除する場合</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\">  </span><span class=\"nx\">detach</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">              </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"linux側から接続解除する場合\">linux側から接続解除する場合</h3>\n<p>linuxから解除するには、まずポート番号を確認する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip port\n≪結果≫\nImported USB devices\n<span class=\"o\">====================</span>\nPort 00: <Port <span class=\"k\">in </span>Use> at Full Speed<span class=\"o\">(</span>12Mbps<span class=\"o\">)</span>\n       Future Technology Devices International, Ltd : FT232 Serial <span class=\"o\">(</span>UART<span class=\"o\">)</span> IC <span class=\"o\">(</span>0403:6001<span class=\"o\">)</span>\n       1-1 -> usbip://172.20.160.1:3240/3-4       ← ホストアドレス\n           -> remote bus/dev 003/004              ← BusID\n           \n</code></pre></div></div>\n\n<p>上記の例ではポート番号は00なので、これをportオプションに指定して以下のように実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip detach <span class=\"nt\">--port</span> 00\n</code></pre></div></div>\n\n<h2 id=\"デバイスを共有解除する\">デバイスを共有解除する</h2>\n\n<p>USBデバイスを共有解除するには、管理者として開いたコマンドプロンプトorPowerShellで以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">unbind</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">           </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nデバイスの共有解除しなければ、PCを再起動しても共有設定されたままになる。<br />\nただし、使用しているUSBポートに別のUSBデバイスを挿入すると共有解除されるが、再度同じUSBデバイスを挿入すれば共有設定される。<br />\n何言ってるか分からんと思うけど、USBデバイス挿抜してみて確かめてみて。</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(Bookworm)のインストール(Raspberry Pi Imager)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(Bookworm)のインストール(Raspberry Pi Imager)</h1>\n      <p>Raspberry Pi OS(bookworm)のRaspberry Pi Imagerを使用したインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>RaspberrypiOSがBookwormになったので、インストール方法のメモ。<br />\n基本的にBullseyeのときと変わらないけど、ちょっと変わったところもあるので。<br />\n<a href=\"/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Bullseyeのときの手順メモ</a>も参照してください。</p>\n\n<h1 id=\"sdカードへの書き込み\">SDカードへの書き込み</h1>\n<p>Raspberry Pi Imager で書き込み。<br />\n使い方はあちこちに書いてあるけど、例えばこちら。</p>\n<ul>\n  <li><a href=\"https://qiita.com/mmake/items/576a2f60dffcd9291da3/\" target=\"_blank\">Raspberry Pi Imager のインストールと使い方</a></li>\n</ul>\n\n<p>バージョン変わると微妙に手順が変わったりするので、最新情報はぐぐってちょ。</p>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n<blockquote>\n  <p>[!NOTE]\n下記の変更をイッパツで行うスクリプトは以下。<br />\nWindowsのコマンドプロンプトで実行すると想定。  Windows版python必要。<br />\nそれぞれの<code class=\"language-plaintext highlighter-rouge\">F=</code>の部分を対象のドライブレターに変更する。</p>\n\n  <ul>\n    <li>UARTにUARTコネクタを使用する場合はこちら\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import re;F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">onfig.txt';a=open(F).read();a=re.sub(r'</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">(?!.*</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">)', '[pi5]</span><span class=\"se\">\\n</span><span class=\"s2\">dtparam=uart0</span><span class=\"se\">\\n\\n</span><span class=\"s2\">[all]</span><span class=\"se\">\\n</span><span class=\"s2\">enable_uart=1</span><span class=\"se\">\\n</span><span class=\"s2\">', a, flags=re.DOTALL);open(F, 'w').write(a)\"</span>\npython <span class=\"nt\">-c</span> <span class=\"s2\">\"F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">mdline.txt';a=open(F).read();a=a.replace(' quiet', '').replace(' splash', '').replace(' plymouth.ignore-serial-consoles', '')+' ipv6.disable=1';open(F, 'w').write(a)\"</span>\n</code></pre></div>      </div>\n    </li>\n    <li>UARTに40pinヘッダのpin8/10(GPIOs 14 & 15)を使用する場合はこちら\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import re;F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">onfig.txt';a=open(F).read();a=re.sub(r'</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">(?!.*</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">)', '[pi5]</span><span class=\"se\">\\n</span><span class=\"s2\">dtparam=uart0_console</span><span class=\"se\">\\n\\n</span><span class=\"s2\">[all]</span><span class=\"se\">\\n</span><span class=\"s2\">enable_uart=1</span><span class=\"se\">\\n</span><span class=\"s2\">', a, flags=re.DOTALL);open(F, 'w').write(a)\"</span>\npython <span class=\"nt\">-c</span> <span class=\"s2\">\"F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">mdline.txt';a=open(F).read();a=a.replace(' quiet', '').replace(' splash', '').replace(' plymouth.ignore-serial-consoles', '')+' ipv6.disable=1';open(F, 'w').write(a)\"</span>\n</code></pre></div>      </div>\n    </li>\n  </ul>\n</blockquote>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行を以下に変更</p>\n\n<ul>\n  <li>UARTにUARTコネクタを使用する場合はこちら</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[pi5]\ndtparam=uart0\n\n[all]\nenable_uart=1\n</code></pre></div></div>\n\n<ul>\n  <li>UARTに40pinヘッダのpin8/10(GPIOs 14 & 15)を使用する場合はこちら</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[pi5]\ndtparam=uart0_console\n\n[all]\nenable_uart=1\n</code></pre></div></div>\n\n<h2 id=\"ipv6の無効化\">IPv6の無効化</h2>\n<p>IPv6を無効化しておきたいときは、\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する。<br />\nこのファイルは1行で書かないといけないので、改行してはいけない。</p>\n\n<h2 id=\"ブートログの表示\">ブートログの表示</h2>\n\n<p>ブートログが見えないと不安な人は、<br />\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> から <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code>\nを削除しておくとよい。</p>\n<blockquote>\n  <p>[!NOTE]\nLITE版では<code class=\"language-plaintext highlighter-rouge\">quiet</code>を削除(それ以外は指定されていないので)</p>\n</blockquote>\n\n<h1 id=\"最初の起動\">最初の起動</h1>\n<p>書き込んだSDカードをRaspberry Piに挿入して電源ON。<br />\nごちょごちょと設定したあと、起動する(途中2回ほどrebootしてるらしい)</p>\n\n<h1 id=\"お約束\">お約束</h1>\n\n<p>ソフト類を最新版にする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n<span class=\"nb\">sudo </span>reboot \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <h4 id=\"ウィンドウマネージャをopenboxに変更したい場合\">ウィンドウマネージャをOpenboxに変更したい場合</h4>\n  <p>VNCに不具合がるなどの理由で以前のバージョンと同じX11ベースのOpenboxに変更したい場合は以下の手順で変更する。<br />\nちなみにOpenboxに変更したい場合は以下のコマンドで変更できる。<br />\nVNCを有効化した後にウィンドウマネージャを変更すると動作が不安定になることがあるので、VNCを有効化する前に変更するのがベター。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config nonint do_wayland W1\n<span class=\"nb\">sudo </span>reboot \n</code></pre></div>  </div>\n\n  <p>VNC有効化後、以下のコマンドでデフォルトのウィンドウマネージャ(wayfire)が無効になっていることを確認する。<br />\nなにも表示されなければOK</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pgrep wayfire\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"お好みで\">お好みで</h1>\n\n<p>その他お好み設定は\n<a href=\"/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</a>\nと同じ。<br />\nめんどくさいのでスクリプトを実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.githubusercontent.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c/raw/pi_setup1.sh\nbash pi_setup1.sh \n<span class=\"c\"># 途中sambaのパスワード設定がある  </span>\n<span class=\"nb\">sudo </span>reboot \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nIpV6無効の環境でwayfireでVNCを有効にする場合、VNCを有効化する前に\n以下のコマンドでwayfireでIPv4を使用するように設定する必要がある。<br />\nこの処理は上の<code class=\"language-plaintext highlighter-rouge\">pi_setup1.sh</code>の処理に含まれている。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /etc/wayvnc/config /etc/wayvnc/config.org\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s/</span><span class=\"se\">\\:\\:</span><span class=\"s2\">/0</span><span class=\"se\">\\.</span><span class=\"s2\">0</span><span class=\"se\">\\.</span><span class=\"s2\">0</span><span class=\"se\">\\.</span><span class=\"s2\">0/g\"</span> /etc/wayvnc/config\n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">/etc/wayvnc/config</code>の2行目の<code class=\"language-plaintext highlighter-rouge\">address=::</code>を<code class=\"language-plaintext highlighter-rouge\">address=0.0.0.0</code>に変更している。</p>\n</blockquote>\n\n<h1 id=\"pyenvのインストール\">pyenvのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<p>ここで一旦ログアウト&再ログイン</p>\n\n<h1 id=\"pythonのインストール\">pythonのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.11.9\npyenv shell 3.11.9 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\npyenv shell <span class=\"nt\">--unset</span> \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi で Text To Speech(音声合成)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi で Text To Speech(音声合成)</h1>\n      <p>Raspberry Pi でpythonを使用してText To Speech(音声合成)を試す</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi でText To Speech(音声合成)をofflineで実行することを試してみます。<br />\n(初回実行時は辞書データをダウンロードするのでインターネットにつながっている必要があります)</p>\n\n<blockquote>\n  <p>[!NOTE]\n環境変数 DISPLAY が設定されている場合、変数が示すマシンでXサーバが実行されている必要があります。<br />\n実行されていない場合は、オーディオ再生の際、コマンドがハングアップします、<br />\nその際は対象マシンでXサーバを実行するか、<code class=\"language-plaintext highlighter-rouge\">unset DISPLAY</code>で環境変数を削除してください。</p>\n</blockquote>\n\n<h1 id=\"スピーカの準備\">スピーカの準備</h1>\n<p>Raspberry Pi5ではオーディオジャックがなくなったので、\n将来のことを考えてUSBスピーカ(USBヘッドセット)を使用することにします。</p>\n\n<h2 id=\"スピーカの接続\">スピーカの接続</h2>\n\n<p>まず、USBスピーカをUSBポートに接続し、スピーカが認識されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>lsusb\nBus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub\nBus 001 Device 003: ID 0c76:161f JMTek, LLC. USB PnP Audio Device   ← これ\nBus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub\nBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub\n</code></pre></div></div>\n\n<h2 id=\"カード番号とデバイス番号の確認\">カード番号とデバイス番号の確認</h2>\n<p>使用するカード番号/デバイス番号を確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay <span class=\"nt\">-l</span>\n<span class=\"k\">****</span> ハードウェアデバイス PLAYBACK のリスト <span class=\"k\">****</span>\nカード 0: vc4hdmi0 <span class=\"o\">[</span>vc4-hdmi-0], デバイス 0: MAI PCM i2s-hifi-0 <span class=\"o\">[</span>MAI PCM i2s-hifi-0]\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\nカード 1: vc4hdmi1 <span class=\"o\">[</span>vc4-hdmi-1], デバイス 0: MAI PCM i2s-hifi-0 <span class=\"o\">[</span>MAI PCM i2s-hifi-0]\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\nカード 2: Headphones <span class=\"o\">[</span>bcm2835 Headphones], デバイス 0: bcm2835 Headphones <span class=\"o\">[</span>bcm2835 Headphones]\n  サブデバイス: 8/8\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\n  サブデバイス <span class=\"c\">#1: subdevice #1</span>\n  サブデバイス <span class=\"c\">#2: subdevice #2</span>\n  サブデバイス <span class=\"c\">#3: subdevice #3</span>\n  サブデバイス <span class=\"c\">#4: subdevice #4</span>\n  サブデバイス <span class=\"c\">#5: subdevice #5</span>\n  サブデバイス <span class=\"c\">#6: subdevice #6</span>\n  サブデバイス <span class=\"c\">#7: subdevice #7</span>\nカード 3: Device <span class=\"o\">[</span>USB PnP Audio Device], デバイス 0: USB Audio <span class=\"o\">[</span>USB Audio]         ← これ\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\n</code></pre></div></div>\n\n<p>カード番号が 3 または ‘Device’、デバイス番号が0であることが分かります</p>\n\n<h2 id=\"テスト再生\">テスト再生</h2>\n<p>テスト再生してみます。<br />\n-D オプションのパラメータは、<code class=\"language-plaintext highlighter-rouge\">plughw:</code>に続けて上で調べたカード番号、<code class=\"language-plaintext highlighter-rouge\">,</code>を挟んでデバイス番号を指定します。<br />\nwavファイルは何でもかまいません。下記はデフォルトでインストール済みのファイルなのでそれを使いました。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay <span class=\"nt\">-D</span> plughw:Device,0 /usr/share/sounds/alsa/Front_Center.wav\n再生中 WAVE <span class=\"s1\">'/usr/share/sounds/alsa/Front_Center.wav'</span> : Signed 16 bit Little Endian, レート 48000 Hz, モノラル\n</code></pre></div></div>\n\n<h2 id=\"デフォルトのオーディオデバイスの設定\">デフォルトのオーディオデバイスの設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">sudo raspi-config</code> を実行し、以下の順で選択します。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">1 System Options</code>\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">S2 Audio</code>\n        <ul>\n          <li>使用するオーディオデバイス( <code class=\"language-plaintext highlighter-rouge\">71 USB PnP Audio Device</code>など )</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">Finish</code>で終了</li>\n</ul>\n\n<p>デフォルト設定が変更されたことを確認するため、上記テスト再生のコマンドから-Dオプションを削除して再生されることを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay /usr/share/sounds/alsa/Front_Center.wav\n再生中 WAVE <span class=\"s1\">'/usr/share/sounds/alsa/Front_Center.wav'</span> : Signed 16 bit Little Endian, レート 48000 Hz, モノラル\n</code></pre></div></div>\n\n<h1 id=\"python仮想環境の作成とモジュールのインストール\">python仮想環境の作成とモジュールのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openjtalk\n<span class=\"nb\">cd</span> /work/openjtalk\n\npyenv virtualenv 3.11.9 openjtalk\npyenv <span class=\"nb\">local </span>openjtalk \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># pyopenjtalkのインストールに必要なのでcmakeをインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n\n<span class=\"c\"># pyopenjtalkのインストールbuildが実行されるので時間がかかる</span>\npip <span class=\"nb\">install </span>pyopenjtalk\n\n<span class=\"c\"># wavファイルの保存に使用するのでscipyもインストール</span>\npip <span class=\"nb\">install </span>scipy\n\n<span class=\"c\"># marineを使う場合は以下も実行</span>\npip <span class=\"nb\">install </span>pyopenjtalk[marine]\n</code></pre></div></div>\n\n<h1 id=\"pyopenjtalk-を実行してみる\">pyopenjtalk を実行してみる</h1>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  talk_test1.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">pyopenjtalk</span>\n<span class=\"kn\">from</span> <span class=\"nn\">scipy.io</span> <span class=\"kn\">import</span> <span class=\"n\">wavfile</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"c1\"># marineを使用する場合はrun_marineをTrueにする\n</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">sr</span> <span class=\"o\">=</span> <span class=\"n\">pyopenjtalk</span><span class=\"p\">.</span><span class=\"n\">tts</span><span class=\"p\">(</span><span class=\"s\">\"おめでとうございます\"</span><span class=\"p\">,</span> <span class=\"n\">run_marine</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n<span class=\"n\">wavfile</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">\"test1.wav\"</span><span class=\"p\">,</span> <span class=\"n\">sr</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">int16</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python talk_test1.py\n</code></pre></div></div>\n\n<p>再生します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>aplay test1.wav\n</code></pre></div></div>\n\n<p>スピーカーから「おめでとうございます」と聞こえたら成功です。おめでとうございます。</p>\n\n<h1 id=\"pythonからオーディオ再生する\">pythonからオーディオ再生する</h1>\n\n<p>オーディオ再生のためのモジュールは色々ありますが、\n下の直接再生に使用するにはnumpyデータを入力できることが必須となるので\nsimpleaudioを使用してみます。</p>\n\n<p>モジュールをインストールします。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># simpleaudioのインストールに必要なパッケージのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libasound2-dev\n\n<span class=\"c\"># インストール</span>\npip <span class=\"nb\">install </span>simpleaudio\n</code></pre></div></div>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  play_test1.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">simpleaudio</span>\n\n<span class=\"n\">wav_obj</span> <span class=\"o\">=</span> <span class=\"n\">simpleaudio</span><span class=\"p\">.</span><span class=\"n\">WaveObject</span><span class=\"p\">.</span><span class=\"n\">from_wave_file</span><span class=\"p\">(</span><span class=\"s\">\"test1.wav\"</span><span class=\"p\">)</span>\n<span class=\"n\">play_obj</span> <span class=\"o\">=</span> <span class=\"n\">wav_obj</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n<span class=\"n\">play_obj</span><span class=\"p\">.</span><span class=\"n\">wait_done</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python play_test1.py\n</code></pre></div></div>\n<h1 id=\"pyopenjtalkで作成した音声を直接再生する\">pyopenjtalkで作成した音声を直接再生する</h1>\n\n<p>逐一wavファイルを作成するのは面倒なので、合成したらすぐ再生するようにしてみます。</p>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  talk_test2.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">pyopenjtalk</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">simpleaudio</span>\n\n<span class=\"c1\"># marineを使用する場合はrun_marineをTrueにする\n</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">sr</span> <span class=\"o\">=</span> <span class=\"n\">pyopenjtalk</span><span class=\"p\">.</span><span class=\"n\">tts</span><span class=\"p\">(</span><span class=\"s\">\"直接再生します\"</span><span class=\"p\">,</span> <span class=\"n\">run_marine</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n<span class=\"c1\"># x : waveform\n# sr: sampling rate\n</span>\n<span class=\"n\">wav_obj</span> <span class=\"o\">=</span> <span class=\"n\">simpleaudio</span><span class=\"p\">.</span><span class=\"n\">WaveObject</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">int16</span><span class=\"p\">),</span> <span class=\"n\">num_channels</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">bytes_per_sample</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">sample_rate</span><span class=\"o\">=</span><span class=\"n\">sr</span><span class=\"p\">)</span>\n<span class=\"n\">play_obj</span> <span class=\"o\">=</span> <span class=\"n\">wav_obj</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n<span class=\"n\">play_obj</span><span class=\"p\">.</span><span class=\"n\">wait_done</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python talk_test2.py\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 22.04をNative環境にインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 22.04をNative環境にインストール</h1>\n      <p>Ubuntu 22.04をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuのダウンロード\">Ubuntuのダウンロード</h1>\n<p><a href=\"https://www.ubuntulinux.jp/download\" target=\"_blank\">Ubuntuの入手</a>からダウンロード<br />\nSecure Boot環境で日本語RemixのISOファイルを使うと<code class=\"language-plaintext highlighter-rouge\">Verification failed: (0x1A) Security Violation</code>\nと怒らたので、jp.ubuntu.comのダウンロードページからUbuntu Desktopをダウンロードした。<br />\nブータブルUSBを作るには、Rufus等を使う(ググってちょ)。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<p>以下の参考ページを参照して起動するとこまでやってちょ。</p>\n\n<ul>\n  <li><a href=\"https://ippei8jp.github.io/memoBlog/2021/07/15/install2004_native.html\" target=\"_blank\">UbuntuをNative環境にインストールする(20.04)</a></li>\n  <li><a href=\"https://ippei8jp.github.io/memoBlog/2022/07/24/install2204.html\" target=\"_blank\">Ubuntu 22.04のVirtualBoxへのインストール</a></li>\n  <li>Ubuntu 22.04 デュアルブートのインストール方法は以下を参考\n    <ul>\n      <li><a href=\"https://dailylife.pman-bros.com/ubuntu22_install/\" target=\"_blank\">Ubuntu 22.04 LTS をインストールする -【マルチブート編】</a></li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"お好みで\">お好みで</h1>\n<p>作業中に画面が消えると鬱陶しいのでパワマネ無効化。<br />\nTAB補完使えばコピペするほどでもないので、最初にやっとく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h1 id=\"最新版にupdate\">最新版にupdate</h1>\n\n<p>とりあえず最新版に</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ついでにsshもインストールしておく。<br />\nwebで調べたコマンドをコピペしたいので。<br />\n参考:<a href=\"https://ippei8jp.github.io/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">ubuntuにSSHサーバをセットアップする</a></p>\n\n<ul>\n  <li>パッケージをインストール\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\n</code></pre></div>    </div>\n    <ul>\n      <li>これだけでパスワード認証は繋がるはず。</li>\n    </ul>\n  </li>\n  <li>公開鍵認証を使用する場合は、公開鍵を<code class=\"language-plaintext highlighter-rouge\">~/.ssh/authorized_keys</code>に追記し、attribute変更。<br />\n(コピペで追記したいのでsshで接続したターミナルから作業するのがベター)</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/.ssh\nvi ~/.ssh/authorized_keys\n<span class=\"c\">### 公開鍵を追記 ###</span>\n<span class=\"nb\">chmod </span>600 ~/.ssh/authorized_keys\n</code></pre></div></div>\n\n<p>念のためここでリブート。</p>\n\n<h1 id=\"chromeとリモートデスクトップのインストール\">chromeとリモートデスクトップのインストール</h1>\n<p>参考: <a href=\"https://qiita.com/grgrjnjn/items/a5c4da336031b63f09a6\" target=\"_blank\">UbuntuにChromeをインストールする手順</a><br />\n参考: <a href=\"https://zenn.dev/karaage0703/articles/cfde5e6a4f43c3\" target=\"_blank\">Linux(Ubuntu)のリモートデスクトップ設定(Google Chrome リモートデスクトップ/xrdp)</a></p>\n\n<h2 id=\"おまじない\">おまじない</h2>\n<p>chrome リモートデスクトップをインストールすると、ローカル端末でのログインができなくなるので、\n以下の処理を行う。</p>\n\n<p>新しく使用する<code class=\"language-plaintext highlighter-rouge\">.desktop</code>ファイルを作成(ubuntuをベースに使用)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /usr/share/xsessions/\n<span class=\"nb\">sudo cp </span>ubuntu.desktop ubuntu-local.desktop\n</code></pre></div></div>\n\n<p>以下のパッチをあてる。</p>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">Name</code>の変更と<code class=\"language-plaintext highlighter-rouge\">Exec</code>に<code class=\"language-plaintext highlighter-rouge\">DISPLAY=\":0\"</code>を追加</p>\n</blockquote>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ubuntu.desktop      2022-04-08 04:07:53.000000000 +0900\n</span><span class=\"gi\">+++ ubuntu-local.desktop        2023-11-11 07:25:37.223280734 +0900\n</span><span class=\"p\">@@ -1,7 +1,7 @@</span>\n [Desktop Entry]\n<span class=\"gd\">-Name=Ubuntu\n</span><span class=\"gi\">+Name=Ubuntu on local\n</span> Comment=This session logs you into Ubuntu\n<span class=\"gd\">-Exec=env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu\n</span><span class=\"gi\">+Exec=env DISPLAY=\":0\" GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu\n</span> TryExec=/usr/bin/gnome-shell\n Type=Application\n DesktopNames=ubuntu:GNOME\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nローカル端末でログインするときはユーザ名選択後、画面右下の歯車アイコンをクリックし、\n「Ubuntu on local」を選択(一度選択すれば記憶されるので2度目以降は確認だけでOK)してログインする。\n (作成したセッションを選択可能にするには、リブートが必要)</p>\n</blockquote>\n\n<h2 id=\"chromeとリモートデスクトップのインストール-1\">chromeとリモートデスクトップのインストール</h2>\n\n<p>手間を省くためにコマンドラインで以下を実行(sshからで可)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール時にエラーにならないようおまじない</span>\n<span class=\"nb\">mkdir</span> ~/.config/chrome-remote-desktop\n\n<span class=\"c\"># リブート時に消せるようにダウンロード先に/tmpを使う</span>\n<span class=\"nb\">cd</span> /tmp\n\n<span class=\"c\"># chromeのダウンロード</span>\nwget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb\n<span class=\"c\"># chromeのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> ./google-chrome-stable_current_amd64.deb\n\n<span class=\"c\"># remote desktopのダウンロード</span>\nwget https://dl.google.com/linux/direct/chrome-remote-desktop_current_amd64.deb\n<span class=\"c\"># remote desktopのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> ./chrome-remote-desktop_current_amd64.deb\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nインストール時、以下のように提案/推奨されるが、入れなくても大丈夫。<br />\n提案パッケージ:<br />\n  python-psutil-doc x11-xfs-utils<br />\n推奨パッケージ:<br />\n  xserver-xorg-video-dummy pipewire</p>\n</blockquote>\n\n<h2 id=\"chrome起動して初期設定googleにログイン\">chrome起動して初期設定&Googleにログイン</h2>\n<p>ローカル端末でchrome起動</p>\n<ul>\n  <li>既定のブラウザにするか、障害レポートを送信するかを選んでOK</li>\n  <li>「Chromeを独自にカスタマイズ」で「開始する」をクリック\n    <ul>\n      <li>あとはお好みで設定</li>\n    </ul>\n  </li>\n  <li>「あなたのChromeをいつでもどこでも」で「続行」をクリック\n    <ul>\n      <li>chromeへのログインで使用するGoogleアカウントにログイン</li>\n    </ul>\n  </li>\n  <li>リモートデスクトップを検索し、「Chromeリモートデスクトップ」を開く\n    <ul>\n      <li><a href=\"https://remotedesktop.google.com/?hl=ja&pli=1\" target=\"_blank\">https://remotedesktop.google.com/?hl=ja&pli=1</a></li>\n    </ul>\n  </li>\n  <li>「パソコンにアクセス」をクリック</li>\n  <li>「リモートアクセスの設定」の「ONにする」ボタンをクリック</li>\n  <li>「名前の設定」で名前を設定して「次へ」</li>\n  <li>「PINの入力」で設定するPINを2回入力して「起動」</li>\n  <li>\n    <p>パスワード入力を求められるのでパスワード入力</p>\n  </li>\n  <li>ローカル端末でログアウト\n    <blockquote>\n      <p>[!WARNING]\nローカル端末でログインしたままだとリモートデスクトップがつながっても画面表示されない</p>\n    </blockquote>\n  </li>\n</ul>\n\n<h2 id=\"window-pc側から接続\">Window PC側から接続</h2>\n<p>Windows PCでリモートデスクトップアプリを起動し、Ubuntuマシンに接続する<br />\nセッションの選択ではUbunto on Xorg または Ubuntuを選択(たぶんどっちも同じ)</p>\n\n<h3 id=\"おまじない1\">おまじない1</h3>\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。<br />\nこのダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下の内容で作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n<p>参考: <a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></p>\n\n<h3 id=\"おまじない2\">おまじない2</h3>\n<p>接続時、毎回セッションの選択をするのは面倒なので、自動で選択できるようにしようとしたが、<br />\nこれをやるとローカル端末でログインできなくなるのでやめておく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n参考までに手順を記載しておく<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.chrome-remote-desktop-session</code>を以下の内容で作成する</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>exec /etc/X11/Xsession 'env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu'\n</code></pre></div>  </div>\n  <p>env以下は使用するセッションに合わせて変更すること。<br />\n(<code class=\"language-plaintext highlighter-rouge\">/usr/share/xsessions/≪セッション名≫.desktop</code>の<code class=\"language-plaintext highlighter-rouge\">Exec</code>行の内容)</p>\n</blockquote>\n\n<h1 id=\"使いそうなプログラムのインストールと使わないプログラムのアンインストール\">使いそうなプログラムのインストールと使わないプログラムのアンインストール</h1>\n\n<h2 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h2>\n\n<p>ま、使うでしょ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweaks \n</code></pre></div></div>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>使うツールがあったら残してちょ。</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h2 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"お好みで-1\">お好みで</h2>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>ディレクトリにコピるだけ。<br />\n下では全部コピってるけど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.0.0/UDEVGothic_v1.0.0.zip \nunzip UDEVGothic_v1.0.0.zip \n<span class=\"nb\">mkdir</span> ~/.fonts\n<span class=\"nb\">cp </span>UDEVGothic_v1.0.0/<span class=\"k\">*</span>.ttf ~/.fonts/\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。<br />\nさっきフォントのインストールに使った端末ウィンドウを使うと\nエラーで端末ウィンドウが落ちるかもしれないんで一旦終了して新しいウィンドウで。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<h1 id=\"その他設定\">その他設定</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>~/.bashrcに以下を追記。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"c\"># Ubuntu22.04だとwaylandになるらしい</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"wayland\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vi\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># # venvの仮想環境名を表示するための設定</span>\n    <span class=\"c\"># show_virtual_env() {</span>\n    <span class=\"c\">#   if [ -n \"$VIRTUAL_ENV\" ]; then</span>\n    <span class=\"c\">#     echo \"($(basename $VIRTUAL_ENV))\"</span>\n    <span class=\"c\">#   fi</span>\n    <span class=\"c\"># }</span>\n    <span class=\"c\"># PS1='$(show_virtual_env)'$PS1</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nUbuntu20.04とちょっとキーが変更されてる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-home <span class=\"nb\">false \n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"ファイルnautilusのデフォルト動作変更\">ファイル(nautilus)のデフォルト動作変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アドレスバーをテキスト形式にする</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences always-use-location-entry <span class=\"nb\">true</span> \n\n<span class=\"c\"># 詳細表示をデフォルトに</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences default-folder-viewer <span class=\"s1\">'list-view'</span> \n\n<span class=\"c\"># 隠しファイルを表示する</span>\n<span class=\"c\"># 隠しファイルの表示はちょっと場所が違う</span>\ngsettings <span class=\"nb\">set </span>org.gtk.Settings.FileChooser show-hidden <span class=\"nb\">true</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアの更新(update-manager)を起動\n    <ul>\n      <li>更新のチェックが始まった場合はちょっと待つ</li>\n      <li>設定…をクリック\n        <ul>\n          <li>アップデートタブを選択</li>\n          <li>アップデートの自動確認を「なし」に変更</li>\n          <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n          <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n          <li>閉じるをクリック</li>\n        </ul>\n      </li>\n      <li>OKで終了</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Chromeリモートデスクトップ環境ではWindowsで設定したのが有効になっているので必要ないが、\nローカル端末で使用する場合に備えて入れ替えを設定しておく。<br />\n方法は、<code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code> に <code class=\"language-plaintext highlighter-rouge\">XKBOPTIONS=\"ctrl:nocaps\"</code> を追加。<br />\n設定を有効にするにはリブート必要。</p>\n\n<p>参考:<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a><br />\nリンク先は「Ubuntu 20.04/18.04 LTS」となっているが、Ubuntu22.04でも同じらしい。</p>\n\n<h3 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h3>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h1 id=\"sambaのインストール\">sambaのインストール</h1>\n\n<p>ツール本体のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加<br />\n作らなかったワークディレクトリの部分は削除してね。<br />\n他にも共有したいディレクトリがあったら追加してちょ。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">force group</code>に設定するグループは存在するグループ(またはユーザ)名に変更してください。</p>\n\n<p>ここではちょっと見たいファイルがあったのでoptも共有してます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"nfsのインストール\">NFSのインストール</h1>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/exports</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n<span class=\"c\"># abcの下にリモートのファイルが見えたらOK</span>\n</code></pre></div></div>\n\n<h1 id=\"pyenvのインストール\">pyenvのインストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<h3 id=\"必要なモジュールをインストール\">必要なモジュールをインストール</h3>\n<p>インストールに必要なモジュールをインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div></div>\n\n<h3 id=\"bluetoothを使用する場合\">bluetoothを使用する場合</h3>\n<p>bluetoothを使用する場合は以下も必要</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>pyenvの設定のため、~/.bashrc に以下を追加。 <br />\n(上記手順で記載済み。念のため再掲しておく)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h2 id=\"sudoでpyenv環境を実行するように設定する\">sudoでpyenv環境を実行するように設定する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo</code>でpythonを実行すると、pyenvの設定に関係なくsystemのpythonが実行されてしまいます。<br />\nこれを防ぐためには、<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers</code>の<code class=\"language-plaintext highlighter-rouge\">Defaults secure_path</code>に以下のpathを追加します。</p>\n\n<ul>\n  <li>«pyenvインストール先»/plugins/pyenv-virtualenv/shims:</li>\n  <li>«pyenvインストール先»shims:</li>\n  <li>«pyenvインストール先»/bin:</li>\n</ul>\n\n<p>具体的には以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 変更前\nDefaults  secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n    ↓\n# 変更後\nDefaults  secure_path=\"/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n</code></pre></div></div>\n<ul>\n  <li></li>\n</ul>\n\n<h2 id=\"pythonのインストール-以降\">pythonのインストール 以降</h2>\n\n<p>参考: <a href=\"http://localhost:4000/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) でI2C Slave</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) でI2C Slave</h1>\n      <p>Raspberry Pi Pico W の SDK を使用してI2C Slaveプログラムを作成する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico のI2C マスタを使用してI2Cデバイスにアクセスするプログラムプログラムは\nネット上のあちこちに落ちているのですが、\nI2Cスレーブとしてホストデバイスからアクセスされるサンプルはあまりありません。<br />\nそこで、あちこち探してプログラム作ったのでメモを残しておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n【ホントのところ】<br />\n「I2Cデバイスをポチったけど、納期が長くてプログラム開発に取り掛かれない~」となって\nなんちゃってI2Cデバイスを作って先行デバッグしようとしました。</p>\n</blockquote>\n\n<p>通信プログラムなので通信相手が必要ですが、今回はRaspberry Pi3上でpython3で動く\n簡単な動作確認プログラムを載せておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n公式サンプルは<code class=\"language-plaintext highlighter-rouge\">pico-examples/i2c/slave_mem_i2c</code>にあります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nmicropython版の例は<a href=\"https://python-academia.com/raspberry-pi-pico-slave/\" target=\"_blank\">ここ</a>\nとかにあるけど、ちぃーっと無理くり感が…</p>\n</blockquote>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"i2cの結線\">I2Cの結線</h2>\n\n<p>以下のように結線します。<br />\nPico側はソース中の割り当て端子を変更すれば別の端子でもOKです。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>Pi3</th>\n      <th>Pico</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>SDA1(pin3)</td>\n      <td>I2C0_SDA/GP16(Pin21)</td>\n    </tr>\n    <tr>\n      <td>SCL1(pin5)</td>\n      <td>I2C0_SCL/GP17(Pin22)</td>\n    </tr>\n  </tbody>\n</table>\n\n<h2 id=\"pi3でのi2c有効化\">Pi3でのI2C有効化</h2>\n\n<p>Pi3で以下のコマンドを実行し、I2Cを有効化します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config nonint do_i2c 0\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nまたは以下のように手動で設定</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config\n</code></pre></div>  </div>\n\n  <p>以下のように設定</p>\n  <ul>\n    <li>3 Interface Options\n      <ul>\n        <li>I4 I2C\n          <ul>\n            <li>「Would you like the ARM I2C interface to be enabled?」<br />\n に対して「はい」を選択</li>\n            <li>「The ARM I2C interface is enabled」\nと表示されるので「了解」</li>\n          </ul>\n        </li>\n        <li>「Finish」で終了</li>\n      </ul>\n    </li>\n  </ul>\n\n</blockquote>\n\n<p>実行後、<code class=\"language-plaintext highlighter-rouge\">/dev/i2c-1</code>ファイルが存在することを確認してください。<br />\nリブートは不要です。</p>\n\n<h2 id=\"i2cツールのインストール\">I2Cツールのインストール</h2>\n\n<p>Pi3に<code class=\"language-plaintext highlighter-rouge\">i2cdetect</code>などのツールをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>i2c-tools\n</code></pre></div></div>\n\n<h1 id=\"picoのプログラム\">Picoのプログラム</h1>\n\n<p>作成したプログラムを以下に示します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n今回元にしたI2Cデバイスは先頭アドレスからのバーストリードのみサポートしていたので<br />\nちょっと一般的なアドレス/データ指定の方法と違うけど、なんとなく想像はつくでしょう…</p>\n</blockquote>\n\n<h2 id=\"メインルーチン\">メインルーチン</h2>\n\n<p>メインルーチンはI2Cを初期化したあと無限ループします。<br />\nループ内ではI2Cに関する処理はなく、生存確認用のLチカと\nデバッグ用に送信データが更新されたときにデータを表示しているだけです。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_test.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/stdlib.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/cyw43_arch.h\"</span><span class=\"cp\">\n</span>\n<span class=\"c1\">// プロトタイプ宣言</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n\n<span class=\"kt\">int</span> <span class=\"nf\">main</span><span class=\"p\">()</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">stdio_init_all</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// STDIOがUSBのとき、USB認識されないことがあるのでstdio初期化の後、ちょっと待つ</span>\n    <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">3000</span><span class=\"p\">);</span>\n\n    <span class=\"n\">puts</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">I2C slave test\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// LEDを使うためにwifi初期化</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">cyw43_arch_init</span><span class=\"p\">())</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"Wi-Fi init failed\"</span><span class=\"p\">);</span>\n        <span class=\"k\">return</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\">// I2Cスレーブ 初期化</span>\n    <span class=\"n\">setup_i2c_slave</span><span class=\"p\">();</span>\n    \n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">disp_next_data</span><span class=\"p\">();</span>\n        <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">1000</span><span class=\"p\">);</span>\n\n        <span class=\"c1\">// ==== 生存確認用にLチカ ====</span>\n        <span class=\"c1\">// 現在の出力値取得</span>\n        <span class=\"n\">bool</span> <span class=\"n\">led_out</span> <span class=\"o\">=</span> <span class=\"n\">cyw43_arch_gpio_get</span> <span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">);</span>\n        <span class=\"c1\">// 出力反転</span>\n        <span class=\"n\">cyw43_arch_gpio_put</span><span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">,</span> <span class=\"o\">!</span><span class=\"n\">led_out</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"i2c処理\">I2C処理</h2>\n\n<h3 id=\"初期化\">初期化</h3>\n<p>I2Cの初期化は<code class=\"language-plaintext highlighter-rouge\">setup_i2c_slave</code>です。<br />\n主に端子の初期化とI2Cの初期化、\nI2Cスレーブの初期化(I2C割り込みハンドラからのコールバックの登録)を行っています。</p>\n\n<h3 id=\"処理本体\">処理本体</h3>\n<p>I2C処理本体は<code class=\"language-plaintext highlighter-rouge\">i2c_slave_handler()</code>です。</p>\n\n<p>これはI2C割り込みハンドラからのコールバック処理です。<br />\nなので、できるだけ速やかにリターンする必要があります\n(printfなどの時間のかかる処理は行わないほうが良い)。</p>\n\n<p>なお、今回はマスタの通信プログラムをデバッグするためのダミーデバイスという位置づけで作ったので\n通信を行うたびに異なるデータを送信するようにしてあります。\nこのデータの更新処理をストップ/リスタートコンディション時に行うようにしてあります。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_test.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">16</span><span class=\"p\">;</span>  <span class=\"c1\">//GP16(Pin21)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">17</span><span class=\"p\">;</span>  <span class=\"c1\">//GP17(Pin22)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">16</span><span class=\"p\">];</span>            <span class=\"c1\">// 読み出しデータ</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>        <span class=\"c1\">// 読み出しインデックス</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_REQ</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// 表示要求あり</span>\n        <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"NEXT: %02x %02x %02x %02x : %02x %02x %02x %02x : %02x %02x %02x %02x : %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">14</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">i</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\">// 次に送信するデータの表示を要求</span>\n    <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n\n<span class=\"c1\">// 読み出しデータの更新</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">update_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"o\">++</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\">// 次に送信するデータの表示を要求</span>\n    <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではない</span>\n<span class=\"c1\">// 例えば、表示要求フラグを立ててメインルーチン側で表示してもらうようにするなど</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"p\">{</span>\n            <span class=\"c1\">// ライト動作はサポートしないのでとりあえず読み捨てておく</span>\n            <span class=\"k\">volatile</span> <span class=\"kt\">uint8_t</span> <span class=\"n\">dummy</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span><span class=\"n\">dummy</span><span class=\"p\">;</span>    <span class=\"c1\">// ワーニング対策</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// 1バイト送信する</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">]);</span>\n        <span class=\"c1\">// 次の転送に備えてインデックスを更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// オーバフローしたら0にもどしておく</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// リードポインタを初期化しておく</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        \n        <span class=\"c1\">// テスト用ダミーデータなので、次の読み出しに備えて値を更新しておく</span>\n        <span class=\"n\">update_data</span><span class=\"p\">();</span>\n        \n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave  done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"cmake設定ファイル\">cmake設定ファイル</h3>\n\n<p>プロジェクト生成ツールで作成したプロジェクト(一般的な設定に「I2C interface」のチェックを追加)に\n<code class=\"language-plaintext highlighter-rouge\">target_link_libraries</code> に <code class=\"language-plaintext highlighter-rouge\">pico_i2c_slave</code>を追加します。<br />\nまた、今回はメインルーチンとI2C処理を別ファイルに分けたので、\n<code class=\"language-plaintext highlighter-rouge\">add_executable</code> に <code class=\"language-plaintext highlighter-rouge\">i2c_slave0.c</code>(追加したファイル名)を追加します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  CMakeLists.txt\n</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># Generated Cmake Pico project file</span>\n\n<span class=\"nb\">cmake_minimum_required</span><span class=\"p\">(</span>VERSION 3.13<span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_C_STANDARD 11<span class=\"p\">)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_CXX_STANDARD 17<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise pico_sdk from installed location</span>\n<span class=\"c1\"># (note this can come from environment, CMake cache etc)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_SDK_PATH <span class=\"s2\">\"/work/pico/pico-sdk\"</span><span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_BOARD pico_w CACHE STRING <span class=\"s2\">\"Board type\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># Pull in Raspberry Pi Pico SDK (must be before project)</span>\n<span class=\"nb\">include</span><span class=\"p\">(</span>pico_sdk_import.cmake<span class=\"p\">)</span>\n\n<span class=\"nb\">if</span> <span class=\"p\">(</span>PICO_SDK_VERSION_STRING VERSION_LESS <span class=\"s2\">\"1.4.0\"</span><span class=\"p\">)</span>\n  <span class=\"nb\">message</span><span class=\"p\">(</span>FATAL_ERROR <span class=\"s2\">\"Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is </span><span class=\"si\">${</span><span class=\"nv\">PICO_SDK_VERSION_STRING</span><span class=\"si\">}</span><span class=\"s2\">\"</span><span class=\"p\">)</span>\n<span class=\"nb\">endif</span><span class=\"p\">()</span>\n\n<span class=\"nb\">project</span><span class=\"p\">(</span>i2c_slave_test C CXX ASM<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise the Raspberry Pi Pico SDK</span>\n<span class=\"nf\">pico_sdk_init</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># Add executable. Default name is the project name, version 0.1</span>\n\n<span class=\"nb\">add_executable</span><span class=\"p\">(</span>i2c_slave_test i2c_slave_test.c i2c_slave0.c<span class=\"p\">)</span>\n\n<span class=\"nf\">pico_set_program_name</span><span class=\"p\">(</span>i2c_slave_test <span class=\"s2\">\"i2c_slave_test\"</span><span class=\"p\">)</span>\n<span class=\"nf\">pico_set_program_version</span><span class=\"p\">(</span>i2c_slave_test <span class=\"s2\">\"0.1\"</span><span class=\"p\">)</span>\n\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>i2c_slave_test 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>i2c_slave_test 0<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard library to the build</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_test\n        pico_stdlib<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard include files to the build</span>\n<span class=\"nb\">target_include_directories</span><span class=\"p\">(</span>i2c_slave_test PRIVATE\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>/.. <span class=\"c1\"># for our common lwipopts or any other standard includes, if required</span>\n<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add any user requested libraries</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_test \n        pico_i2c_slave\n        hardware_i2c\n        pico_cyw43_arch_none\n        <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_add_extra_outputs</span><span class=\"p\">(</span>i2c_slave_test<span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>あとはビルドしてRaspberry Pi Picoに書き込みます。</p>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認です。<br />\nここからはRaspberry Pi3 での作業です。</p>\n\n<h2 id=\"i2cdetect\">i2cdetect</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdetect</code> で I2Cバス上でデバイスが検出されるか確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n\n<p>Picoのプログラムで設定したスレーブアドレス(<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>の設定値。上のプログラムだと0x17)\nが表示されていればOKです。<br />\n表示されていない場合はPicoのプログラムやボードの結線を見直してください。</p>\n\n<h2 id=\"レジスタリードプログラム\">レジスタリードプログラム</h2>\n<p>Raspberry Pi3で以下のプログラムを実行します。<br />\n<code class=\"language-plaintext highlighter-rouge\">i2c_address</code>の設定値は上のプログラムの<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>の設定値に合わせます。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">smbus2</span> <span class=\"kn\">import</span> <span class=\"n\">SMBus</span><span class=\"p\">,</span> <span class=\"n\">i2c_msg</span>\n\n<span class=\"n\">i2c_bus</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>                 <span class=\"c1\"># バス番号\n</span><span class=\"n\">i2c_address</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span>          <span class=\"c1\"># スレーブアドレス\n</span><span class=\"n\">data_size</span> <span class=\"o\">=</span> <span class=\"mi\">16</span>              <span class=\"c1\"># リードデータサイズ\n</span>\n<span class=\"c1\"># バスオープン\n</span><span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">SMBus</span><span class=\"p\">(</span><span class=\"n\">i2c_bus</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ読み出し\n</span><span class=\"n\">read</span> <span class=\"o\">=</span> <span class=\"n\">i2c_msg</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">(</span><span class=\"n\">i2c_address</span><span class=\"p\">,</span> <span class=\"n\">data_size</span><span class=\"p\">)</span>\n<span class=\"n\">bus</span><span class=\"p\">.</span><span class=\"n\">i2c_rdwr</span><span class=\"p\">(</span><span class=\"n\">read</span><span class=\"p\">)</span>\n<span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">read</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>正常に読み出せれば、以下のように結果が表示されます(10進数)。<br />\n(以下は何回か実行したあとの結果です)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n</code></pre></div></div>\n\n<p>同時にPicoのシリアルポートからは以下のように次に読み出せるデータが表示されます(16進数)。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>NEXT: 06 07 08 09 : 0a 0b 0c 0d : 0e 0f 10 11 : 12 13 14 15\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</h1>\n      <p>Raspberry Pi Pico W の SDK を使用したプログラムをRaspberryPi3 + Visual Studio CodeでSWDデバッグする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico W の SDK を使用したプログラムをRaspberryPi3 + Visual Studio CodeでSWDデバッグするときのメモ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPi4 や Pi ZERO 2 W でも同様だと思うが、実際に試したのが Pi3 だったので。<br />\nたぶん Pi ZERO や Pi2 ではやめておいた方が無難。<br />\nPi ZERO 2 W やRAM512KByteだからビミョーかも…</p>\n</blockquote>\n\n<p><a href=\"https://www.raspberrypi.com/documentation/microcontrollers/\" target=\"_blank\">公式ドキュメントサイト</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico-JP.pdf\" target=\"_blank\">公式スタートアップガイド(日本語版)</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a></p>\n\n<p>試したときはRaspberryPi OS Lite(64bit) 使用(通常版でも大丈夫と思う)。</p>\n\n<h1 id=\"raspberrypi3のセットアップ\">RaspberryPi3のセットアップ</h1>\n\n<p>RaspberryPi3をセットアップします。<br />\nVisual Studio Code で リモートSSH接続するので、SSHが公開鍵認証で接続できるようにしておくこと。<br />\nセットアップの手順は\n<a href=\"https://ippei8jp.github.io/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</a>\nなど参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\nターゲットボードにPico W を使用する場合はボード種別を指定しておくこと</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"export PICO_BOARD=pico_w\"</span> <span class=\"o\">>></span> ~/.bashrc\n<span class=\"nb\">source</span> ~/.bashrc\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"セットアップスクリプトの実行\">セットアップスクリプトの実行</h2>\n<p>公式ドキュメントに記載されている通り、セットアップスクリプトを実行すればセットアップはほぼ自動です。<br />\nただし、今回はVisual Studio CodeをRaspberryPi上ではなく、WindowsPC上で動かし、\nリモートSSHでRaspberryPiに接続する方法をとるので、Visual Studio Codeのインストールは不要です。<br />\nまた、私はRaspberryPiのシリアルコンソールを残しておきたいので、UARTのセットアップも行いません。<br />\n(UARTは別途USB-Serialアダプタを使用して接続)</p>\n\n<p>以下のようにセットアップスクリプトを実行します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/work</code>ディレクトリにインストールすることにしています。<br />\n別のディレクトリにインストールする場合は読み替えてください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n\n<span class=\"c\"># スクリプトダウンロード</span>\nwget https://raw.githubusercontent.com/raspberrypi/pico-setup/master/pico_setup.sh \n\n<span class=\"c\"># VSCODEのインストールとUARTの設定をスキップしてセットアップ</span>\n<span class=\"nv\">SKIP_VSCODE</span><span class=\"o\">=</span>1 <span class=\"nv\">SKIP_UART</span><span class=\"o\">=</span>1 bash pico_setup.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nopenOCDのコンパイルとかで時間がかかるので(私が試したときは30分くらい)、<br />\nお茶でも飲んでのんびりお待ちくらはい。</p>\n</blockquote>\n\n<h2 id=\"セットアップスクリプト後の変更\">セットアップスクリプト後の変更</h2>\n\n<p>セットアップスクリプトでサンプルプログラムを一部ビルドしてくれますが、\nVisual Studio Code上の開発環境で作り直すので<code class=\"language-plaintext highlighter-rouge\">pico-examples/build</code>ディレクトリは削除しておいてください。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> /work/pico/pico-examples/build\n</code></pre></div></div>\n\n<p>また、Visual Studio Codeの設定ファイルを<code class=\"language-plaintext highlighter-rouge\">pico-examples/.vscode</code>ディレクトリに作成しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/pico/pico-examples\n<span class=\"nb\">mkdir</span> .vscode\n<span class=\"nb\">cp </span>ide/vscode/launch-raspberrypi-swd.json .vscode/launch.json\n<span class=\"nb\">cp </span>ide/vscode/settings.json .vscode/settings.json\n</code></pre></div></div>\n\n<p>このままだとビルドが全ビルドになってしまい、時間がかかってしまうのでビルドターゲットを指定できるように変更しておきます。<br />\n【2024.08.29修正】\nどこかのタイミングのバージョンアップで設定できる内容が大幅に変更されたようなので、setting.jsonを以下の内容で全書き換えしておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  settings.json\n</p>\n\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"p\">{</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.configureOnOpen\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"kc\">false</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.advanced\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n    </span><span class=\"nl\">\"build\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"buildTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"ctest\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"debug\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"launchTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n     </span><span class=\"nl\">\"launch\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"workflow\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"cpack\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">}</span><span class=\"w\">    \n  </span><span class=\"p\">},</span><span class=\"w\">\n</span><span class=\"p\">}</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h1 id=\"raspberry-pi3とraspberry-pi-pico-の接続\">Raspberry Pi3とRaspberry Pi Pico の接続</h1>\n<p>この辺で一旦Raspberry Pi3をシャットダウンし、Raspberry Pi Picoと接続します(最初に接続しておいても良いけど)。<br />\n接続方法は 公式スタートアップガイド の 「Chapter 5. Flash Programming with SWD」の下の「5.2. SWD Port Wiring」\nあたりを参照してください。<br />\n私はPicoのシリアルポートをRaspberryPiではなくUSB-Serialに接続するようにしたので、図の上3本の結線は行わず\nPi3のGPIO24とPicoのSWDIO、Pi3のGPIO25とPicoのSWDCLK、双方のGND同士 の3本を結線しました。<br />\n(PicoのPin1~3はUSB-Serialに接続し、WindowsPCかRaspberry Pi3に接続)</p>\n\n<h2 id=\"visual-studio-coce-起動フォルダのオープン\">Visual Studio COCE 起動&フォルダのオープン</h2>\n\n<p>ホストPCでVisual Studio COCE 起動。<br />\nリモートSSHでRaspberryPi3 に接続し、セットアップツールでインストールした\nサンプルプログラムのディレクトリを開きます(上の例では/work/pico/pico-example)</p>\n\n<h2 id=\"拡張機能のインストール\">拡張機能のインストール</h2>\n<p>これは最初の起動時のみ実行します。</p>\n\n<p>拡張機能で「Cmake Tools」「C/C++(C/C++ for Visual Studio Code)」「Cortex Debug」をRaspberry Pi3 にインストールします。<br />\n(ホストPCではないのでSSH接続した後でインストールすること)</p>\n\n<p>「Cmake Tools」のインストールが完了したら歯車アイコン(設定)をクリックして設定画面を開き、\n“CMake: Parallel Jobs” の設定値を0から1(または2)に変更\n(0だと設定できる上限値になるはずだけど、プロセッサ数4に対して6が設定されてしまい、システムがハングアップしてしまうことがあるので)</p>\n\n<p>右下に「プロジェクト”pico-examples”を構成しますか? ソース:CMake Tools(拡張機能)」と表示されるのでYesをクリック<br />\n続いて「プロジェクトを開いたときに常に構成しますか? ソース:CMake Tools(拡張機能)」 と表示されるので「はい」をクリック</p>\n\n<h2 id=\"ビルドデバッグ\">ビルド~デバッグ</h2>\n<p>ステータスバーの「キットが選択されていません」をクリックすると\nウィンドウ上部に「pico-examplesのキットを選択してください」と表示されるので\n「GCC 12.2.1  arm-none-eabi」を選択(バージョンは異なるかも)</p>\n\n<blockquote>\n  <p>[!NOTE]\n「この大規模なワークスペース フォルダーでのファイルの変更をウォッチできません。\nこの問題を解決するには、手順のリンクに従ってください。 」\nと表示された場合\n/etc/sysctl.conf に以下を追記</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>fs.inotify.max_user_watches = 524288\n</code></pre></div>  </div>\n  <p>設定を反映</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sysctl <span class=\"nt\">-p</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>ステータスバーで「プロジェクトを構成しています: pico-examples」が消えるのを待つ)</p>\n\n<p>ステータスバーで「既定のビルドターゲットの設定(ステータスバーの表示にマウスカーソルをあてると表示されるメッセージ)」と\n「起動するターゲットを選択します(ステータスバーの表示にマウスカーソルをあてると表示されるメッセージ)」を\nクリックしてデバッグしたいターゲットに設定します(例えば、picow_blink)。\nこれらば同じターゲットを指定する必要があります。(ビルドターゲットはallでも良いが、ビルドに時間がかかる)</p>\n<blockquote>\n  <p>[!NOTE]\nサンプルにあるide/vscode/settings.json そのままだと「既定のビルドターゲットの設定」がallのまま変更できないのでビルドに時間がかかるため\n上記の変更を行っています。</p>\n</blockquote>\n\n<p>構成が完了したら「実行とデバッグ」ウィンドウを開いて、右向き三角マーク(デバッグの開始)をクリック<br />\n(右向き三角マーク(デバッグの開始)が無ければ「実行とデバッグ」をクリック)<br />\nbuildが始まって、終わったらデバッガが起動します。<br />\nあとは他のデバッグ同様、RUNやSTEPなどでデバッグしてください。</p>\n\n<h1 id=\"自作プロジェクトの作成\">自作プロジェクトの作成</h1>\n\n<p>サンプルプログラムを改造してうんぬんするのはダサいだけでなく、関係ない処理が色々動いて\nビルドに時間がかかるので、自作プロジェクトの作成をした方が良いです。</p>\n\n<p><a href=\"https://ippei8jp.github.io/memoBlog/2023/10/11/RasPiPico_2.html\" target=\"_blank\">Raspberry Pi Pico W で SDK</a>\nの「自作プロジェクトの作成」にまとめておきましたが、デバッガの指定など追加手順もあるので\n再掲します。</p>\n\n<h2 id=\"プロジェクト生成ツールのインストール\">プロジェクト生成ツールのインストール</h2>\n<p>プロジェクト生成ツールをインストールして起動スクリプトを作成します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ダウンロード</span>\n<span class=\"nb\">cd</span> /work/pico/\ngit clone https://github.com/raspberrypi/pico-project-generator.git\n\n<span class=\"c\"># 起動用スクリプトの作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ~/bin\n<span class=\"nb\">cat</span> <span class=\"o\">></span> ~/bin/pico_project <span class=\"o\"><<</span> <span class=\"sh\">\"</span><span class=\"no\">_EOF_</span><span class=\"sh\">\"\n/work/Pico/pico-project-generator/pico_project.py --nouart --usb  --gui &\n</span><span class=\"no\">_EOF_\n\n</span><span class=\"nb\">chmod</span> +x ~/bin/pico_project\n\n<span class=\"c\"># tkinter のインストール(RaspberryPi OS lite の場合は要インストール)</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>python3-tk\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nそれまで<code class=\"language-plaintext highlighter-rouge\">~/bin</code>が存在していない場合は一旦ログアウトして再ログインで\n<code class=\"language-plaintext highlighter-rouge\">~/bin</code>にpathを通す(変数ゴチョゴチョやっても良いけど、再ログインが手っ取り早い)。</p>\n</blockquote>\n\n<h2 id=\"プロジェクト生成ツールの起動プロジェクト出力\">プロジェクト生成ツールの起動~プロジェクト出力</h2>\n\n<p>リモート接続で使用している場合はDISPLAY変数が設定されていること(ホストマシン)と、\nホストマシンでX-serverが動作していることを確認し、\nプロジェクト生成ツール起動スクリプトを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pico_project\n</code></pre></div></div>\n<p>ホストマシン上にプロジェクト生成ツールのウィンドウが表示されます。</p>\n\n<p>各パラメータを設定し、OKボタンをクリックしてプロジェクトを生成します。<br />\nこのウィンドウで必要な設定を行います。</p>\n\n<ul>\n  <li>Project Name に プロジェクト名を設定</li>\n  <li>Board Type でpico_w を選択</li>\n  <li>Library Options   PiCO Wirless Options で必要なオプションをチェック</li>\n  <li>Console Options は必要なら変更してください。<br />\n(常にUART使うなら起動スクリプトのオプション変更した方が良いかも)</li>\n  <li>Code Options は 必要なら設定。 Advancedボタンをクリックすればさらに多くのパラメータが設定できます。</li>\n  <li>その下は必要なら設定してちょ。</li>\n  <li>一番下の IDE Options は、「Create VSCode Project」をチェックし、「Debugger」に「SWD」を選択します。</li>\n</ul>\n\n<p>OKボタンをクリックしたらプロジェクトが作成され、cmakeが実行されます。<br />\n実行結果を表示するウィンドウが表示されますので、確認してOKボタンでクローズしてください。</p>\n\n<p>プロジェクト生成ツールはもう不要なのでクローズしてください。</p>\n\n<p>生成されたプロジェクトディレクトリの<code class=\"language-plaintext highlighter-rouge\">.vscode/settings.json</code> を以下の内容で全書き換えします。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  settings.json\n</p>\n\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"p\">{</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.configureOnOpen\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"kc\">false</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.advanced\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n    </span><span class=\"nl\">\"build\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"buildTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"ctest\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"debug\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"launchTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n     </span><span class=\"nl\">\"launch\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"workflow\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"cpack\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">}</span><span class=\"w\">    \n  </span><span class=\"p\">},</span><span class=\"w\">\n</span><span class=\"p\">}</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n毎回修正するのが面倒なら、<code class=\"language-plaintext highlighter-rouge\">pico_project.py</code>の\n関数<code class=\"language-plaintext highlighter-rouge\">generateProjectFiles</code>内の変数<code class=\"language-plaintext highlighter-rouge\">s1</code>の定義(1195行目あたり)\nを上記の内容で書き換えてしまえば生成時にこの内容にできる。<br />\n(そのうち公式さんが修正するだろうけど)</p>\n</blockquote>\n\n<h2 id=\"visual-studio-code-でプロジェクトを開くデバッグ\">Visual Studio Code でプロジェクトを開く~デバッグ</h2>\n\n<p>Visual Studio Code のリモートエクスプローラからRaspberry Pi に接続し、作成したディレクトリを開きます。</p>\n\n<p>ProjectNameで指定した名前.c が生成されているので必要な変更を行います。<br />\nファイルを追加する場合は <code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code> の修正も忘れずに。</p>\n\n<p>ステータスバーの「キットが選択されていません」をクリックすると 上に「XXXXのキットを選択してください」と表示されるので\n「GCC 12.2.1  arm-none-eabi」を選択(バージョンは異なるかも)<br />\n構成が完了したら「実行とデバッグ」ウィンドウを開いて、右向き三角マーク(デバッグの開始)をクリック<br />\n(右向き三角マーク(デバッグの開始)が無ければ「実行とデバッグ」をクリック)<br />\n上中央に「ターゲットの起動対象を選択します」と表示されるので、プロジェクト名で指定した名前を選択します。</p>\n\n<p>コンパイルが始まり、エラーがなければそのままデバッガが起動し、main関数の先頭でbreakします。</p>\n\n<p>あとは普通にデバッグしてくらはい。</p>\n\n<h2 id=\"ソースファイルの追加\">ソースファイルの追加</h2>\n\n<p>ソースファイルを追加する場合は<code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code> の <code class=\"language-plaintext highlighter-rouge\">add_executable</code>に追加するソースファイルを追加します。</p>\n\n<p>変更前</p>\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">add_executable</span><span class=\"p\">(</span>test1 test1.c<span class=\"p\">)</span>\n</code></pre></div></div>\n<p>変更後</p>\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">add_executable</span><span class=\"p\">(</span>test1 test1.c sub.c<span class=\"p\">)</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W で SDK</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W で SDK</h1>\n      <p>Raspberry Pi Pico W で SDK を使用したプログラム開発</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico W で SDK を使用したプログラム開発方法のメモ</p>\n\n<p><a href=\"https://www.raspberrypi.com/documentation/microcontrollers/\" target=\"_blank\">公式ドキュメントサイト</a></p>\n\n<h1 id=\"セットアップ手順\">セットアップ手順</h1>\n<p>以下を参考すれば大体分かります。 <br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico-JP.pdf\" target=\"_blank\">公式スタートアップガイド(日本語版)</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a></p>\n\n<p>以下は作業メモ。<br />\n環境はWSL2上のubuntu20.04。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPi用のセットアップのスクリプトは<a href=\"https://github.com/raspberrypi/pico-setup\" target=\"_blank\">ここ</a> にある <code class=\"language-plaintext highlighter-rouge\">pico_setup.sh</code> <br />\nそれ以外のLinuxでもうごくっぽいですが、余計なものまで入ってしまいそうなので、ここでは手動でセットアップします。</p>\n</blockquote>\n\n<h2 id=\"必要なツールをインストールする\">必要なツールをインストールする</h2>\n\n<p>以下のコマンドでインストールできます。\ngitとかは既に入ってるものとして。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential\n</code></pre></div></div>\n\n<h2 id=\"sdkをダウンロードする\">SDKをダウンロードする</h2>\n\n<p>ますは作業ディレクトリを作成してSDKをダウンロードします。<br />\n以下では <code class=\"language-plaintext highlighter-rouge\">/work/Pico</code> を作業ディレクトリとしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Pico <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Pico\ngit clone https://github.com/raspberrypi/pico-sdk.git\n<span class=\"nb\">cd </span>pico-sdk/\ngit submodule update <span class=\"nt\">--init</span>\n<span class=\"nb\">cd</span> ..\n</code></pre></div></div>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n\n<p>以下のコマンドを実行し、環境変数を設定します。<br />\n上でSDKのダウンロード先を変更している場合はそれにあわせて変更してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PICO_SDK_PATH</span><span class=\"o\">=</span>/work/Pico/pico-sdk\n</code></pre></div></div>\n\n<p>次回起動時にそなえて、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code> に同様のコマンドを追加しておきます。</p>\n\n<h2 id=\"サンプルプログラムをダウンロードする\">サンプルプログラムをダウンロードする</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/raspberrypi/pico-examples.git\n</code></pre></div></div>\n\n<h2 id=\"lチカしてみる\">Lチカしてみる</h2>\n\n<p><a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a>の\n「Chapter 3. Blinking an LED in C」にあるのはPico用のサンプルなので、Pico Wでは使えません。<br />\n(正確にはGPIO端子にLEDを接続すれば使えるが、オンボードのLEDは点滅しない)<br />\nで、Pico W 用の手順をまとめてみました。</p>\n\n<h3 id=\"cmakeの実行\">cmakeの実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>pico-examples\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake .. <span class=\"nt\">-DPICO_BOARD</span><span class=\"o\">=</span>pico_w\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ncmake のオプションに <code class=\"language-plaintext highlighter-rouge\">-DPICO_BOARD=pico_w</code>を追加することでPico W用の設定が有効になります。</p>\n</blockquote>\n\n<h3 id=\"lチカプログラムのビルド\">Lチカプログラムのビルド</h3>\n\n<p>その場でmakeするとすべてのサンプルプログラムがビルドされますが、時間がかかるので\nLチカプログラムだけビルドします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>pico_w/wifi/blink/\nmake\n\n</code></pre></div></div>\n\n<p>これで <code class=\"language-plaintext highlighter-rouge\">pico-examples/build/pico_w/wifi/blink</code> の <code class=\"language-plaintext highlighter-rouge\">picow_blink.uf2</code>をpicoに書き込めばボード上のLEDが点滅するはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPico W のLチカのソースは <code class=\"language-plaintext highlighter-rouge\">pico-examples/pico_w/wifi/blink</code></p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">pico-examples\\pico</code> はpico用(Wなし)なので、実行してもオンボードのLEDが点灯しません。 \nこれを実行するには外付けLEDが必要です。</p>\n</blockquote>\n\n<h1 id=\"コンソール出力をusbに出力する\">コンソール出力をUSBに出力する</h1>\n\n<p>デフォルトでコンソール入出力はUART0に割り当てられています(端子はGP0(TX)/GP1(RX))。<br />\nUARTに接続するのが面倒なときはUSBから仮想COMポートに入出力できます。<br />\n手順は、ソースディレクトリの <code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>に以下を追加してmakeします。<br />\n例ではターゲット名に<code class=\"language-plaintext highlighter-rouge\">picow_blink</code>を使用していますが、使用するターゲットに合わせて変更してください。</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># enable usb output, disable uart output</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>picow_blink 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>picow_blink 0<span class=\"p\">)</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>を変更した場合でも <code class=\"language-plaintext highlighter-rouge\">make</code>を実行すればこの変更も反映されます。</p>\n</blockquote>\n\n<p>出来上がったuf2ファイルをPicoに書き込んだら自動的にリブートされるので、<br />\nPCに仮想COMポートドライバがインストールされたらTeratermで対象のCOMポートに接続します。</p>\n\n<h1 id=\"自作プロジェクトの作成\">自作プロジェクトの作成</h1>\n<p>サンプルプログラムを改造してうんぬんするのはダサいので、自作のプロジェクトを作ってみます。<br />\n一から作るのは面倒なので、プロジェクト生成ツールを使います。</p>\n\n<h2 id=\"プロジェクト生成ツールのダウンロード\">プロジェクト生成ツールのダウンロード</h2>\n\n<p>githubにプロジェクト生成ツールのリポジトリがあるのでダウンロードします。<br />\n以下では 前に作成した作業ディレクトリ <code class=\"language-plaintext highlighter-rouge\">/work/Pico</code> をダウンロードディレクトリとしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/Pico\ngit clone https://github.com/raspberrypi/pico-project-generator.git\n</code></pre></div></div>\n\n<p>ダウロードしたプログラムを直接起動しても良いですが、<br />\nオプション指定など忘れっぽいので起動スクリプトを用意しておきます。</p>\n\n<p>pathの通ったディレクトリ(<code class=\"language-plaintext highlighter-rouge\">~/bin</code>など)に以下の内容でファイルを作成し、実行属性を付与します。<br />\nファイル名は<code class=\"language-plaintext highlighter-rouge\">pico_project</code>とでもしておいてください。<br />\n実行ファイルのパスはダウンロード先に合わせて変更してね。<br />\n追加したいオプションがあったらご自由にどうぞ。<br />\nGUIを起動するので、最後に & をつけてバックグラウンド実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/Pico/pico-project-generator/pico_project.py <span class=\"nt\">--nouart</span> <span class=\"nt\">--usb</span>  <span class=\"nt\">--gui</span> &\n</code></pre></div></div>\n\n<h2 id=\"プロジェクトの作成\">プロジェクトの作成</h2>\n\n<p>上で作成したスクリプトを実行するとProject Generator のウィンドウが表示されます。<br />\nこのウィンドウで必要な設定を行います。</p>\n\n<ul>\n  <li>Project Name に プロジェクト名を設定</li>\n  <li>Board Type でpico_w を選択</li>\n  <li>Library Options   PiCO Wirless Options で必要なオプションをチェック</li>\n  <li>Console Options は必要なら変更してください。<br />\n(常にUART使うなら起動スクリプトのオプション変更した方が良いかも)</li>\n  <li>Code Options は 必要なら設定。 Advancedボタンをクリックすればさらに多くのパラメータが設定できます。</li>\n  <li>その下は必要なら設定してちょ。</li>\n</ul>\n\n<p>OKボタンをクリックしたらプロジェクトが作成され、cmakeが実行されます。<br />\n実行結果を表示するウィンドウが表示されますので、確認してOKボタンでクローズしてください。<br />\nLocationで指定したディレクトリ下のProjectNameで指定した名前のディレクトリに\nProjectNameで指定した名前.c が生成されているので必要な変更を行います。</p>\n\n<p>あとはコンソールでLocationで指定したディレクトリ下のProjectNameで指定したディレクトリ下の\nbuildディレクトリに移動し、<code class=\"language-plaintext highlighter-rouge\">make</code>を実行します。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico Wでmicropython with Visual Studio Code</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico Wでmicropython with Visual Studio Code</h1>\n      <p>Raspberry Pi Pico W でmicropython の開発にVisual Studio Codeを使用する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico Wでmicropython を使用する際の開発環境(IDE)に 公式では Thonny が推奨されていますが、\nVisual Studio Codeを使用することもできます。<br />\nこのとき、拡張機能 「MicroPico」(旧称Pico-W-Go) を使用します。<br />\nここでは先人の成果を<del>パクり</del> 参照しつつ、なんとなく手順を書いてみることにします。</p>\n\n<h1 id=\"環境構築\">環境構築</h1>\n\n<h2 id=\"pc側の準備\">PC側の準備</h2>\n<p>セットアップ手順は以下が分かりやすい。<br />\n<a href=\"https://flatisle.com/raspberrypi/2289/\" target=\"_blank\">Pico W で遊ぼう(環境構築)</a><br />\nただし、モジュール名が「Pico-W-Go」から「MicroPico」に変更されているので、読み替え必要。</p>\n\n<p>PC側はVisual Studio Code がインストールされていれば 拡張機能で「MicroPico」を検索してインストールするだけ。</p>\n\n<h2 id=\"本体側の準備\">本体側の準備</h2>\n<p>本体側はファームウェアの書き換えを行う。<br />\nファームウェアの最新版は\n<a href=\"https://www.raspberrypi.com/documentation/microcontrollers/micropython.html\" target=\"_blank\">Raspberry Pi Documentation > MicroPython</a>\nからダウンロードできます。<br />\nまた、<a href=\"https://micropython.org/download/RPI_PICO_W/\" target=\"_blank\">MicroPython > DOWNLOAD > Pico W</a>\nには、Nightly buildsのバイナリもあったりします。</p>\n\n<h2 id=\"動作確認\">動作確認</h2>\n<p>Raspberry pi Pico をPCに接続しておいて、Visual Studio Code を起動。</p>\n\n<ul>\n  <li>メニューの「ターミナル」→「新しいターミナル」でターミナルウィンドウを開く(デフォルト状態だとPowershellが実行される)。</li>\n  <li>ターミナルウィンドウの右上の「+」ボタン(新しいターミナル)のドロップダウンリストを開いて\n「Pico(W) vREPL」を選択してvREPLに接続する。<br />\n(+をクリックするとPowershellが新しく開かれるので右のvっぽい記号をクリックする)</li>\n  <li>以下のような表示が出る。<br />\n(バージョン番号とかはファームウェアによって異なる)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>MicroPython v1.20.0-198-g0eacdeb1c on 2023-06-13; Raspberry Pi Pico W with RP2040\nType \"help()\" for more information or .cls/.clear to clear the terminal.\n\n>>> \n</code></pre></div></div>\n\n<p>ここで色々コマンドを入力すれば実行できる</p>\n\n<h1 id=\"いつでもwifiにつなげるように準備\">いつでもwifiにつなげるように準備</h1>\n\n<p>適当なところにフォルダを作成し(以下の例では「test」)、その下にlibフォルダを作り、\nその下にmy_wifi.py として以下のファイルを作成しておく。<br />\n1行目~2行目は自分の環境に合わせて変更しておくこと。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    test\n     +-- lib\n          +-- my_wifi.py\n          \n</code></pre></div></div>\n\n<!-- ファイル名を付けたいときはこれを指定-->\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  my_wifi.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SSID_NAME</span> <span class=\"o\">=</span> <span class=\"s\">\"SSID名\"</span>\n<span class=\"n\">SSID_PASS</span> <span class=\"o\">=</span> <span class=\"s\">\"SSIDパスワード\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">utime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">network</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n<span class=\"c1\"># ==== connecti to wifi access point ============================================\n</span><span class=\"k\">def</span> <span class=\"nf\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">,</span> <span class=\"n\">timeout</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">):</span>\n    <span class=\"n\">wifi</span><span class=\"o\">=</span> <span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">WLAN</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">STA_IF</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'already Connected.    connect skip'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">active</span><span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">)</span>\n        <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"ow\">and</span> <span class=\"n\">timeout</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'.'</span><span class=\"p\">,</span> <span class=\"n\">end</span><span class=\"o\">=</span><span class=\"s\">''</span><span class=\"p\">)</span>\n            <span class=\"n\">utime</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">timeout</span> <span class=\"o\">-=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">():</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">Connected'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Connection failed!'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">False</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">disconnect</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">disconnect</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"n\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">SSID_NAME</span><span class=\"p\">,</span> <span class=\"n\">SSID_PASS</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">ifconfig</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n<p>Visual Studio Code のエクスプローラウィンドウで「フォルダを開く」ボタンをクリック\n(またはメニューの「ファイル」→「フォルダを開く」を選択)し、\n上で作成したフォルダ(例ではtest)を開きます。</p>\n\n<p>コマンドパレットで「MicroPico: Upload project to Pico」を選択します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n現在書き込まれているファイルをすべて消去するには<br />\nコマンドパレットで「MicroPico: Delete all files from board」を選択します。</p>\n\n</blockquote>\n\n<p>実際に書き込まれたかはターミナルウィンドウで以下のように実行することで確認できます。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">>>></span> <span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'lib'</span><span class=\"p\">]</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/lib'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'my_wifi.py'</span><span class=\"p\">]</span>\n</code></pre></div></div>\n<p>または後述の仮想ファイルシステムを使用しても確認できます。</p>\n\n<p>でもって、使用するプログラムで<code class=\"language-plaintext highlighter-rouge\">import my_wifi</code> とやれば接続できます。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">my_wifi.isconnected()</code> で接続中かが分かります。\n<code class=\"language-plaintext highlighter-rouge\">my_wifi.disconnect()</code> でAPから切断できます。</p>\n\n<h1 id=\"仮想ファイルシステムを使用する\">仮想ファイルシステムを使用する</h1>\n<p>仮想ファイルシステムを使用すると、現在PaspberryPi Pico(W)のストレージに書き込まれているファイルを\n直接確認/操作することができます。</p>\n\n<ul>\n  <li>コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n  <li>エクスプローラウィンドウに「Pico (W) Remote Workspace」ができ、その下にディレクトリ/ファイルが表示される</li>\n</ul>\n\n<p>ここのファイルを開くとPaspberryPi Pico(W)のストレージにあるファイルを直接参照できます。<br />\nまた、内容を変更して保存すると PaspberryPi Pico(W)のストレージに直接格納されます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPC上のファイルとPaspberryPi Pico(W)のストレージ上のファイルをあちこち弄くると\nどちらをどう書き換えたか分からなくなるので、できるだけPC上のファイルを書き換えて「Upload project to Pico」で\nPaspberryPi Pico(W)のストレージを同期するのが良いと思います。</p>\n</blockquote>\n\n<p>mipコマンドでダウンロードしたモジュールや、プログラムでPaspberryPi Pico(W)のストレージ上に作成したファイルをPCのコピーするには、</p>\n<ul>\n  <li>エクスプローラウィンドウで仮想ファイルシステム上のコピーしたいフォルダまたはファイルを選択</li>\n  <li>CTRLキーを押しながらコピーしたいPC上のフォルダの位置にドラッグ&ドロップ\n    <ul>\n      <li>CTRLキーを押さないでドラッグ&ドロップした場合は移動になるので、「移動しますか?」と聞かれる。移動するなら「移動」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<p>仮想ファイルシステムを消すには、</p>\n<ul>\n  <li>再度コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n</ul>\n\n<p>で、エクスプローラウィンドウから「Pico (W) Remote Workspace」が消えます。<br />\n(エクスプローラウィンドウの表示が消えるだけで、PaspberryPi Pico(W)のストレージから消えるわけではありません)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>キーボードコマンダーのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>キーボードコマンダーのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用キーボードコマンダーのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/18/key_commander_1.html\" target=\"_blank\">キーボードコマンダーのひな型(C言語版)</a>\nのpython版も作/memoBlog定して使うだけなんだけど、<br />\nstdinの設定を元に戻すのを忘れないように、クラス化してデストラクタで設定を戻すようにしてみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれまでatexitモジュール使って終了処理ルーチン登録して<br />\nそこで元に戻してたけど、処理追加忘れて悲しいことになったことが数知れず…</p>\n</blockquote>\n\n<h1 id=\"ちょっと解説\">ちょっと解説</h1>\n<p>このクラスは、複数の箇所からインスタンスを作成してしまうとstdinの設定変更が複数箇所で行われてしまい、<br />\nデストラクタの実行順序によっては正常に元に戻せなくなる可能性がある。<br />\nそれを回避するため、Singletonパターンを適用し、インスタンスが一つだけ保持するようにした。</p>\n\n<p>しかし、これだけでは不十分で、コンストラクタ(<code class=\"language-plaintext highlighter-rouge\">__init__()</code>)が<code class=\"language-plaintext highlighter-rouge\">KeyReader()</code>実行の度に実行されてしまう。(下のNOTE参照) <br />\nそこで、インスタンス変数にコンストラクタ実行済みフラグ(<code class=\"language-plaintext highlighter-rouge\">_inited</code>)を用意し、\nこれが存在しないときのみコンストラクタ処理を実行するようにしている。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">__new__</code>、<code class=\"language-plaintext highlighter-rouge\">__init__</code>、<code class=\"language-plaintext highlighter-rouge\">__del__</code>の実行タイミングは以下のプログラムで確認できる。</p>\n\n  <pre><code class=\"language-pythn\">class Hoge:\n    def __new__(cls, *args, **kargs):\n        print(\"__new__\")\n        if not hasattr(cls, \"_instance\"):\n            print(\"create\")\n            cls._instance = super().__new__(cls)\n        return cls._instance\n    \n    # コンストラクタ\n    def __init__(self):\n        print(\"__init__\")\n        if not hasattr(self, \"_inited\"):\n            print(\"init\")\n            self._inited = True\n    \n    # デストラクタ\n    def __del__(self):\n        print(\"__del__\")\n    \n    def __call__(self):\n        print(\"__call__\")\n\ndef func2() :\n    h2 = Hoge()\n    print(\"h2 before\")\n    h2()\n    print(\"h2 after\")\n\ndef func1() :\n    h1 = Hoge()\n    print(\"h1 before\")\n    h1()\n    print(\"h1 after\")\n\nprint(\"func1 before\")\nfunc1()\nprint(\"func1 after\")\n\nprint(\"func2 before\")\nfunc2()\nprint(\"func2 after\")\n\nprint(\"end\")\n\n</code></pre>\n  <p>実行結果は以下。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>func1 before\n__new__\ncreate                  ← 1回だけ表示されている\n__init__\ninit                    ← 1回だけ表示されている\nh1 before\n__call__\nh1 after\nfunc1 after\nfunc2 before\n__new__\n__init__\nh2 before\n__call__\nh2 after\nfunc2 after\nend\n__del__\n</code></pre></div>  </div>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">Hoge()</code>が実行されると、<code class=\"language-plaintext highlighter-rouge\">__new__()</code>が実行されるが、\n2回目以降は新たにインスタンスを作成せずクラス変数<code class=\"language-plaintext highlighter-rouge\">_instance</code>に格納されたインスタンスを返す。<br />\n(2回目は「create」が表示されていない)</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__init__()</code>が<code class=\"language-plaintext highlighter-rouge\">Hoge()</code>実行の度に実行されているのが分かる。<br />\n(つまりインスタンス生成時に実行されるわけではない)<br />\n<code class=\"language-plaintext highlighter-rouge\">__init__()</code>内でインスタンス変数<code class=\"language-plaintext highlighter-rouge\">_inited</code>の存在をチェックしているので<br />\n「init」は1回しか表示されていないのが分かる。</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__del__()</code> はインスタンス破棄時に実行されるので、1回しか実行されない。</p>\n\n</blockquote>\n\n<p>その他のプログラムの動作についてはソース読んでちょ。<br />\nって、ほとんど何もしてないけど。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>キーボードコマンダーのひな型(C言語版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>キーボードコマンダーのひな型(C言語版)</h1>\n      <p>linuxでのテストプログラム用キーボードコマンダー</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/15/test_shell_1.html\" target=\"_blank\">test shellのひな型</a>\nのようなテストシェルでコマンド処理するほどでもないが、いくつかのパターンを繰り返し実行してテストしてみたい\n場合に使えるキーボードコマンダー(という名前がふさわしいか分からないが)のひな型を作ってみた。</p>\n\n<p>キー入力1個(例えば<code class=\"language-plaintext highlighter-rouge\">a</code>キー)でリターンを押さずに何らかの処理が実行できると便利な時がある。<br />\nまた、ターゲットボードのスイッチ入力の代替処理としても便利かもしれない。</p>\n\n<p>Windowsの<code class=\"language-plaintext highlighter-rouge\">getch()</code>関数みたいなものと言えば分かるかな?<br />\nキー入力自体はブロッキング処理なので、<code class=\"language-plaintext highlighter-rouge\">kbhit()</code>みたいな使い方はできない。<br />\n(これを行うには<code class=\"language-plaintext highlighter-rouge\">select()</code>をタイムアウト付きで組み合わせて使う必要があるが、\n簡単なテスト用を想定しているので そこまでは対応しない)</p>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n大体コメントに書いたつもり。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6435ac7e3381ec2f8af0b1fdb166d469\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6435ac7e3381ec2f8af0b1fdb166d469.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>test shellのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>test shellのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用コマンド入力処理のサンプルのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/15/test_shell_1.html\" target=\"_blank\">test shellのひな型</a>\nでC言語版を作ったので、python版も作っておこうかと作ってみた。</p>\n\n<p>pythonには『行指向のコマンドインタープリタのサポート』というcmdモジュールが標準で用意されている。<br />\nこれを使用すれば、そんなに手間もかからず実装できる。<br />\n補完処理やヘルプ表示も簡単。<br />\nコマンドの大文字/小文字同一視はできなかったけど…</p>\n\n<p>コマンド補完だけでなく、パラメータ補完も可能。<br />\nもちろん、補完のための処理は書かないといけないけど。</p>\n\n<p>標準モジュールしか使ってないので、モジュールをインストールする必要なし。</p>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n大体コメントに書いたつもり。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>test shellのひな型</title>\n  </head>\n  <body>\n    <header>\n      <h1>test shellのひな型</h1>\n      <p>linuxでのテストプログラム用コマンド入力処理のサンプル</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>linuxでプログラムを作ったとき、ユニットテストを各処理(コマンド)単位で行いたいときに、テストシェルを作ると便利。<br />\nでも、その都度作っていると効率悪いので、ひな型を作ってみた。<br />\nどうせなら、コマンドヒストリとか、入力補完とかあると便利だなぁ~、ということで、<br />\n<code class=\"language-plaintext highlighter-rouge\">readline</code>使ってそれらを実現しておく。</p>\n\n<p>たぶん、bash使ってるシステムなら<code class=\"language-plaintext highlighter-rouge\">libreadline</code>も入ってるだろうから、特にインストールとかも不要。</p>\n\n<h1 id=\"コンパイル方法\">コンパイル方法</h1>\n<p>以下のコマンドでコンパイルできる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gcc test_shell.c <span class=\"nt\">-lreadline</span> <span class=\"nt\">-o</span> test_shell\n</code></pre></div></div>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n『コマンド定義』の部分を所望のコマンドと処理に書き換えて使ってちょ。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/fbccd09aefa28dd097a13c68d0111d0d\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/fbccd09aefa28dd097a13c68d0111d0d.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINO 2022.1のbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1はRaspberry Pi OS(64bit)向けのバイナリがリリースされていないので、自力でbuildしてみます。</p>\n\n<p>今回もUbuntu上のDockerコンテナを使用しましたが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思います。</p>\n\n<p>前回はPythonを諦めてクロスコンパイルする方法とbuild時間を諦めてセルフコンパイル(エミュレーション)する方法を使いましたが、<br />\n今回はPython以外をクロスコンパイル、Python関連部をセルフコンパイル(エミュレーション)して生成物をマージする方法をとってみます。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_2022.1_pi64 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_2022.1_pi64\n</code></pre></div></div>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>workディレクトリを作成し、openvino と openvino_contrib のリポジトリをcloneします。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 2022.1.1 <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib checkout 1a28b530ab40d2ad79ab29021dfddfbbc7d2db0b\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の2022.1だと一部のノードが未対応とエラーになるため、対応済みのcommitを使用します。<br />\ntagが振られていないので、commit IDを指定してcheckoutします。<br />\nこれ以降のcommitではopenvinoのバージョン2022.2が必要になります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ntagやbranchが設定されていない場合はcloneでcheckoutするバージョンを指定できないため、\n一旦cloneしてからcommit IDを指定してcheckoutします。<br />\nsubmoluleのcheckoutは対象のバージョンをcheckoutしてから行います。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の最新commit(試した時点ではcommit ID <code class=\"language-plaintext highlighter-rouge\">fd2ac364435757d23a9b3e91d67235b5e6555bf9</code>)を使用する場合は\nopenvinoのバージョン2022.2を使用する必要がありますが、試した時点で <code class=\"language-plaintext highlighter-rouge\">2022.2.0.dev20220829</code> がリリースされているので\nこれを使用します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0.dev20220829  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit -C ./work/openvino_contrib checkout fd2ac364435757d23a9b3e91d67235b5e6555bf9\ngit -C ./work/openvino_contrib submodule update --init --recursive --depth 1\n</code></pre></div>  </div>\n  <blockquote>\n    <p>2022.2.0正式リリース後はこんな感じになるのかな?</p>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  -b 2022.2    --recursive --depth 1 https://github.com/openvinotoolkit/openvino_contrib.git\n</code></pre></div>    </div>\n  </blockquote>\n\n  <p>この場合、NVIDIA GPUのpluginのbuildでエラーになるため、以下のcmakeのオプションに以下のオプションを追加します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      -D BUILD_nvidia_plugin=OFF\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h1 id=\"openvinoのbuildクロスコンパイル\">openVINOのBuild(クロスコンパイル)</h1>\n\n<p>クロスコンパイルでpython関連以外の部分をbuildします。</p>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir cross</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">cross/Dockerfile</code>を作成します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cross/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates:arm64 <span class=\"se\">\\\n</span>    libboost-regex-dev:arm64 <span class=\"se\">\\\n</span>    libgtk2.0-dev:arm64 <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev:arm64 <span class=\"se\">\\\n</span>    libcairo2-dev:arm64 <span class=\"se\">\\\n</span>    libpango1.0-dev:arm64 <span class=\"se\">\\\n</span>    libglib2.0-dev:arm64 <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev:arm64 <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗します</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeは新しめのをインストールしておきたいので、3.23.2をbuildして使用しています。<br />\nもしかすると、<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたものをそのまま使っても大丈夫かもしれませんが。</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_cross cross\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\ncacheを使わずimage buildしたい場合は<code class=\"language-plaintext highlighter-rouge\">--no-cache</code>オプションを追加します。<br />\n以前に作ったイメージのキャッシュを使って<code class=\"language-plaintext highlighter-rouge\">apt install</code>がエラーになったことがあったので。<br />\n(デフォルトのリポジトリに変更があったらしい)</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_cross_2 ov_2022.1_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_cross_2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_2022.1_pi64_cross_2 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/cmake/arm64.toolchain.cmake <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_BEH_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLDNN</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_FUNCTIONAL_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">THREADING</span><span class=\"o\">=</span>SEQ <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">CONTRIB_TOP</span><span class=\"k\">}</span>/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span> 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=${WORK_DIR}/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"クロスコンパイル終了\">クロスコンパイル終了</h3>\n<p>クロスコンパイルはここまでなので、コンテナから抜ける。</p>\n\n<h1 id=\"openvinoのbuildセルフコンパイル\">openVINOのBuild(セルフコンパイル)</h1>\n\n<p>セルフコンパイルでpython関連部分をbuildします。<br />\ncythonを使うときにクロスコンパイルする方法が分からないので、セルフコンパイルで。</p>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir emu</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">emu/Dockerfile</code>を作成します。</p>\n\n<p>python部だけなので、こんなにライブラリとか要らない気もしますが、全部セルフコンパイルするときのことも考えて\n全部入りのイメージを作っておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  emu/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates <span class=\"se\">\\\n</span>    libboost-regex-dev <span class=\"se\">\\\n</span>    libgtk2.0-dev <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev <span class=\"se\">\\\n</span>    libcairo2-dev <span class=\"se\">\\\n</span>    libpango1.0-dev <span class=\"se\">\\\n</span>    libglib2.0-dev <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_emu emu\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_emu_2 ov_2022.1_pi64_emu /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_emu_2\n</code></pre></div></div>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成-1\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build_python <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build_python\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">InferenceEngineDeveloperPackage_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/build <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/src/bindings/python 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">CMAKE_INSTALL_PREFIX</code>の設定はクロスコンパイルのときと同じ設定にしてください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npyenvでインストールしたpythonなど、デフォルトでないpythonを使用する場合に指定します。<br />\n(以下の設定値はubuntu 22.04の標準インストールの場合のパスなのであまり参考にならないかも)</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  -D PYTHON_EXECUTABLE=/usr/bin/python3.8 \\\n  -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.8.so \\\n  -D PYTHON_INCLUDE_DIR=/usr/include/python3.8 \\\n  -D PYTHON_MODULE_EXTENSION=\".so\" \\\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"make-1\">make</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。</p>\n\n<h3 id=\"セルフコンパイル終了\">セルフコンパイル終了</h3>\n<p>セルフコンパイルはここまでなので、コンテナから抜けます。</p>\n\n<h1 id=\"インストール媒体の作成\">インストール媒体の作成</h1>\n\n<p>ホスト側の<code class=\"language-plaintext highlighter-rouge\">work</code>ディレクトリ内を見ると、<code class=\"language-plaintext highlighter-rouge\">intel</code>ディレクトリが出来ているので、ここをtarなどで固めておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>work\n<span class=\"nb\">tar </span>czvf ov1.tar.gz intel/\n</code></pre></div></div>\n\n<p>この<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiにコピーして展開します。</p>\n\n<h1 id=\"raspberrypiへのインストール\">RaspberryPiへのインストール</h1>\n\n<h2 id=\"インストール\">インストール</h2>\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiの適当なディレクトリに展開します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/proj</code>ディレクトリに展開しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /proj/\n<span class=\"nb\">tar </span>xzvf ov1.tar.gz \n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<p>これで<code class=\"language-plaintext highlighter-rouge\">/proj/intel/openvino</code>ディレクトリにインストールされました。</p>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n<p>環境変数の設定のため、以下を実行します。<br />\nshell起動の度に実行が必要なので<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>などに書いておくと良いです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/intel/openvino/setupvars.sh \n</code></pre></div></div>\n\n<h2 id=\"udevルールの設定\">udevルールの設定</h2>\n<p>以下のスクリプトを実行すればNCS2を挿せば認識されるようになります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/proj/intel/openvino/install_dependencies/install_NCS_udev_rules.sh \n</code></pre></div></div>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n<p>openCVの必要になるので、インストールしておきます。<br />\n今回はお手軽にpipでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認用のプログラムは<a href=\"https://github.com/ippei8jp/ov_trial_2022.1\" target=\"_blank\">https://github.com/ippei8jp/ov_trial_2022.1</a> とかにあります。<br />\nでもモデルのダウンロード/コンバートはRaspberryPiではできないので、UbuntuやWondowsで実行したものをコピーして使用してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</h1>\n      <p>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使うためのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1ではpypiからモジュールインストールするだけで使えるようになったのだけれど(python使用時)、<br />\nNCS2を使用しようとすると以下のようなエラーが発生します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>RuntimeError: Cannot load library 'libopenvino_intel_myriad_plugin.so: libopenvino_intel_myriad_plugin.so: cannot open shared object file: No such file or directory\n</code></pre></div></div>\n\n<p>どうやらNCS2(myriad)用のshared libraryがないらしい。<br />\nインストールミスか?と思ったけど、pypiのインストールファイル確認してみたけど、やっぱり入っていない。</p>\n<blockquote>\n  <p>[!NOTE]\nwhlファイルの拡張子をzipに変更するとファイルの中身を確認できる</p>\n</blockquote>\n\n<p>そこで、ソースからNCS2用のshared libraryをbuildしてみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p>参考: <a href=\"https://github.com/openvinotoolkit/openvino/wiki/BuildingForLinux\" target=\"_blank\">BuildingForLinux</a></p>\n\n<p>今回はWSL2の仮想マシンでbuildしてみることにする。<br />\nまた、NCS2用のshared libraryだけが目的なので、pythonモジュールとかはbuildしていない。<br />\nたぶん、ちゃんとCMAKEのオプション設定すればbuild時間が短くなるかもしれないけど、そこはお手軽最優先で。</p>\n\n<blockquote>\n  <p>[!NOTE]\n色々とbuildのために``apt install`するので、WSL2上のcloneした仮想マシンで実行した。<br />\nNCS2はWSL2上で使えないけど、buildするだけなら大丈夫みたい。<br />\n仮想マシンはUbuntu22.04を使用。 たぶん、20.04でも同様と思われる。<br />\nまぁ、Docker使えという説もある…</p>\n</blockquote>\n\n<h2 id=\"ソース取得\">ソース取得</h2>\n\n<p>openVINOのリポジトリからソース取得。<br />\n例によって<code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけてディスク容量&通信時間節約。<br />\n今回はcontribは使わない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> /work  clone  <span class=\"nt\">-b</span> 2022.1.0 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> /work/openvino submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n<span class=\"nb\">cd</span> /work/openvino\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこれ書いてる時点で2022.1.1がリリースされているけど、-bオプション変えればOKでしょう。\nたぶん。。。</p>\n</blockquote>\n\n<h2 id=\"必要なモジュールのインストール\">必要なモジュールのインストール</h2>\n\n<p>必要なモジュールはスクリプトファイルにまとめられているので、それを実行するだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash install_build_dependencies.sh \n</code></pre></div></div>\n\n<p>cmakeのバージョン3.17以上が必要なので、cmakeがそれ以下だとcmakeをソースからbuildしてくれる。<br />\nUbuntu22.04のデフォルト状態だとcmakeのバージョンは3.16なのでbuildが実行される。<br />\nちょっと時間がかかるけど、気長にお待ちください。</p>\n\n<h1 id=\"build\">build</h1>\n\n<p>準備ができたので、buildを実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>make.log\n</code></pre></div></div>\n\n<p>あとはひたすら待つ。<br />\n(うちの環境では1時間くらいだったかな)</p>\n\n<h1 id=\"ターゲットマシンにコピー\">ターゲットマシンにコピー</h1>\n\n<p>makeが終わると、以下のファイルが出来ているはず。<br />\nこの2つをNCS2を使用するターゲットマシンにコピーする。</p>\n\n<ul>\n  <li>openvino/bin/intel64/Release/lib/libopenvino_intel_myriad_plugin.so</li>\n  <li>openvino/bin/intel64/Release/lib/usb-ma2x8x.mvcmd</li>\n</ul>\n\n<p>ターゲットマシンのコピー先はopenVINOモジュールのインストール先の<code class=\"language-plaintext highlighter-rouge\">openvino/libs/</code>ディレクトリの下。<br />\n<code class=\"language-plaintext highlighter-rouge\">libopenvino.so</code>など、soファイルが並んでいるはず。</p>\n\n<p>なお、openVINOモジュールのインストール先は以下のようなコマンドで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"^openvino\"</span>\n</code></pre></div></div>\n\n<p>コピーの方法はエクスプローラでもrcpでも何でもよい。 \nエクスプローラなど、Windows経由でコピーすると実行属性が落ちてしまうけど、<br />\nそもそも実行属性必要ないので気にしなくて良いです。</p>\n\n<h1 id=\"テスト\">テスト</h1>\n<p>NCS2を使用してプログラム実行してみて、エラーにならずに実行できればOK。</p>\n\n<h1 id=\"つぶやき\">つぶやき</h1>\n<p>でも、なんでNCS2用のライブラリ入ってないんだろ?<br />\n単なる入れ忘れ? サポート終了目前?</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 22.04のVirtualBoxへのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 22.04のVirtualBoxへのインストール</h1>\n      <p>Ubuntu 22.04のVirtualBoxへのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 22.04のVirtualBoxへのインストール手順をまとめてみた。\n20.04と大差ないけど、微妙に違う点もあるので。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2204-インストール媒体の入手\">Ubuntu 22.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら:\n<a href=\"https://www.ubuntulinux.jp/products/JA-Localized/download\" target=\"_blank\">Ubuntu Desktop 日本語 Remixのダウンロード</a><br />\n日本語環境構築するなら本家よりRemix版を使った方がなにかと便利(な気がする)。<br />\n<a href=\"https://jp.ubuntu.com/download\" target=\"_blank\">本家はこちら</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを4096MB以上に設定しておくこと</strong></p>\n<blockquote>\n  <p>[!NOTE]\n推奨環境が4GB以上なので。<br />\nウィンドウマネージャだけ動いている状態で1GBちょい使用だったので、\n2048MBでも動くと思う。でも、何か動かしたらすぐ足りなくなりそう。 <br />\nそれにしても、どんどん必要メモリが大きくなるな。<br />\n仮想環境で4GBってことは、HostOS環境下には8GB以上は必要ってことだよな。<br />\nプロセッサも2個割り当てておいた方が良いのかな?<br />\nこれは様子見てからどうするか決めよう。</p>\n</blockquote>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<blockquote>\n  <p>[!TIP]\nウィンドウが画面からはみ出して「続ける」ボタンが押せないときは、Alt+F7キーを押したあと、マウスでドラッグすると\nウィンドウを移動できるので、ボタンが見えるようところまで移動してクリックしてちょ。</p>\n</blockquote>\n\n<p>以下の説明が図付きで分かりやすい:\n<a href=\"https://qiita.com/HirMtsd/items/d43fc5215a88cbf414c9\" target=\"_blank\">Windows11上のVirtualBoxにUbuntu22.04LTSをインストール</a><br />\nWindows11って書いてあるけど、Windows10でも同じ。<br />\nここの説明では「不完全な言語サポート」うんぬんの説明があるけど、日本語Remix版でインストールすると、この部分は不要みたい。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<p>まだGuestAdditionをインストールしてないからコピペできないけど、BashのTab補完が効くので、\nちょろっと入力してあとは補完に頼れば大丈夫。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面 を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源管理を選択<br />\n右側で画面のブランクのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>裏でソフトウェアの更新が動いていると、ロックファイルがロックされてしばらく適用できないので、<br />\nそうなっちゃったらお茶でも飲んでしばらくお待ちください。<br />\nソフトウェアの更新による自動更新を止める方法は後ほど。</p>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweaks \n</code></pre></div></div>\n\n<h3 id=\"一旦リブート\">一旦リブート</h3>\n<p>更新適用のため。</p>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>以前にマウントしたものが残ってたらアンマウントしておくこと(インストール後初めてなのでマウントされてることはないけれど)。<br />\nVirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<blockquote>\n  <p>[!TIPS]\nプログラムが自動で始まらない場合は、CDROMのマウント先(たぶん、<code class=\"language-plaintext highlighter-rouge\">/media/<USER>/VBox_GAs_x.x.xx/</code>)に移動して<code class=\"language-plaintext highlighter-rouge\">sudo VBoxLinuxAdditions.run</code>を実行すれば良い。</p>\n</blockquote>\n\n<h3 id=\"再度リブート\">再度リブート</h3>\n<p>GuestAdditionによる更新適用のため。</p>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから「デバイス」→「クリップボードの共有」→「双方向」<br />\nを選択。\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<h3 id=\"使わないのでアンインストール\">使わないのでアンインストール</h3>\n\n<p>使うツールがあったら残してちょ。</p>\n\n<h4 id=\"ツール類\">ツール類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h4 id=\"ゲーム類\">ゲーム類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h4 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"お好みで\">お好みで</h2>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>ディレクトリにコピるだけ。<br />\n下では全部コピってるけど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.0.0/UDEVGothic_v1.0.0.zip \nunzip UDEVGothic_v1.0.0.zip \n<span class=\"nb\">mkdir</span> ~/.fonts\n<span class=\"nb\">cp </span>UDEVGothic_v1.0.0/<span class=\"k\">*</span>.ttf ~/.fonts/\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。<br />\nさっきフォントのインストールに使った端末ウィンドウを使うと\nエラーで端末ウィンドウが落ちるかもしれないんで一旦終了して新しいウィンドウで。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<h3 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h3>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h3 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h3>\n\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h3 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h3>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>~/.bashrcに以下を追記。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"c\"># Ubuntu22.04だとwaylandになるらしい</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"wayland\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vi\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># # venvの仮想環境名を表示するための設定</span>\n    <span class=\"c\"># show_virtual_env() {</span>\n    <span class=\"c\">#   if [ -n \"$VIRTUAL_ENV\" ]; then</span>\n    <span class=\"c\">#     echo \"($(basename $VIRTUAL_ENV))\"</span>\n    <span class=\"c\">#   fi</span>\n    <span class=\"c\"># }</span>\n    <span class=\"c\"># PS1='$(show_virtual_env)'$PS1</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># openVINO の設定はdirenvで</span>\n<span class=\"c\"># for openVINO</span>\n<span class=\"c\"># source /opt/intel/openvino_2021/bin/setupvars.sh</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nUbuntu20.04とちょっとキーが変更されてる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-home <span class=\"nb\">false \n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"sambaのインストール\">sambaのインストール</h3>\n\n<p>ツール本体のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加<br />\n作らなかったワークディレクトリの部分は削除してね。<br />\n他にも共有したいディレクトリがあったら追加してちょ。<br />\nここではOpenVINOのサンプルとか見たかったのでoptを共有してます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n<span class=\"c\"># abcの下にリモートのファイルが見えたらOK</span>\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"ファイルnautilusのデフォルト動作変更\">ファイル(nautilus)のデフォルト動作変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アドレスバーをテキスト形式にする</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences always-use-location-entry <span class=\"nb\">true</span> \n\n<span class=\"c\"># 詳細表示をデフォルトに</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences default-folder-viewer <span class=\"s1\">'list-view'</span> \n\n<span class=\"c\"># 隠しファイルを表示する</span>\n<span class=\"c\"># 隠しファイルの表示はちょっと場所が違う</span>\ngsettings <span class=\"nb\">set </span>org.gtk.Settings.FileChooser show-hidden <span class=\"nb\">true</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアの更新(update-manager)を起動\n    <ul>\n      <li>更新のチェックが始まった場合はちょっと待つ</li>\n      <li>設定…をクリック\n        <ul>\n          <li>アップデートタブを選択</li>\n          <li>アップデートの自動確認を「なし」に変更</li>\n          <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n          <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n          <li>閉じるをクリック</li>\n        </ul>\n      </li>\n      <li>OKで終了</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a><br />\nリンク先は「Ubuntu 20.04/18.04 LTS」となっているが、Ubuntu22.04でも同じらしい。<br />\nNative環境にインストールしてないので未確認だけど…</p>\n\n<p>リブート必要だが、以下のIPv6無効化とまとめてリブートでも可。</p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<p>マスタイメージを残しておいて、色々な環境をお試しするには仮想マシンをクローンして使うのがおススメ。<br />\nVirtualBoxのメインウィンドウでマスタイメージの仮想マシンを右クリック→クローンを選択、名前とパスを設定し、あとはごにょごにょ…</p>\n\n<p>クローンした仮想マシンを起動し、必要な変更を加える。</p>\n\n<h2 id=\"ネットワーク設定の変更\">ネットワーク設定の変更</h2>\n\n<p>マシン名とか同じ名前だと色々不都合があるので、変更しておく。<br />\n他のクローン仮想環境と同時に使わないならそのままでも良いけど。<br />\nIPアドレスも固定で割り振っておくと名前が引けない時にさくっと分かってなにかと便利…なんだけど、最近はWindowsもUbuntuもRaspberryPiもmDNSがサポートされてるから自動割り当てのままでもそんなに不便はないかも。</p>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<p>このコマンドで<code class=\"language-plaintext highlighter-rouge\">/etc/hostname</code>が書き換えられる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<p>もちろん、vimとかで書き換えても可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<p>下のコマンドを実行するための接続名を確認しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<p>IPアドレスを手動割り当てに変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> \n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<p>IPアドレスを手動割り当てに変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> gw4 <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nIPアドレスの変更をGUIで行うには以下。<br />\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>まとめて実行するならこちら。<br />\nホスト名、接続名、IPアドレスなどは適宜変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># マシン番号の設定とホスト名の設定</span>\n<span class=\"nv\">number</span><span class=\"o\">=</span>30\n<span class=\"nv\">new_hostname</span><span class=\"o\">=</span>skull<span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span>\n\n<span class=\"c\"># HOSTNAMEの変更</span>\n<span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/ubuntu-22.*</span><span class=\"nv\">$/</span><span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span><span class=\"s2\">/\"</span> /etc/hosts\n\n<span class=\"c\"># HOST ONLY ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.56.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n\n<span class=\"c\"># BRIDGE ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.78.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> gw4 <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<h2 id=\"あとはお約束\">あとはお約束</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>VirtalBoxのバージョンが変更されているときは、GuestAdditionのバージョンアップも忘れずに。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</h1>\n      <p>Raspberry Pi OS(64bit)のRaspberry Pi Imagerを使用したインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>また手順が変わったみたいなので、メモも更新。<br />\n(2023/10/15 最新版での試行結果を反映)</p>\n\n<h1 id=\"sdカードへの書き込み\">SDカードへの書き込み</h1>\n\n<p>Raspberry Pi Imager なるツールを使うようになったらしい。<br />\n使い方はあちこちに書いてあるけど、例えばこちら。</p>\n<ul>\n  <li><a href=\"https://ascii.jp/elem/000/004/094/4094421/\" target=\"_blank\">Raspberry Pi Imagerの使い方 ― v1.7.2以降 対応版</a></li>\n  <li><a href=\"https://www.mikan-tech.net/entry/raspi-imager-headless-setup\" target=\"_blank\">Raspberry Pi Imagerが新しくなった!Lite版もらくらくHeadless Setup</a></li>\n</ul>\n\n<p>これを使うと、最初のユーザを自由に設定できるので、これまでのpiユーザを変更するなんてことはやらなくて済む。<br />\nWi-Fiの設定やSSHの設定も(なんかWindowsが適切に設定されてれば公開鍵が自動で設定されるみたい)ここでできる。</p>\n\n<p>パスワードが設定ファイルに書き出されるので(さすがに平文ではない、最初の起動が終わったら削除される)、<br />\nセキュリティ上気になる場合は仮パスワードを設定しておいて<br />\n最初にログインしたときに変更する、なんてことをやった方が良いと言ってる解説ページもあった。</p>\n\n<blockquote>\n  <p>[!WARNING]\n<del>なぜかSSHの認証方法が毎回「パスワード認証を使う」になってしまうので、公開鍵を使うときは再度設定が必要。</del> \n(1.7.5では改善された模様)</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\n<del>(少なくとも)2023/10以降のバージョンはopenSSHのバージョンがRSA非対応になっているので、 \n 鍵ファイル作成の際はRSA以外(ed25519など)で作成する必要がある。</del> <br />\n(2023/10/21 誤解してたので書き直し)<br />\n(少なくとも)2023/10以降のバージョンはopenSSHのバージョンが SSH-RSA 非対応になっているので、<br />\nTeraterm Ver4.106以前など RSA-SHA2未対応の環境ではRSA鍵では繋がらない。 \nその場合は RSA以外(ed25519など)で作成すれば良い。<br />\nssh-keygenのデフォルトはRSAなので、<code class=\"language-plaintext highlighter-rouge\">ssh-keygen -t ed25519</code> などとする。<br />\nもちろん、Teraterm Ver4.107以降に変更するという手もある。</p>\n</blockquote>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1\n</code></pre></div></div>\n<h2 id=\"ipv6の無効化\">IPv6の無効化</h2>\n<p>IPv6を無効化しておきたいときは、\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する。<br />\nこのファイルは1行で書かないといけないので、改行してはいけない。</p>\n\n<blockquote>\n  <p>[!WARNING]\n<del>以前はこれで無効化できていたはずだけど、2023/10現在 この手順では無効化できないらしい。<br />\n下でセットアップスクリプトで無効化処理を実行するように変更した。</del> <br />\n(2023/10/21 間違ってたので削除)</p>\n</blockquote>\n\n<h2 id=\"ブートログの表示\">ブートログの表示</h2>\n\n<p>ブートログが見えないと不安な人は、<br />\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> から <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code>\nを削除しておくとよい。</p>\n<blockquote>\n  <p>[!NOTE]\nLITE版では<code class=\"language-plaintext highlighter-rouge\">quiet</code>を削除(それ以外は指定されていないので)</p>\n</blockquote>\n\n<h1 id=\"最初の起動\">最初の起動</h1>\n<p>書き込んだSDカードをRaspberry Piに挿入して電源ON。<br />\nごちょごちょと設定したあと、起動する(途中2回ほどrebootしてるらしい)</p>\n\n<p>あとは起動後の設定。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># アップデート実行\nsudo apt update\nsudo apt upgrade\n\n# リブート\nsudo reboot\n</code></pre></div></div>\n\n<h1 id=\"カスタマイズ\">カスタマイズ</h1>\n\n<blockquote>\n  <p>[!NOTE]\n以降の処理をスクリプトにまとめました。<br />\n<a href=\"https://gist.github.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c\" target=\"_blank\">Raspberry Pi セットアップスクリプト </a><br />\n以下の手順で実行できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.githubusercontent.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c/raw/pi_setup1.sh\nbash pi_setup1.sh\n</code></pre></div>  </div>\n  <p>LITE版を使うときは変数<code class=\"language-plaintext highlighter-rouge\">LITE_OS</code>に<code class=\"language-plaintext highlighter-rouge\">1</code>を設定して実行します。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> <span class=\"nv\">LITE_OS</span><span class=\"o\">=</span>1 bash pi_setup1.sh\n</code></pre></div>  </div>\n\n  <p>途中でパスワード入力しないといけないので、完全自動じゃないけど、かなり手間は省けるはず。<br />\n実行後、<code class=\"language-plaintext highlighter-rouge\">pi_setup1.sh</code>は不要なので削除して可。<br />\n実行が終わったらリブートすること。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>reboot\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h2 id=\"resizeスクリプトの取得\">resizeスクリプトの取得</h2>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/4f39afbcd8471426421944b597f3a5f2963984c6/resize.py\n\n<span class=\"nb\">chmod</span> +x resize.py\n\n./resize.py\n</code></pre></div></div>\n\n<h2 id=\"ロケールの変更\">ロケールの変更</h2>\n<p>日本語表示のため、ロケールを変更する。<br />\n(imagerだとキーボードレイアウトの変更はやってくれるけど、ロケールの変更はやってくれないらしいので)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ロケールの変更</span>\n<span class=\"nb\">sudo </span>raspi-config nonint do_change_locale ja_JP.UTF-8\n\n<span class=\"c\"># リブートまでとりあえずLANGのみ変更で日本語表示</span>\n<span class=\"nb\">export </span><span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF-8\n</code></pre></div></div>\n\n<h2 id=\"bashrc-の変更\">.bashrc の変更</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n</code></pre></div></div>\n\n<h2 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h2>\n\n<p>物理キーボード接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]<br />\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n\n</blockquote>\n\n<h2 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h2>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h2 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h2>\n\n<p>まずはワークディレクトリの作成</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown $USER:$USER /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a $USER\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo service smbd reload\nsudo service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"vncサーバの有効化\">VNCサーバの有効化</h2>\n\n<p>リモートデスクトップを使うために、VNCサーバの有効化を行う。<br />\nLITE版では不要。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    # VNCサーバの有効化\n    3 Interfacing Options\n        I3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>\n            The VNC Server is enabled\n            と表示されるので <Ok>\n\n    # VNC解像度の設定\n    2 Display Options\n        D5 VNC Resolution\n        \n            解像度が色々表示されるので、\n            使いたい解像度を選択(例えば 1920x1080 )して<Select>\n            The resolution is set to «選択した解像度»\n            と表示されるので <Ok>\n    # 設定終了\n    <Finish>\n</code></pre></div></div>\n\n<h2 id=\"ipv6-の無効化\">IPv6 の無効化</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code>での設定では無効化できなくなったと思ったけど、勘違いだった。<br />\nなので、上記の<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する方法でOK。</p>\n\n<p>でも、その時に<code class=\"language-plaintext highlighter-rouge\">mncli</code>コマンドで無効化するスクリプトを作ったので、せっかくなので残しておく。</p>\n\n<p>接続名一覧を取得し、 それぞれに対して無効化するコマンドを実行する。<br />\n接続名に「有線接続 1」と空白が含まれている接続があるので、一時的に空白をセミコロンに置換して処理を行っている。<br />\n(これをやらないと「有線接続」と「1」に分けて処理されてしまう)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 接続一覧を取得</span>\n<span class=\"nv\">conn_data</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli <span class=\"nt\">-t</span> connection<span class=\"si\">)</span>\n\n<span class=\"c\"># 空白を\";\"に置換(配列代入時に誤動作するのを防止)</span>\n<span class=\"nv\">conn_data</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">conn_data</span><span class=\"p\">// /</span><span class=\"s2\">\";\"</span><span class=\"k\">}</span>\n\n<span class=\"c\"># ':'区切りで1列目をconnections配列に格納</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"s2\">\"</span><span class=\"nv\">$conn_data</span><span class=\"s2\">\"</span> | <span class=\"nb\">cut</span> <span class=\"nt\">-d</span><span class=\"s2\">\":\"</span> <span class=\"nt\">-f1</span><span class=\"si\">)</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 配列の要素を処理</span>\n<span class=\"k\">for </span>connection <span class=\"k\">in</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[@]</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 上で;に置換した空白を戻す</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"p\">//</span><span class=\"s2\">\";\"</span><span class=\"p\">/</span><span class=\"s2\">\" \"</span><span class=\"k\">}</span>\n\n    <span class=\"k\">if</span> <span class=\"o\">[[</span> <span class=\"s2\">\"</span><span class=\"nv\">$connection</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s1\">'lo'</span> <span class=\"o\">]]</span><span class=\"p\">;</span> <span class=\"k\">then</span>    <span class=\"c\"># loデバイスは無効にできないので除外</span>\n      <span class=\"nb\">echo</span> <span class=\"s2\">\"disable </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span> \n      <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> ipv6.method </span><span class=\"se\">\\\"</span><span class=\"s2\">disabled</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n      <span class=\"c\"># 有効にする場合はこちら</span>\n      <span class=\"c\"># cmd=\"sudo nmcli connection modify \\\"${connection}\\\" ipv6.method \\\"auto\\\"\"</span>\n      <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n      <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone</span>\n</code></pre></div></div>\n\n<h1 id=\"splash-screenの再有効化\">Splash screenの再有効化</h1>\n\n<p>セットアップ時にブートログが表示されるようにしたけど、<br />\nやっぱり表示したくなくなった(Splash screenを表示)、てなときは以下で。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S6 Splash Screen\n            Would you like to show the splash screen at boot?\n            と聞かれるので有効化するときは <Yes> を選択\n            Splash screen at boot is enabled)\n            と表示されるので <Ok>\n\n    Would you like to reboot now?\n    と聞かれるので、その場でリブートしてよければ<Yes>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n直接<code class=\"language-plaintext highlighter-rouge\">/boot/cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code> を追加しても良い。<br />\nLITE版では <code class=\"language-plaintext highlighter-rouge\">quiet</code>のみ追加。</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Pythonのasyncioでnon-blockingなコンソール入力</title>\n  </head>\n  <body>\n    <header>\n      <h1>Pythonのasyncioでnon-blockingなコンソール入力</h1>\n      <p>Pythonのasyncioでnon-blockingなコンソール入力を行うためのクラス</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでasyncioを使ったときにnon-blockingなコンソール入力(キーボード入力)ができなくて困ったので、実現するためのクラスを作ってみた。</p>\n\n<p>もともと Linux用に作ったら、Windowsだとうまく動かない。<br />\nちょっと汚い方法だけど、とりあえず動くようにしてお茶を濁しておく。<br />\n(あんまりテストしてないから動かなかったらごめん)</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/5033eec9b9b774ede4f87604a51fb162.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>お試しならこのソースをそのまま実行すると実行できます。<br />\n<code class=\"language-plaintext highlighter-rouge\">char_mode = False</code> の部分を変更すると、1行入力モードと1文字入力モードを切り替えられます。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout_mode = True</code> の部分を変更すると、タイムアウトなしとタイムアウトありを切り替えられます。</p>\n\n<p>実際に使用するには、このソースをimportして使ってください。</p>\n\n<h1 id=\"注意\">注意</h1>\n\n<p>Linuxで1文字入力モードを使っている場合は、終了時(例外で死んだ場合も含めて)<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行しないと悲しいことになります。<br />\n(ターミナルの入力モードが変更されてしまうので、うまく入力できなくなる)<br />\nそのために、<code class=\"language-plaintext highlighter-rouge\">atexit.retister()</code>で終了処理ルーチンを登録し、その中で<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行するようにしています。</p>\n\n<h1 id=\"ひとりごと\">ひとりごと</h1>\n\n<p>asyncioのサンプルって、タスク1個で動かしてることが多いからあんまり ありがたみが分からんのかな…<br />\nあと、タスクとコルーチンが同じように語られていて分かり難いのもあると思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi で python で PWM</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi で python で PWM</h1>\n      <p>Raspberry Pi 上で python で PWMの制御を行うブログラムの雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Piでロボットアームを制御するのに、PWMのテストを行ったときのプログラムソースを貼っておく。<br />\n使ったロボットアーム: <a href=\"https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1\" target=\"_blank\">https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1</a></p>\n\n<p>ソフトウェアPWMだと他の処理の負荷によってジッタが発生し、ガタガタいうのでこの使い方はあまり実用的ではない。<br />\nハードウェアPWMを使う(pigpio か wiringpi が必要)、PWM制御を担うMCUを用意してコマンド通信(TCP/IPやBluetoothなど経由)で制御するのが現実的かも。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>PRi.GPIOを使うので、インストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>RPi.GPIO\n</code></pre></div></div>\n\n<p>プログラムの設定にあわせてGPIOとサーボモータを接続しておく(または接続に合わせてプログラム修正)。<br />\nスイッチで調整できるようにしてあるけど、キーボードから調整できるのでスイッチの接続は必須ではない。</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/0e8eeedb37d59c85b6ae6085da2a2cb4.js\"></script>\n</dev>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">GPIO.add_event_detect()</code>には<code class=\"language-plaintext highlighter-rouge\">bouncetime=«チャタリング除去時間(msec)»</code>を追加しておくのが良いかも。<br />\n参考: <a href=\"https://tomosoft.jp/design/?p=8685\" target=\"_blank\">GPIOエッジ検出コールバック関数 | TomoSoft</a></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n公式マニュアルは存在しないらしい。<br />\n唯一以下のページがそれっぽい情報を掲載している。<br />\n<a href=\"https://sourceforge.net/p/raspberry-gpio-python/wiki/Examples/\" target=\"_blank\">raspberry-gpio-python / Wiki / Examples</a><br />\nあとはソース読むしかないんだけど、python - C インタフェースを理解してないと苦しい…<br />\nソース全体を<code class=\"language-plaintext highlighter-rouge\">python function</code>で検索すると出てくるけど全部じゃない…<br />\nソースはここ: <a href=\"https://pypi.org/project/RPi.GPIO/#files\" target=\"_blank\">RPi.GPIO · PyPI</a></p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>プログラム実行して、スイッチかキーボードで出力値変えてみる。<br />\n設定値の範囲は個体差があるので、適当に変更必要。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MediaPipeの手の認識でお絵かき</title>\n  </head>\n  <body>\n    <header>\n      <h1>MediaPipeの手の認識でお絵かき</h1>\n      <p>MediaPipe Handsでの手の認識結果と使ってお絵かきしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>MediaPipeで手の認識</p>\n\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』の手の認識子処理を使って空間にお絵かきしてみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』を参照。</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<h2 id=\"共通ルーチン\">共通ルーチン</h2>\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』を参照。</p>\n\n<h2 id=\"お絵かきプログラム\">お絵かきプログラム</h2>\n\n<p>お絵かきプログラム本体。<br />\n人差し指先端に点を打っていくことでお絵かきしている。<br />\n人差し指だけ立てた状態(ジェスチャ ONE)だと赤、人差し指と中指を立てた状態(ジェスチャ PEACE)だと緑で描画するようにしてあるが、この組み合わせにあまり意味はない。なんとなく色を切り替えてみたかったので。<br />\nコマンドラインオプションと表示中操作についてはソース見てちょ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  oekaki.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n<span class=\"n\">HandLandmark</span> <span class=\"o\">=</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span>  <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span>         <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n<span class=\"c1\">#     parser.add_argument(\"-nh\", \"--num_hand\",         default=2,   type=int,     help=\"(optional) Max number of hands\")\n</span>    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n# max_num_hands            = args.num_hand            # 検出する手の個数\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"mi\">1</span>                        <span class=\"c1\"># 検出する手の個数 今回は1固定\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">verbose2</span>                 <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>\n\n<span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">True</span>                    <span class=\"c1\"># 鏡像使用\n</span><span class=\"n\">fg_only</span>                  <span class=\"o\">=</span> <span class=\"bp\">False</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"n\">COLOR_WHITE</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_BLUE</span>  <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_GREEN</span> <span class=\"o\">=</span> <span class=\"p\">(</span>  <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_RED</span>   <span class=\"o\">=</span> <span class=\"p\">(</span>  <span class=\"mi\">0</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># カメラ\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像サイズ\n</span><span class=\"n\">image_width</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n<span class=\"n\">image_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n<span class=\"n\">fps</span>          <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'image size : </span><span class=\"si\">{</span><span class=\"n\">image_width</span><span class=\"si\">}</span><span class=\"s\"> x </span><span class=\"si\">{</span><span class=\"n\">image_height</span><span class=\"si\">}</span><span class=\"s\"> @ </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">Hz'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前景イメージを作成\n</span><span class=\"n\">image_fg</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">full</span><span class=\"p\">((</span><span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span>   <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">,</span>            <span class=\"c1\"># 動画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>        <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 前のフレーム処理完了時刻を初期化\n</span>    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># キャプチャ\n</span>        <span class=\"n\">success</span><span class=\"p\">,</span> <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">success</span><span class=\"p\">:</span>\n            <span class=\"c1\"># エラーになったら再度キャプチャ\n</span>            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Ignoring empty camera frame.\"</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>        <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n            <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        \n        <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>        <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>        <span class=\"c1\"># 検出できたか?\n</span>            <span class=\"c1\"># ポーズの認識\n</span>            <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 人差し指先の位置\n</span>            <span class=\"n\">finger_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n            <span class=\"n\">finger_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'(</span><span class=\"si\">{</span><span class=\"n\">finger_x</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">finger_y</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">)  </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ポーズによって色を変更\n</span>            <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"o\">==</span> <span class=\"s\">'ONE'</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"n\">COLOR_RED</span>           <span class=\"c1\"># 赤\n</span>            <span class=\"k\">elif</span> <span class=\"n\">gesture</span> <span class=\"o\">==</span> <span class=\"s\">'PEACE'</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"n\">COLOR_GREEN</span>         <span class=\"c1\"># 緑\n</span>            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n            <span class=\"k\">if</span> <span class=\"n\">color</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># 前景イメージに点を打つ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">circle</span><span class=\"p\">(</span><span class=\"n\">image_fg</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">finger_x</span><span class=\"p\">,</span> <span class=\"n\">finger_y</span><span class=\"p\">)</span> <span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span><span class=\"o\">=-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># フレーム処理時間\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 現在のフレーム処理完了時刻\n</span>        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>                   <span class=\"c1\"># このフレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        \n        <span class=\"c1\"># FPS表示\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                <span class=\"sa\">f</span><span class=\"s\">'FPS:</span><span class=\"si\">{</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>  <span class=\"c1\"># 文字列\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">50</span><span class=\"p\">),</span>                    <span class=\"c1\"># 座標\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                <span class=\"n\">COLOR_RED</span><span class=\"p\">,</span>                  <span class=\"c1\"># 色\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>            <span class=\"p\">)</span>\n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"n\">fg_only</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 前景イメージだけ表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image_fg</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 画像を重ね合わせ(COLOR_WHITEを透過色として指定)て表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">where</span><span class=\"p\">(</span><span class=\"n\">image_fg</span> <span class=\"o\">==</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">image_fg</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># 表示終了待ち\n</span>        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'c'</span><span class=\"p\">):</span>\n            <span class=\"c1\"># 前景イメージを初期化\n</span>            <span class=\"n\">image_fg</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">full</span><span class=\"p\">((</span><span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'d'</span><span class=\"p\">):</span>\n            <span class=\"n\">fg_only</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">fg_only</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'v'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'b'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose2</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose2</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'p'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imwrite</span><span class=\"p\">(</span>\n                    <span class=\"sa\">f</span><span class=\"s\">'z_oekaki_</span><span class=\"si\">{</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">now</span><span class=\"p\">().</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s\">\"%d_%H%M%S\"</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">.jpg'</span><span class=\"p\">,</span> \n                    <span class=\"n\">image_fg</span>\n                <span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"c1\"># ウィンドウをすべて閉じる\n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># カメラリリース\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: oekaki.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD]\n                 <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h1 id=\"感想\">感想</h1>\n\n<p>それなりにお絵かきできるけど…</p>\n<ul>\n  <li>認識処理が遅いと手をゆっくり動かさないと線にならない</li>\n  <li>ポーズの認識の精度がイマイチで描画結果が微妙な感じになる</li>\n</ul>\n\n<p>実際にユーザインタフェースとして使うには色々と工夫が必要かな。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MediaPipeで手の認識</title>\n  </head>\n  <body>\n    <header>\n      <h1>MediaPipeで手の認識</h1>\n      <p>MediaPipe Handsで手の認識処理をやってみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>MediaPipe Handsを使って手の認識処理を行ってみる。<br />\nMediaPipeを使用するとかなり簡単に手の特徴点を取得できる。<br />\nまた、各特徴点の位置がわかるので、それらの位置関係からポーズを取得することもできる。</p>\n\n<p>参考: <a href=\"https://google.github.io/mediapipe/solutions/hands.html\" target=\"_blank\">https://google.github.io/mediapipe/solutions/hands.html</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/mediapipe\n<span class=\"nb\">cd</span> /work/ble/mediapipe\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 mediapipe\npyenv <span class=\"nb\">local </span>mediapipe\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>mediapipe\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<h2 id=\"共通ルーチン\">共通ルーチン</h2>\n\n<p>各指の関節と指先の位置関係から指が伸びているのか、曲がっているのかを判別し(親指だけは各関節の角度から判別)、<br />\nその組み合わせからどのようなポーズなのかを判別している。<br />\nアルゴリズムは <a href=\"https://github.com/geaxgx/openvino_hand_tracker\">https://github.com/geaxgx/openvino_hand_tracker</a> から拝借した。<br />\n元のプログラムは各関節の位置を検出された手の画像を回転して角度調整した画像のY座標から取得しているが、<br />\n今回は手の角度が分からないので、手首から各関節位置までの距離を比較するように変更した。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  hand_gesture.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">HandLandmark</span> <span class=\"o\">=</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">distance</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">):</span>\n    <span class=\"c1\"># a, b: 2 points in 3D (x,y,z)\n</span>    <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">a</span> <span class=\"o\">-</span> <span class=\"n\">b</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">angle</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">,</span> <span class=\"n\">c</span><span class=\"p\">):</span>\n    <span class=\"c1\"># a, b and c : points as np.array([x, y, z]) \n</span>    <span class=\"n\">ba</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">-</span> <span class=\"n\">b</span>\n    <span class=\"n\">bc</span> <span class=\"o\">=</span> <span class=\"n\">c</span> <span class=\"o\">-</span> <span class=\"n\">b</span>\n    <span class=\"n\">cosine_angle</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">dot</span><span class=\"p\">(</span><span class=\"n\">ba</span><span class=\"p\">,</span> <span class=\"n\">bc</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">ba</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">bc</span><span class=\"p\">))</span>\n    <span class=\"n\">angle</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arccos</span><span class=\"p\">(</span><span class=\"n\">cosine_angle</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">degrees</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ジェスチャの認識\n# 参考: https://github.com/geaxgx/openvino_hand_tracker\n</span><span class=\"k\">def</span> <span class=\"nf\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">debug</span> <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">):</span>\n    <span class=\"c1\"># 各landmarkの手首からの距離を求める\n</span>    <span class=\"n\">lm_pos</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([[</span><span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">z</span><span class=\"p\">]</span> <span class=\"k\">for</span> <span class=\"n\">lm</span> <span class=\"ow\">in</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">])</span>    <span class=\"c1\"># 計算のためndarray化\n</span>    <span class=\"c1\"># lm_pos = np.array([[lm.x, lm.y] for lm in landmarks.landmark])          # 計算のためndarray化(zは無視)\n</span>    <span class=\"n\">r_</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span> <span class=\"o\">-</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">WRIST</span><span class=\"p\">],</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>        <span class=\"c1\"># numpyなので一括計算\n</span>    \n    <span class=\"c1\"># 親指の角度で状態判別\n</span>    <span class=\"n\">distance0</span> <span class=\"o\">=</span> <span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">],</span>     <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指の第二関節と人差し指の付け根の距離\n</span>    <span class=\"n\">distance1</span> <span class=\"o\">=</span> <span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span>    <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">]</span>        <span class=\"p\">)</span>     <span class=\"c1\"># 親指の付け根と親指の第二関節の距離\n</span>    <span class=\"n\">angle0</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">WRIST</span><span class=\"p\">],</span>      <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_CMC</span><span class=\"p\">],</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指付け根の角度\n</span>    <span class=\"n\">angle1</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_CMC</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">]</span> <span class=\"p\">)</span>     <span class=\"c1\"># 親指第二関節の角度\n</span>    <span class=\"n\">angle2</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_TIP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指第一関節の角度\n</span>    <span class=\"n\">thumb_angle</span> <span class=\"o\">=</span> <span class=\"n\">angle0</span> <span class=\"o\">+</span> <span class=\"n\">angle1</span> <span class=\"o\">+</span> <span class=\"n\">angle2</span>\n    <span class=\"k\">if</span> <span class=\"n\">thumb_angle</span> <span class=\"o\">></span> <span class=\"mi\">460</span> <span class=\"ow\">and</span> <span class=\"n\">distance0</span> <span class=\"o\">/</span> <span class=\"n\">distance1</span> <span class=\"o\">></span> <span class=\"mf\">1.2</span><span class=\"p\">:</span> \n        <span class=\"n\">thumb_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">thumb_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># 人差し指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 中指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 薬指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 小指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># Gesture\n</span>    <span class=\"k\">if</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FIST\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"OK\"</span> \n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"PEACE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"ONE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"TWO\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"THREE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>      <span class=\"c1\"># 日本型の3\n</span>        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"THREE_J\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FOUR\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FIVE\"</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># for debug\n</span>    <span class=\"c1\"># print(f'{r_[HandLandmark.INDEX_FINGER_MCP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_PIP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_DIP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_TIP]:6.3f}    {index_state}')\n</span>\n    <span class=\"k\">if</span> <span class=\"n\">debug</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">21</span><span class=\"p\">):</span>\n            <span class=\"n\">lm_x</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"c1\"># * image_width\n</span>            <span class=\"n\">lm_y</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"c1\"># * image_height\n</span>            <span class=\"n\">lm_z</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">z</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">HandLandmark</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">))</span><span class=\"si\">:</span><span class=\"mi\">32</span><span class=\"n\">s</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">:</span><span class=\"mi\">2</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">):   </span><span class=\"si\">{</span><span class=\"n\">lm_x</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">lm_y</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">lm_z</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">:</span><span class=\"mf\">6.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">gesture</span>\n</code></pre></div></div>\n\n<h2 id=\"カメラ画像から認識\">カメラ画像から認識</h2>\n<p>カメラ画像から認識してみる。<br />\nこっちの方が用途は多いかな。<br />\nコマンドラインオプションについてはソース見てちょ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  test_camera.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span>  <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span>         <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-nh\"</span><span class=\"p\">,</span> <span class=\"s\">\"--num_hand\"</span><span class=\"p\">,</span>         <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span>   <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Max number of hands\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num_hand</span>            <span class=\"c1\"># 検出する手の個数\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">verbose2</span>                 <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>\n<span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">True</span>                    <span class=\"c1\"># 鏡像使用\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># カメラ\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span>   <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">,</span>            <span class=\"c1\"># 動画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>        <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 前のフレーム処理完了時刻を初期化\n</span>    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># キャプチャ\n</span>        <span class=\"n\">success</span><span class=\"p\">,</span> <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">success</span><span class=\"p\">:</span>\n            <span class=\"c1\"># エラーになったら再度キャプチャ\n</span>            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Ignoring empty camera frame.\"</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>        <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n            <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像サイズ\n</span>        <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n        \n        <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>        <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># 検出結果の処理\n</span>        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">handedness</span> <span class=\"ow\">in</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_handedness</span><span class=\"p\">):</span>\n                <span class=\"k\">if</span> <span class=\"n\">verbose</span> <span class=\"ow\">or</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'--------------------------------------------------------------------------'</span><span class=\"p\">)</span>\n                \n                <span class=\"c1\"># データは鏡像として判別されているので、鏡像でなければラベルを入れ替え\n</span>                <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span> <span class=\"o\">==</span> <span class=\"s\">\"Left\"</span> <span class=\"p\">:</span>\n                        <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Right\"</span>\n                    <span class=\"k\">else</span> <span class=\"p\">:</span>\n                        <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Left\"</span>\n                \n                <span class=\"c1\"># ジェスチャの認識\n</span>                <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n                \n                <span class=\"k\">if</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'==== sore ======================='</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">index</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'score   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">score</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'label   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>            <span class=\"c1\"># あんまりあてにならないな...\n</span>                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'gesture : </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'================================='</span><span class=\"p\">)</span>\n                \n                <span class=\"c1\"># landmarkの描画\n</span>                <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">draw_landmarks</span><span class=\"p\">(</span>\n                    <span class=\"n\">image</span><span class=\"p\">,</span>                              <span class=\"c1\"># 画像\n</span>                    <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span>                     <span class=\"c1\"># ランドマーク\n</span>                    <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span>          <span class=\"c1\"># ランドマーク接続リスト\n</span>                    <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_landmarks_style</span><span class=\"p\">(),</span>       <span class=\"c1\"># ランドマーク描画スタイル\n</span>                    <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_connections_style</span><span class=\"p\">()</span>      <span class=\"c1\"># 接続描画スタイル\n</span>                <span class=\"p\">)</span>\n                <span class=\"c1\"># ジェスチャ表示\n</span>                <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># 人差し指の付け根あたりに表示\n</span>                    <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n                    <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                        <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                        <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>     <span class=\"c1\"># 文字列\n</span>                        <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">),</span>                     <span class=\"c1\"># 座標\n</span>                        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                        <span class=\"mi\">1</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                        <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                        <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>                    <span class=\"p\">)</span>\n        \n        <span class=\"c1\"># フレーム処理時間\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 現在のフレーム処理完了時刻\n</span>        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>                   <span class=\"c1\"># このフレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        \n        <span class=\"c1\"># FPS表示\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                <span class=\"sa\">f</span><span class=\"s\">'FPS:</span><span class=\"si\">{</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>  <span class=\"c1\"># 文字列\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">50</span><span class=\"p\">),</span>                    <span class=\"c1\"># 座標\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>            <span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示終了待ち\n</span>        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'v'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'b'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose2</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose2</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"c1\"># ウィンドウをすべて閉じる\n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># カメラリリース\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"静止画像から認識\">静止画像から認識</h2>\n\n<p>デバッグ用途など、静止画から認識する場合はこちら。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  test_photo.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'input'</span><span class=\"p\">,</span> <span class=\"n\">metavar</span><span class=\"o\">=</span><span class=\"s\">\"INPUT_FILE\"</span><span class=\"p\">,</span>                          <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Path to the input picture \"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                 <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--world'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                         <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp world landmark map\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-nh\"</span><span class=\"p\">,</span> <span class=\"s\">\"--num_hand\"</span><span class=\"p\">,</span>         <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span>   <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Max number of hands\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># 入力ファイル名\n</span><span class=\"nb\">file</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num_hand</span>            <span class=\"c1\"># 検出する手の個数\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">False</span>                    <span class=\"c1\"># 鏡像使用しない\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span> <span class=\"o\">=</span> <span class=\"bp\">True</span><span class=\"p\">,</span>               <span class=\"c1\"># 静止画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>                    <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"c1\"># 画像読み込み\n</span>    <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'file name : </span><span class=\"si\">{</span><span class=\"nb\">file</span><span class=\"si\">}</span><span class=\"s\">   image size : </span><span class=\"si\">{</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>    <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n        <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    \n    <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>    <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># 検出結果の処理\n</span>    <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">handedness</span> <span class=\"ow\">in</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_handedness</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">verbose</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'--------------------------------------------------------------------------'</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># データは鏡像として判別されているので、鏡像でなければラベルを入れ替え\n</span>            <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n                <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span> <span class=\"o\">==</span> <span class=\"s\">\"Left\"</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Right\"</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Left\"</span>\n            \n            <span class=\"c1\"># ジェスチャの認識\n</span>            <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n            \n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'==== sore ======================='</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">index</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'score   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">score</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'label   : </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'gesture : </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'================================='</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># landmarkの描画\n</span>            <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">draw_landmarks</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                              <span class=\"c1\"># 画像\n</span>                <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span>                     <span class=\"c1\"># ランドマーク\n</span>                <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span>          <span class=\"c1\"># ランドマーク接続リスト\n</span>                <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_landmarks_style</span><span class=\"p\">(),</span>       <span class=\"c1\"># ランドマーク描画スタイル\n</span>                <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_connections_style</span><span class=\"p\">()</span>      <span class=\"c1\"># 接続描画スタイル\n</span>            <span class=\"p\">)</span>\n            <span class=\"c1\"># ジェスチャ表示\n</span>            <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># 人差し指の付け根あたりに表示\n</span>                <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n                <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                    <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                    <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>     <span class=\"c1\"># 文字列\n</span>                    <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">),</span>                     <span class=\"c1\"># 座標\n</span>                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                    <span class=\"mi\">1</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                    <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                    <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>                <span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"** NO HANDS **\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 表示終了待ち\n</span>    <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'p'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imwrite</span><span class=\"p\">(</span>\n                    <span class=\"s\">'output_'</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">),</span> \n                    <span class=\"n\">image</span>\n                <span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"ow\">not</span> <span class=\"n\">k</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n          <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># ウィンドウをすべて閉じる\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">world</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># hand world landmarks の 3D座標の表示\n</span>        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_world_landmarks</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">hand_world_landmarks</span> <span class=\"ow\">in</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_world_landmarks</span><span class=\"p\">:</span>\n                <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">plot_landmarks</span><span class=\"p\">(</span>\n                                <span class=\"n\">hand_world_landmarks</span><span class=\"p\">,</span> \n                                <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span> \n                                <span class=\"n\">azimuth</span><span class=\"o\">=</span><span class=\"mi\">5</span>\n                            <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<h2 id=\"カメラ画像から認識-1\">カメラ画像から認識</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: test_camera.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-nh</span> NUM_HAND]\n                      <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">-nh</span> NUM_HAND, <span class=\"nt\">--num_hand</span> NUM_HAND\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Max number of hands\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h2 id=\"静止画像から認識-1\">静止画像から認識</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: test_photo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--world</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-nh</span> NUM_HAND]\n                     <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n                     INPUT_FILE\n\npositional arguments:\n  INPUT_FILE            Path to the input picture\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">--world</span>               <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp world landmark map\n  <span class=\"nt\">-nh</span> NUM_HAND, <span class=\"nt\">--num_hand</span> NUM_HAND\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Max number of hands\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h1 id=\"説明\">説明</h1>\n\n<p>説明….するほどのことはないな。<br />\nほとんど出来あいの処理。</p>\n\n<p>各指の状態からポーズを取得する処理を変更すれば、ほかの認識(ジャンケン認識など)にも変更可能。<br />\nまた、人差し指の指先をトラッキングしていけば、バーチャルお絵描きなんてのもできるかも。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINOのクロスコンパイル</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINOのクロスコンパイル</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild(クロスコンパイル環境)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi OS(64bit)向けにopenVINOをクロスコンパイルする方法についてまとめた。<br />\nセルフコンパイル(Docker使用)については『<a href=\"/memoBlog/2022/03/07/openVINO_build_2.html\" target=\"_blank\">openVINO(Raspberry Pi OS(64bit)向け)のbuild</a>』を参照。<br />\nただ、クロスコンパイルだとセルフコンパイルの10倍くらい速い(環境によるけど)ので、クロスコンパイルがおススメ。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_cross <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_cross\n</code></pre></div></div>\n\n<h2 id=\"ソースの取得\">ソースの取得</h2>\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h3>\n<p>以下の1つのpatchファイルを作成する。<br />\nサンプル(テスト?)プログラムのBuildを抑制してコンパイル時間の短縮を計っている。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"opencv-の-gitリポジトリを-clone\">openCV の gitリポジトリを clone</h3>\n<p>opencv のリポジトリをcloneする(opencvのBuildを行わない場合は不要)。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libgtk-3-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_cross <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_cross_1 ov_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_cross_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_cross_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n<p>ここからコンテナ内</p>\n\n<h2 id=\"buildディレクトリの作成\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openvino/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/openvino/build\n</code></pre></div></div>\n\n<h2 id=\"cmake実行\">cmake実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm64.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_SAMPLES</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLANG_FORMAT</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_OPENCV</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n    .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>サンプルはBuildしないので、ENABLE_SAMPLES=OFF を設定</li>\n    <li>ソースをいじるわけではないので、ENABLE_CLANG_FORMAT=OFF を設定</li>\n    <li>openCVインストールされていないので、ENABLE_OPENCV=OFF を設定<br />\n(サンプルのBuildしないのでopenCVなくても大丈夫)</li>\n  </ul>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nログには いくつかWarningがあるが、とくに問題はなさそう</p>\n</blockquote>\n\n<h2 id=\"make\">make</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h2 id=\"その他細々したところ\">その他細々したところ</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"c\"># クロスコンパイルを反映したファイル名になっていないので修正</span>\n<span class=\"nb\">mv</span> /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-x86_64-linux-gnu.so /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-aarch64-linux-gnu.so\n\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>CPU Extentionは<code class=\"language-plaintext highlighter-rouge\">make install</code>でコピーされないので手動でインストールする。</li>\n    <li>バイナリリリースに<code class=\"language-plaintext highlighter-rouge\">inference_engine</code>のシンボリックリンクがあるので同様に作成しておく。</li>\n    <li>ngraphのライブラリファイルのファイル名がx86_64(ホスト環境の名前)になっているので、aarch64に修正。<br />\nバイナリ自体はaarch64になっているので、ファイル名のリネームだけでOK。<br />\n本来はファイル名決めてるところで対処するのが良いのだろうけど、とりあえず力技で。</li>\n  </ul>\n</blockquote>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<p>openCVのBuild方法についてもメモっておく。<br />\npythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。<br />\nその場合は、ここはスキップしても大丈夫。<br />\nopenVINOをBuildしたDockerコンテナで引き続き作業を行う</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk-3-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libjpeg-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libpng-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev:arm64\n</code></pre></div></div>\n<h2 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n</code></pre></div></div>\n<h2 id=\"cmakeの実行\">cmakeの実行</h2>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PKG_CONFIG_LIBDIR</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_ENABLE_PKG_CONFIG</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_FIND_ROOT_PATH</span><span class=\"o\">=</span>/ <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span>/work/opencv/platforms/linux/aarch64-gnu.toolchain.cmake <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_NUMPY_INCLUDE_DIRS</span><span class=\"o\">=</span>/usr/lib/python3/dist-packages/numpy/core/include <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n       .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあらかじめ環境変数<code class=\"language-plaintext highlighter-rouge\">PKG_CONFIG_LIBDIR</code>を設定して<code class=\"language-plaintext highlighter-rouge\">pkg-config</code>でaarch64のライブラリとNativeのツール類を参照するように設定しておく。<br />\nこれをやらないと、libjpegとかをインストールしてあることを検出できない</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeのオプションに <code class=\"language-plaintext highlighter-rouge\">-D CMAKE_FIND_DEBUG_MODE=1</code>を追加すると\ncmake中の<code class=\"language-plaintext highlighter-rouge\">find_xxx</code>の動作のログが出力されるので、パッケージのサーチなどの検索パスの確認などが容易になる。</p>\n</blockquote>\n\n<h2 id=\"make-1\">make</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install-1\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino/opencv</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/opencv</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-D CMAKE_INSTALL_PREFIX=/work/opt/intel/openvino/opencv</code>の部分を変更すれば良いけど、ここはopenVINOのインストール先と合わせておかないとうまく動かない。</p>\n\n<h1 id=\"実機へのインストール\">実機へのインストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">opt</code>ディレクトリ以下を丸ごとアーカイブする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<p>作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>をRaspberryPiの適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"コンテナから出る\">コンテナから出る</h1>\n<p>Dockerコンテナは作業終了したら終了しておく。<br />\nCTRL-D でshell終了</p>\n\n<h1 id=\"補足\">補足</h1>\n<p>コンテナにインストールされているパッケージは以下の通り。<br />\nバージョン違いで動かなくなることもあるかもしれんので、念のため。</p>\n\n<p>こんな感じで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span> | <span class=\"nb\">grep</span> <span class=\"nt\">-v</span> automatic\n</code></pre></div></div>\n\n<p>で、こんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>build-essential/stable,now 12.9 amd64 [installed]\ncmake/stable,now 3.18.4-2+deb11u1 amd64 [installed]\ncrossbuild-essential-arm64/stable,stable,now 12.9 all [installed]\ncython3/stable,now 0.29.21-3+b1 amd64 [installed]\ngit/stable,now 1:2.30.2-1 amd64 [installed]\nlibavcodec-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibavformat-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibgstreamer-plugins-base1.0-dev/stable,now 1.18.4-2 arm64 [installed]\nlibgstreamer1.0-dev/stable,now 1.18.4-2.1 arm64 [installed]\nlibgtk-3-dev/stable,now 3.24.24-4 arm64 [installed]\nlibjpeg-dev/stable,now 1:2.0.6-4 arm64 [installed]\nlibpng-dev/stable,now 1.6.37-3 arm64 [installed]\nlibprotobuf-dev/stable,now 3.12.4-1 arm64 [installed]\nlibprotoc-dev/stable,now 3.12.4-1 arm64 [installed]\nlibpython3-dev/stable,now 3.9.2-3 arm64 [installed]\nlibswscale-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibtiff-dev/stable,now 4.2.0-1 arm64 [installed]\nlibusb-1.0-0-dev/stable,now 2:1.0.24-3 arm64 [installed]\nlibwebp-dev/stable,now 0.6.1-2.1 arm64 [installed]\nprotobuf-compiler/stable,now 3.12.4-1 amd64 [installed]\npython3-minimal/stable,now 3.9.2-3 amd64 [installed]\npython3-numpy/stable,now 1:1.19.5-1 amd64 [installed]\npython3-pip/stable,stable,now 20.3.4-4 all [installed]\nscons/stable,stable,now 4.0.1+dfsg-2 all [installed]\nwget/stable,now 1.21-1+deb11u1 amd64 [installed]\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>aspberry Pi OS(64bit)がリリースされたが、openVINOのBuild済みモジュールはまだこれに対応していない。<br />\nそのうち対応されると思うけど、とりあえず自前でBuildする方法を調べてみた。<br />\nついでにCPU Extensionも作成しておく。<br />\nなお、Raspberry Pi OS(32bit Buster)向けのBuild手順については、\n『<a href=\"/memoBlog/2021/10/28/openVINO_build.html\" target=\"_blank\">openVINO(Raspberry Pi向け)のbuild</a>』を参照。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<p>今回もARM版Dockerコンテナを使用してセルフコンパイルする方法で行う。<br />\n手順そのものは特殊なことはないので、Raspberry Pi上のNative環境でもBuildできそうだけど、\nディスク容量とかスワップ領域とか気にしないといけないかもしれないので試してない。<br />\n(今回はクロスコンパイル環境はなし。cythonの出力モジュールも使いたかったので)</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_emu\n</code></pre></div></div>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h2 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h2>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n32bit版との差分はこんな感じ。<br />\nあれ?32bit版の<code class=\"language-plaintext highlighter-rouge\">python-minimal</code>って間違ってる?<br />\n<code class=\"language-plaintext highlighter-rouge\">python3-numpy</code>で依存モジュールとしてインストールされて事なきを得たのか?<br />\n実質、ベースイメージを変更してるだけだな。</p>\n\n  <div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- Dockerfile.old\t2022-03-01 07:26:28.774187231 +0900\n</span><span class=\"gi\">+++ Dockerfile\t2022-03-01 07:19:45.668393598 +0900\n</span><span class=\"p\">@@ -1,4 +1,4 @@</span>\n<span class=\"gd\">-FROM arm32v7/debian:buster\n</span><span class=\"gi\">+FROM arm64v8/debian:bullseye\n</span> \n USER root\n \n<span class=\"p\">@@ -18,7 +18,7 @@</span>\n     libprotobuf-dev libprotoc-dev protobuf-compiler \\\n     cmake \\\n     python3-pip \\\n<span class=\"gd\">-    python-minimal \\\n</span><span class=\"gi\">+    python3-minimal \\\n</span>     python3-numpy cython3 scons\n \n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_emu_1 ov_pi64_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<p>数時間レベルでかかるので、のんびり待ちましょう。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"その他細々したところ\">その他細々したところ</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コメント\">コメント</h3>\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール\">実機へのインストール</h2>\n\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>を適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>ついでにopenCVのBuild方法についてもメモっておく。</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>openCVのリポジトリをcloneしておく。<br />\n指定するタグは適宜変更してください。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n<p>新しいDockerコンテナ作っても良いけど、別にその必要もないので上記のコンテナをそのまま使用する。</p>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n  <h2 id=\"本番-1\">本番</h2>\n</blockquote>\n\n<h3 id=\"準備-2\">準備</h3>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk2.0-dev  libjpeg-dev libpng-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev\n</code></pre></div></div>\n\n<h3 id=\"build\">Build</h3>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n\n<span class=\"c\"># インストール</span>\nmake <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf opencv.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コンテナから出る-1\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール-1\">実機へのインストール</h2>\n<p>openVINOをBuildしたコンテナで続けてBuildした場合は<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>にopenVINO、openCVがインストールされている。<br />\nこれを適当なディレクトリに展開して環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば良い。</p>\n\n<p>別のコンテナを使用したり、openVINOのBuild結果を削除していた場合は、<br />\n最終的に作成した<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>をopenVINOをインストールしたディレクトリに展開する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール</h1>\n      <p>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロード\">ダウンロード</h1>\n\n<p><a href=\"https://www.raspberrypi.com/software/operating-systems/\" target=\"_blank\">Raspberry Pi OS</a>ページの <br />\n「Manually install an operating system image」の「See all download options」をクリック、<br />\n「Raspberry Pi OS (64-bit)」の「Raspberry Pi OS with desktop」の「Download」をクリックしてダウンロード<br />\n試したのは Release date: January 28th 2022</p>\n\n<blockquote>\n  <p>[!NOTE]\n「Archive」リンクから過去のリリースも入手できる</p>\n</blockquote>\n\n<p>なんか見るたびにページ構成変わるよなぁ….😩💨</p>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nシリアルコンソールの送信改行コードはCRにしておくこと。<br />\nそうしないと、ビミョーに悲しいことが起こる場合がある。</p>\n\n</blockquote>\n\n<h2 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h2>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>の  最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group</code>と<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>については使用するモニタに合わせる。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group=2</code>はモニタ種別でDMT(一般的にモニタディスプレイ)、<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_mode=82</code>が 1920x1080 60Hz(1080p)を示している。<br />\n設定値の内容については、<a href=\"https://www.raspberrypi.com/documentation/computers/config_txt.html#hdmi-mode\" target=\"_blank\">HDMI Mode</a>を参照。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>はテキストモードで表示したいサイズに合わせる。1920と1080とか、1280と720とか。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># display resolution force setting</span>\n<span class=\"nv\">hdmi_group</span><span class=\"o\">=</span>2\n<span class=\"nv\">hdmi_mode</span><span class=\"o\">=</span>82\n<span class=\"nv\">framebuffer_width</span><span class=\"o\">=</span>1920\n<span class=\"nv\">framebuffer_height</span><span class=\"o\">=</span>1080\n<span class=\"nv\">hdmi_force_hotplug</span><span class=\"o\">=</span>1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nHDMIディスプレイを常に接続しているなら設定しなくても問題ないが、\nHDMIディスプレイをはずしてVNCでリモート接続だけする場合は設定しておかないと\n解像度が1024x768までしか設定できなくなるので注意。</p>\n</blockquote>\n\n<h3 id=\"vncが遅い問題対応\">VNCが遅い問題対応</h3>\n<p>このバージョンではHDMIディスプレイを繋いでいない状態でVNCで接続すると表示がとても遅くなる問題がある。<br />\n回避するには、<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code>に以下追記する。<br />\n<code class=\"language-plaintext highlighter-rouge\">1920x1080@60D</code>の部分は上記の<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>や<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>の設定値に合わせる。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>video=HDMI-A-1:1920x1080@60D\n</code></pre></div></div>\n\n<p>具体的にはこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>console=serial0,115200 console=tty1 root=PARTUUID=b635b4ec-02 rootfstype=ext4 fsck.repair=yes video=HDMI-A-1:1920x1080@60D rootwait\n</code></pre></div></div>\n\n<p>参考URL:<a href=\"https://forums.raspberrypi.com/viewtopic.php?p=1935714#p1935711\">Re: Bullseye vncserver is very slow without display</a></p>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。<br />\nSSID名は ダブルクォーテーションで囲む。<br />\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://qiita.com/mt08/items/2da1cce534dfdc84f5e3#%E7%92%B0%E5%A2%83\" target=\"_blank\">[メモ] (らずぱい)Windows上から固定IP設定 (Raspberry Pi Static IP)</a>\nにWindows版の<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase.exe</code>へのリンクがある。<br />\nワタシはUbuntuや別のRasberryPiで作ったから使ってないけど…</p>\n</blockquote>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase \"SSID名\" \"暗号化キー\"\n        ↓ 実行結果\nnetwork={\n        ssid=\"SSID名\"\n        #psk=\"暗号化キー\"\n        psk=ほにゃらら~~~ほにゃらら~~~\n}\n</code></pre></div></div>\n\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。<br />\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<blockquote>\n  <p>[!NOTE]\n起動後、公開鍵ファイルの設置を行うには、<br />\n<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">ubuntuにSSHサーバをセットアップする</a> <br />\nの「秘密鍵と公開鍵の生成と公開鍵ファイルの設置」の部分を参照。<br />\n(ページはUbuntuについて書いてあるけど、サーバがセットアップ済みなことを除けばRaspberry Pi OSでも同じ)</p>\n</blockquote>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># アップデート実行\nsudo apt update\nsudo apt upgrade\n# リブート\nsudo reboot\n</code></pre></div></div>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S7 Splash Screen\n            Would you like to show the splash screen at boot?\n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこの操作で/boot/cmdline.txtが書き換えられるらしい。</p>\n\n</blockquote>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# 新ユーザのパスワード変更する\npasswd\n《パスワードを設定》\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\" target=\"_blank\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n            B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/4f39afbcd8471426421944b597f3a5f2963984c6/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nresize.pyは以前python2ベースで作ってあったが、<br />\nこのバージョンからpython2がデフォルトでインストールされなくなったので、<br />\npython3ベースに修正したのでURLが変更されています。</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n\n<p>物理キーボード接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]<br />\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n\n</blockquote>\n\n<h1 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h1>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n\n<p>まずはワークディレクトリの作成</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo service smbd reload\nsudo service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo vi /etc/hostname\nsudo vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>s``udo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    3 Interfacing Options\n        I3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>\n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n\n<p>Windows側のクライアントは、<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a>\nから VNC Viewerをダウンロード。\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。\n日本語化の手順はこちらを参考に。 <a href=\"http://xn--u9j0md1592aqmt715c.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>SDカードイメージのバックアップを取るならこちら。<br />\n<a href=\"/memoBlog/2021/07/18/sd_image_2.html\" target=\"_blank\">Raspbian SDカードイメージファイルの作成(改訂版)</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Bluetooth classic でシリアル通信(SPP)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Bluetooth classic でシリアル通信(SPP)</h1>\n      <p>ESP32 Bluetooth classic(SPP)を使用してシリアル通信するデモプログラム</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>シリアル通信でデータを送受信したいけど、有線接続はできない場合にBluetooth classicのSPP(Serial Port Profile )を使用して\nCOMポートとして接続する方法のデモ。<br />\nesp-idfのサンプルプログラムが私にとっては複雑怪奇だったので、ちょっとシンプルにしてみた。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは</p>\n<ul>\n  <li>VFS版: <a href=\"https://github.com/ippei8jp/BT_SPP_VFS\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_VFS</a></li>\n  <li>Callback版: <a href=\"https://github.com/ippei8jp/BT_SPP_CB\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_CB</a></li>\n</ul>\n\n<p>にあるのでcloneしてください。</p>\n\n<p>このプログラムではPC等のCOMポートへ/から接続して送信したデータをエコーバックするだけのデモプログラムです。<br />\nそれぞれのイベント発生時に発生イベントとパラメータを表示するようにしてあるので、動作の理解の一助になります…\nなったらいいな…でも期待はするな….</p>\n\n<p>上記2つのリポジトリはファイル構成を合わせてあるので、diffをとるとVFSとCallbackでどのような違いがあるのか分かりやすい<br />\n… かもね…</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<ul>\n  <li>VFS版: <a href=\"https://github.com/ippei8jp/BT_SPP_VFS#readme\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_VFS#readme</a></li>\n  <li>Callback版: <a href=\"https://github.com/ippei8jp/BT_SPP_CB#readme\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_CB#readme</a></li>\n</ul>\n\n<p>を参照してください。</p>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ <br />\n最近こればっかりや…</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>エコーバックタスクをコマンドシェルタスクなどに入れ替えるとすぐ使える…とも思えんけど…<br />\n踏み台くらいにはなるでしょう。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>BLEでアプリケーションパラメータ設定</title>\n  </head>\n  <body>\n    <header>\n      <h1>BLEでアプリケーションパラメータ設定</h1>\n      <p>ESP32 BLEを使用してアプリケーションパラメータの設定を変更する処理の雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>アプリケーションを作成したとき、マシン名のように端末毎に変更を変更したり、\nサーバ名のように設置条件によって変更したいパラメータってありますよね。<br />\nいつもは起動時に設定モードに入ったり、動作中に簡易シェルを動かしてコンソール(UART)から設定していましたが、<br />\n実装面積などの関係でUARTが接続できなかったりした場合、それ以外の方法としてBLEで設定する方法を考えました。<br />\n(ESP32の場合、Flash書き換えでUART使うので繋がない訳にはいかないのですが…)</p>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nを参考にカスタムプロファイルでアプリケーションパラメータをread/writeできるようにしてみました。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは<a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a><br />\nにあるのでcloneしてください。</p>\n\n<p>このプログラムではアプリケーションはWi-Fiに接続するだけの処理です。<br />\nうまくパラメータが設定できて、nvsに保存しておけば、2回目以降はBLEによる設定なしにWi-Fiに接続することができます。<br />\n接続できれば、外部マシンからpingを打って応答があることが確認できます。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a> のREADME.mdを参照してください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nパラメータの設定はRaspberryPiのpythonから行っていますが、その気になればAndroidのBLE接続確認ツールなどからでも設定できます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n設定パラメータにループインターバルがありますが、プログラム中では参照していません。<br />\n数値を設定する例として入れてあります。</p>\n</blockquote>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>設定したいパラメータが増えてたら、Characteristicを増やしていけばいくらでも対応できるハズ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>pythonでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に pythonスクリプトでアクセスしてみる方法についてのメモ。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<p>pythonスクリプトはRaspberryPiで動作している(実際に試したのはPi4だが、Pi3/Pi0wでも同様)。<br />\nubuntu-PCでも同様にできるはずだが、うちのマシンは内蔵Bluetoothのバージョンが古くてBLE非対応だったので試してない。<br />\nwindows-PCはよくわからん…</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/test1\n<span class=\"nb\">cd</span> /work/ble/test1\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.9.10 bluepy\npyenv <span class=\"nb\">local </span>bluepy\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>bluepy\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/9bbdfa53526411967975097cfbcc66e6.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>ESP32側はAdvertising 開始状態にしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>python ble_hr.py\n</code></pre></div></div>\n<p>デバイスのスキャンを行うので<code class=\"language-plaintext highlighter-rouge\">sudo</code>が必要。</p>\n<blockquote>\n  <p>[!NOTE]\nもし、scanせずにアドレスを指定して実行するだけの処理に書き換えれば<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要になる。</p>\n</blockquote>\n\n<h1 id=\"説明\">説明</h1>\n\n<h2 id=\"ble_hr_delegateクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR_Delegate</code>クラス</h2>\n<p>Notifyを受け取っての処理は<code class=\"language-plaintext highlighter-rouge\">bluepy.btle.DefaultDelegate</code>クラスを継承したクラスを作成して登録する必要がある。<br />\n処理自体は<code class=\"language-plaintext highlighter-rouge\">handleNotification</code>メソッドをオーバーライドして定義する。<br />\n受け取るデータ<code class=\"language-plaintext highlighter-rouge\">data</code>はbytes型なので、数値として使用する場合は<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換してやる必要があるが、<br />\nこの時のエンディアンは接続しているデバイスのFW仕様によるので、どちらを使うかはあらかじめ確認しておく必要がある。<br />\n(大抵はFWを動かしているCPUのエンディアンなのかな?)</p>\n\n<h2 id=\"ble_hrクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR</code>クラス</h2>\n<p>peripheralを操作するための処理をクラス化してある。<br />\nクラス化は必須ではないけど、処理をまとめておいた方が分かりやすいかな?と思ったので。</p>\n\n<p>コンストラクタ、接続、Characteristicのリード/ライト、Notifyの有効化/無効化/ポーリング、切断などの処理がある。</p>\n\n<h2 id=\"main関数\"><code class=\"language-plaintext highlighter-rouge\">main</code>関数</h2>\n<p>メイン処理。<br />\n処理の流れはこんな感じ。</p>\n<ul>\n  <li>デバイスのスキャン</li>\n  <li>スキャン結果から指定されたUUIDを持つデバイスを探す\n    <ul>\n      <li>UUIDやデバイス名が必ずしも同じところにあるとは限らないので色々読んでみる必要がある</li>\n    </ul>\n  </li>\n  <li>複数のデバイスを同時に操作することも可能だが、今回は最初の1個だけを決め打ちで使う</li>\n  <li>接続</li>\n  <li>Characteristicのリード\n    <ul>\n      <li>ここもリード結果はbytes型なので、<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換する</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト\n    <ul>\n      <li>ライトデータはbytes型に変換する必要があるが、この処理は、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.write()</code>で変換しているのでここではそのまま。</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト結果の確認\n    <ul>\n      <li>ライトできたか確認するために、再度リードしている</li>\n    </ul>\n  </li>\n  <li>Notifyの有効化</li>\n  <li>Notifyが通知されることを確認するために少し待つ\n    <ul>\n      <li>Notifyを待つ間、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.waitForNotifications()</code>(<code class=\"language-plaintext highlighter-rouge\">Peripheral.waitForNotifications()</code>のラッパ)をコールし続ける必要がある。<br />\nこれをコールしないとNotifyを受信できない(キューイングされるがコールバックは実行されない)。</li>\n    </ul>\n  </li>\n  <li>Notifyの無効化\n    <ul>\n      <li>Notifyが入らないことを確認するためにちょっと待つ</li>\n    </ul>\n  </li>\n  <li>切断</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry PiでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry PiでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に Raspberry Pi からアクセスしてみる方法についてのメモ。</p>\n\n<p>Androidでアクセスすると、色々とブラックボックスで処理されてどうなってるのか分かり難いので理解を深める意味で試してみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"メモ\">メモ</h1>\n\n<p>ここにあるように、BLEでは「ボンディング(参照先ではペアリングと表記)なし」で実行するのが無難と思われる<br />\n<a href=\"https://www.musen-connect.co.jp/blog/course/trial-production/ble-beginner-8/\" target=\"_blank\">【サルでもわかるBLE入門】(8) ペアリング</a></p>\n\n<p>Wiresharkによるパケットキャプチャの解説(たぶん、そんなレイヤでデバッグすることはないと思うけど)<br />\n<a href=\"https://re-engines.com/2021/08/16/ble-secure/\" target=\"_blank\">BLEのペアリングをWiresharkでキャプチャしながら学ぶ</a></p>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<h1 id=\"ペリフェラル機器をスキャン\">ペリフェラル機器をスキャン</h1>\n\n<p>まずは接続可能デバイスをスキャンしないと始まらないので、スキャンする。<br />\nもちろん、ESP32側はAdvertising 開始状態である必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo timeout </span>5s hcitool lescan        ← 5秒間スキャンしてみる\nLE Scan ...\n48:BA:7E:24:D0:AA <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n50:17:FC:8C:D1:87 ESP_BLE_HR            ←見つかった\nE4:9A:9F:40:AD:09 <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\nC4:49:BB:8A:7F:6C EX-ZR1800-8A7F6B\nC4:49:BB:8A:7F:6C <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hcitool lescan</code>の実行には<code class=\"language-plaintext highlighter-rouge\">sudo</code>必須。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout 5s</code> を付けずにCTRL+Cで停止しても良い。</p>\n\n<h1 id=\"対象デバイスにアクセスしてみる\">対象デバイスにアクセスしてみる</h1>\n\n<blockquote>\n  <p>[!NOTE]\n<strong>UUIDについて</strong></p>\n\n  <p>16bit UUIDは以下のXXXXの部分(それ以外の部分が一致しないものは128bit UUID)<br />\n<code class=\"language-plaintext highlighter-rouge\">0000XXXX-0000-1000-8000-00805f9b34fb</code></p>\n\n  <p>16bit UUIDは 以下のページを参照<br />\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a></p>\n</blockquote>\n\n<h2 id=\"コマンド起動と接続\">コマンド起動と接続</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">gatttool</code>の実行に<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要。<br />\n<code class=\"language-plaintext highlighter-rouge\">«アドレス»</code> には上でみつけたアドレスを指定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>gatttool <span class=\"nt\">-t</span> random <span class=\"nt\">-I</span> <span class=\"nt\">-b</span> «アドレス»             ← ツールの実行   以下、インタラクティブモードに入る\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> connect                  ← 接続 \nAttempting to connect to 50:17:FC:8C:D1:87\nConnection successful                             ← 接続成功  \n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"サービス一覧を取得\">サービス一覧を取得</h2>\n\n<p>サービスの一覧を取得してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> primary\nattr handle: 0x0001, end grp handle: 0x0005 uuid: 00001801-0000-1000-8000-00805f9b34fb\nattr handle: 0x0014, end grp handle: 0x001c uuid: 00001800-0000-1000-8000-00805f9b34fb\nattr handle: 0x0028, end grp handle: 0xffff uuid: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<p>それぞれこんな意味</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>UUID</th>\n      <th>種別</th>\n      <th>ハンドル範囲</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>1801</td>\n      <td>Generic Attribute</td>\n      <td>0x0001 ~ 0x0005</td>\n    </tr>\n    <tr>\n      <td>1800</td>\n      <td>Generic Acces</td>\n      <td>0x0014 ~ 0x001c</td>\n    </tr>\n    <tr>\n      <td>180d</td>\n      <td>Heart Rate</td>\n      <td>0x0028 ~ 0xffff</td>\n    </tr>\n  </tbody>\n</table>\n\n<h2 id=\"generic-accesを調べてみる\">Generic Accesを調べてみる</h2>\n\n<p>上で調べたGeneric Acces のハンドル範囲を指定して実行。<br />\n表示されるUUIDを\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a>\nで探して右側にメモっておいた。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x14 0x1c\nhandle: 0x0014, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0015, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb        ← device name\nhandle: 0x0017, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb        ← Appearance\nhandle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb        ← Central Address Resolution\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"device-name-を読んでみる\">device name を読んでみる</h2>\n\n<p>とりあえず devece nameを読んでみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x016                       ← handle 0x16<span class=\"o\">(</span>device name<span class=\"o\">)</span> のリード\nCharacteristic value/descriptor: 45 53 50 5f 42 4c 45 5f 48 52     ← 結果\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<p>このままだとなんだかわからん…<br />\n別ウィンドゥで以下を実行。<br />\nただし、<code class=\"language-plaintext highlighter-rouge\">nkf</code>はデフォルトでインストールされていないので<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールする。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">echo</code>の中身には上でリードした結果をコピペする。<br />\nこれを<code class=\"language-plaintext highlighter-rouge\">xxd</code>コマンドでバイナリに変換、<br />\n<code class=\"language-plaintext highlighter-rouge\">nkf</code>で文字コード変換を行う(これだとUTF-8→UTF-8なのであんまり意味ない気が…)。<br />\n結果は改行されずに、プロンプトが続けて表示されるので注意。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">echo</span> <span class=\"s2\">\"45 53 50 5f 42 4c 45 5f 48 52\"</span>  | xxd <span class=\"nt\">-p</span> <span class=\"nt\">-r</span>  | nkf <span class=\"nt\">-WwmQ</span>\nESP_BLE_HR        ← おぉ、読めてる\n<span class=\"nv\">$ </span>\n</code></pre></div></div>\n\n<h2 id=\"heart-rateサービスを調べてみる\">Heart Rateサービスを調べてみる</h2>\n<p>同様にHeart Rateサービスについて調べてみる。<br />\nUUIDについてのメモも同様。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x0028 0xffff\nhandle: 0x0028, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0029, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002a, uuid: 00002a37-0000-1000-8000-00805f9b34fb        ← Heart Rate Measurement\nhandle: 0x002b, uuid: 00002902-0000-1000-8000-00805f9b34fb        ← Client Characteristic Configuration\nhandle: 0x002c, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002d, uuid: 00002a38-0000-1000-8000-00805f9b34fb        ← Body Sensor Location\nhandle: 0x002e, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002f, uuid: 00002a39-0000-1000-8000-00805f9b34fb        ← Heart Rate Control Point\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"heart-rate-control-point-を読み書きしてみる\">Heart Rate Control Point を読み書きしてみる</h2>\n\n<p>Characteristicの読み書きを試すため、Heart Rate Control Point(ハンドル0x2f;c<code class=\"language-plaintext highlighter-rouge\">har-desc</code>の結果から取得)にアクセスしてみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 読んでみる\nCharacteristic value/descriptor: 00                   ← 読めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 01       ← 書いてみる\nCharacteristic value was written successfully         ← 書けた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 確認してみる\nCharacteristic value/descriptor: 01                   ← 書けてる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 0x02     ← 書き込み値に0xを付けたらエラーになる\nError: Characteristic Write Request failed: Attribute value length is invalid\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<h2 id=\"notificationを有効にしてみる\">Notificationを有効にしてみる</h2>\n\n<p>NotificationをONにするにはCCCを操作する。<br />\nNotificationで受信したデータは自動で表示される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 00 00                ← Notification OFFになってる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0100     ← Notification ON にしてみる<span class=\"o\">(</span>0100を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\nNotification handle <span class=\"o\">=</span> 0x002a value: 50 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 51 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 52 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 01 00                ← Notification ONになってる\nNotification handle <span class=\"o\">=</span> 0x002a value: 53 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 54 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 55 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 56 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 57 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0000     ← Notification OFF にしてみる<span class=\"o\">(</span>0000を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>                              ← 以降、Notificationは停止\n</code></pre></div></div>\n\n<h2 id=\"書き込み禁止のcharacteristicに書き込んでみる\">書き込み禁止のCharacteristicに書き込んでみる</h2>\n\n<p>書き込み禁止のCharacteristicに書き込んでみるとどうなるか試してみる。<br />\n当然エラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>50:17:FC:8C:D1:87][LE]> char-write-req 0x2d 01         ← Body Sensor Locationに書き込んでみる\nError: Characteristic Write Request failed: Attribute can<span class=\"s1\">'t be written   ← エラーになった\n</span></code></pre></div></div>\n\n<h2 id=\"切断する\">切断する</h2>\n\n<p>操作が終わったら切断する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> disconnect                        ← 切断\n<span class=\"o\">(</span>gatttool:1840<span class=\"o\">)</span>: GLib-WARNING <span class=\"k\">**</span>: 12:55:27.500: Invalid file descriptor.   ← なんか言われるけど無視して良い\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> <span class=\"nb\">exit</span>                              ← インタラクティブモードの終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る\n</code></pre></div></div>\n\n<h1 id=\"bluetoothctlでアクセス参考\">bluetoothctlでアクセス(参考)</h1>\n\n<p>「ボンディングする」設定の場合、bluetoothctlでアクセスする必要がある。<br />\nボンディングしない設定で使う分には関係ないが、せっかく調べたのでメモっておく。</p>\n\n<p>ボンディング前後でアドレス違ったりしてイマイチ使いにくい。<br />\nどうしても「ボンディングする」にしなければならない場合は、自身のアドレスをパブリックアドレスにしておけばちょっとマシかも。</p>\n\n<h2 id=\"メモ-1\">メモ</h2>\n\n<p>bluetoothctlのコマンド <br />\n<a href=\"https://qiita.com/noraworld/items/55c0cb1eb52cf8dccc12\" target=\"_blank\">bluetoothctl のコマンド一覧と使い方をまとめてみた</a></p>\n\n<p>bluetoothctlだとGATTへのアクセスができないっぽいので、ボンディングの登録/解除以外は使えないっぽいな…</p>\n\n<h2 id=\"前提-1\">前提</h2>\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス           (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングする                           (ESP_LE_AUTH_REQ_SC_MITM_BOND)</li>\n  <li>IO capabilityはcapabilityはDisplayYesNo    (ESP_IO_CAP_IO)</li>\n</ul>\n\n<h2 id=\"起動\">起動</h2>\n\n<p>ツールの起動。<br />\n<code class=\"language-plaintext highlighter-rouge\">sudo</code>必要<br />\n以下インタラクティブモードで操作。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo </span>bluetoothctl                                        ← 起動\n</code></pre></div></div>\n\n<h2 id=\"スキャン\">スキャン</h2>\n\n<p>接続可能デバイスを見つけるためにスキャンする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# scan on                                       ← スキャン開始\nDiscovery started\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>NEW] Device 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\n<span class=\"o\">[</span>NEW] Device 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\n<span class=\"o\">[</span>NEW] Device 62:D1:88:DD:4F:7C リビングルーム\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E RSSI: <span class=\"nt\">-38</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower: 3\n・・・\n<span class=\"o\">[</span>bluetooth]# scan off                                      ← スキャン停止\nDiscovery stopped\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: no\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower is nil\n・・・\n<span class=\"o\">[</span>bluetooth]# devices                                       ← 接続可能デバイスの表示\nDevice 5A:E1:9A:05:96:E0 ESP_BLE_HR                        ← これがESP32<span class=\"o\">(</span>ランダムアドレスなので起動の度に変化する<span class=\"o\">)</span>\nDevice 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\nDevice 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\nDevice 62:D1:88:DD:4F:7C リビングルーム\n\n</code></pre></div></div>\n\n<h2 id=\"agentの登録\">agentの登録</h2>\n\n<p>ボンディングのために、agentを登録する(数字を入力したり、Yes/Noを選択したりするやつ)。<br />\nこちらの設定と相手側の設定の組み合わせで最終的にどの方法が使われるか決定される。<br />\nたとえば、こちら側を NoInputNoOutput に設定しておけば、相手側が DisplayYesNo であってもYes/Noの入力は求められない。<br />\n逆の設定でも同様。</p>\n\n<p>登録された状態で他のCapabilityで登録しようとしても「既に登録済み」と言われるので、念のため一旦登録解除してから登録しておく。<br />\nこのあたり、情報少なくてイマイチよく分からない…</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# agent off                                    ← 一旦agentの登録解除\nAgent unregistered                                         ← 解除された\n<span class=\"o\">[</span>ESP_BLE_HR]# agent DisplayYesNo                           ← DisplayYesNoで登録\nAgent registered                                           ← 登録された\n</code></pre></div></div>\n\n<h2 id=\"接続\">接続</h2>\n\n<p>接続する。<code class=\"language-plaintext highlighter-rouge\">connect</code>でなく、<code class=\"language-plaintext highlighter-rouge\">pair</code>で実行。<br />\n<code class=\"language-plaintext highlighter-rouge\">connect</code>による接続は後述。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# pair 5A:E1:9A:05:96:E0                       ← 接続\nAttempting to pair with 5A:E1:9A:05:96:E0\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 Connected: <span class=\"nb\">yes\n</span>Request confirmation\n<span class=\"o\">[</span>agent] Confirm passkey 680456 <span class=\"o\">(</span><span class=\"nb\">yes</span>/no<span class=\"o\">)</span>:                   ← agentがYes/Noを聞いてくる\n<span class=\"o\">[</span>NEW] Primary Service                                      ← これが自動的に表示されて上の質問を見失うので注意!!\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001\n        00001801-0000-1000-8000-00805f9b34fb\n        Generic Attribute Profile\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001/char0002\n        00002a05-0000-1000-8000-00805f9b34fb\n        Service Changed\n・・・\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0028/char002e\n        00002a39-0000-1000-8000-00805f9b34fb\n        Heart Rate Control Point\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001800-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001801-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 ServicesResolved: <span class=\"nb\">yes\nyes</span>                                                         ← yesを入力<span class=\"o\">(</span>同時に相手側でもyes入力<span class=\"o\">)</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Address: 94:B9:7E:65:AF:5E\nPairing successful                                         ← 接続された\n<span class=\"o\">[</span>ESP_BLE_HR]# paired-devices                               ← ボンディング結果を確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR                        ← advertisingがランダムアドレスでもパブリックアドレスで登録されるので注意!!\n<span class=\"o\">[</span>ESP_BLE_HR]#                                                以降、接続はこのアドレスを使用する!!\n</code></pre></div></div>\n\n<h2 id=\"切断\">切断</h2>\n\n<p>切断する。<br />\nCharacteristicアクセスできないので、実質ボンディングするのみ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断する\nAttempting to disconnect from 94:B9:7E:65:AF:5E            ← パブリックアドレスが表示されている\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<h2 id=\"再接続\">再接続</h2>\n\n<p>ボンディング済みのデバイスに再接続する場合の手順。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスの表示\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# connect 94:B9:7E:65:AF:5E                     ← 表示されたアドレスで接続\nAttempting to connect to 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: <span class=\"nb\">yes\n</span>Connection successful                                      ← 接続された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断\nAttempting to disconnect from 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<p>ボンディングしてない機器に対して<code class=\"language-plaintext highlighter-rouge\">connect</code>すると、<code class=\"language-plaintext highlighter-rouge\">agent off</code> で <code class=\"language-plaintext highlighter-rouge\">pair</code> したような動作になる模様。</p>\n\n<h2 id=\"ボンディング解除\">ボンディング解除</h2>\n\n<p>ボンディング済みデバイスを登録削除する。<br />\nESP32側も忘れず登録削除しておくこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスを確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# remove 94:B9:7E:65:AF:5E                      ← ボンディング解除\n<span class=\"o\">[</span>DEL] Descriptor                                           ← なんか ずらずらっと削除されたと出る\n        /org/bluez/hci0/dev_5F_76_EF_D2_45_E7/service0001/char0002/desc0004\n        00002902-0000-1000-8000-00805f9b34fb\n        Client Characteristic Configuration\n・・・\nDevice has been removed                                    ← 削除された\n<span class=\"o\">[</span>bluetooth]# paired-devices                                ← 確認\n<span class=\"o\">[</span>bluetooth]#                                               ← 削除されてる\n</code></pre></div></div>\n\n<h2 id=\"ツールの終了\">ツールの終了</h2>\n\n<p>ツールを終了してShellに戻る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# <span class=\"nb\">exit</span>                                          ← またはquitまたはCTRL+Dで終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る \n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でBLEのデモを動かす 補足</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でBLEのデモを動かす 補足</h1>\n      <p>ESP32にBLEのデモの認証方法についての補足</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a>\nでは認証方法(IO capability なので入出能力と言うべきか? あまり直感的でないのでここでは認証方法と呼んでおこう)<br />\nを<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_NONE</code>(NoInputNoOutput; 入出力なし)に設定していたが、これを別の認証方法に変更する場合についてのメモ。</p>\n<blockquote>\n  <p>[!NOTE]\n自作の範囲だと<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_NONE</code>しか使わないと思うけど、使いたくなった時に備えて。</p>\n</blockquote>\n\n<h1 id=\"esp_io_cap_none-noinputnooutput\">ESP_IO_CAP_NONE (NoInputNoOutput)</h1>\n<p>入出力両方なし。<br />\npasskey(PINcode)入力などはなし。<br />\n接続すると自動的に鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (92315) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (92315) BLE_HEART_RATE:     connection start\nV (92975) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (92975) BLE_HEART_RATE:     event nor handled\nV (93245) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (93245) BLE_HEART_RATE:     event nor handled\nE (97855) BT_BTM: btm_ble_remove_resolving_list_entry_complete remove resolving list error 0x2\nV (98285) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (98285) BLE_HEART_RATE:     event nor handled\nW (98335) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (98375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98375) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (98375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98375) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (98385) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98385) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (98405) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98405) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (98405) nvs: nvs_open_from_partition bt_config.conf 1\nD (98415) nvs: nvs_set_blob bt_cfg_key0 475\nD (98425) nvs: nvs_close 4\nD (98425) nvs: nvs_open_from_partition bt_config.conf 1\nD (98425) nvs: nvs_set_blob bt_cfg_key0 475\nD (98485) nvs: nvs_close 5\nD (98485) nvs: nvs_open_from_partition bt_config.conf 1\nD (98485) nvs: nvs_set_blob bt_cfg_key0 475\nD (98495) nvs: nvs_close 6\nD (98495) nvs: nvs_open_from_partition bt_config.conf 1\nD (98495) nvs: nvs_set_blob bt_cfg_key0 475\nD (98515) nvs: nvs_close 7\nD (98515) nvs: nvs_open_from_partition bt_config.conf 1\nD (98515) nvs: nvs_set_blob bt_cfg_key0 475\nD (98515) nvs: nvs_close 8\nV (98515) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (98525) BLE_HEART_RATE:     remote BD_ADDR: 5d5308bb0efd\nI (98525) BLE_HEART_RATE:     address type = 1\nI (98535) BLE_HEART_RATE:     pair status = success\nI (98535) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_BOND\nI (98545) BLE_HEART_RATE:     Bonded devices number : 1\nI (98545) BLE_HEART_RATE:     Bonded devices list :\nI (98555) BLE_HEART_RATE:        0 :   5d:53:08:bb:0e:fd\nV (99025) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99025) BLE_HEART_RATE:     event nor handled\nV (99545) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99545) BLE_HEART_RATE:     event nor handled\nV (99755) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99755) BLE_HEART_RATE:     event nor handled```\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_out-displayonly\">ESP_IO_CAP_OUT (DisplayOnly)</h1>\n<p>表示機器のみ必要。<br />\n自分が指定するpasskeyをコンソール等に表示し、相手側(ホスト)にpasskey(PINcode)入力させる。</p>\n\n<p>passkeyは<code class=\"language-plaintext highlighter-rouge\">esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, ~);</code>で設定するので、<br />\n必ず表示しなくてはいけない、ということはない(BTヘッドフォンなどでマニュアルに「0000を入力」などと書かれているのと同じ)。</p>\n\n<p>相手側には入力手段が必須。</p>\n\n<p>GAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:               // passkey通知要求イベント\n        // 自身がDisplayOnly(ESP_IO_CAP_OUT)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_PASSKEY_NOTIF_EVT ====\");\n        // passkeyの表示\n        printf(\"**** The passkey Notify number:%06d\\n\", param->ble_security.key_notif.passkey);\n        break;\n</code></pre></div></div>\n\n<p>相手側で入力されたpasskeyが正しければ鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (17105) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (17105) BLE_HEART_RATE:     connection start\nV (17775) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17775) BLE_HEART_RATE:     event nor handled\nV (18025) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (18025) BLE_HEART_RATE:     event nor handled\nV (21935) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_PASSKEY_NOTIF_EVT(11)\nI (21935) BLE_HEART_RATE:     ==== ESP_GAP_BLE_PASSKEY_NOTIF_EVT ====\n**** The passkey Notify number:123456                     ← 相手側にこのpasskeyを入力\nV (22185) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (22185) BLE_HEART_RATE:     event nor handled\nW (33505) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (33535) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33535) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (33535) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33535) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (33545) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33545) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (33575) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33575) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (33575) nvs: nvs_open_from_partition bt_config.conf 1\nD (33575) nvs: nvs_set_blob bt_cfg_key0 250\nD (33595) nvs: nvs_close 4\nD (33595) nvs: nvs_open_from_partition bt_config.conf 1\nD (33595) nvs: nvs_set_blob bt_cfg_key0 264\nD (33605) nvs: nvs_close 5\nD (33605) nvs: nvs_open_from_partition bt_config.conf 1\nD (33605) nvs: nvs_set_blob bt_cfg_key0 347\nD (33625) nvs: nvs_close 6\nD (33625) nvs: nvs_open_from_partition bt_config.conf 1\nD (33625) nvs: nvs_set_blob bt_cfg_key0 407\nD (33625) nvs: nvs_close 7\nD (33625) nvs: nvs_open_from_partition bt_config.conf 1\nD (33635) nvs: nvs_set_blob bt_cfg_key0 462\nD (33635) nvs: nvs_close 8\nD (33645) nvs: nvs_open_from_partition bt_config.conf 1\nD (33645) nvs: nvs_set_blob bt_cfg_key0 476\nD (33655) nvs: nvs_close 9\nV (33655) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (33655) BLE_HEART_RATE:     remote BD_ADDR: 786562f732fc\nI (33655) BLE_HEART_RATE:     address type = 1\nI (33665) BLE_HEART_RATE:     pair status = success\nI (33665) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (33675) BLE_HEART_RATE:     Bonded devices number : 1\nI (33675) BLE_HEART_RATE:     Bonded devices list :\nI (33685) BLE_HEART_RATE:        0 :   78:65:62:f7:32:fc\nV (34185) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34185) BLE_HEART_RATE:     event nor handled\nV (34695) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34695) BLE_HEART_RATE:     event nor handled\nV (34885) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34885) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<p>passkeyを間違えると当然接続されない。<br />\n接続が成功したかどうかは、ログの以下の部分で判別できる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (27095) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (27095) BLE_HEART_RATE:     remote BD_ADDR: 67c015dc4505\nI (27105) BLE_HEART_RATE:     address type = 1\nI (27105) BLE_HEART_RATE:     pair status = fail            ← failしている\nI (27115) BLE_HEART_RATE:     reason = 0x51                 ← 失敗した原因だけど、ドキュメントがない...\nI (27115) BLE_HEART_RATE:     Bonded devices number : 0\nI (27125) BLE_HEART_RATE:     Bonded devices list :\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_in--keyboardonly\">ESP_IO_CAP_IN  (KeyboardOnly)</h1>\n<p>入力機器のみ必要。<br />\n相手側に表示されたpasskeyをコンソール等から入力する。</p>\n\n<p>passkeyは相手側から指定される値なので、どのような値かは相手の仕様による。<br />\n相手側には表示手段が必須。</p>\n\n<p>GAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_PASSKEY_REQ_EVT:                 // passkey 要求\n        // KeyboardOnly(ESP_IO_CAP_IN)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_PASSKEY_REQ_EVT ====\");\n        // 以下の関数で相手側に表示されたパスキーを返す\n        uint32_t    passkey;\n        char        passkey_buff[16];\n        int         passkey_len;\n        do {\n            printf(\"**** input paskey : \");\n            fflush(stdout);\n            passkey_len = uart_gets(passkey_buff, sizeof(passkey_buff));\n        } while (passkey_len == 0);\n        passkey = (uint32_t)strtol(passkey_buff, NULL, 10);\n        esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, passkey);\n        break;\n</code></pre></div></div>\n\n<p>passkeyに使用している<code class=\"language-plaintext highlighter-rouge\">uart_gets()</code>関数については後述。</p>\n\n<p>入力したpasskeyが正しければ鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (16805) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (16805) BLE_HEART_RATE:     connection start\nV (17425) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17425) BLE_HEART_RATE:     event nor handled\nV (17675) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17685) BLE_HEART_RATE:     event nor handled\nE (20765) BT_BTM: btm_ble_remove_resolving_list_entry_complete remove resolving list error 0x2\nV (20955) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_PASSKEY_REQ_EVT(12)\nI (20955) BLE_HEART_RATE:     ==== ESP_GAP_BLE_PASSKEY_REQ_EVT ====\n**** input paskey : 047528                                  ← 相手側で表示されているpasskeyを入力\nV (36455) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (36455) BLE_HEART_RATE:     event nor handled\nW (37335) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (37375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37375) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (37375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37375) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (37385) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37385) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (37405) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37405) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (37415) nvs: nvs_open_from_partition bt_config.conf 1\nD (37415) nvs: nvs_set_blob bt_cfg_key0 476\nD (37425) nvs: nvs_close 4\nD (37425) nvs: nvs_open_from_partition bt_config.conf 1\nD (37425) nvs: nvs_set_blob bt_cfg_key0 476\nD (37495) nvs: nvs_close 5\nD (37495) nvs: nvs_open_from_partition bt_config.conf 1\nD (37495) nvs: nvs_set_blob bt_cfg_key0 476\nD (37505) nvs: nvs_close 6\nD (37505) nvs: nvs_open_from_partition bt_config.conf 1\nD (37505) nvs: nvs_set_blob bt_cfg_key0 476\nD (37525) nvs: nvs_close 7\nD (37525) nvs: nvs_open_from_partition bt_config.conf 1\nD (37525) nvs: nvs_set_blob bt_cfg_key0 476\nD (37525) nvs: nvs_close 8\nV (37525) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (37535) BLE_HEART_RATE:     remote BD_ADDR: 786562f732fc\nI (37535) BLE_HEART_RATE:     address type = 1\nI (37545) BLE_HEART_RATE:     pair status = success\nI (37545) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (37555) BLE_HEART_RATE:     Bonded devices number : 1\nI (37555) BLE_HEART_RATE:     Bonded devices list :\nI (37565) BLE_HEART_RATE:        0 :   78:65:62:f7:32:fc\nV (38255) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (38255) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<p>passkeyを間違えたときの動作は <code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_OUT</code>(DisplayOnly)の場合と同様。</p>\n\n<h1 id=\"esp_io_cap_io-displayyesno\">ESP_IO_CAP_IO (DisplayYesNo)</h1>\n<p>入力機器/表示機器 両方必要。</p>\n\n<p>相手側に表示されたpasskeyとコンソールに表示されたpasskeyを目視確認して等しければyを入力し、相手側でも接続許可をタップする。\n確認せずにYesを選択しても良いけど、それならこのモードを指定する必要はないでしょう。</p>\n\n<p>相手側にも入力/表示手段が必須。<br />\nGAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_NC_REQ_EVT:                      // 数値比較リクエスト イベント\n        // DisplayYesNo(ESP_IO_CAP_IO)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_NC_REQ_EVT ====\");\n        printf(\"**** the passkey Notify number:%d\\n\", param->ble_security.key_notif.passkey);\n        printf(\"**** Accept? (y/n) : \");\n        fflush(stdout);\n        int kb_key = uart_getchar();\n        printf(\"%c\\n\", kb_key);\n        if (kb_key == 'y' || kb_key == 'Y') {\n            // 接続受け入れ\n            esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true);\n        }\n        else {\n            // 接続拒否\n            esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, false);\n        }\n        break;\n</code></pre></div></div>\n\n<p>両方でyesを選択すれば鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (14185) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (14185) BLE_HEART_RATE:     connection start\nV (14855) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (14855) BLE_HEART_RATE:     event nor handled\nV (15145) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (15145) BLE_HEART_RATE:     event nor handled\nE (18775) BT_SMP: Value for numeric comparison = 260195\nV (18775) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_NC_REQ_EVT(16)\nI (18775) BLE_HEART_RATE:     ==== ESP_GAP_BLE_NC_REQ_EVT ====\n**** the passkey Notify number:260195                                               ← 相手側で表示されている数値と目視比較\n**** Accept? (y/n) : y                                                              ← y 入力、相手側でもyesクリック\nV (26785) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (26785) BLE_HEART_RATE:     event nor handled\nW (28245) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (28275) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28275) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (28275) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28285) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (28285) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28295) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (28305) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28305) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (28315) nvs: nvs_open_from_partition bt_config.conf 1\nD (28315) nvs: nvs_set_blob bt_cfg_key0 250\nD (28325) nvs: nvs_close 4\nD (28325) nvs: nvs_open_from_partition bt_config.conf 1\nD (28325) nvs: nvs_set_blob bt_cfg_key0 264\nD (28335) nvs: nvs_close 5\nD (28335) nvs: nvs_open_from_partition bt_config.conf 1\nD (28335) nvs: nvs_set_blob bt_cfg_key0 347\nD (28355) nvs: nvs_close 6\nD (28355) nvs: nvs_open_from_partition bt_config.conf 1\nD (28355) nvs: nvs_set_blob bt_cfg_key0 407\nD (28365) nvs: nvs_close 7\nD (28365) nvs: nvs_open_from_partition bt_config.conf 1\nD (28365) nvs: nvs_set_blob bt_cfg_key0 462\nD (28385) nvs: nvs_close 8\nD (28385) nvs: nvs_open_from_partition bt_config.conf 1\nD (28385) nvs: nvs_set_blob bt_cfg_key0 476\nD (28395) nvs: nvs_close 9\nV (28395) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (28395) BLE_HEART_RATE:     remote BD_ADDR: 612610f26701\nI (28395) BLE_HEART_RATE:     address type = 1\nI (28405) BLE_HEART_RATE:     pair status = success\nI (28405) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (28415) BLE_HEART_RATE:     Bonded devices number : 1\nI (28415) BLE_HEART_RATE:     Bonded devices list :\nI (28425) BLE_HEART_RATE:        0 :   61:26:10:f2:67:01\nV (28905) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (28905) BLE_HEART_RATE:     event nor handled\nV (29435) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (29435) BLE_HEART_RATE:     event nor handled\nV (29655) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (29655) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_kbdisp-keyboard-display\">ESP_IO_CAP_KBDISP (Keyboard display)</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_OUT</code>(DisplayOnly) と <code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_IN</code>(KeyboardOnly) の合わせ技かと思いきや、<br />\n<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_IO</code>(DisplayYesNo)と同じ動作。<br />\nたしかにキーボードと表示両方必要だわな。。。</p>\n\n<h1 id=\"コンソール入力ルーチン\">コンソール入力ルーチン</h1>\n<p>passkeyの入力など、コンソールからの入力が必要な場合、<code class=\"language-plaintext highlighter-rouge\">gets()</code>などを使用するとキー入力待ちの間タスク切り替えが行われずに他のタスクが動作できない。<br />\n(esp-idfはFreeRTOSを使用したマルチタスク構成)。\nそこで、<code class=\"language-plaintext highlighter-rouge\">gets()</code>/<code class=\"language-plaintext highlighter-rouge\">getchar()</code>の代わりとなる関数を用意した。<br />\n動作としては、キー入力待ちの少しの間、<code class=\"language-plaintext highlighter-rouge\">vTaskDelay()</code>でCPUを解放して他のタスクの動作を阻害しないようにしている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">uart_checkkey()</code>は今回使ってないけど、〇秒以内に入力がなければデフォルトで動作、のような動作を実現するのに使用する関数。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">printf()</code>もあちこちのタスクから出力する場合はセマフォで排他処理した方が良いけど、今回は特に問題になりそうにないのでそのまま使用。</p>\n\n<p>Buildは これらのファイルをsrcディレクトリにぶち込むだけでOK。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  uart_console.h\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#include    <stdio.h>\n#include    <stdint.h>\n#include    <stdbool.h>\n\nextern bool uart_checkkey(int loop_num);\nextern int uart_getchar(void);\nextern int uart_gets(char* buf, int max);\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  uart_console.c\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#include    <stdio.h>\n#include    <stdint.h>\n#include    <stdbool.h>\n#include    <string.h>\n#include    <stdarg.h>\n\n#include    \"freertos/FreeRTOS.h\"\n#include    \"freertos/task.h\"\n#include    \"esp_system.h\"\n#include    \"rom/uart.h\"\n\n#include    \"uart_console.h\"\n\n// ========= UARTからの入力待ち ===============================================\n// param    loop_num: 待ち時間(単位100msec)\n// return   true: キー入力があった     false: キー入力はなかった\nbool uart_checkkey(int loop_num)\n{\n    bool    ret = false;\n    uint8_t ch;\n     for (int loop_cnt = 0; loop_cnt < loop_num; loop_cnt++) {\n        // UARTから1文字取得\n        if (uart_rx_one_char(&ch) == OK) {\n            // 入力あり\n            ret = true;\n            break;\n        }\n        if ((loop_cnt % 5)== 0) {\n            // たくさん出ると鬱陶しいので5回毎に\n            putchar('.');\n            fflush(stdout);\n        }\n        // 100ms待つ\n        vTaskDelay(100 / portTICK_RATE_MS);\n    }\n    putchar('\\n');\n\n    // バッファにたまっているデータを読み捨てる\n    while (uart_rx_one_char(&ch) == OK);\n    return ret;\n}\n\n\n// ========= UARTから1文字取得 ================================================\n// param    なし\n// return   文字コード\n// note     CRは無視するので注意\nint uart_getchar(void)\n{\n    uint8_t ch;\n    while (1) {\n        // UARTから1文字取得\n        if (uart_rx_one_char(&ch) == OK) {\n            // 入力あり\n            if (ch == '\\r') {\n                // CRなら次の値を取得\n                continue;\n            }\n            // 入力された値を返す\n            return ch;\n        }\n        // 100ms待つ(CPUを握りっぱなしにしないように)\n        vTaskDelay(100 / portTICK_RATE_MS);\n    }\n}\n\n// ========= UARTから1行取得 ===================================================\n// param    buf: 文字列格納領域へのポインタ\n//          max: 最大文字列長\n// return   入力された文字列長\nint uart_gets(char* buf, int max)\n{\n    int     i = 0;\n    while (i < (max - 1)) {     // null terminate の分を空けておくので max - 1\n        char ch = uart_getchar();\n        if (ch == '\\n') {\n            // LFで終了\n            putchar(ch);\n            fflush(stdout);\n            break;\n        }\n        if (ch == '\\b' || ch == 0x7f) {     // BackSpace or DEL\n            if (i > 0) {        // 先頭でない\n                i--;            // ポインタを一つ前に\n                putchar('\\b');  // 前の文字の表示を削除\n                putchar(' ');\n                putchar('\\b');\n                fflush(stdout);\n            }\n        }\n        else {\n            // それ以外の文字はバッファに格納\n            buf[i] = ch;\n            i++;\n            putchar(ch);        // 表示\n            fflush(stdout);\n        }\n    }\n    buf[i] = '\\0';          // null terminate\n    return i;\n}\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でBLEのデモを動かす</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でBLEのデモを動かす</h1>\n      <p>ESP32にBLEのデモを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>gistにupしたので、gistの埋め込みリンク貼っとく(コードをコピペするのめんどくさかったから)。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/3719faf64374d438fd879ce567becb4b\" target=\"_blank\">こちら</a> \nからどうぞ。</p>\n\n<script src=\"https://gist.github.com/ippei8jp/3719faf64374d438fd879ce567becb4b.js\"></script>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でJTAGデバッグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でJTAGデバッグ</h1>\n      <p>ESP32にFT232Hを接続してJTAGデバッグしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>ESP32のデフォルトの開発環境だと、シリアル通信でFlash書き込んで、<br />\nせいぜいprintfデバッグするしかないが、<br />\nJTAG接続でオンチップデバッグ機能を使えば、もっと使いやすくなるはず。</p>\n\n<p>ESP32のボードは<a href=\"https://www.espressif.com/en/products/devkits/esp32-devkitc\" target=\"_blank\">ESP32-DevKitC-VE</a>\n(<a href=\"https://www.espressif.com/sites/default/files/documentation/esp32-wrover-e_esp32-wrover-ie_datasheet_en.pdf\" target=\"_blank\">ESP32-WROVER-E</a>搭載)\nを使用。</p>\n\n<p>JTAGコントローラは<a href=\"https://ftdichip.com/products/ft232hl/\" target=\"_blank\">FTDIのFT232HL</a>を使用した\n<a href=\"https://akizukidenshi.com/catalog/g/gK-06503/\" target=\"_blank\">秋月電子のAE-FT232HL</a>を使用する(安価なので)。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://www.sunhayato.co.jp/material2/ett09/item_759\" target=\"_blank\">サンハヤトのMM-FT232H</a>\nが拡張コネクタが付いてて使いやすそうなんだけど、お値段かなりお高め…orz…</p>\n</blockquote>\n\n<p>IDEは以前はEclipse一択だったけど、最近はVisual Studio Code に拡張機能<a href=\"https://platformio.org/\" target=\"_blank\">PlatformIO</a>を使うのが\n流行ってるみたいなので、こっちを選択。<br />\nもう Visual Studio Code 最強だな…</p>\n\n<h1 id=\"まずはチュートリアルに沿って試してみる\">まずはチュートリアルに沿って試してみる</h1>\n\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html\" target=\"_blank\">PlatformIOの公式チュートリアル</a>に沿ってツールのインストール~JTAGを使用しないプログラムの書き込み、実行を試す。</p>\n\n<p>まずはツールとボードの動作確認ということで、まだJTAGモジュールは接続しない。</p>\n\n<h2 id=\"ツールのインストール\">ツールのインストール</h2>\n<p>これは上記ページには書いてないので、こっちを参照(Visual Studio Codeインストール済みなら参照するまでもないけど。)<br />\n<a href=\"https://kunsen.net/2018/07/28/post-618/\" target=\"_blank\">薫染庵 途上日誌 PlatformIO IDE for VSCode でESP32のプログラム開発</a><br />\n「3 ESP32プロジェクト作成」の手前まで(以降の説明はarduinoプロジェクトなので)。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPlatformIOのインストールには結構時間がかかる(数分くらい)。 \n右下に出るinstalling~のウィンドウが見難いので「ハングアップした~」と焦って強制終了しないように注意。</p>\n</blockquote>\n\n<h2 id=\"プロジェクトの作成\">プロジェクトの作成</h2>\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#setting-up-the-project\" target=\"_blank\">公式チュートリアルのSetting Up the Project</a>\nに従ってプロジェクトを作成。</p>\n<ul>\n  <li>Nameにプロジェクト名を設定</li>\n  <li>Boardで<code class=\"language-plaintext highlighter-rouge\">Espressif ESP32 Dev Module</code>を選択</li>\n  <li>Frameworkで<code class=\"language-plaintext highlighter-rouge\">Espressif IoT Development Framework</code>を選択(ESP-IDF)</li>\n  <li>Project Wizardの一番下、Locationのチェックをはずすとフォルダを選択できる<br />\nここで指定したフォルダの下にNameで設定した名前のフォルダが作られる<br />\nチェックしたままだと<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%\\Documents\\PlatformIO\\Projects\\</code>に作成されるらしい</li>\n  <li>「このフォルダーないのファイルの作成者を信頼しますか?」と聞かれたら、「はい」を選択</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n初回のみ、プロジェクトを作成すると、自動でESP-IDFがインストールされる。<br />\n環境にもよるけど、15分とかのオーダで覚悟してちょ。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nESP-IDFのインストールにはpythonが必要だが、platformioが自前で持っているのでインストールしなくても大丈夫っぽい。<br />\ngitはインストールしとかないとダメなのかな?なくても大丈夫な気もするけどわからん。</p>\n</blockquote>\n\n<h2 id=\"iniファイルの修正\">iniファイルの修正</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">platformio.ini</code>に<code class=\"language-plaintext highlighter-rouge\">monitor_speed = 115200</code>の1行を追加<br />\n最終的なの内容は以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = espidf\nmonitor_speed = 115200\n</code></pre></div></div>\n\n<h2 id=\"ソースコードの追加\">ソースコードの追加</h2>\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#adding-code-to-the-generated-project\" target=\"_blank\">公式チュートリアルのAdding Code to the Generated Project</a>\nにあるソースを<code class=\"language-plaintext highlighter-rouge\">src\\main.c</code>にコピペする</p>\n\n<blockquote>\n  <p>[!NOTE]\nCMakeLists.txtがどーたらこーたらとwarningが書いてあるけど、無視して良い。<br />\nバージョン変わってちょっと書き方変わったらしい。</p>\n</blockquote>\n\n<p>そのままでも無問題だけど、以下のパッチをあてておくと LEDがチカチカして かつ コンソールにカウント値が表示されるので、\nプログラムが動いてることが一目瞭然。<br />\n(もちろん、IO26端子にLEDを接続しておかないと見えないよ。端子変えるなら<code class=\"language-plaintext highlighter-rouge\">GPIO_NUM_26</code>の部分(2か所)を適当に変更してちょ。)</p>\n\n<p>あと、<code class=\"language-plaintext highlighter-rouge\">tcpip_adapter_init()</code>が非推奨だとワーニングがでるので、<code class=\"language-plaintext highlighter-rouge\">esp_netif_init()</code>に変更してある。<br />\n参考:<a href=\"https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/tcpip_adapter_migration.html\">https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/tcpip_adapter_migration.html</a></p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.c.org  2021-12-26 11:13:05.474815000 +0900\n</span><span class=\"gi\">+++ main.c      2021-12-26 11:12:42.842345600 +0900\n</span><span class=\"p\">@@ -18,6 +18,9 @@</span>\n #include \"lwip/err.h\"\n #include \"lwip/sys.h\"\n\n+#include       <stdio.h>\n<span class=\"gi\">+#include \"driver/gpio.h\"\n+\n</span> #define EXAMPLE_ESP_WIFI_SSID      \"mywifissid\"\n #define EXAMPLE_ESP_WIFI_PASS      \"mywifipass\"\n #define EXAMPLE_MAX_STA_CONN       (3)\n<span class=\"p\">@@ -40,7 +43,7 @@</span>\n\n void wifi_init_softap()\n {\n<span class=\"gd\">-    tcpip_adapter_init();\n</span><span class=\"gi\">+    esp_netif_init();\n</span>     ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();\n<span class=\"p\">@@ -81,4 +84,14 @@</span>\n\n     ESP_LOGI(TAG, \"ESP_WIFI_MODE_AP\");\n     wifi_init_softap();\n<span class=\"gi\">+\n+    gpio_set_direction(GPIO_NUM_26, GPIO_MODE_OUTPUT);\n+    int level = 0;\n+    int count = 0;\n+    while (true) {\n+        gpio_set_level(GPIO_NUM_26, level);\n+        level = !level;\n+        printf(\"count=%d\\n\", count++);\n+        vTaskDelay(300 / portTICK_PERIOD_MS);\n+    }\n</span> }\n</code></pre></div></div>\n\n<h2 id=\"ビルド\">ビルド</h2>\n<p>ビルド実行方法色々書いてあるけど、お好きな方法でどうぞ。<br />\n初回はライブラリもビルドするので時間がかかる。<br />\n(<code class=\"language-plaintext highlighter-rouge\">platform.ini</code>修正時も?)</p>\n\n<p>ターミナルに<code class=\"language-plaintext highlighter-rouge\">SUCCESS</code>と出てるのを確認して次へ。</p>\n\n<p>ターミナルの内容確認して不要になったら何かキーを押すと閉じられる。</p>\n\n<h2 id=\"ターゲットプログラムのダウンロード\">ターゲットプログラムのダウンロード</h2>\n<p>チュートリアルページにはuploadって書いてあるけど、普通はdownloadだと思うんだけど…<br />\nこれもお好きな方法でどうぞ。</p>\n\n<h2 id=\"実行状況の確認\">実行状況の確認</h2>\n<p>シリアルモニタでコンソール入出力を確認できる。<br />\nこれも起動方法はお好きな方法でどうぞ。</p>\n\n<p>うまく動いてたら、スマホやタブレットでWi-Fiスキャンすると「mywifissid」というSSIDが見つかるはず。<br />\n接続してもつながらないけど、なんか接続要求を受けたのがコンソールに表示されるみたい。</p>\n\n<h1 id=\"jtagデバッガを使用したデバッグ\">JTAGデバッガを使用したデバッグ</h1>\n<p>PlatformIOとESP32の動作が確認できたので、次はJTAGデバッガ。<br />\n念のため、cleanしてbuildファイルを一度消しておくのが良いかもしれない。</p>\n\n<p>でも、公式チュートリアルの<a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#debugging-the-firmware\" target=\"_blank\">Debugging the Firmware</a> \n以降は <a href=\"https://www.olimex.com/Products/ARM/JTAG/ARM-USB-OCD-H/\" target=\"_blank\">OLIMEXのARM-USB-OCD-H</a>\nを使用することが前提なので、今回は参照しない。</p>\n\n<p>代わりに<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h\" target=\"_blank\">Long-ship ESP32をPlatformIO上でJTAG(FT232H)デバッグする</a>を参照。<br />\n(でも、微妙に異なるのでちょっと補足書いとく)<br />\n<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc7\" target=\"_blank\">事前準備(自動書き込み)</a>までは上記で済んでいるのでスキップ。</p>\n\n<h2 id=\"ドライバの更新\">ドライバの更新</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc8\" target=\"_blank\">ドライバ更新</a>\nにあるように、ドライバの更新をする。</p>\n\n<p>ドライバ更新の詳しい手順は<a href=\"https://www.m-kobayashi.org/working_log/2018/06/10_01.html\" target=\"_blank\">ESP32で遊ぶ 開発環境を作る (4)</a>の「FT232HL のドライバをインストール」あたりを参照すると分かりやすい。</p>\n\n<p>最初に PCにFT232Hを接続しておくことを忘れないように。<br />\nツールは、<a href=\"https://zadig.akeo.ie/\" target=\"_blank\">Zadigのページ </a>のダウンロードからダウンロード。2021/12/23現在の最新は2.7。<br />\nメニューのoptions→ListAllDevices をやるのを忘れずに(忘れると表示されなくて「あれ?」となります(^^ゞ ) <br />\n対象のデバイスを見つけやすいように、不要なUSBデバイス(特に他のFTDIデバイス)は取り外しておいた方がいいかも。</p>\n\n<p>これは最初に1回やればOK</p>\n\n<h2 id=\"esp32とft232hの結線\">ESP32とFT232Hの結線</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc9\" target=\"_blank\">結線</a>の記載とは\nボードが異なるので、ボードのコネクタ名を含めて結線情報を掲載しておく。<br />\n以下の端子を結線する。</p>\n\n<table style=\"width:400px;\" border=\"3\">\n  <tbody>\n    <tr bgcolor=\"#ff7f7f\">\n      <th colspan=\"2\" width=\"50%\"><strong>FT232H</strong></th>\n      <th colspan=\"2\"><strong>ESP32</strong></th>\n    </tr>\n    <tr>\n      <td width=\"25%\">AD0(TxD)</td><td>J2-7</td>\n      <td width=\"25%\">IO13</td><td>J1-15</td>\n    </tr>\n    <tr>\n      <td>AD1(RxD)</td><td>J2-8</td>\n      <td>IO12</td><td>J1-13</td>\n    </tr>\n    <tr>\n      <td>AD2(RTS#)</td><td>J2-9</td>\n      <td>IO15</td><td>J2-17</td>\n    </tr>\n    <tr>\n      <td>AD3(CTS#)</td><td>J2-10</td>\n      <td>GPIO14</td><td>J3-12</td>\n    </tr>\n    <tr>\n      <td>AD5</td><td>J2-12</td>\n      <td>EN</td><td>J1-2</td>\n    </tr>\n    <tr>\n      <td>GND</td><td>J1-1</td>\n      <td>GND</td><td>J3-1</td>\n    </tr>\n  </tbody>\n</table>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc9\" target=\"_blank\">結線</a>には<br />\nAC1-EN結線と書いてあるけど、<br />\n設定値から判断してAD5-EN結線と思われる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://www.m-kobayashi.org/working_log/2018/06/10_01.html\" target=\"_blank\">ESP32で遊ぶ 開発環境を作る (4)</a>には<br />\nENの結線書いてないけど、結線なくても動くらしい。<br />\nRESET信号がJTAG側から入るのかな?</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nespressifのページによると、sRSTはオプションで繋いでも対応してるコンフィギュレーションが少ないと書いてある。<br />\nでも、CH_PDってどこやねん?<br />\n<a href=\"https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html#jtag-debugging-selecting-jtag-adapter\">https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html#jtag-debugging-selecting-jtag-adapter</a></p>\n</blockquote>\n\n<h2 id=\"iniファイルの修正-1\">iniファイルの修正</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">platformio.ini</code>に<code class=\"language-plaintext highlighter-rouge\">debug_tool = minimodule</code>の1行を追加<br />\n最終的なの内容は以下の通り。<br />\nこれはプロジェクト毎に必要。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = espidf\nmonitor_speed = 115200\ndebug_tool = minimodule\n</code></pre></div></div>\n<h2 id=\"minimoduleの設定変更\">minimoduleの設定変更</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc11\" target=\"_blank\">minimoduleの設定変更</a> のように以下のパッチでファイル修正<br />\n(コメントは変えなくても良いけど、あとで参照して分からなくなるので変更しておく)</p>\n\n<blockquote>\n  <p>[!WARNING]\nこの段階では<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%.platformio\\packages\\tool-openocd-esp32\\</code>ディレクトリがまだない(ダウウンロードされていない)ので、<br />\n一度、Visual Studio Codeのデバッグサイドバーを開き、デバッグターゲットに「PIO Debug」を選択し、実行ボタン(三角アイコン)をクリック<br />\nコンパイルが行われたあと、デバッガプログラムをダウンロードし、起動される。<br />\nデバッガの起動でエラー(<code class=\"language-plaintext highlighter-rouge\">no device found</code>)になるので、一旦キャンセルし、以下の修正を行う。</p>\n</blockquote>\n\n<p>修正するファイル:<br />\n<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%.platformio\\packages\\tool-openocd-esp32\\share\\openocd\\scripts\\interface\\ftdi\\minimodule.cfg</code></p>\n\n<p>変更内容は、ディスクリプタとPID(FT2232H→FT232H)。<br />\n変更後、Visual Studio Codeの再起動必要。<br />\nこれは最初に1回やればOK</p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- minimodule.cfg.org  2021-07-21 22:38:02.000000000 +0900\n</span><span class=\"gi\">+++ minimodule.cfg      2021-12-26 13:09:51.740579600 +0900\n</span><span class=\"p\">@@ -1,16 +1,16 @@</span>\n #\n<span class=\"gd\">-# FTDI MiniModule\n</span><span class=\"gi\">+# Akizuki AE-FT232HL(FTDI FT232HL)\n</span> #\n<span class=\"gd\">-# http://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT2232H_Mini_Module.pdf\n</span><span class=\"gi\">+# https://akizukidenshi.com/catalog/g/gK-06503/\n</span> #\n\n interface ftdi\n<span class=\"gd\">-ftdi_device_desc \"FT2232H MiniModule\"\n-ftdi_vid_pid 0x0403 0x6010\n</span><span class=\"gi\">+ftdi_device_desc \"Single RS232-HS\"\n+ftdi_vid_pid 0x0403 0x6014\n</span>\n # Every pin set as high impedance except TCK, TDI, TDO and TMS\n ftdi_layout_init 0x0008 0x000b\n\n-# nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip)\n<span class=\"gi\">+# nSRST defined on pin J2-12 of AE-FT232HL(pin ADBUS5 [AD5] on the FT232HL chip)\n</span> # This choice is arbitrary. Use other GPIO pin if desired.\n ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n好きなツール名を付けれれば良いんだけど、できないみたいなので一番近いものを修正して使用するということらしい。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">ftdi_layout_signal</code>の設定値を変えればESP32のEN端子に接続するFT232Hの端子を変更できるはずだけど試してない。<br />\nたぶん、値の意味はbit15から順に、 <code class=\"language-plaintext highlighter-rouge\">GPIOH7</code>、<code class=\"language-plaintext highlighter-rouge\">GPIOH6</code>、・・・、<code class=\"language-plaintext highlighter-rouge\">GPIOH0</code>、<code class=\"language-plaintext highlighter-rouge\">GPIOL3</code>、・・・、<code class=\"language-plaintext highlighter-rouge\">GPIOL0</code>、\n<code class=\"language-plaintext highlighter-rouge\">TMS/CS</code>、<code class=\"language-plaintext highlighter-rouge\">TDO/DI</code>、<code class=\"language-plaintext highlighter-rouge\">TDI/DO</code>、<code class=\"language-plaintext highlighter-rouge\">TCK/SK</code>に割り当てられていて、それらの端子は<code class=\"language-plaintext highlighter-rouge\">AC7</code>~<code class=\"language-plaintext highlighter-rouge\">AC0</code>、<code class=\"language-plaintext highlighter-rouge\">AD7</code>~<code class=\"language-plaintext highlighter-rouge\">AD0</code>にあたるものと思われる。<br />\n<a href=\"https://ftdichip.com/wp-content/uploads/2020/08/DS_FT232H.pdf\" target=\"_blank\">https://ftdichip.com/wp-content/uploads/2020/08/DS_FT232H.pdf</a> の「3.2 FT232H Pin Description」の表の\nMPSSEの桁を参照。<br />\nよって、<code class=\"language-plaintext highlighter-rouge\">ftdi_layout_signal</code>の設定値<code class=\"language-plaintext highlighter-rouge\">0x80</code>はAD5端子にあたると推測できる。<br />\nでも、つながなくても動いてるなぁ… 🤔</p>\n</blockquote>\n\n<h2 id=\"デバッグ\">デバッグ</h2>\n<p>Visual Studio Codeのデバッグサイドバーを開き、デバッグターゲットに「PIO Debug」を選択し、実行ボタン(三角アイコン)をクリックすると\nターゲットの依存関係にしたがってbuildを行い、ダウンロード、実行(<code class=\"language-plaintext highlighter-rouge\">app_main()</code>の先頭で一旦停止)を行う。<br />\nなお、デバッグターゲットに「PIO Debug (skip Pre-Debug)」だと、buildは行わず ダウンロード~のみ行う。\n「PIO Debug (without uploading)」ダウンロードも行わず、実行のみ。<br />\n通常は「PIO Debug」を選んでおけば問題ない。</p>\n\n<p>変数の確認やブレークポイントの設定、実行制御(go, step over, step in,…)などは他の環境と大差ない。 <br />\nレジスタダンプも動いてるっぽい。<br />\nコールスタックも動いてるっぽい。<br />\nメモリと逆アセンブルは動かし方分からんかった…</p>\n\n<blockquote>\n  <p>[!NOTE]\nコンソール入出力もVSCodeで上記のシリアルモニタ起動で送受信を行うことができるが、<br />\n外部ツール(TeraTermなど)でモニタすることが可能。<br />\nFlashの書き換えがJTAG経由なので、シリアルポートを他のツールがつかんだままでも大丈夫みたい。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\nプログラムを実行すると、コンソールに<code class=\"language-plaintext highlighter-rouge\">Brownout detector was triggered</code>と表示されてリセットを繰り返すことがある。<br />\nこれは、電圧低下を検出したことによるfail safeのリセット動作らしい。<br />\nWi-Fiを有効化したとき、モジュールに流れる電流が10mA程度→100~200mA程度(実測値)に上がる。<br />\nモジュールを接続しているUSB Hubにたくさんのデバイスを接続していると、電流を確保できなくなって 電圧が低下することがある模様。<br />\nこの場合、USB Hubに接続されている他のデバイスを取り外すか、セルフパワードHubに交換すると正常に動作するようになる。 <br />\nあと、使用するUSBケーブルのインピーダンスが大きいと電流増加で電圧が低下するので、大電流対応のUSBケーブルを使用しましょう。</p>\n\n</blockquote>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その3)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(VAE+SAC編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_1.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a>、\n<a href=\"/memoBlog/2021/12/09/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その2)</a>\nではDonkeyCar simulatorに添付のサンプルプログラムを実行してみたが、結果がイマイチだったので別のプログラムを試してみる。<br />\n<del>パクった</del> 参考にしたのは、<a href=\"https://masato-ka.hatenablog.com/entry/2020/04/29/153505?fbclid=IwAR1sjfiN1dAGRn6vIKU9vOSnfoCCsmgvVXRV_MWaLdUr3FeIUvUAr1Ef_yo\" target=\"_blank\">Jetson Nanoで動く深層強化学習を使ったラジコン向け自動運転ソフトウェアの紹介</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim3\n<span class=\"nb\">cd</span> /work2/donkey_sim3/\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 donkey_sim3\npyenv <span class=\"nb\">local </span>donkey_sim3 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>torch\npip <span class=\"nb\">install </span>torchvision\npip <span class=\"nb\">install </span>pyyaml\npip <span class=\"nb\">install </span>stable_baselines3\npip <span class=\"nb\">install </span>gym\npip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n\n<span class=\"c\"># tensorboard も必要</span>\npip <span class=\"nb\">install </span>tensorboard\n<span class=\"c\"># たぶん要らないけど、念のため入れとく(tensorboard 実行時になんか言われるので)</span>\npip <span class=\"nb\">install </span>tensorflow\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n今回は stable-baselines3 を使用するので、 tensorflow ではなく、pytorch。<br />\nしかし、tensorboardは必要(学習ログ記録のため)。<br />\ntensorboardで可視化機能を使用する際はtensorflowが入ってないと実行時になんか言われるので\n念のためtensorflowも入れとく(たぶん入れなくても大丈夫)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n試したときのモジュール類のバージョンは以下の通り</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>opencv-python                4.5.4.60\ntorch                        1.10.0\ntorchvision                  0.11.1\nPyYAML                       6.0\nstable-baselines3            1.3.0\ngym                          0.19.0\ngym-donkeycar                1.1.1      ← Githubのtagはv21.07.24\ntensorboard                  2.7.0\ntensorflow                   2.7.0\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a> と同じ</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n<h3 id=\"プログラム拾ってくる\">プログラム拾ってくる。</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/masato-ka/airc-rl-agent.git\n<span class=\"nb\">cd </span>airc-rl-agent/\ngit checkout <span class=\"nt\">-b</span> release-v1.5.2 refs/tags/release-v1.5.2\n</code></pre></div></div>\n\n<h3 id=\"パッチをあてる\">パッチをあてる。</h3>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/config.yml b/config.yml\nindex bda2308..3bf2ad4 100644\n</span><span class=\"gd\">--- a/config.yml\n</span><span class=\"gi\">+++ b/config.yml\n</span><span class=\"p\">@@ -48,8 +48,8 @@</span> AGENT_SETTING:\n   N_COMMAND_HISTORY: 20\n   MIN_STEERING: -1.0\n   MAX_STEERING: 1.0\n<span class=\"gd\">-  MIN_THROTTLE: 0.7 # 0.4\n-  MAX_THROTTLE: 0.95 # 0.9\n</span><span class=\"gi\">+  MIN_THROTTLE: 0.3  # 0.7  # 0.4\n+  MAX_THROTTLE: 0.95 # 0.95 # 0.9\n</span>   MAX_STEERING_DIFF: 0.9 #0.35\n \n JETRACER_SETTING:\n<span class=\"gh\">diff --git a/learning_racer/commands/subcommand.py b/learning_racer/commands/subcommand.py\nindex 0cf6eac..e4474e7 100644\n</span><span class=\"gd\">--- a/learning_racer/commands/subcommand.py\n</span><span class=\"gi\">+++ b/learning_racer/commands/subcommand.py\n</span><span class=\"p\">@@ -56,6 +56,7 @@</span> def command_train(args, config):\n     model = CustomSAC(agent, args, config)\n     model.lean(callback=callback)\n     model.save(args.save)\n<span class=\"gi\">+    agent.close()\n</span> \n \n def command_demo(args, config):\n<span class=\"p\">@@ -65,4 +66,14 @@</span> def command_demo(args, config):\n     for step in range(args.time_steps):\n         if step % 100 == 0: print(\"step: \", step)\n         action, _states = model.predict(obs)\n<span class=\"gi\">+        steer = action[0]\n+        throttle = action[1]\n</span>         obs, rewards, dones, info = agent.step(action)\n<span class=\"gi\">+        steer2 = agent.action_history[-2]\n+        throttle2 = agent.action_history[-1]\n+        speed = info[\"speed\"]\n+        cte = info[\"cte\"]\n+        print(f'steer:{steer:9.5f}    steer2:{steer2:9.5f}    throttle:{throttle:9.5f}    throttle2:{throttle2:9.5f}    speed:{speed:9.5f}    cte:{cte:9.5f}')\n+        if dones :\n+            obs = agent.reset()\n+    agent.close()\n</span><span class=\"gh\">diff --git a/learning_racer/racer.py b/learning_racer/racer.py\nindex 3e67ca2..dee0905 100644\n</span><span class=\"gd\">--- a/learning_racer/racer.py\n</span><span class=\"gi\">+++ b/learning_racer/racer.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import sys\n+import os\n+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))\n+\n</span> import argparse\n from learning_racer.commands.subcommand import command_demo, command_train\n from learning_racer.config import ConfigReader\n<span class=\"p\">@@ -8,6 +12,20 @@</span> logger = getLogger(__name__)\n \n __version__ = '1.5.1'\n \n<span class=\"gi\">+track_list = [\n+    \"donkey-generated-roads-v0\",\n+    \"donkey-warehouse-v0\",\n+    \"donkey-avc-sparkfun-v0\",\n+    \"donkey-generated-track-v0\",\n+    \"donkey-mountain-track-v0\",\n+    \"donkey-roboracingleague-track-v0\",\n+    \"donkey-waveshare-v0\",\n+    \"donkey-minimonaco-track-v0\",\n+    \"donkey-warren-track-v0\",\n+    \"donkey-thunderhill-track-v0\",\n+    \"donkey-circuit-launch-track-v0\",\n+]\n+\n</span> parser = argparse.ArgumentParser(description='Learning Racer command.')\n parser.add_argument('--version', action='version', version='learning_racer version {} .'.format(__version__))\n subparser = parser.add_subparsers()\n<span class=\"p\">@@ -39,7 +57,7 @@</span> parser_train.add_argument('-host', '--sim-host', help='Define host IP of DonkeyS\n parser_train.add_argument('-port', '--sim-port', help='Define port number of DonkeySim host.',\n                           default='9091', type=int)\n parser_train.add_argument('-track', '--sim-track', help='Define track name for DonkeySim',\n<span class=\"gd\">-                          default='donkey-generated-track-v0', type=str)\n</span><span class=\"gi\">+                          default='donkey-generated-track-v0', type=str, choices=track_list)\n</span> parser_train.set_defaults(handler=command_train)\n \n # demo subcommand.\n<span class=\"p\">@@ -63,7 +81,7 @@</span> parser_demo.add_argument('-host', '--sim-host', help='Define host IP of DonkeySi\n parser_demo.add_argument('-port', '--sim-port', help='Define port number of DonkeySim host.',\n                          default='9091', type=int)\n parser_demo.add_argument('-track', '--sim-track', help='Define track name for DonkeySim',\n<span class=\"gd\">-                         default='donkey-generated-track-v0', type=str)\n</span><span class=\"gi\">+                         default='donkey-generated-track-v0', type=str, choices=track_list)\n</span> parser_demo.add_argument('-user', '--sim-user', help='Define user name for own car that showed DonkeySim',\n                          default='anonymous', type=str)\n parser_demo.add_argument('-car', '--sim-car', help='Define car model type for own car that showed DonkeySim',\n<span class=\"gh\">diff --git a/learning_racer/sac/custom_sac.py b/learning_racer/sac/custom_sac.py\nindex 734fd95..3642ca8 100644\n</span><span class=\"gd\">--- a/learning_racer/sac/custom_sac.py\n</span><span class=\"gi\">+++ b/learning_racer/sac/custom_sac.py\n</span><span class=\"p\">@@ -21,6 +21,7 @@</span> def _load_sac(agent, args, config, policy):\n                     sde_sample_freq=config.sac_sde_sample_freq()\n                     )\n     else:\n<span class=\"gi\">+        print(f\"**** load model{args.load_model} ****\")\n</span>         model = SAC.load(args.load_model, env=agent,\n                          policy_kwargs=policy,\n                          verbose=config.sac_verbose(),\n<span class=\"p\">@@ -31,7 +32,7 @@</span> def _load_sac(agent, args, config, policy):\n                          ent_coef=config.sac_ent_coef(), learning_rate=config.sac_learning_rate(),\n                          tensorboard_log=\"tblog\", gamma=config.sac_gamma(), tau=config.sac_tau(),\n                          use_sde_at_warmup=config.sac_use_sde_at_warmup(), use_sde=config.sac_use_sde(),\n<span class=\"gd\">-                         sde_sample_freq=config.sac_sample_freq(), n_episodes_rollout=1)\n</span><span class=\"gi\">+                         sde_sample_freq=config.sac_sde_sample_freq(), n_episodes_rollout=1)\n</span>     return model\n \n \n<span class=\"gh\">diff --git a/learning_racer/sac/hyperparam.py b/learning_racer/sac/hyperparam.py\nindex e58b3fa..5b4b3f0 100644\n</span><span class=\"gd\">--- a/learning_racer/sac/hyperparam.py\n</span><span class=\"gi\">+++ b/learning_racer/sac/hyperparam.py\n</span><span class=\"p\">@@ -2,7 +2,6 @@</span> import math\n \n from learning_racer.config.config import ConfigReader\n \n<span class=\"gd\">-hit_counter = 0\n</span> speed_counter = 0\n config = ConfigReader()\n \n<span class=\"p\">@@ -27,29 +26,32 @@</span> def reward_sim(self, done):\n \n \n # For gym_donkey\n<span class=\"gd\">-hit_counter = 0\n</span> speed_counter = 0\n initial = False\n \n \n def episode_over_sim(self):\n<span class=\"gd\">-    global hit_counter, speed_counter, initial\n</span><span class=\"gi\">+    global speed_counter, initial\n</span>     #    print(self.speed)\n \n     if not initial and self.speed > 3.0:\n         initial = True\n \n     if self.hit != \"none\":\n<span class=\"gd\">-        hit_counter += 1\n-        if hit_counter > 5:\n-            self.over = True\n-            hit_counter = 0\n</span><span class=\"gi\">+        self.over = True\n+        initial = False\n+    elif math.fabs(self.cte) > self.max_cte * 1.5:\n+        self.over = True\n+        initial = False\n</span>     elif self.speed < 0.03 and initial:\n         speed_counter += 1\n         if speed_counter > 10:\n             self.over = True\n             speed_counter = 0\n<span class=\"gi\">+            initial = False\n</span>     elif self.missed_checkpoint:\n         self.over = True\n<span class=\"gi\">+        initial = False\n</span>     elif self.dq:\n         self.over = True\n<span class=\"gi\">+        initial = False\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n主な変更内容は、</p>\n  <ul>\n    <li>config.yml\n      <ul>\n        <li>MIN_THROTTLE の値修正(ちょっと速すぎな感じだったので)</li>\n      </ul>\n    </li>\n    <li>learning_racer/commands/subcommand.py\n      <ul>\n        <li>simulatorのクローズ処理を追加</li>\n        <li>demo時の状態表示を追加</li>\n        <li>demo時のdonesステータスでsimulator初期化を追加</li>\n      </ul>\n    </li>\n    <li>learning_racer/racer.py\n      <ul>\n        <li>pip installせずに実行できるよう、sys.pathを修正する部分の追加</li>\n      </ul>\n    </li>\n    <li>learning_racer/sac/custom_sac.py\n      <ul>\n        <li>typo修正</li>\n      </ul>\n    </li>\n    <li>learning_racer/sac/hyperparam.py\n      <ul>\n        <li>エピソード終了判定<code class=\"language-plaintext highlighter-rouge\">episode_over_sim()</code>の変更</li>\n      </ul>\n    </li>\n  </ul>\n\n</blockquote>\n\n<h3 id=\"vaeの学習済みモデルを拾ってくる\">VAEの学習済みモデルを拾ってくる</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>learning_racer/\nwget <span class=\"s2\">\"https://drive.google.com/uc?export=download&id=19r1yuwiRGGV-BjzjoCzwX8zmA8ZKFNcC\"</span> <span class=\"nt\">-O</span> vae.torch\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこのVAEの学習済みモデルは<code class=\"language-plaintext highlighter-rouge\">donkey-generated-track-v0</code>用なので、\n以下の実行ではこのコースを使用する(<code class=\"language-plaintext highlighter-rouge\">-track</code>オプションのデフォルト)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">donkey-waveshare-v0</code>は簡単なコースなので流用できるっぽい。</p>\n</blockquote>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習。<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\nシミュレータ実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python racer.py train <span class=\"nt\">-robot</span><span class=\"o\">=</span>sim <span class=\"nt\">-vae</span><span class=\"o\">=</span>./vae.torch <span class=\"nt\">-config</span><span class=\"o\">=</span>../config.yml <span class=\"nt\">-device</span><span class=\"o\">=</span>cpu <span class=\"nt\">-host</span><span class=\"o\">=</span>192.168.78.200 \n</code></pre></div></div>\n\n<p>追加学習する場合は元のモデルファイルを<code class=\"language-plaintext highlighter-rouge\">-l</code>オプションで指定します。<br />\n学習に使用するステップ数を変更する場合は<code class=\"language-plaintext highlighter-rouge\">-steps</code>オプションで指定します(デフォルトは5000)。<br />\nその他詳細はソースを見てちょ。</p>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンド<code class=\"language-plaintext highlighter-rouge\">train</code>を<code class=\"language-plaintext highlighter-rouge\">demo</code>に変更するだけです。<br />\nテストを実行するステップ数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--steps</code>オプションで指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python racer.py demo <span class=\"nt\">-robot</span><span class=\"o\">=</span>sim <span class=\"nt\">-vae</span><span class=\"o\">=</span>./vae.torch <span class=\"nt\">-config</span><span class=\"o\">=</span>../config.yml <span class=\"nt\">-device</span><span class=\"o\">=</span>cpu <span class=\"nt\">-host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<p>途中で止めたい場合はCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>のはやめとく。</p>\n\n<p>おおざっぱに言うと、コースの画像を入力してその特徴を抽出するVAE(Variational Auto Encoder)と\nVAEの出力と過去の操作(steering/throttle)の履歴を入力に次の操作を決定するSAC(Soft-Actor-Critic)で構成されている。</p>\n\n<p>VAEはあらかじめ大量のコース画像を撮影したデータで学習しておく(<code class=\"language-plaintext highlighter-rouge\">airc-rl-agent/notebooks/colabo/VAE_CNN.ipyn</code>)。<br />\nこの学習はカメラ画像さえ用意できていれば実機(or シミュレータ)は不要なので、Google Colaboratoryなど高性能のマシンで一気に学習できる。<br />\n上記では参照元ページで用意されていた学習済みモデルを使用している。</p>\n\n<p>VAEは車載カメラ画像(RGBのカラー画像)で160x120pixelにリサイズしたものの下部160x80pixelを入力としている。<br />\n出力は32個のデータ。</p>\n\n<p>VAEは160x80x3(38400)の画素データを32の出力に圧縮するので、そのまま画素データを入力するより学習効率が上がるのかな??<br />\nちゃんと検証してないけど、「右カーブ」とか「左カーブ」とか「直進」みたいな情報に集約されるのかな?</p>\n\n<p>SACの入力はVAEの出力(32個)と過去の操作履歴(過去何回分かは<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.N_COMMAND_HISTOR</code>で指定。\n上記手順で使用した設定値は20なので、steeringとthrottleの2個 × 20 で40個)を使用。<br />\n出力はsteeringとthrottleの2個のデータ。</p>\n\n<p>SACの出力はそのまま車の操作に使用するのではなく、<br />\nthrottleは<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.MIN_THROTTLE</code>と<code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.MAX_THROTTLE</code>で指定した範囲に変換。<br />\nsteeringは前回の設定値との差が<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">MAX_STEERING_DIFF</code>で指定した値を超えないように制限処理、<br />\nを行って使用する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その2)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(PPO2編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_1.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a>\nではポリシーにDDQNを使用したサンプルを実行してみたが、今回はもう一つのサンプル(PPO2を使用)を試してみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim2\n<span class=\"nb\">cd</span> /work2/donkey_sim2\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv <span class=\"nb\">install </span>3.7.12 \npyenv virtualenv 3.7.12 donkey_sim2\npyenv <span class=\"nb\">local </span>donkey_sim2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>stable-baselines\npip <span class=\"nb\">install </span><span class=\"nv\">tensorflow</span><span class=\"o\">==</span>1.14.0\n\n<span class=\"c\"># 現時点での最新リリース v21.7.24 をcheckoutしておく</span>\ngit clone https://github.com/tawnkramer/gym-donkeycar <span class=\"nt\">-b</span> v21.07.24\n\n<span class=\"c\"># gym-donkeycarライブラリのインストール</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-e</span> gym-donkeycar\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nstable-baselines は tensorflow ~1.14.0 しかサポートしていないので、バージョン指定してインストールする。<br />\ntensorflow 1.14.0 は python ~3.7 しかサポートしていないので、3.7系の最新版を使用している。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ngym-donkeycar は -e (–editable) オプション付きでインストールしているので、編集も可能。 \ngit cloneした先を参照しているので、インストール後もgym-donkeycarを削除しちゃダメ。</p>\n\n  <p>githubから直接インストールする場合は以下。<br />\nこの場合、パッケージは通常のディレクトリにインストールされる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n</code></pre></div>  </div>\n  <p>でも、以下でサンプルプログラム使うので、git cloneもしないとダメ。</p>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a> と同じ</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<p>用意されているサンプルプログラムにパッチをあてようと思ったのだけど、<br />\n<code class=\"language-plaintext highlighter-rouge\">ppo_train.py</code> はやっつけ感満載のイマイチソースなので いっそ全書き換えで。</p>\n\n<p>主な対応内容は、</p>\n<ul>\n  <li>一定間隔でモデルの保存を行うようcallbackクラスの追加</li>\n  <li>シミュレータのリモート実行対応(<code class=\"language-plaintext highlighter-rouge\">--host</code>)</li>\n  <li>学習回数指定オプション(<code class=\"language-plaintext highlighter-rouge\">--step</code>)</li>\n  <li>テスト回数指定オプション(<code class=\"language-plaintext highlighter-rouge\">--test_step</code>)</li>\n  <li>保存したモデルファイルをロードしてからの学習に対応</li>\n  <li></li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ppo.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">signal</span>\n<span class=\"kn\">import</span> <span class=\"nn\">argparse</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">typing</span>\n<span class=\"kn\">from</span> <span class=\"nn\">typing</span> <span class=\"kn\">import</span> <span class=\"n\">Union</span><span class=\"p\">,</span> <span class=\"n\">List</span><span class=\"p\">,</span> <span class=\"n\">Dict</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">,</span> <span class=\"n\">Optional</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">gym</span>\n<span class=\"kn\">import</span> <span class=\"nn\">gym_donkeycar</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines</span> <span class=\"kn\">import</span> <span class=\"n\">PPO2</span>\n<span class=\"c1\"># from stable_baselines.common import set_global_seeds\n</span><span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.policies</span> <span class=\"kn\">import</span> <span class=\"n\">CnnPolicy</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.vec_env</span> <span class=\"kn\">import</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.callbacks</span> <span class=\"kn\">import</span> <span class=\"n\">EventCallback</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.base_class</span> <span class=\"kn\">import</span> <span class=\"n\">BaseRLModel</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MyCallback</span><span class=\"p\">(</span><span class=\"n\">EventCallback</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> \n                 <span class=\"n\">eval_env</span><span class=\"p\">:</span> <span class=\"n\">Union</span><span class=\"p\">[</span><span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">Env</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span><span class=\"p\">],</span>\n                 <span class=\"n\">save_freq</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">1000</span><span class=\"p\">,</span>\n                 <span class=\"n\">save_file</span><span class=\"p\">:</span> <span class=\"n\">Optional</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"bp\">None</span><span class=\"p\">,</span>\n                 <span class=\"n\">verbose</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">MyCallback</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"n\">verbose</span><span class=\"o\">=</span><span class=\"n\">verbose</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span> <span class=\"o\">=</span> <span class=\"n\">save_file</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">=</span> <span class=\"n\">save_freq</span>\n        \n        <span class=\"c1\"># Convert to VecEnv for consistency\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">eval_env</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span><span class=\"p\">):</span>\n            <span class=\"n\">eval_env</span> <span class=\"o\">=</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">([</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"n\">eval_env</span><span class=\"p\">])</span>\n            \n        <span class=\"k\">assert</span> <span class=\"n\">eval_env</span><span class=\"p\">.</span><span class=\"n\">num_envs</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"You must pass only one environment for evaluation\"</span>\n        \n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">eval_env</span> <span class=\"o\">=</span> <span class=\"n\">eval_env</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">init_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">model</span><span class=\"p\">:</span> <span class=\"s\">'BaseRLModel'</span><span class=\"p\">)</span> <span class=\"o\">-></span> <span class=\"bp\">None</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#### INIT ####\"</span><span class=\"p\">)</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">EventCallback</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">init_callback</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">_init_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#### _INIT ####\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">_on_step</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"o\">-></span> <span class=\"nb\">bool</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">></span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">n_calls</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">now</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">now</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">verbose</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">now</span><span class=\"si\">}</span><span class=\"s\"> saving...'</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span> <span class=\"p\">:</span>\n                <span class=\"n\">now_str</span>  <span class=\"o\">=</span> <span class=\"n\">now</span><span class=\"p\">.</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s\">'%y%m%d_%H%M%S'</span><span class=\"p\">)</span>\n                <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span>\n                <span class=\"c1\"># filename = os.path.join(os.path.dirname(self.save_file), f'{now_str}_{os.path.basename(self.save_file)}')\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">True</span>\n    \n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Initialize the donkey environment\n</span>    <span class=\"c1\"># where env_name one of:\n</span>    <span class=\"n\">env_list</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-roads-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-avc-sparkfun-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-roboracingleague-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-waveshare-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-minimonaco-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-warren-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-thunderhill-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-circuit-launch-track-v0\"</span><span class=\"p\">,</span>\n    <span class=\"p\">]</span>\n    \n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s\">\"ppo_train\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--sim\"</span><span class=\"p\">,</span>\n        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span>\n        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"sim_path\"</span><span class=\"p\">,</span>\n        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\"</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--model\"</span><span class=\"p\">,</span>     <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"ppo_donkey\"</span><span class=\"p\">,</span>  <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--host\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"127.0.0.1\"</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"simulator address\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--port\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">9091</span><span class=\"p\">,</span>          <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--step\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">,</span>         <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test_step\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">,</span>             <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test\"</span><span class=\"p\">,</span>      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">,</span>             <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"load the trained model and play\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--env_name\"</span><span class=\"p\">,</span>  <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"name of donkey sim environment\"</span><span class=\"p\">,</span> <span class=\"n\">choices</span><span class=\"o\">=</span><span class=\"n\">env_list</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">test_step</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test_step</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span> <span class=\"ow\">and</span> <span class=\"n\">test_step</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"n\">test_step</span> <span class=\"o\">=</span> <span class=\"mi\">1000</span>\n        \n    <span class=\"c1\"># Complement the file extension\n</span>    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s\">\".zip\"</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span> <span class=\"o\">+</span> <span class=\"s\">\".zip\"</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    \n    <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s\">\"exe_path\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sim</span><span class=\"p\">,</span>\n        <span class=\"s\">\"host\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">host</span><span class=\"p\">,</span>\n        <span class=\"s\">\"port\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">port</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_style\"</span><span class=\"p\">:</span> <span class=\"s\">\"car01\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_rgb\"</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span>\n        <span class=\"s\">\"car_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"me\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"font_size\"</span><span class=\"p\">:</span> <span class=\"mi\">100</span><span class=\"p\">,</span>\n        <span class=\"s\">\"racer_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"PPO\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"country\"</span><span class=\"p\">:</span> <span class=\"s\">\"USA\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"bio\"</span><span class=\"p\">:</span> <span class=\"s\">\"Learning to drive w PPO RL\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"guid\"</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"p\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()),</span>\n        <span class=\"s\">\"max_cte\"</span><span class=\"p\">:</span> <span class=\"mi\">10</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\"># Make an environment test our trained policy\n</span>    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">make</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">env_name</span><span class=\"p\">,</span> <span class=\"n\">conf</span><span class=\"o\">=</span><span class=\"n\">conf</span><span class=\"p\">)</span>\n    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">([</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"n\">env</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># hook terninate signal\n</span>    <span class=\"k\">def</span> <span class=\"nf\">signal_handler</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"catching ctrl+c\"</span><span class=\"p\">)</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGINT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGTERM</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGABRT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">try</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># check model path\n</span>        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">):</span>\n            <span class=\"c1\"># load model\n</span>            <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">PPO2</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">,</span> <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span> \n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">:</span>\n                <span class=\"c1\"># create model\n</span>                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"create new model\"</span><span class=\"p\">)</span>\n                <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">PPO2</span><span class=\"p\">(</span><span class=\"n\">CnnPolicy</span><span class=\"p\">,</span> <span class=\"n\">env</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">raise</span> <span class=\"nb\">ValueError</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Error: the file </span><span class=\"si\">{</span><span class=\"n\">model_path</span><span class=\"si\">}</span><span class=\"s\"> could not be found\"</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># change throttle lower limit\n</span>        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">action_space</span><span class=\"p\">.</span><span class=\"n\">low</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.1</span>\n        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">:</span>\n            <span class=\"c1\"># in training mode\n</span>            \n            <span class=\"n\">callback</span> <span class=\"o\">=</span> <span class=\"n\">MyCallback</span><span class=\"p\">(</span><span class=\"n\">env</span><span class=\"p\">,</span> <span class=\"n\">save_freq</span> <span class=\"o\">=</span> <span class=\"mi\">5000</span><span class=\"p\">,</span> <span class=\"n\">save_file</span> <span class=\"o\">=</span> <span class=\"n\">model_path</span><span class=\"p\">,</span> <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"c1\"># callback = MyCallback(env, save_freq = 10, verbose = 1)\n</span>            \n            <span class=\"c1\"># set up model in learning mode with goal number of timesteps to complete\n</span>            <span class=\"c1\"># model.learn(total_timesteps=10000)\n</span>            <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">learn</span><span class=\"p\">(</span><span class=\"n\">total_timesteps</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">,</span> <span class=\"n\">callback</span><span class=\"o\">=</span><span class=\"n\">callback</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># save model\n</span>            <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stert testing...\"</span><span class=\"p\">)</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">reset</span><span class=\"p\">()</span>\n        <span class=\"n\">prev_done_count</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">test_step</span><span class=\"p\">):</span>\n            <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">_states</span> <span class=\"o\">=</span> <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n            <span class=\"n\">obs</span><span class=\"p\">,</span> <span class=\"n\">rewards</span><span class=\"p\">,</span> <span class=\"n\">dones</span><span class=\"p\">,</span> <span class=\"n\">info</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">(</span><span class=\"n\">action</span><span class=\"p\">)</span>\n            <span class=\"c1\"># print(f\"cnt : {i}    rewards : {rewards[0]}    dones : {dones[0]}    pos : {info[0]['pos']}, CrossTrackError : {info[0]['cte']}, speed : {info[0]['speed']}\")\n</span>            <span class=\"c1\"># print(f\"+++ info: {info} +++\")\n</span>            <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">render</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">dones</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'dones flag detected : </span><span class=\"si\">{</span><span class=\"n\">i</span> <span class=\"o\">-</span> <span class=\"n\">prev_done_count</span><span class=\"si\">}</span><span class=\"s\">  (</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n                <span class=\"n\">prev_done_count</span> <span class=\"o\">=</span> <span class=\"n\">i</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done testing\"</span><span class=\"p\">)</span>\n        \n    <span class=\"k\">except</span> <span class=\"nb\">KeyboardInterrupt</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stopping run...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n</code></pre></div></div>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習。<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションに<code class=\"language-plaintext highlighter-rouge\">remote</code>を、実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>examples/reinforcement_learning\npython ppo.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n学習回数を指定するには<code class=\"language-plaintext highlighter-rouge\">--step</code>オプションで指定します。<br />\n指定する回数はエピソード数ではなく、アクション数。<br />\n例えば、<code class=\"language-plaintext highlighter-rouge\">--step=100000</code></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nローカルマシンでシミュレータを実行する場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションにDonkeyCar シミュレータ起動コマンドをフルパスで指定します。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションは不要です。<br />\nシミュレータをあらかじめ起動しておく必要はなく、自動的に起動されます。</p>\n</blockquote>\n\n<p>モデルの保存間隔は<code class=\"language-plaintext highlighter-rouge\">MyCallback</code>のインスタンス生成時に<code class=\"language-plaintext highlighter-rouge\">save_freq = 5000</code>で指定していますので、必要なら変更してください。</p>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンドに<code class=\"language-plaintext highlighter-rouge\">--test</code>を指定するだけです。<br />\nテストを実行するステップ数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--test_step</code>オプションで指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ppo.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--test</span> \n</code></pre></div></div>\n<p>途中で止めたい場合はCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>ほど複雑じゃないので省略。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その1)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(DDQN編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"https://qiita.com/bathtimefish/items/a9b23681720527c0bd7e?fbclid=IwAR3sbaoBn09U7pFL4AKyEOXMi0wNXyAYi9jODUzO1muYr-N7q6hFG-hDfKs\" target=\"_blank\">DonkeyCar3シミュレーターで強化学習してみる</a>のマネをしてDonkeyCarシミュレータライブラリの中にあるサンプルのddqn.pyを実行してみる。<br />\n参考:<br />\nDQNについてはここが分かりやすかったかな。<br />\n<a href=\"https://www.tcom242242.net/entry/ai-2/%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/%E6%B7%B1%E5%B1%A4%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/%E3%80%90%E6%B7%B1%E5%B1%A4%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92%E3%80%91deep_q_network_%E3%82%92tensorflow%E3%81%A7%E5%AE%9F%E8%A3%85/\" target=\"_blank\">【深層強化学習,入門】Deep Q Network(DQN)の解説とPythonで実装 〜図を使って説明〜 </a><br />\n<a href=\"https://www.tcom242242.net/entry/ai-2/%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92/%e3%80%90%e6%b7%b1%e5%b1%a4%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92%e3%80%91double-q-network/\" target=\"_blank\">【深層強化学習】Double Deep Q Network(DDQN)</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim\n<span class=\"nb\">cd</span> /work2/donkey_sim\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 donkey_sim\npyenv <span class=\"nb\">local </span>donkey_sim \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n\n<span class=\"c\"># 現時点での最新リリース v21.7.24 をcheckoutしておく</span>\ngit clone https://github.com/tawnkramer/gym-donkeycar <span class=\"nt\">-b</span> v21.07.24\n\n<span class=\"c\"># gym-donkeycarライブラリのインストール</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-e</span> gym-donkeycar\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ngym-donkeycar は -e (–editable) オプション付きでインストールしているので、編集も可能。 \ngit cloneした先を参照しているので、インストール後もgym-donkeycarを削除しちゃダメ。</p>\n\n  <p>githubから直接インストールする場合は以下。<br />\nこの場合、パッケージは通常のディレクトリにインストールされる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n</code></pre></div>  </div>\n  <p>でも、以下でサンプルプログラム使うので、git cloneもしないとダメ。</p>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p>以下のページから実行するプラットフォームに合わせて<code class=\"language-plaintext highlighter-rouge\">DonkeySimXXXX.zip</code>(XXXXはプラットフォーム名)をダウンロードし、<br />\n適当なディレクトリに展開しておきます。<br />\n(Linux/Macの場合は実行属性付けるのを忘れずに)<br />\n<a href=\"https://github.com/tawnkramer/gym-donkeycar/releases\">https://github.com/tawnkramer/gym-donkeycar/releases</a></p>\n\n<p>マシンスペックがそれほど高くない場合は別マシンで実行してリモート接続するのがおススメ。<br />\nSSH接続で実行する場合はリモート必須。</p>\n\n<h2 id=\"patchをあてる\">patchをあてる</h2>\n\n<p>以下のパッチファイルを使用してサンプルプログラムにパッチをあてます。<br />\n内容は、</p>\n<ul>\n  <li>なぜか<code class=\"language-plaintext highlighter-rouge\">gym_donkeycar</code>がimportされてなかった</li>\n  <li>tensorflow 1.13以降2.0未満用の設定をバージョン情報からスキップできるようにした</li>\n  <li>シミュレータのリモート実行対応(hostオプション追加)</li>\n  <li>探索率(ε値)の初期値設定オプションの追加<br />\n探索率(ε値)については<a href=\"https://www.tcom242242.net/entry/ai-2/%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/epsilon-greedy/\" target=\"_blank\">ε-greedy行動選択 </a>を参照</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  rl_sample.patch\n</p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/examples/reinforcement_learning/ddqn.py b/examples/reinforcement_learning/ddqn.py\nindex 87c74f0..5c32f49 100755\n</span><span class=\"gd\">--- a/examples/reinforcement_learning/ddqn.py\n</span><span class=\"gi\">+++ b/examples/reinforcement_learning/ddqn.py\n</span><span class=\"p\">@@ -21,6 +21,8 @@</span> from tensorflow.keras.layers import Activation, Conv2D, Dense, Flatten\n from tensorflow.keras.models import Sequential\n from tensorflow.keras.optimizers import Adam\n \n<span class=\"gi\">+import gym_donkeycar\n+\n</span> EPISODES = 10000\n img_rows, img_cols = 80, 80\n # Convert image into Black and white\n<span class=\"p\">@@ -121,6 +123,9 @@</span> class DQNAgent:\n         if self.epsilon > self.epsilon_min:\n             self.epsilon -= (self.initial_epsilon - self.epsilon_min) / self.explore\n \n<span class=\"gi\">+    def set_epsilon(self, epsilon):\n+        self.epsilon = epsilon\n+\n</span>     def train_replay(self):\n         if len(self.memory) < self.train_start:\n             return\n<span class=\"p\">@@ -196,15 +201,17 @@</span> def run_ddqn(args):\n     run a DDQN training session, or test it's result, with the donkey simulator\n     \"\"\"\n \n<span class=\"gd\">-    # only needed if TF==1.13.1\n-    config = tf.ConfigProto()\n-    config.gpu_options.allow_growth = True\n-    sess = tf.Session(config=config)\n-    K.set_session(sess)\n</span><span class=\"gi\">+    tf_ver = tf.__version__.split('.')\n+    if (tf_ver[0] == 1 and tf_ver[1] >= 13) :\n+        # only needed if TF==1.13.1\n+        config = tf.ConfigProto()\n+        config.gpu_options.allow_growth = True\n+        sess = tf.Session(config=config)\n+        K.set_session(sess)\n</span> \n     conf = {\n         \"exe_path\": args.sim,\n<span class=\"gd\">-        \"host\": \"127.0.0.1\",\n</span><span class=\"gi\">+        \"host\": args.host,\n</span>         \"port\": args.port,\n         \"body_style\": \"donkey\",\n         \"body_rgb\": (128, 128, 128),\n<span class=\"p\">@@ -237,6 +244,9 @@</span> def run_ddqn(args):\n     try:\n         agent = DQNAgent(state_size, action_space, train=not args.test)\n \n<span class=\"gi\">+        if args.epsilon > 0 :\n+            agent.set_epsilon(args.epsilon)\n+\n</span>         throttle = args.throttle  # Set throttle as constant value\n \n         episodes = []\n<span class=\"p\">@@ -350,6 +360,7 @@</span> if __name__ == \"__main__\":\n         default=\"manual\",\n         help=\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\",\n     )\n<span class=\"gi\">+    parser.add_argument(\"--host\", type=str, default=\"127.0.0.1\", help=\"simulator address\")\n</span>     parser.add_argument(\"--model\", type=str, default=\"rl_driver.h5\", help=\"path to model\")\n     parser.add_argument(\"--test\", action=\"store_true\", help=\"agent uses learned model to navigate env\")\n     parser.add_argument(\"--port\", type=int, default=9091, help=\"port to use for websockets\")\n<span class=\"p\">@@ -357,6 +368,7 @@</span> if __name__ == \"__main__\":\n     parser.add_argument(\n         \"--env_name\", type=str, default=\"donkey-warehouse-v0\", help=\"name of donkey sim environment\", choices=env_list\n     )\n<span class=\"gi\">+    parser.add_argument(\"--epsilon\", type=float, default=0.0, help=\"initial epsilon value\")\n</span> \n     args = parser.parse_args()\n</code></pre></div></div>\n\n<p>以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>gym-donkeycar/\npatch <span class=\"nt\">-p1</span> < rl_sample.patch \n</code></pre></div></div>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習しないと話にならないので学習します。<br />\n強化学習は教師データが要らないので、準備がラクチン…  でも学習には時間がかかる…<br />\nDonkeyCar シミュレータをリモートマシンで実行する場合、<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションに<code class=\"language-plaintext highlighter-rouge\">remote</code>を、実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>examples/reinforcement_learning\npython ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルマシンでシミュレータを実行する場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションにDonkeyCar シミュレータ起動コマンドをフルパスで指定します。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションは不要です。<br />\nシミュレータをあらかじめ起動しておく必要はなく、自動的に起動されます。</p>\n</blockquote>\n\n<p>エピソード毎に学習結果が <code class=\"language-plaintext highlighter-rouge\">rl_driver.h5</code>に保存されるので、任意のタイミングでCTRL-Cで中断できます。<br />\n次回学習を再開する場合は、ログとして表示されている<code class=\"language-plaintext highlighter-rouge\">epsilon: 0.XXXXXXX</code>の部分の最後の値を覚えておいてください。<br />\nこのプログラムではε値は0.02を下回ると固定されるので、ある程度学習が進んだ状態では<code class=\"language-plaintext highlighter-rouge\">0.02</code>だと思っても問題ないでしょう。</p>\n\n<p>学習を再開する場合は以下のように上記コマンドに<code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプションを追加して実行します。<br />\n(<code class=\"language-plaintext highlighter-rouge\">0.XXXXXXX</code>の部分は上で覚えておいた値。ピッタリ同じでなくて大体で可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--epsilon</span><span class=\"o\">=</span>0.XXXXXXX\n</code></pre></div></div>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンドに<code class=\"language-plaintext highlighter-rouge\">--test</code>を指定するだけです。<br />\n<code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプションは指定しません。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--test</span>\n</code></pre></div></div>\n<p>うまく学習が進んでいれば、コースアウトすることなく周回してくれるハズ。<br />\n学習時と同様、コースアウトすると自動的にスタート位置に戻って再スタートします。<br />\n適当にCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>以下はソースを読んだ時のメモです。<br />\n書いてみたけど、自分で読んでも なにが何だか分からない…😢</p>\n\n<h2 id=\"冒頭部分\">冒頭部分</h2>\n<p>この辺はお約束なので。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"s\">\"\"\"\nfile: ddqn.py\nauthor: Felix Yu\ndate: 2018-09-12\noriginal: https://github.com/flyyufelix/donkey_rl/blob/master/donkey_rl/src/ddqn.py\n\"\"\"</span>\n<span class=\"kn\">import</span> <span class=\"nn\">argparse</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">signal</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">from</span> <span class=\"nn\">collections</span> <span class=\"kn\">import</span> <span class=\"n\">deque</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">gym</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">tensorflow</span> <span class=\"k\">as</span> <span class=\"n\">tf</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras</span> <span class=\"kn\">import</span> <span class=\"n\">backend</span> <span class=\"k\">as</span> <span class=\"n\">K</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.layers</span> <span class=\"kn\">import</span> <span class=\"n\">Activation</span><span class=\"p\">,</span> <span class=\"n\">Conv2D</span><span class=\"p\">,</span> <span class=\"n\">Dense</span><span class=\"p\">,</span> <span class=\"n\">Flatten</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.models</span> <span class=\"kn\">import</span> <span class=\"n\">Sequential</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.optimizers</span> <span class=\"kn\">import</span> <span class=\"n\">Adam</span>\n\n</code></pre></div></div>\n<h2 id=\"冒頭部分その2\">冒頭部分その2</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">gym_donkey</code>をimportしないとDonkeyCarシミュレータと接続できないので。<br />\nなぜかオリジナルでは入ってなかった。<br />\n<code class=\"language-plaintext highlighter-rouge\">if __name__ == \"__main__\":</code>付けといた方が良いかもしれんが、とりあえずそのままimportしておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">gym_donkeycar</span>\n\n</code></pre></div></div>\n\n<h2 id=\"パラメータの設定\">パラメータの設定</h2>\n<p>意味は以下の通り。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: center\">変数</th>\n      <th style=\"text-align: left\">意味</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: center\">EPISODES</td>\n      <td style=\"text-align: left\">学習回数</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_rows</td>\n      <td style=\"text-align: left\">入力に使用する画像サイズ(Y)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_cols</td>\n      <td style=\"text-align: left\">入力に使用する画像サイズ(X)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_channels</td>\n      <td style=\"text-align: left\">入力に過去何フレーム分のデータを使用するか</td>\n    </tr>\n  </tbody>\n</table>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">EPISODES</span> <span class=\"o\">=</span> <span class=\"mi\">10000</span>\n<span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span> <span class=\"o\">=</span> <span class=\"mi\">80</span><span class=\"p\">,</span> <span class=\"mi\">80</span>\n<span class=\"c1\"># Convert image into Black and white\n</span><span class=\"n\">img_channels</span> <span class=\"o\">=</span> <span class=\"mi\">4</span>  <span class=\"c1\"># We stack 4 frames\n</span></code></pre></div></div>\n\n<h2 id=\"強化学習エージェントクラス\">強化学習エージェントクラス</h2>\n\n<p>強化学習のエージェントを定義したクラスです。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">DQNAgent</span><span class=\"p\">:</span>\n</code></pre></div></div>\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>クラス変数</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: center\">変数</th>\n      <th style=\"text-align: left\">意味</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: center\">t</td>\n      <td style=\"text-align: left\">実行カウンタ(ステータス表示用のみ使用)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">max_Q</td>\n      <td style=\"text-align: left\">Q値の最大値(ステータス表示用のみ使用)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">train</td>\n      <td style=\"text-align: left\">学習モード/テストモード(<code class=\"language-plaintext highlighter-rouge\">--test</code>オプションで指定)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">state_size</td>\n      <td style=\"text-align: left\">モデルの入力層のサイズ。現状未使用</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">action_space</td>\n      <td style=\"text-align: left\">シミュレータの現在のステアリング/スロットル設定値取得用</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">action_size</td>\n      <td style=\"text-align: left\">未使用。たぶん、ステアリング角を何分割するかの定義(15)にすべきだと思う</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">discount_factor</td>\n      <td style=\"text-align: left\">割引率(γ値) (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">learning_rate</td>\n      <td style=\"text-align: left\">学習率 (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">epsilon</td>\n      <td style=\"text-align: left\">現在の探索率(ε値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">initial_epsilon</td>\n      <td style=\"text-align: left\">探索率の最大値  最小率と共に探索率の変更率を計算する(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">epsilon_min</td>\n      <td style=\"text-align: left\">探索率の最小値 学習時の探索率をこれより小さくしない(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">explore</td>\n      <td style=\"text-align: left\">探索率を最小値にするまでの回数(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">batch_size</td>\n      <td style=\"text-align: left\">バッチサイズ (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">train_start</td>\n      <td style=\"text-align: left\">学習開始タイミング(最初は学習を行わない)(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">memory</td>\n      <td style=\"text-align: left\">Experience Buffer</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">model</td>\n      <td style=\"text-align: left\">メインモデル</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">target_model</td>\n      <td style=\"text-align: left\">ターゲットモデル(double DQNなので)</td>\n    </tr>\n  </tbody>\n</table>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state_size</span><span class=\"p\">,</span> <span class=\"n\">action_space</span><span class=\"p\">,</span> <span class=\"n\">train</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">max_Q</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train</span> <span class=\"o\">=</span> <span class=\"n\">train</span>\n\n        <span class=\"c1\"># Get size of state and action\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">state_size</span> <span class=\"o\">=</span> <span class=\"n\">state_size</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_space</span> <span class=\"o\">=</span> <span class=\"n\">action_space</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_size</span> <span class=\"o\">=</span> <span class=\"n\">action_space</span>\n\n        <span class=\"c1\"># These are hyper parameters for the DQN\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">discount_factor</span> <span class=\"o\">=</span> <span class=\"mf\">0.99</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">learning_rate</span> <span class=\"o\">=</span> <span class=\"mf\">1e-4</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1e-6</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1e-6</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span> <span class=\"o\">=</span> <span class=\"mf\">0.02</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">64</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train_start</span> <span class=\"o\">=</span> <span class=\"mi\">100</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">explore</span> <span class=\"o\">=</span> <span class=\"mi\">10000</span>\n\n        <span class=\"c1\"># Create replay memory using deque\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span> <span class=\"o\">=</span> <span class=\"n\">deque</span><span class=\"p\">(</span><span class=\"n\">maxlen</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Create main model and target model\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">build_model</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">build_model</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># Copy the model to target model\n</span>        <span class=\"c1\"># --> initialize the target model so that the parameters of model & target model to be same\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_target_model</span><span class=\"p\">()</span>\n\n</code></pre></div></div>\n<h3 id=\"モデルの生成\">モデルの生成</h3>\n\n<p>そんなに複雑なモデルではないみたい。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">build_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Sequential</span><span class=\"p\">()</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span>\n            <span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">24</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">,</span> <span class=\"n\">input_shape</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">,</span> <span class=\"n\">img_channels</span><span class=\"p\">))</span>\n        <span class=\"p\">)</span>  <span class=\"c1\"># 80*80*4\n</span>        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">32</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Flatten</span><span class=\"p\">())</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Dense</span><span class=\"p\">(</span><span class=\"mi\">512</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n\n        <span class=\"c1\"># 15 categorical bins for Steering angles\n</span>        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Dense</span><span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">activation</span><span class=\"o\">=</span><span class=\"s\">\"linear\"</span><span class=\"p\">))</span>\n\n        <span class=\"n\">adam</span> <span class=\"o\">=</span> <span class=\"n\">Adam</span><span class=\"p\">(</span><span class=\"n\">lr</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">learning_rate</span><span class=\"p\">)</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"nb\">compile</span><span class=\"p\">(</span><span class=\"n\">loss</span><span class=\"o\">=</span><span class=\"s\">\"mse\"</span><span class=\"p\">,</span> <span class=\"n\">optimizer</span><span class=\"o\">=</span><span class=\"n\">adam</span><span class=\"p\">)</span>\n\n        <span class=\"k\">return</span> <span class=\"n\">model</span>\n\n</code></pre></div></div>\n<h3 id=\"rgbグレースケール変換処理\">RGB→グレースケール変換処理</h3>\n<p>シミュレータの出力はRGB画像、モデルの入力はグレースケール画像なので、その変換を行うための関数。<br />\n<code class=\"language-plaintext highlighter-rouge\">cv2.dst = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)</code> で良い気もするが…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">rgb2gray</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">rgb</span><span class=\"p\">):</span>\n        <span class=\"s\">\"\"\"\n        take a numpy rgb image return a new single channel image converted to greyscale\n        \"\"\"</span>\n        <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">dot</span><span class=\"p\">(</span><span class=\"n\">rgb</span><span class=\"p\">[...,</span> <span class=\"p\">:</span><span class=\"mi\">3</span><span class=\"p\">],</span> <span class=\"p\">[</span><span class=\"mf\">0.299</span><span class=\"p\">,</span> <span class=\"mf\">0.587</span><span class=\"p\">,</span> <span class=\"mf\">0.114</span><span class=\"p\">])</span>\n\n</code></pre></div></div>\n\n<h3 id=\"入力画像前処理\">入力画像前処理</h3>\n<p>シミュレータの出力画像をモデルの入力データに変換する処理。<br />\nRGBからグレースケールに変換し、リサイズを行う。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">process_image</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">obs</span><span class=\"p\">):</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rgb2gray</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">obs</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ターゲットモデルのパラメータ更新\">ターゲットモデルのパラメータ更新</h3>\n\n<p>メインモデルのパラメータをターゲットモデルにコピーする</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">update_target_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span><span class=\"p\">.</span><span class=\"n\">set_weights</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">get_weights</span><span class=\"p\">())</span>\n\n</code></pre></div></div>\n\n<h3 id=\"現在の環境での次の行動を取得する\">現在の環境での次の行動を取得する</h3>\n\n<p>乱数を発生し、ε値以下だったら環境が生成したランダム値(<code class=\"language-plaintext highlighter-rouge\">self.action_space.sample()[0]</code>)を返す。<br />\nそれ以外はメインモデルで予測した結果を返す。<br />\nその際、モデルの出力結果そのままではなく、どのステアリング位置に当たるかの量子化を行って返す。<br />\n(得られるのはステアリング情報だけで、スロットル情報は固定値)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Get action from model using epsilon-greedy policy\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_action</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">rand</span><span class=\"p\">()</span> <span class=\"o\"><=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_space</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"c1\"># print(\"Return Max Q Prediction\")\n</span>            <span class=\"n\">q_value</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">)</span>\n\n            <span class=\"c1\"># Convert q array to steering value\n</span>            <span class=\"k\">return</span> <span class=\"n\">linear_unbin</span><span class=\"p\">(</span><span class=\"n\">q_value</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<h3 id=\"状態等の保存\">状態等の保存</h3>\n<p>現在の状態(state)、行動(action)、報酬(reward)、行動後の状態(next_state)、\n終了フラグ(done)をExperience Bufferに保存する。<br />\n(Experience Buffer は Experience Replayに使用するためのデータを保存しておくところ)<br />\n<code class=\"language-plaintext highlighter-rouge\">memory</code> は <code class=\"language-plaintext highlighter-rouge\">collections.dque()</code>で作成しているので、指定サイズを超えたときは古いデータから順に削除される。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">replay_memory</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">next_state</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">((</span><span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">next_state</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">))</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ε値の更新\">ε値の更新</h3>\n\n<p>現在のε値が最小値より大きかったら一定比率で小さくしていく。<br />\n最小値以下になっていたらそのまま。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">update_epsilon</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">></span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">-=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">-</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">explore</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ε値の初期設定\">ε値の初期設定</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプション追加したので、指定値でε値を変更する処理を追加。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">set_epsilon</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">epsilon</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"n\">epsilon</span>\n</code></pre></div></div>\n\n<h3 id=\"学習\">学習</h3>\n\n<p>Experience Bufferから任意の経験を取り出し、Q Networkをミニバッチ学習(Experience Replay)</p>\n\n<p>記憶したデータ数が<code class=\"language-plaintext highlighter-rouge\">self.train_start</code>に達するまでは何もしない。<br />\nバッチ学習に使用するデータをExperience Bufferから取り出し、<br />\nそれぞれの配列にバラす(<code class=\"language-plaintext highlighter-rouge\">state_t</code>,<code class=\"language-plaintext highlighter-rouge\">action_t</code>, <code class=\"language-plaintext highlighter-rouge\">reward_t</code>, <code class=\"language-plaintext highlighter-rouge\">state_t1</code>, <code class=\"language-plaintext highlighter-rouge\">terminal</code>)。<br />\n<code class=\"language-plaintext highlighter-rouge\">state_t</code>と<code class=\"language-plaintext highlighter-rouge\">state_t1</code>は<code class=\"language-plaintext highlighter-rouge\">np.concatenate()</code>でndarrayにまとめておく。<br />\n11行目の<code class=\"language-plaintext highlighter-rouge\">self.model.predict(state_t)</code>は<code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>の取得にしか使用されておらず、</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>はステータス表示にしか使用されてなく、無駄な計算なので、削除するのが良いと思われる(無駄な計算なので)。<br />\nその場合、<code class=\"language-plaintext highlighter-rouge\">targets</code>の初期化は<code class=\"language-plaintext highlighter-rouge\">targets = np.zeros((batch_size, 15))</code>で行う。<br />\n(<code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>を参照しているところも削除。あるいは<code class=\"language-plaintext highlighter-rouge\">get_action()</code>で戻り値として返すのも手か。)</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">state_t1</code>を入力としてメインモデルをターゲットモデルを使用して得られた出力から出力期待値を取得し、<br />\n学習を行う<code class=\"language-plaintext highlighter-rouge\">self.model.train_on_batch(state_t, targets)</code>。<br />\nこの辺は\n<a href=\"https://www.tcom242242.net/entry/ai-2/%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92/%e3%80%90%e6%b7%b1%e5%b1%a4%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92%e3%80%91double-q-network/\" target=\"_blank\">【深層強化学習】Double Deep Q Network(DDQN)</a>\nのソースとかを見ると分かったような分からないような気になれるかも…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">train_replay</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train_start</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span>\n\n        <span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">batch_size</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">))</span>\n        <span class=\"n\">minibatch</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">,</span> <span class=\"n\">batch_size</span><span class=\"p\">)</span>\n\n        <span class=\"n\">state_t</span><span class=\"p\">,</span> <span class=\"n\">action_t</span><span class=\"p\">,</span> <span class=\"n\">reward_t</span><span class=\"p\">,</span> <span class=\"n\">state_t1</span><span class=\"p\">,</span> <span class=\"n\">terminal</span> <span class=\"o\">=</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">minibatch</span><span class=\"p\">)</span>\n        <span class=\"n\">state_t</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">concatenate</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">)</span>\n        <span class=\"n\">state_t1</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">concatenate</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"n\">targets</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">max_Q</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n        <span class=\"n\">target_val</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"n\">target_val_</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">batch_size</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">terminal</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]:</span>\n                <span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">action_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">reward_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">target_val</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">])</span>\n                <span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">action_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">reward_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">discount_factor</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">target_val_</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">a</span><span class=\"p\">])</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">train_on_batch</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">,</span> <span class=\"n\">targets</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"モデルのロード\">モデルのロード</h3>\n\n<p>モデルの読み込み先はメインモデル。<br />\nこのあと、ターゲットモデルへコピーするので、ここではターゲットモデルは触らない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">load_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">load_weights</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"モデルの保存\">モデルの保存</h3>\n\n<p>メインモデルをファイルに保存する。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Save the model which is under training\n</span>    <span class=\"k\">def</span> <span class=\"nf\">save_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save_weights</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"ステアリング角モデル出力形式変換\">ステアリング角→モデル出力形式変換</h2>\n\n<p>ステアリング角(-1~1)をモデル出力形式(要素数15の配列のどれか1つに1が入る)に変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">linear_bin</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    Convert a value to a categorical array.\n\n    Parameters\n    ----------\n    a : int or float\n        A value between -1 and 1\n\n    Returns\n    -------\n    list of int\n        A list of length 15 with one item set to 1, which represents the linear value, and all other items set to 0.\n    \"\"\"</span>\n    <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    <span class=\"n\">b</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">a</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"mi\">2</span> <span class=\"o\">/</span> <span class=\"mi\">14</span><span class=\"p\">))</span>\n    <span class=\"n\">arr</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">)</span>\n    <span class=\"n\">arr</span><span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">b</span><span class=\"p\">)]</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">return</span> <span class=\"n\">arr</span>\n</code></pre></div></div>\n\n<h2 id=\"モデル出力形式ステアリング角変換\">モデル出力形式→ステアリング角変換</h2>\n\n<p>モデル出力のうち、最大値を持つindexに相当するステアリング角を取得する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">linear_unbin</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    Convert a categorical array to value.\n\n    See Also\n    --------\n    linear_bin\n    \"\"\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">15</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"nb\">ValueError</span><span class=\"p\">(</span><span class=\"s\">\"Illegal array length, must be 15\"</span><span class=\"p\">)</span>\n    <span class=\"n\">b</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">)</span>\n    <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">b</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"mi\">2</span> <span class=\"o\">/</span> <span class=\"mi\">14</span><span class=\"p\">)</span> <span class=\"o\">-</span> <span class=\"mi\">1</span>\n    <span class=\"k\">return</span> <span class=\"n\">a</span>\n</code></pre></div></div>\n\n<h2 id=\"メインルーチン\">メインルーチン</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">run_ddqn</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    run a DDQN training session, or test it's result, with the donkey simulator\n    \"\"\"</span>\n</code></pre></div></div>\n\n<h3 id=\"tensorflow-1131でのおまじない\">Tensorflow 1.13.1でのおまじない</h3>\n\n<p>Tensorflow 2 を使用したかったので、処理不要。<br />\nコメントアウトすれば良いのだけれど、なんとなくバージョンで分けてみた。<br />\n1.14以降では要るのかな?要ると思って書いてみた。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tf_ver</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">__version__</span><span class=\"p\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">'.'</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">tf_ver</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">tf_ver</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"mi\">13</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># only needed if TF==1.13.1\n</span>        <span class=\"n\">config</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">ConfigProto</span><span class=\"p\">()</span>\n        <span class=\"n\">config</span><span class=\"p\">.</span><span class=\"n\">gpu_options</span><span class=\"p\">.</span><span class=\"n\">allow_growth</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"n\">sess</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">Session</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">=</span><span class=\"n\">config</span><span class=\"p\">)</span>\n        <span class=\"n\">K</span><span class=\"p\">.</span><span class=\"n\">set_session</span><span class=\"p\">(</span><span class=\"n\">sess</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"シミュレータ環境の構築\">シミュレータ環境の構築</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">body_style</code> には <code class=\"language-plaintext highlighter-rouge\">donkey</code>、 <code class=\"language-plaintext highlighter-rouge\">bare</code>、<code class=\"language-plaintext highlighter-rouge\">car01</code>、<code class=\"language-plaintext highlighter-rouge\">cybertruck</code>、<code class=\"language-plaintext highlighter-rouge\">f1</code>が使用できるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">body_rgb</code> で 色を指定できるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">car_name</code> でシミュレータに表示される名前を指定。複数の車を走らせるときに見分けられるみたい。<br />\n<code class=\"language-plaintext highlighter-rouge\">font_size</code>で名前のフォントサイズを指定。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s\">\"exe_path\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sim</span><span class=\"p\">,</span>\n        <span class=\"s\">\"host\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">host</span><span class=\"p\">,</span>\n        <span class=\"s\">\"port\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">port</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_style\"</span><span class=\"p\">:</span> <span class=\"s\">\"donkey\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_rgb\"</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span>\n        <span class=\"s\">\"car_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"me\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"font_size\"</span><span class=\"p\">:</span> <span class=\"mi\">100</span><span class=\"p\">,</span>\n        <span class=\"s\">\"racer_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"DDQN\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"country\"</span><span class=\"p\">:</span> <span class=\"s\">\"USA\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"bio\"</span><span class=\"p\">:</span> <span class=\"s\">\"Learning to drive w DDQN RL\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"guid\"</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"p\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()),</span>\n        <span class=\"s\">\"max_cte\"</span><span class=\"p\">:</span> <span class=\"mi\">10</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\"># Construct gym environment. Starts the simulator if path is given.\n</span>    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">make</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">env_name</span><span class=\"p\">,</span> <span class=\"n\">conf</span><span class=\"o\">=</span><span class=\"n\">conf</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"プログラム終了時のフックルーチンの定義と登録\">プログラム終了時のフックルーチンの定義と登録</h3>\n\n<p>プログラム終了時にシミュレータの終了処理を行うようにフックルーチンを登録する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># not working on windows...\n</span>    <span class=\"k\">def</span> <span class=\"nf\">signal_handler</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"catching ctrl+c\"</span><span class=\"p\">)</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">unwrapped</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGINT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGTERM</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGABRT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"パラメータ用変数の定義\">パラメータ用変数の定義</h3>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Get size of state and action from environment\n</span>    <span class=\"n\">state_size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">,</span> <span class=\"n\">img_channels</span><span class=\"p\">)</span>\n    <span class=\"n\">action_space</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">action_space</span>  <span class=\"c1\"># Steering and Throttle\n</span></code></pre></div></div>\n\n<h3 id=\"エージェントの生成\">エージェントの生成</h3>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">agent</span> <span class=\"o\">=</span> <span class=\"n\">DQNAgent</span><span class=\"p\">(</span><span class=\"n\">state_size</span><span class=\"p\">,</span> <span class=\"n\">action_space</span><span class=\"p\">,</span> <span class=\"n\">train</span><span class=\"o\">=</span><span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ε値の設定\">ε値の設定</h3>\n\n<p>オプションでε値が指定されていたら設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">></span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">set_epsilon</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スロットル値の設定\">スロットル値の設定</h3>\n\n<p>スロットルの設定は固定値(コマンドラインオプションで設定)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">throttle</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">throttle</span>  <span class=\"c1\"># Set throttle as constant value\n</span>\n        <span class=\"n\">episodes</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n</code></pre></div></div>\n\n<h3 id=\"モデルのロード-1\">モデルのロード</h3>\n\n<p>モデルファイルがあれば読み込む。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">):</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"load the saved model\"</span><span class=\"p\">)</span>\n            <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">load_model</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"学習ループ\">学習ループ</h3>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">for</span> <span class=\"n\">e</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">EPISODES</span><span class=\"p\">):</span>\n\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Episode: \"</span><span class=\"p\">,</span> <span class=\"n\">e</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h4 id=\"スタート位置へ移動\">スタート位置へ移動</h4>\n\n<p><code class=\"language-plaintext highlighter-rouge\">obs</code> ← スタート時のカメラ画像<br />\n<code class=\"language-plaintext highlighter-rouge\">x_t</code> ← <code class=\"language-plaintext highlighter-rouge\">obs</code> をモデルの入力形式に合わせて変換(グレースケール化&リサイズ) <br />\n<code class=\"language-plaintext highlighter-rouge\">s_t</code> ← <code class=\"language-plaintext highlighter-rouge\">x_t</code>を4枚分コピー(入力画像は過去4枚分を使用するので)(ちゃんと<code class=\"language-plaintext highlighter-rouge\">img_channels</code>参照して欲しいけど)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"n\">done</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">reset</span><span class=\"p\">()</span>\n\n            <span class=\"n\">episode_len</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n            <span class=\"n\">x_t</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">process_image</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n\n            <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">stack</span><span class=\"p\">((</span><span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">),</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"c1\"># In Keras, need to reshape\n</span>            <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>  <span class=\"c1\"># 1*80*80*4\n</span></code></pre></div></div>\n\n<h4 id=\"エピソードループ\">エピソードループ</h4>\n\n<p>終了フラグがセットされるまでループ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">done</span><span class=\"p\">:</span>\n</code></pre></div></div>\n\n<h5 id=\"現在の状態から行動を予測しシミュレータで実行\">現在の状態から行動を予測し、シミュレータで実行</h5>\n\n<p><code class=\"language-plaintext highlighter-rouge\">steering</code> ← 予測結果<br />\n<code class=\"language-plaintext highlighter-rouge\">env.step()</code>でシミュレータステップ実行<br />\n<code class=\"language-plaintext highlighter-rouge\">x_t1</code> ←ステップ実行後のカメラ画像<br />\n<code class=\"language-plaintext highlighter-rouge\">s_t1</code> ← 現在の入力データの一番古いものを削除し、今回の画像を追加</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"c1\"># Get action for the current state and go one step in environment\n</span>                <span class=\"n\">steering</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">get_action</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">)</span>\n                <span class=\"n\">action</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">steering</span><span class=\"p\">,</span> <span class=\"n\">throttle</span><span class=\"p\">]</span>\n                <span class=\"n\">next_obs</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">,</span> <span class=\"n\">info</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">(</span><span class=\"n\">action</span><span class=\"p\">)</span>\n\n                <span class=\"n\">x_t1</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">process_image</span><span class=\"p\">(</span><span class=\"n\">next_obs</span><span class=\"p\">)</span>\n\n                <span class=\"n\">x_t1</span> <span class=\"o\">=</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"mi\">1</span><span class=\"p\">)</span>  <span class=\"c1\"># 1x80x80x1\n</span>                <span class=\"n\">s_t1</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">x_t1</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">:,</span> <span class=\"p\">:</span><span class=\"mi\">3</span><span class=\"p\">],</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>  <span class=\"c1\"># 1x80x80x4\n</span></code></pre></div></div>\n\n<h5 id=\"experience-bufferに現在の状態を保存\">Experience Bufferに現在の状態を保存</h5>\n\n<p>ε値の更新も</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"c1\"># Save the sample <s, a, r, s'> to the replay memory\n</span>                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">replay_memory</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">linear_bin</span><span class=\"p\">(</span><span class=\"n\">steering</span><span class=\"p\">)),</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">s_t1</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">)</span>\n                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">update_epsilon</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h5 id=\"学習実行\">学習実行</h5>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n                    <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train_replay</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h5 id=\"ループ更新処理とステータス表示\">ループ更新処理とステータス表示</h5>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">s_t1</span>\n                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"n\">episode_len</span> <span class=\"o\">=</span> <span class=\"n\">episode_len</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">%</span> <span class=\"mi\">30</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span>\n                        <span class=\"s\">\"EPISODE\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">e</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"TIMESTEP\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ ACTION\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">action</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ REWARD\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">reward</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ EPISODE LENGTH\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">episode_len</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ Q_MAX \"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">max_Q</span><span class=\"p\">,</span>\n                    <span class=\"p\">)</span>\n</code></pre></div></div>\n<h5 id=\"ループ更新処理とステータス表示-1\">ループ更新処理とステータス表示</h5>\n\n<p><code class=\"language-plaintext highlighter-rouge\">agent.update_target_model()</code>でターゲットモデルの更新\n<code class=\"language-plaintext highlighter-rouge\">episodes.append(e)</code>はデバッグ用?</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"k\">if</span> <span class=\"n\">done</span><span class=\"p\">:</span>\n\n                    <span class=\"c1\"># Every episode update the target model to be same with model\n</span>                    <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">update_target_model</span><span class=\"p\">()</span>\n\n                    <span class=\"n\">episodes</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n\n                    <span class=\"c1\"># Save model for each episode\n</span>                    <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">save_model</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n\n                    <span class=\"k\">print</span><span class=\"p\">(</span>\n                        <span class=\"s\">\"episode:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">e</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"  memory length:\"</span><span class=\"p\">,</span>\n                        <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">),</span>\n                        <span class=\"s\">\"  epsilon:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">,</span>\n                        <span class=\"s\">\" episode length:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">episode_len</span><span class=\"p\">,</span>\n                    <span class=\"p\">)</span>\n</code></pre></div></div>\n<h4 id=\"エピソードループと学習ループの終わり\">エピソードループと学習ループの終わり</h4>\n<p>キーボード割り込み例外と終了処理</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">except</span> <span class=\"nb\">KeyboardInterrupt</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stopping run...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">finally</span><span class=\"p\">:</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">unwrapped</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"コマンドライン解析処理まわり\">コマンドライン解析処理まわり</h2>\n\n<p>コマンドライン解析処理とメインルーチンへのジャンプ</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n\n    <span class=\"c1\"># Initialize the donkey environment\n</span>    <span class=\"c1\"># where env_name one of:\n</span>    <span class=\"n\">env_list</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-roads-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-avc-sparkfun-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-roboracingleague-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-waveshare-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-minimonaco-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-warren-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-thunderhill-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-circuit-launch-track-v0\"</span><span class=\"p\">,</span>\n    <span class=\"p\">]</span>\n\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s\">\"ddqn\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--sim\"</span><span class=\"p\">,</span>\n        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span>\n        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"manual\"</span><span class=\"p\">,</span>\n        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\"</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--host\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"127.0.0.1\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"simulator address\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"rl_driver.h5\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"agent uses learned model to navigate env\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--port\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">9091</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for websockets\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--throttle\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.3</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"constant throttle for driving\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--env_name\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"name of donkey sim environment\"</span><span class=\"p\">,</span> <span class=\"n\">choices</span><span class=\"o\">=</span><span class=\"n\">env_list</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--epsilon\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"initial epsilon value\"</span><span class=\"p\">)</span>\n\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n    <span class=\"n\">run_ddqn</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"でもってこんな改造をするとちょびっと計算量が減る\">でもって、こんな改造をするとちょびっと計算量が減る</h2>\n<p>シミュレータに表示される車を変更してるのはご愛敬😅</p>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ddqn.py.old\t2021-12-02 06:25:02.149997073 +0900\n</span><span class=\"gi\">+++ ddqn.py\t2021-12-03 07:14:49.346378878 +0900\n</span><span class=\"p\">@@ -98,9 +98,10 @@</span>\n         return np.dot(rgb[..., :3], [0.299, 0.587, 0.114])\n \n     def process_image(self, obs):\n<span class=\"gd\">-        obs = self.rgb2gray(obs)\n-        obs = cv2.resize(obs, (img_rows, img_cols))\n-        return obs\n</span><span class=\"gi\">+        # obs1 = self.rgb2gray(obs)\n+        obs1 = cv2.dst = cv2.cvtColor(obs, cv2.COLOR_RGB2GRAY)\n+        obs2 = cv2.resize(obs1, (img_rows, img_cols))\n+        return obs2\n</span> \n     def update_target_model(self):\n         self.target_model.set_weights(self.model.get_weights())\n<span class=\"p\">@@ -108,13 +109,17 @@</span>\n     # Get action from model using epsilon-greedy policy\n     def get_action(self, s_t):\n         if np.random.rand() <= self.epsilon:\n<span class=\"gd\">-            return self.action_space.sample()[0]\n</span><span class=\"gi\">+            return self.action_space.sample()[0], 0\n</span>         else:\n             # print(\"Return Max Q Prediction\")\n             q_value = self.model.predict(s_t)\n \n<span class=\"gi\">+            max_q = np.amax(q_value[0])\n+            if self.max_Q < max_q :\n+                self.max_Q = max_q\n+\n</span>             # Convert q array to steering value\n<span class=\"gd\">-            return linear_unbin(q_value[0])\n</span><span class=\"gi\">+            return linear_unbin(q_value[0]), max_q\n</span> \n     def replay_memory(self, state, action, reward, next_state, done):\n         self.memory.append((state, action, reward, next_state, done))\n<span class=\"p\">@@ -136,16 +141,16 @@</span>\n         state_t, action_t, reward_t, state_t1, terminal = zip(*minibatch)\n         state_t = np.concatenate(state_t)\n         state_t1 = np.concatenate(state_t1)\n<span class=\"gd\">-        targets = self.model.predict(state_t)\n-        self.max_Q = np.max(targets[0])\n-        target_val = self.model.predict(state_t1)\n-        target_val_ = self.target_model.predict(state_t1)\n</span><span class=\"gi\">+\n+        targets = np.zeros((batch_size, 15))\n+        q_val = self.model.predict(state_t1)\n+        target_q_val = self.target_model.predict(state_t1)\n</span>         for i in range(batch_size):\n             if terminal[i]:\n                 targets[i][action_t[i]] = reward_t[i]\n             else:\n<span class=\"gd\">-                a = np.argmax(target_val[i])\n-                targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_val_[i][a])\n</span><span class=\"gi\">+                a = np.argmax(q_val[i])\n+                targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_q_val[i][a])\n</span> \n         self.model.train_on_batch(state_t, targets)\n \n<span class=\"p\">@@ -213,8 +218,8 @@</span>\n         \"exe_path\": args.sim,\n         \"host\": args.host,\n         \"port\": args.port,\n<span class=\"gd\">-        \"body_style\": \"donkey\",\n-        \"body_rgb\": (128, 128, 128),\n</span><span class=\"gi\">+        \"body_style\": \"f1\",\n+        \"body_rgb\": (255, 128, 128),\n</span>         \"car_name\": \"me\",\n         \"font_size\": 100,\n         \"racer_name\": \"DDQN\",\n<span class=\"p\">@@ -273,7 +278,7 @@</span>\n             while not done:\n \n                 # Get action for the current state and go one step in environment\n<span class=\"gd\">-                steering = agent.get_action(s_t)\n</span><span class=\"gi\">+                steering, max_Q = agent.get_action(s_t)\n</span>                 action = [steering, throttle]\n                 next_obs, reward, done, info = env.step(action)\n \n<span class=\"p\">@@ -305,7 +310,7 @@</span>\n                         \"/ EPISODE LENGTH\",\n                         episode_len,\n                         \"/ Q_MAX \",\n<span class=\"gd\">-                        agent.max_Q,\n</span><span class=\"gi\">+                        max_Q,\n</span>                     )\n \n                 if done:\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi向け)のbuild</h1>\n      <p>Raspberry Pi向けopenVINOのbuild(特にCPU extension)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi用 openVINO は デフォルト状態ではCPUで実行できない(NCS2必須)。<br />\nそこで、オープンソース版openVINOを使用してCPU extensionを作成してみる。<br />\nとはいえ、CPU extension だけサクっと作成できなくて、openVINO全体を作成するハメに…</p>\n\n<p>Raspberry Pi 実機でbuildすると、ディスク容量がバカにならないし、<br />\nあまり実環境を弄りたくなかったので、<br />\nUbuntuマシン上のDockerコンテナで実行する方法を試してみる(Docker Desktop for Windowsでもできると思う)</p>\n\n<h1 id=\"arm版dockerコンテナを使用したセルフコンパイル\">ARM版Dockerコンテナを使用したセルフコンパイル</h1>\n\n<p>Dockerコンテナ全体をQEMU上でARMエミュレーションしてくれるので、特に難しいことを考えずに<br />\nネイティブ環境と変わりなくあつかえる。<br />\nでも、かなり遅い(実機よりちょっと速い?同じくらい?)。<br />\n試した環境では、x86_64な環境でクロスコンパイルした場合の15倍くらいかかった。  <br />\n(M1 Mac上でACVMを使うとかなり早いという噂も…M1 Mac持ってない😢  <a href=\"https://qiita.com/kose3/items/af9edc9c40c9ae8fc5c3\" target=\"_blank\">参考</a>  )</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h3 id=\"qemuのインストール\">qemuのインストール</h3>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_emu\n</code></pre></div></div>\n\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm32v7/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成\">patchファイルを作成</h3>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_emu_1 ov_pi_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n以下のオプションを追加すると少しは速くなるかと思ったが、あまり変わらない。</p>\n  <ul>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_OPENCV=OFF</code></li>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_SAMPLES=OFF</code></li>\n  </ul>\n</blockquote>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。</p>\n\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./inference_engine</code> がない\n    <ul>\n      <li>実体は <code class=\"language-plaintext highlighter-rouge\">deployment_tools/inference_engine</code> なので、シンボリックリンクを作れば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/opencv/</code>からコピーすれば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>opencvのpythonモジュールがない\n        <ul>\n          <li>どこから持ってくれば良いんだろう?</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h3 id=\"実機へのインストール\">実機へのインストール</h3>\n<p>CPU extensionだけなら<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l/</code><br />\nへコピーするだけで良い。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれはmake install してもこれはコピーされないらしい。</p>\n</blockquote>\n\n<p>openVINO全体のインストールなら<code class=\"language-plaintext highlighter-rouge\">work/opt/intel/openvino</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/</code>にコピーすれば良いのだけど、opencvのpythonインタフェースがないので注意。<br />\nということで、実際に試していない…</p>\n\n<blockquote>\n  <p>[!NOTE]\n※※※※ メモ ※※※※ <br />\nopenCVはここでbuildするのではなく、<br />\n<a href=\"https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/\" target=\"_blank\">https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/</a> \nからbuild済みモジュールをダウンロードして<br />\n<code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/</code><br />\nに展開している。</p>\n</blockquote>\n\n<h1 id=\"i386版32bit-x86dockerコンテナを使用したクロスコンパイル\">i386版(32bit x86)Dockerコンテナを使用したクロスコンパイル</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>セルフコンパイルは時間がかかりすぎるので、クロスコンパイルで試してみた。<br />\nかなり早くなったが、一部使えないモジュールが…<br />\n当初の目的のCPU extensionは使えるので、掲載しとく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n当初、64bit版debianをベースに作業しようとしたが、\npybind11のbuildで以下のように怒られる。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Make Error at build/_deps/pybind11-src/tools/FindPythonLibsNew.cmake:127 (message):\n  Python config failure: Python is 64-bit, chosen compiler is 32-bit\nCall Stack (most recent call first):\n  build/_deps/pybind11-src/tools/pybind11Tools.cmake:16 (find_package)\n  build/_deps/pybind11-src/CMakeLists.txt:33 (include)\n</code></pre></div>  </div>\n  <p>以下のような対策が考えられる。</p>\n  <ul>\n    <li>FindPythonLibsNew.cmakeにbit数チェックをしないようにパッチを当てる\n      <ul>\n        <li>やり方がよう分からん…</li>\n      </ul>\n    </li>\n    <li>amd64なdebianに32bitのpythonをインストールする\n      <ul>\n        <li>イマイチうまくインストールできなかった</li>\n      </ul>\n    </li>\n  </ul>\n\n  <p>しかたないので、32bit版debianで作ることにした</p>\n</blockquote>\n\n<h2 id=\"準備-1\">準備</h2>\n\n<h3 id=\"作業用ディレクトリの準備-1\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_buster_32 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_buster_32\n</code></pre></div></div>\n<h3 id=\"openvino-の-gitリポジトリを-clone-1\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> i386/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> armhf <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-armhf <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:armhf <span class=\"se\">\\\n</span>    libgtk-3-dev:armhf <span class=\"se\">\\\n</span>    libavcodec-dev:armhf <span class=\"se\">\\\n</span>    libavformat-dev:armhf <span class=\"se\">\\\n</span>    libswscale-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:armhf <span class=\"se\">\\\n</span>    libpython3-dev:armhf <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python-argparse <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"c\"># aptでインストールするので削除</span>\n<span class=\"c\"># RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.3/cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     tar xzvf cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     (cd cmake-3.21.3 && ./bootstrap --parallel=$(nproc --all) -- -DCMAKE_USE_OPENSSL=OFF && make --jobs=$(nproc --all) && make install) && \\</span>\n<span class=\"c\">#     rm -rf cmake-3.21.3 cmake-3.21.3.tar.gz</span>\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"patchファイルを作成-1\">patchファイルを作成</h3>\n\n<p>以下の2つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch1.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake\nindex 6cb15a0..66a1ef6 100644\n</span><span class=\"gd\">--- a/cmake/dependencies.cmake\n</span><span class=\"gi\">+++ b/cmake/dependencies.cmake\n</span><span class=\"p\">@@ -19,8 +19,9 @@</span> if(CMAKE_CROSSCOMPILING AND CMAKE_HOST_SYSTEM_NAME MATCHES Linux AND CMAKE_HOST_\n     find_program(\n         SYSTEM_PROTOC\n         NAMES protoc\n<span class=\"gd\">-        PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n-        NO_DEFAULT_PATH)\n</span><span class=\"gi\">+        # PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n+        # NO_DEFAULT_PATH)\n+        )\n</span>     if(NOT SYSTEM_PROTOC)\n         message(FATAL_ERROR \"[ONNX IMPORTER] Missing host protoc binary\")\n     endif()\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる-1\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../patch1.patch<span class=\"o\">)</span>\n<span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino apply ../../patch1.patch\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_buster_32 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32_1</code> を使用。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_buster_32_1 ov_pi_buster_32 /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/386) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_buster_32_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_buster_32_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make-1\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n\n<p>コンテナから出て、<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の \n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l</code>/<br />\nへコピーする</p>\n\n<blockquote>\n  <p>[!WARNING]\ncythonの出力がx86のコードを吐くので、pythonモジュールの一部に正常に動作しないものがある。<br />\npythonモジュールを使いたいときはセルフコンパイルするしかないかな?</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerでopenVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerでopenVINO</h1>\n      <p>DockerでopenVINOプログラムの開発</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>DockerコンテナでopenVINOのプログラム開発を行う手順。<br />\n↓ここを参考にUbuntu 20.04/openVINO 2021.3に変更してみる。ついでによく使う機能の準備もやっておく。<br />\n<a href=\"https://kuttsun.blogspot.com/2021/06/openvino-docker.html\">https://kuttsun.blogspot.com/2021/06/openvino-docker.html</a></p>\n\n<h1 id=\"dockerイメージの作成\">Dockerイメージの作成</h1>\n\n<p>上の参照先を参考に公式イメージに必要な処理を加えておく。<br />\nDockerfile は以下。<br />\n参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>ベースをopenVINO/ubuntu20に変更</li>\n  <li>sudoとvimとless入れとく。sudoはパスワードなしで動作するようにしとく。</li>\n  <li>開発マシンなのでbaskhの補完機能を有効にしておく</li>\n  <li>キーバインド変更 ( <code class=\"language-plaintext highlighter-rouge\">^p</code> / <code class=\"language-plaintext highlighter-rouge\">^n</code> )</li>\n  <li>日本語文字化け対策</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code> がキー入力待ちになってbuildエラーになるので<code class=\"language-plaintext highlighter-rouge\">-y</code>オプションを追加</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-docker highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースイメージ</span>\n<span class=\"k\">FROM</span><span class=\"s\"> openvino/ubuntu20_dev:2021.3</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">ENV</span><span class=\"s\"> DEBIAN_FRONTEND=noninteractive</span>\n\n<span class=\"c\"># sudo と vim と less のインストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install sudo </span>vim less <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo </span>openvino <span class=\"nv\">ALL</span><span class=\"o\">=</span><span class=\"se\">\\(</span>root<span class=\"se\">\\)</span> NOPASSWD:ALL <span class=\"o\">></span> /etc/sudoers.d/openvino <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">chmod </span>0440 /etc/sudoers.d/openvino\n\n<span class=\"c\"># bashの補完機能 & キーバインドの設定 & 日本語文字化け対策</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nb\">install </span>bash-completion <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"s2\">\". /usr/share/bash-completion/bash_completion\"</span> <span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-n</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-forward' </span><span class=\"se\">\\n\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-p</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-backward'</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">export LANG=C.UTF-8</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">export LANGUAGE=en_US:</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc\n\n<span class=\"c\"># 依存パッケージのインストール(-yオプションで Yes自動選択)</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies <span class=\"o\">&&</span> ./install_openvino_dependencies.sh <span class=\"nt\">-y</span>\n\n<span class=\"c\"># サンプル、デモアプリのビルド</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/samples/cpp <span class=\"o\">&&</span> ./build_samples.sh\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/demos <span class=\"o\">&&</span> ./build_demos.sh\n<span class=\"c\"># /opt/intel/openvino_2021/deployment_tools/demo にデモアプリがある</span>\n\n<span class=\"c\"># 他に必要なものを適宜インストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>wget git python3-pip\n<span class=\"k\">RUN </span>pip3 <span class=\"nb\">install </span>onnxruntime flask\n\n<span class=\"c\"># aptのクリア</span>\n<span class=\"k\">RUN </span>apt clean <span class=\"o\">&&</span> <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> /var/lib/apt/lists/<span class=\"k\">*</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> openvino</span>\n\n<span class=\"c\"># bash起動</span>\n<span class=\"k\">CMD</span><span class=\"s\"> [ \"/bin/bash\" ]</span>\n</code></pre></div></div>\n\n<h1 id=\"ビルド\">ビルド</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker build <span class=\"nt\">-t</span> myopenvino/ubuntu20_dev:2021.3 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h1 id=\"コンテナの生成\">コンテナの生成</h1>\n<p>参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>カレントディレクトリ下のworkを/workに割り当てるように追加</li>\n  <li>GPU関連の設定を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ./work\ndocker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"se\">\\</span>\n       <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"se\">\\</span>\n       myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nX-Windowの表示先(<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code> 変数) は ここで固定されるので、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を変更したい場合は<br />\nコンテナをスタートした後、コンテナ内で手打ちで設定するか、<br />\n変更後の<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を設定したターミナルから以下を実行。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> openvino_2021.3 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<p>Windows の場合は以下な感じ。<br />\nDISPLAY変数は環境に合わせて変更してちょ。<br />\nNCS周りの設定は削除してある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.204:0.0 <span class=\"nt\">-v</span> %CD%<span class=\"se\">\\w</span>ork:/work myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ndocker をWSL上のコマンドラインから起動しているときは<code class=\"language-plaintext highlighter-rouge\">%CD%</code>でなく<code class=\"language-plaintext highlighter-rouge\">$PWD</code><br />\nPowerShellでコマンドを複数行に分割する場合は、行末記号は<code class=\"language-plaintext highlighter-rouge\">\\</code> ではなく <code class=\"language-plaintext highlighter-rouge\">`</code><br />\nコマンドプロンプトでは<code class=\"language-plaintext highlighter-rouge\">^</code> NYAGOSは分からん😢<br />\nそれぞれ違ってびみょーにストレス…</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> openvino_2021.3\n</code></pre></div></div>\n\n<p>コンテナ内でデモを動かしてみる<br />\n(デモの実行で必要なライブラリ類がインストールされたりするので、実行しましょう)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ~/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/demo1.log\n\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/dem2.log\n</code></pre></div></div>\n\n<p>前に作ったプログラムを試してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\ngit clone https://github.com/ippei8jp/ov_trial.git\n<span class=\"c\"># 入力画像の準備</span>\n<span class=\"nb\">cd </span>ov_trial/images/\nbash download.sh\n<span class=\"c\"># モデルファイルの準備(mobilenet-ssdのダウンロードがエラーになるけど大勢に影響ない) </span>\n<span class=\"nb\">cd</span> ../convert_model_ssd/\nbash convert_model_ssd.sh \n\n<span class=\"c\"># 認識してみる</span>\n<span class=\"nb\">cd</span> ../ssd/\nbash test.sh list\nbash test.sh 6\n</code></pre></div></div>\n\n<h1 id=\"ncs2の使用ubuntuのみ\">NCS2の使用(ubuntuのみ)</h1>\n<p>ubuntuではホストに接続したNCS2を使用することもできる。<br />\nただし、DockerコンテナからNCS2を使用するにはDokerホスト側にドライバをインストールしておく必要がある。<br />\n(udevルールだけ?イマイチ自信ないのでフルパッケージでインストールしておいた)<br />\n以下の部分がNCS2を使用するために必要な設定。(上記コマンド例では設定済み)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</h1>\n      <p>ローカル(Windows)のVSCodeからリモートホスト(ubuntu)上のDockerコンテナ内のプログラムをデバッグする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからUbuntu上のDockerコンテナに接続してデバッグする方法。</p>\n\n<p>UbuntuへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>\nsudo なしで Docker動かせるようにしとく必要あり</p>\n\n<h1 id=\"リモートホストへの接続\">リモートホストへの接続</h1>\n<p>UbuntuへのSSH接続の準備については<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">こちら</a></p>\n\n<h2 id=\"手順\">手順</h2>\n<ul>\n  <li>WindowsマシンでVScode 起動する</li>\n  <li>拡張機能「Remote Development」をインストールしておく。</li>\n  <li>左下にある「><」ボタンをクリック</li>\n  <li>上にメニューが出るので、「Connect to host…」 または「Connect Current Window to Host…」を選択</li>\n  <li>続いて「Select configured SSH host~」で接続するホストを選択。\n    <ul>\n      <li>新規接続の場合は「Add New SSH Host…」を選択</li>\n      <li>「ssh «user»@«IPアドレス or マシン名»」</li>\n      <li>設定を保存するファイルを選択。特に理由がなければ c:\\Users\\«ユーザ».config でいいかな。</li>\n      <li>右下に「Host added!」ウィンドウが出るので「Connect」をクリック</li>\n      <li>初めて接続するホストの場合、上にSelect the platform of remote host “~” と聞かれるのでOS種別を選択</li>\n      <li>「あんた«OS»を選らんだでー。~に保存したから変えたかったら ここ変更しぃや~」みたいなことを言ってるウィンドウが出るので「Don’t Show Again」をクリック</li>\n    </ul>\n  </li>\n  <li>接続された。右下の「><」ボタンが「>< SSH:«マシン名»」に変わっている。</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n一度接続すればリモートエクスプローラ(SSH TARGETS)に表示されるのでそこから接続しても良い。</p>\n</blockquote>\n\n<p>リモートホスト上のプログラムをデバッグしたい場合はここでフォルダを開いてごちょごちょやればよい。</p>\n\n<h1 id=\"dockerコンテナへの接続\">Dockerコンテナへの接続</h1>\n<h2 id=\"準備\">準備</h2>\n<p>WindowsマシンにDocker desktop for windows が必要になるので、インストールしておく。<br />\nWindowsへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\">こちら</a><br />\nCLIだけでよさそうなんだけど、CLIだけってのがどこかにあるのか分からんかったのでとりあえず全部入れた。<br />\nDocker Desktopは動いてなくて良いので、Exitして可。<br />\n普段から使わないならDocker Dashboardの設定のGeneralから「Start Docker Desktop when you log in」のチェックを はずしておけばOK。</p>\n\n<h2 id=\"dockerexeで疎通確認\">docker.exeで疎通確認</h2>\n<p>コマンドプロンプト等で以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">set </span><span class=\"nv\">DOCKER_HOST</span><span class=\"o\">=</span>ssh://«ユーザ名»@«ホスト»\ndocker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<p>リモートホスト上のコンテナの状態が返ってくるか確認。</p>\n\n<h2 id=\"docker-hostの設定\">DOCKER HOSTの設定</h2>\n<p>VScodeの<code class=\"language-plaintext highlighter-rouge\">settings.json</code> に以下の一文を追加する。もちろん上で確認した内容で。</p>\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\">    </span><span class=\"nl\">\"docker.host\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"ssh://«ユーザ名»@«ホスト»\"</span><span class=\"err\">,</span><span class=\"w\">\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルにつなぎたいときはこの行をコメントアウト(<code class=\"language-plaintext highlighter-rouge\">//</code>をつける)すればOK。<br />\n<code class=\"language-plaintext highlighter-rouge\">setting.json</code>はJSONファイルだけど、 <code class=\"language-plaintext highlighter-rouge\">//</code>でコメントアウトできる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nVScode settings.json の開き方</p>\n  <ul>\n    <li>メニュー ファイル→ユーザ設定→ 設定</li>\n    <li>設定画面の右上のボタン「設定(JSON)を開く」をクリック</li>\n  </ul>\n\n  <p>または</p>\n  <ul>\n    <li>メニュー表示→コマンドパレット</li>\n    <li>Preference:  Open Settings(JSON) を選択</li>\n  </ul>\n</blockquote>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その1\">VScodeでリモート エクスプローラからリモートホストに接続(その1)</h2>\n<p>リモートホストに拡張機能 Docker と Docker Explorer をインストールしておき、\nDockerペインを開くとリモートホスト上のコンテナとかが見える</p>\n\n<p>ここでは既にリモートホスト上でコンテナ作成済みとする。<br />\n(イメージからコンテナ作ったりDockerfileからBuildしたりできると思うけど、今はおいとく)</p>\n\n<ul>\n  <li>接続するコンテナが起動していない場合はDockerペインで使用するコンテナを右クリック→Start でコンテナを起動</li>\n  <li>起動したら対象コンテナのアイコンが三角マークになる</li>\n  <li>同じくDockerペインで使用するコンテナを右クリック→Attach Visual Studio Code を選択</li>\n  <li>select the container to attach VS Code と聞かれるのでアタッチするコンテナを選択(コンテナ選択してAttachしたはずだけど、なぜかここで再度選択が必要)</li>\n  <li>初めて接続した場合は「Attaching to a container may execute arbitrary code」<br />\nと言われるので、変なコードが実行されないことが分かっていれば Got it をクリック</li>\n  <li>接続された。右下の「><」ボタンが「>< Conteiner «コンテナ名»」に変わっている。</li>\n</ul>\n\n<p>あとはリモート SSH や ローカルのDockerでのデバッグと同じ。</p>\n\n<h2 id=\"接続の終了\">接続の終了</h2>\n<p>接続を終了する場合は</p>\n<ul>\n  <li>メニュー表示→コマンドパレット</li>\n  <li>Remote:  Close Remote Connection を選択</li>\n</ul>\n\n<p>このとき、コンテナからだけでなく、リモートホストからも切断される。</p>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その2\">VScodeでリモート エクスプローラからリモートホストに接続(その2)</h2>\n<p>リモートエクスプローラ(Containers)で接続するコンテナを右クリックし、「Attach to Container」または「Attach in New Window」を選択<br />\n(コンテナが起動されていなければ起動して)コンテナに接続される。</p>\n\n<p>あんまりごちょごちょしなくて済むのでこっちの方がおススメかな。</p>\n\n<h1 id=\"ネットワークポート\">ネットワークポート</h1>\n<p>通常Cockerコンテナ内のネットワークポートをホストや外部コンピュータからアクセスするには、<br />\nコンテナ作成時に-p (–publish) オプションで接続を受け入れるポート番号を指定する必要があるが、<br />\nVScodeから接続している場合は、Docker内のネットワークポートにVScodeが実行されているマシンからlocalhost:«ポート番号»で接続できる。<br />\n(アクセス遅いけど、ちょっと別のポート開けて試したい なんて時には便利)</p>\n\n<p>ただし、これはDockerが動作しているホストコンピュータや他のコンピュータからはアクセスできない。<br />\nこれらからアクセスするには-pオプションを指定する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n<p><a href=\"https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0\">https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0</a><br />\n↑ここにある、「Remote-Containers: Open Folder in Container…」での手順はリモートホストに接続した状態では実行できないらしい。<br />\nどうしてもこのコンテナでデバッグしたい場合は、<br />\n一旦リモートホスト上でVSCodeを起動してコンテナを作成しておき、<br />\nその後ローカルPCからこのコンテナにアタッチするような手順をふめばデバッグできる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ubuntuにSSHサーバをセットアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ubuntuにSSHサーバをセットアップする</h1>\n      <p>ubuntuにSSHサーバをセットアップするし、公開鍵認証を設定する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuにsshサーバをセットアップする\">UbuntuにSSHサーバをセットアップする</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n\n<p>この状態でWindowsなどから以下のコマンドで接続するとパスワード認証でlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«ユーザ名»@«IPアドレス»<span class=\"s1\">'s password: «パスワードを入力»  \n</span></code></pre></div></div>\n\n<p>リモート接続でshellを使うだけならこれでも良いが、\nVScodeでリモートデバッグをしたりするときなどはパスワード入力を何回も行う必要があったりして面倒。<br />\nそこで、公開鍵認証を設定してパスワード入力を不要にする。</p>\n\n<h1 id=\"秘密鍵と公開鍵の生成と公開鍵ファイルの設置\">秘密鍵と公開鍵の生成と公開鍵ファイルの設置</h1>\n<p>Windowsマシンで以下のコマンドを実行して秘密鍵ファイルと公開鍵ファイルを生成する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh-keygen.exe <span class=\"nt\">-t</span> rsa\n<span class=\"o\">(</span>リターン3回<span class=\"o\">)</span>\n※ 本当はpassphase入れないといけないけど、ローカルお試し環境なので省略\n</code></pre></div></div>\n<p>実行すると以下のファイルが出来る</p>\n<ul>\n  <li>%USERPROFILE%/.ssh/id_rsa</li>\n  <li>%USERPROFILE%/.ssh/id_rsa.pub</li>\n</ul>\n\n<p>このうち、<code class=\"language-plaintext highlighter-rouge\">id_rsa.pub</code>をUbuntuマシンの <code class=\"language-plaintext highlighter-rouge\">~/.ssh</code>へ<code class=\"language-plaintext highlighter-rouge\">authorized_keys</code>というファイル名でコピー(既に存在する場合は追記)する。</p>\n<blockquote>\n  <p>[!NOTE]\nやり方検索すると<code class=\"language-plaintext highlighter-rouge\">scp</code>コマンドでコピーする方法が紹介されているが、\n家の中だけなのでネットワークドライブ経由でのコピーや\nファイル自体はテキストファイルなので、SSH接続したshellからエディタを起動して\nコピペするのでも良い。</p>\n</blockquote>\n\n<p>コピーが完了したらファイルのパーミッションを変更する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod </span>600 ~/.ssh/authorized_keys\n</code></pre></div></div>\n\n<h1 id=\"接続テスト\">接続テスト</h1>\n<p>この状態でWindowsマシンから以下のコマンドで接続するとパスワード認証なしでlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«パスワード入力なしで接続»\n</code></pre></div></div>\n\n<p>Windows側のユーザディレクトリ/.ssh/config の設定もやっておくと便利<br />\n参考: <a href=\"https://qiita.com/passol78/items/2ad123e39efeb1a5286b\">https://qiita.com/passol78/items/2ad123e39efeb1a5286b</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerコンテナからGUIを起動する</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerコンテナからGUIを起動する</h1>\n      <p>Windos/Ubuntu の DockerコンテナからGUIを起動する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuでローカルのデスクトップに表示する場合\">Ubuntuでローカルのデスクトップに表示する場合</h1>\n<p>Docker(ubuntu)のみ。<br />\nコンテナ生成時に以下のように<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数の設定と<code class=\"language-plaintext highlighter-rouge\">/tmp/.X11-unix/</code>のマウントを行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test3 <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n<p>この場合、表示する前にホスト側で以下を実行しておく必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>xhost +local:\n</code></pre></div></div>\n<p>実行していない場合、GUI起動コマンド実行で以下のエラーが出る。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>No protocol specified\nError: Can't open display: XXX\n</code></pre></div></div>\n\n<p>Ubuntuを再起動したときに設定は忘れられてしまうので、起動の度に実行必要。</p>\n\n<blockquote>\n  <p>[!NOTE]\nxhostはセキュリティ上問題があるとのことだが、家の中だけだし、localだけなら許可してもいいかな…\nrc.localあたりに書いとこうかと思ったけど、使用するときだけ実行するのが無難かな。</p>\n</blockquote>\n\n<h1 id=\"windows上のvcxsrvに表示する場合\">Windows上のVcXsrvに表示する場合</h1>\n<p>Docker(windows)だとコレ一択。<br />\nDocker(ubuntu)でも大丈夫。<br />\nなので、Docker(ubuntu)にリモート接続で使用することがある場合はこっちを使っておくのが良いと思う。<br />\nWindowsマシンのIPアドレスが192.168.XXX.XXX(マシン名指定不可)だとして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test4 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XXX.XXX:0.0 <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>VSCodeでDocker内のpythonプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>VSCodeでDocker内のpythonプログラムをデバッグする</h1>\n      <p>VSCodeでDocker内のpythonプログラムをデバッグする(Windos/Ubuntu)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからWindows上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nubuntu上のVSCodeからubuntu上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nどちらもほぼ同じ手順でデバッグできる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>VScodeに拡張機能Python、Docker、Remote Containers をインストールしておく</p>\n\n<h1 id=\"コンテナ起動\">コンテナ起動</h1>\n<p>ターミナルからコンテナ起動する<br />\nソースの編集をしやすいように、ホストのフォルダを<code class=\"language-plaintext highlighter-rouge\">/work</code>に割り当てている。<br />\nいや、VSCodeで編集すれば問題ないんだけどさ…<br />\nいつも編集は別のエディタ使ってたりするとコンテナ内のファイルいじるのが面倒なので…</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Windows\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> /m/work/zzz:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ubuntu\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> <span class=\"sb\">`</span><span class=\"nb\">realpath</span> .<span class=\"sb\">`</span>:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンテナを一度作成してあれば起動していなくても大丈夫らしい。</p>\n</blockquote>\n\n<h1 id=\"コンテナに接続\">コンテナに接続</h1>\n<p>VScodeのリモートエクスプローラにコンテナが見える</p>\n<blockquote>\n  <p>[!NOTE]\nRemote SSHやRemote WSLがインストールされている場合はリモートエクスプローラ上部のドロップダウンリストからContainersを選択</p>\n</blockquote>\n\n<p>対象のコンテナを右クリックして<code class=\"language-plaintext highlighter-rouge\">Attach to Container</code> または<code class=\"language-plaintext highlighter-rouge\">Attach in New Window</code>をクリック<br />\n<code class=\"language-plaintext highlighter-rouge\">Attaching to a container may execute arbitrary code</code><br />\nと言われるたら、変なコードが実行されないことが分かっていれば <code class=\"language-plaintext highlighter-rouge\">Got it</code> をクリック</p>\n<blockquote>\n  <p>[!NOTE]\n一度開いたフォルダはその下にショートカットが表示されているので、そこから開けば手っ取り早い。</p>\n</blockquote>\n\n<p>コンテナが開く</p>\n\n<p>コンテナ内には拡張機能が入ってないので、必要な拡張機能をインストールする</p>\n\n<h1 id=\"デバッグ\">デバッグ</h1>\n<p>エクスプローラでデバッグしたいフォルダを開いてソースを開く(VSCodeの設定によっては前回開いていたフォルダが開かれる)<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Python: Select Interpreter</code> で 使用するpythonを選択する。<br />\nこのとき、必ずしも使用するpythonのpathが表示されているとは限らないので、<br />\n(逆にコンテナ内にないホスト側のものが表示されたりする😢)<br />\n表示されていない場合は<code class=\"language-plaintext highlighter-rouge\">+ Enter Interpreter path...</code>から使用するpythonを選択する。<br />\n上記イメージの場合、<code class=\"language-plaintext highlighter-rouge\">/usr/local/bin/python3</code> なので、これを設定。</p>\n<blockquote>\n  <p>[!NOTE]\nあらかじめコンソールで which python3 して調べておく</p>\n</blockquote>\n\n<p>あとはローカルと同じようにデバッグできる。</p>\n\n<h1 id=\"コンテナとの接続終了\">コンテナとの接続終了</h1>\n\n<p>コンテナとの接続を終了するときは<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Remote: Close Remote Connection</code> で終了する。</p>\n\n<p>接続終了してもコンテナを停止しないので、別途停止処理を行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker stop py_test2\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>こういうのもある。<br />\n(参照しているのはmicrosoft純正のサンプルらしい)<br />\n普通にDocker使うのと異なるファイル<code class=\"language-plaintext highlighter-rouge\">devcontainer.json</code>を使うので、\n便利なんだか不便なんだか…<br />\nDocker拡張機能なくても動かせた気がする。<br />\n<a href=\"https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html\">https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Dockerをインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Dockerをインストールする</h1>\n      <p>Windos/Ubuntu に Dockerをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows10-home-に-dockerをインストールする\">Windows10 Home に Dockerをインストールする</h1>\n<p>HomeだとWSL2必須なので、WSL2はあらかじめインストールして使用できるようにしておく。<br />\n<a href=\"/memoBlog/2021/03/03/WSL_memo.html\" target=\"_blank\">WSL2 メモ</a></p>\n\n<p><a href=\"https://docs.docker.jp/docker-for-windows/install-windows-home.html\" target=\"_blank\">https://docs.docker.jp/docker-for-windows/install-windows-home.html</a> を参考にインストールする。 <br />\nとはいっても、<a href=\"https://hub.docker.com/editions/community/docker-ce-desktop-windows/\" target=\"_blank\">https://hub.docker.com/editions/community/docker-ce-desktop-windows/</a>からダウンロードして実行するだけ。</p>\n\n<p>コンテナを一杯作るとデータ領域がどんどん肥大していくので、Cドライブから変更しておいた方が良いかも。<br />\n<a href=\"https://nosubject.io/windowsdocker-desktop-move-disk-image/\" target=\"_blank\">Docker Desktop の ディスク領域 を Cドライブから別のドライブへ移動する方法</a><br />\nを参考に作業すればOK。<br />\nVHDをエクスポート、元の仮想マシンのレジストリを削除、他の場所へ同名でインポート、とやってる。</p>\n\n<h1 id=\"ubuntu-に-dockerをインストールする\">Ubuntu に Dockerをインストールする</h1>\n<p><a href=\"https://docs.docker.jp/linux/step_one.html\" target=\"_blank\">https://docs.docker.jp/linux/step_one.html</a> を参考にインストールする。 <br />\n実際は以下を実行するだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>curl <span class=\"nt\">-fsSL</span> https://get.docker.com/ | sh\n</code></pre></div></div>\n\n<p>docker実行に逐一<code class=\"language-plaintext highlighter-rouge\">sudo</code>をつけるのは面倒なので、以下の設定をしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> docker\n</code></pre></div></div>\n<p>設定後は念のためリブートしておく(logoutだけで可らしいけど)。</p>\n\n<h1 id=\"インストール後のお試し実行\">インストール後のお試し実行</h1>\n<p>正常に動いていることを確認するためになんか動かしてみる。<br />\n以下はWindows版で書かれているが、基本的にUbuntuでも同じ。<br />\n<a href=\"https://qiita.com/nanaki11/items/97e5685ed84547526be2\" target=\"_blank\">https://qiita.com/nanaki11/items/97e5685ed84547526be2</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">docker pull</code>はしなくても<code class=\"language-plaintext highlighter-rouge\">docker run</code>したときにローカルにimegeがなければ自動でダウンロードしてくれるらしい。</p>\n\n<h1 id=\"コマンド例\">コマンド例</h1>\n<p>ちょろっと試したコマンド群</p>\n<h2 id=\"コンテナの生成\">コンテナの生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの起動\">コンテナの起動</h2>\n<p>終了したコンテナの再開も同じ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> py_test\n</code></pre></div></div>\n\n<h2 id=\"コンテナに新たなコンソール接続\">コンテナに新たなコンソール接続</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> py_test /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの生成と起動を同時に行う\">コンテナの生成と起動を同時に行う</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">create</code>を<code class=\"language-plaintext highlighter-rouge\">run</code>に変えるだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"nwork-を-work-にマウントする場合windows\">n:\\work を /work にマウントする場合(Windows)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /n/work:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"カレントディレクトリを-work-にマウントする場合ubuntu\">カレントディレクトリを /work にマウントする場合(ubuntu)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナ一覧起動中のもののみ\">コンテナ一覧(起動中のもののみ)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<h2 id=\"コンテナ一覧終了したものを含む\">コンテナ一覧(終了したものを含む)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n\n<h2 id=\"pull済みイメージ一覧\">pull済みイメージ一覧</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<h2 id=\"コンテナの情報を確認する\">コンテナの情報を確認する</h2>\n<p>下記コマンドでJSONデータが出力される。<br />\n直近で興味ありそうなのは<code class=\"language-plaintext highlighter-rouge\">HostConfig</code>、<code class=\"language-plaintext highlighter-rouge\">Mounts</code>、<code class=\"language-plaintext highlighter-rouge\">NetworkSettings</code>あたりかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker inspect py_test2\n</code></pre></div></div>\n\n<h1 id=\"どんなイメージがあるのか\">どんなイメージがあるのか?</h1>\n<p><a href=\"https://hub.docker.com/search?type=image\" target=\"_blank\">dockerhub</a>でサーチしてちょ。</p>\n\n<h1 id=\"dockerはwsl2でどんな感じで動いているのか\">DockerはWSL2でどんな感じで動いているのか?</h1>\n<p>あんまり意味ないけど。<br />\n<a href=\"https://www.docker.com/blog/new-docker-desktop-wsl2-backend/\" target=\"_blank\">https://www.docker.com/blog/new-docker-desktop-wsl2-backend/</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</h1>\n      <p>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>SDカードのアクセスが遅いのと、USBドライブの方が大容量のメディアを入手しやすいので\nUSBドライブをブートデバイスに変更してみる。</p>\n\n<p>といっても、Jetpack4.5以降ではブートローダがUSBからのブートをサポートしたので、かなり簡単になった。</p>\n\n<p>Jetpack4.4のときのメモは<a href=\"/memoBlog/2020/10/30/Jetson_usb_boot.html\" target=\"_blank\">Jetson nano をUSBドライブからブートできるようにする</a> にあります。</p>\n\n<h1 id=\"ディスクイメージの書き込み\">ディスクイメージの書き込み</h1>\n<p>通常セットアップを行ったSDカードのディスクイメージをUSBドライブにコピーします。\nSDカード→USBドライブ直接でも構いませんし、バックアップとして作成したディスクイメージファイルからでも構いません。</p>\n\n<p>ubuntu PCでディスクイメージファイルからコピーする場合はこんな感じ。<br />\n<code class=\"language-plaintext highlighter-rouge\">/dev/sdc</code> の部分は環境により異なるので注意(間違って他のディスクに上書きしないように!!)。<br />\n<code class=\"language-plaintext highlighter-rouge\">jetpack46_XXXXXXXX.img</code>がディスクイメージファイルのファイル名です。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"nv\">of</span><span class=\"o\">=</span>/dev/sdc <span class=\"k\">if</span><span class=\"o\">=</span>jetpack46_XXXXXXXX.img <span class=\"nv\">bs</span><span class=\"o\">=</span>1M <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div></div>\n\n<h1 id=\"bootデバイス変更のための設定\">BOOTデバイス変更のための設定</h1>\n\n<p>ディスクイメージを書き込んたUSBドライブをSDカードブートした Jetson nano や ubuntu PCに接続し、\n設定ファイルを書き換えます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ディスクのマウント</span>\n<span class=\"nb\">sudo </span>mount /dev/sdc1 /mnt\n<span class=\"nb\">cd</span> /mnt/boot/extlinux/\n<span class=\"c\"># オリジナルファイルのバックアップ</span>\n<span class=\"nb\">sudo cp </span>extlinux.conf extlinux.conf.mmc\n<span class=\"c\"># 編集</span>\n<span class=\"nb\">sudo </span>vi extlinux.conf\n</code></pre></div></div>\n\n<p>以下のように変更します\n具体的には<code class=\"language-plaintext highlighter-rouge\">/mnt/boot/extlinux/extlinux.conf</code> 内の \n<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0p1</code>を<code class=\"language-plaintext highlighter-rouge\">/dev/sda1</code>に変更します。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- extlinux.conf.mmc\t2021-09-14 06:02:45.889520568 +0900\n</span><span class=\"gi\">+++ extlinux.conf\t2021-09-14 06:03:29.453873117 +0900\n</span><span class=\"p\">@@ -7,7 +7,7 @@</span>\n       MENU LABEL primary kernel\n       LINUX /boot/Image\n       INITRD /boot/initrd\n<span class=\"gd\">-      APPEND ${cbootargs} loglevel=6 root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 ipv6.disable=1\n</span><span class=\"gi\">+      APPEND ${cbootargs} loglevel=6 root=/dev/sda1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 ipv6.disable=1\n</span> \n # When testing a custom kernel, it is recommended that you create a backup of\n # the original kernel and add a new entry to this file so that the device can\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nrootパラメータはパーティションのUUIDを書いておくのが最近の作法らしいが\n大抵 マウント先は <code class=\"language-plaintext highlighter-rouge\">/dev/sda1</code> なので、お手軽にこっちで指定する。</p>\n</blockquote>\n\n<h1 id=\"ついでに設定\">ついでに設定</h1>\n<p>ついでにパーティションサイズも変更しておくと良いです。</p>\n\n<h1 id=\"boot\">BOOT</h1>\n<p>あとはJetson nano にUSBドライブを接続し、元々ブートに使用していた<strong>SDカードを取り外し</strong>て電源ON。</p>\n\n<p>起動後、USBドライブがrootにマウントされていることを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">mount</code>で確認しても良いけど、いっぱい出てきて鬱陶しいので<code class=\"language-plaintext highlighter-rouge\">df</code>で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">df</span> <span class=\"nt\">-h</span> /\n</code></pre></div></div>\n<p>こんな感じで行頭にマウント元が表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Filesystem      Size  Used Avail Use% Mounted on\n/dev/sda1       108G   13G   91G  13% /\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</h1>\n      <p>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/09/13/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする(Jetpack4.6)</a>\nではVNCにvinoをインストールしましたが、vinoはキー入力/画面描画のレスポンスがかなり遅く、\n結構なストレスになります。<br />\nそこで、代わりに<a href=\"https://tigervnc.org/\">tigerVNC</a>をインストールしてみます。</p>\n\n<p>最初に結論を書いておきますが、レスポンスはvinoより良くなるのですが、クリップボードの共有\n(ホスト/ターゲット間でのコピペ)ができないので、普段使いにはあまり使い勝手が良くありません。<br />\ngithubのリポジトリもずいぶん前から更新されていないみたいなので、今後改善される可能性も低そうです。<br />\nなので、私は使っていません(^^ゞ</p>\n\n<h1 id=\"前準備\">前準備</h1>\n<p>vinoをセットアップしてある場合は停止しておいてください。<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.config/autostart/vino-server.desktop</code> を削除しておけば大丈夫でしょう。<br />\n以下、vinoのセットアップは行っていないものとして記載します。</p>\n\n<h1 id=\"tigervncの設定\">tigerVNCの設定</h1>\n\n<h2 id=\"tiger-vnc-のインストール\">tiger VNC のインストール</h2>\n<p>必要なプログラムをインストールします</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tigervnc-standalone-server tigervnc-scraping-server\n</code></pre></div></div>\n\n<h2 id=\"vncのパスワードの設定\">VNCのパスワードの設定</h2>\n<p>接続パスワードを設定します</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vncpasswd\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">Password:</code>と<code class=\"language-plaintext highlighter-rouge\">Verify:</code>で設定するパスワードを入力<br />\n<code class=\"language-plaintext highlighter-rouge\">Would you like to enter a view-only password (y/n)?</code>には <code class=\"language-plaintext highlighter-rouge\">n</code>を入力<br />\nVNCクライアントから接続する際にこのパスワードを入力します</p>\n\n<h2 id=\"自動loginの設定\">自動loginの設定</h2>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定します</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h2 id=\"解像度の設定\">解像度の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n<h2 id=\"ここで一旦リブートする\">ここで一旦リブートする</h2>\n<p>リブートしないと下の単体テストで「displayがopenできない」とエラーになる模様。</p>\n\n<h2 id=\"手動で動かしてみる画面のミラーリング\">手動で動かしてみる(画面のミラーリング)</h2>\n\n<p>動作確認として、サーバを手動で起動してみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>x0vncserver <span class=\"nt\">-display</span> :0 <span class=\"nt\">-passwordfile</span> ~/.vnc/passwd\n</code></pre></div></div>\n\n<p>サーバが起動したら、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続します。</p>\n\n<p>正常に設定できていればVNCクライアントにデスクトップが表示されます。</p>\n\n<h2 id=\"自動起動の設定\">自動起動の設定</h2>\n<p>逐一<code class=\"language-plaintext highlighter-rouge\">x0vncserver</code>を起動するのは面倒なので、自動で起動するように設定しておきます。</p>\n\n<p>参考: <a href=\"https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f\">https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/systemd/system/x0vncserver.service</code> を以下の内容で作成します。<br />\nただし、<code class=\"language-plaintext highlighter-rouge\">XXXXXXXX</code>の部分は 自分のユーザ名に置き換えてください。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Remote desktop service (VNC)\nAfter=syslog.target\nAfter=network.target remote-fs.target nss-lookup.target\nAfter=x11-common.service \n\n[Service]\nType=forking\nUser=XXXXXXXX\nGroup=XXXXXXXX\nWorkingDirectory=/home/XXXXXXXX\nExecStart=/bin/sh -c 'sleep 10 && /usr/bin/x0vncserver -display :0  -rfbport 5900 -passwordfile /home/XXXXXXXX/.vnc/passwd &'\n\n[Install]\nWantedBy=multi-user.target\n</code></pre></div></div>\n\n<h2 id=\"サービスの起動と確認\">サービスの起動と確認</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl start x0vncserver\n<span class=\"nb\">sudo </span>systemctl status x0vncserver\n</code></pre></div></div>\n\n<p>以下のように出力されることを確認します</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>● x0vncserver.service - Remote desktop service (VNC)\n   Loaded: loaded (/etc/systemd/system/x0vncserver.service; enabled; vendor pres\n   Active: active (running) since Fri 2021-09-03 11:08:07 JST; 8s ago\n  Process: 14646 ExecStart=/bin/sh -c sleep 10 && /usr/bin/x0vncserver -display ・・・・\n Main PID: 14659 (sh)\n    Tasks: 2 (limit: 4172)\n   CGroup: /system.slice/x0vncserver.service\n           ├─14659 /bin/sh -c sleep 10 && /usr/bin/x0vncserver -display :0  ・・・・\n           └─14666 sleep 10\n\n 9月 03 11:08:07 jetson systemd[1]: Starting Remote desktop service (VNC)...\n 9月 03 11:08:07 jetson systemd[1]: Started Remote desktop service (VNC).\n</code></pre></div></div>\n\n<h2 id=\"サービスの有効化\">サービスの有効化</h2>\n<p>起動時に自動実行されるように、サービスの有効化を行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl <span class=\"nb\">enable </span>x0vncserver\n</code></pre></div></div>\n\n<h2 id=\"リブート\">リブート</h2>\n\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続します。</p>\n\n<p>正常に起動できていればVNCクライアントにデスクトップが表示されます。</p>\n\n<h1 id=\"別のやり方参考\">別のやり方(参考)</h1>\n<p>ディスプレイとは別のデスクトップを表示する場合は以下の手順で。<br />\nここではwindow managerにlxdeを使用していますので、モニタ表示とは異なる見た目になりますし、\nウィンドウマネージャの設定も同じではありません。</p>\n\n<p>参考:<a href=\"https://forums.developer.nvidia.com/t/how-to-setup-tigervnc-on-jetson-nano/174244\">https://forums.developer.nvidia.com/t/how-to-setup-tigervnc-on-jetson-nano/174244</a></p>\n\n<p>一回試しただけ(ちゃんとメモってなかった)なので、抜けとかあるかも。</p>\n\n<h2 id=\"tiger-vnc-のインストール-1\">Tiger VNC のインストール</h2>\n<p>必要なプログラムをインストールします</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tigervnc-standalone-server\n</code></pre></div></div>\n\n<h2 id=\"vncのパスワードの設定-1\">VNCのパスワードの設定</h2>\n<p>接続パスワードを設定します</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vncpasswd\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">Password:</code>と<code class=\"language-plaintext highlighter-rouge\">Verify:</code>で設定するパスワードを入力<br />\n<code class=\"language-plaintext highlighter-rouge\">Would you like to enter a view-only password (y/n)?</code>には <code class=\"language-plaintext highlighter-rouge\">n</code>を入力<br />\nVNCクライアントから接続する際にこのパスワードを入力します</p>\n\n<h2 id=\"自動loginの設定-1\">自動loginの設定</h2>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定します</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h2 id=\"解像度の設定-1\">解像度の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n\n<h2 id=\"vncxstartup-の作成\">~/.vnc/xstartup の作成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.vnc/xstartup</code> を以下の内容で作成します<br />\nXXXXXXXX は 自分のユーザ名に置き換えてください</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">!</span>/bin/sh\n<span class=\"nb\">export </span><span class=\"nv\">XDG_RUNTIME_DIR</span><span class=\"o\">=</span>/run/user/1000\n<span class=\"nb\">export </span><span class=\"nv\">XKL_XMODMAP_DISABLE</span><span class=\"o\">=</span>1\n<span class=\"nb\">unset </span>SESSION_MANAGER\n<span class=\"nb\">unset </span>DBUS_SESSION_BUS_ADDRESS\nxrdb /home/XXXXXXXX/.Xresources\nxsetroot <span class=\"nt\">-solid</span> grey\ngnome-session &\nstartlxde &\n</code></pre></div></div>\n\n<p>実行属性を付けます</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod </span>755 ~/.vnc/xstartup\n</code></pre></div></div>\n\n<h2 id=\"xresources-ファイルの作成\">.Xresources ファイルの作成</h2>\n<p>.Xresources ファイルを作成します</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">touch</span> ~/.Xresources\n</code></pre></div></div>\n\n<h2 id=\"vncの自動起動の設定\">VNCの自動起動の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/systemd/system/vncserver@.service</code>を以下の内容で作成します<br />\nXXXXXXXX は 自分のユーザ名に置き換えてください</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Start TigerVNC Server at startup\nAfter=syslog.target network.target\n\n[Service]\nType=forking\nUser=XXXXXXXX\nGroup=XXXXXXXX\nWorkingDirectory=/home/XXXXXXXX\nPIDFile=/home/XXXXXXXX/.vnc/%H:%i.pid\nExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1\nExecStart=/usr/bin/vncserver :%i -depth 24 -geometry 1920x1080 -nolisten tcp\n\nExecStop=/usr/bin/vncserver -kill :%i\n\n[Install]\nWantedBy=multi-user.target\n</code></pre></div></div>\n\n<h2 id=\"リモートからのアクセス許可\">リモートからのアクセス許可</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/vnc.conf</code> に以下を追記してリモートアクセスを許可します</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$localhost = “no”;\n</code></pre></div></div>\n\n<h2 id=\"systemctl-enable-の代わりにシンボリックリンクの作成\">systemctl enable の代わりにシンボリックリンクの作成</h2>\n<p>参照元がこうなってたので。<br />\n<code class=\"language-plaintext highlighter-rouge\">sudo systemctl enable vncserver@</code>でも良い気がするけど。ここのファイル名でポート番号決めてる?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /etc/systemd/system/multi-user.target.wants/\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /etc/systemd/system/vncserver@.service vncserver@1.service\n</code></pre></div></div>\n\n<h2 id=\"リブートする\">リブートする</h2>\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5901に接続します。<br />\n(VNCクライアントの接続先に<code class=\"language-plaintext highlighter-rouge\">«JetsonのIPアドレス»:5901</code> を指定します)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をセットアップする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をセットアップする(Jetpack4.6)</h1>\n      <p>Jetson nano をセットアップする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Nvidiaの<a href=\"https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/\">Jetson nano</a>をセットアップしたときのメモ<br />\nJetpack4.4のときのメモは<a href=\"/memoBlog/2020/10/23/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする</a> にあります。</p>\n\n<h1 id=\"参照先\">参照先</h1>\n<ul>\n  <li><a href=\"https://monoist.atmarkit.co.jp/mn/articles/1905/30/news029.html\">「Jetson Nano」の電源を入れて立ち上げる</a>\n    <ul>\n      <li>わりと詳しく書いてある</li>\n    </ul>\n  </li>\n  <li><a href=\"https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit\">Getting Started With Jetson Nano Developer Kit </a>\n    <ul>\n      <li>本家</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"シリアルコンソールの使用\">シリアルコンソールの使用</h1>\n<p>シリアルコンソールが必要なら接続できる。<br />\n特に設定等は必要ない。  <br />\n接続端子は以下を参照</p>\n<ul>\n  <li><a href=\"https://www.jetsonhacks.com/2019/04/19/jetson-nano-serial-console/\">Jetson Nano – Serial Console</a>\nの 「Wiring」の下の「Jetson Nano B01」を参照。</li>\n</ul>\n\n<p>シリアルポートの設定は115200bps/8bit/none/1bit/none</p>\n\n<p>その他、コネクタ類の配置が分かりにくい場合は、\n<a href=\"https://developer.download.nvidia.com/assets/embedded/secure/jetson/Nano/docs/NV_Jetson_Nano_Developer_Kit_User_Guide.pdf?yIbsUqvBKxI1G6r3WW7cOdheZGv2-eSfaFW_kMt3dSgi0NJ7h77OwFHr5b-rquc3IX7Tyrt8FV6IKD4DHqvP4_LzhWt55tb071gqXlNGwBPYCOC5pnEKAla8D-B82bPjhQMykANFyn-EhxZRHC8AIBYWuVwwwXVPWtCOjs34Tg50oBdN0vBNoyUlZMRFXLNJ2to\">JETSON NANO DEVELOPER KIT</a>\nのP22 に<strong>Developer kit module and carrier board: rev B01 top view</strong>として配置図が掲載されているので参照のこと。</p>\n\n<h1 id=\"sdカードの作成firstboot\">SDカードの作成~FirstBoot</h1>\n<p>基本的に参照先の通り。<br />\n<a href=\"https://developer.nvidia.com/embedded/downloads\">https://developer.nvidia.com/embedded/downloads</a>\nから「Jetson Nano Developer Kit SD Card Image」  の Version 「4.6」 をダウンロード<br />\n(他のバージョンが必要ならそのバージョンで)</p>\n\n<p>ファーストブートで設定が終わったら、何はともあれ最新版にアップデート。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ここで一旦リブートしておく。</p>\n\n<h1 id=\"sshでの接続\">SSHでの接続</h1>\n<p>特に設定などは必要ない。<br />\nTeraTermなどで接続すれば良い。\nUbuntuではmDNSが動いているので、«マシン名».localでアクセスできる。</p>\n\n<p>TeraTerm使用時のコマンドは以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\"C:\\Program Files (x86)\\teraterm\\ttermpro.exe\" /auth=password /user=«ユーザ名» /passwd=«パスワード» «JetsonのIPアドレス or マシン名.local»\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nSSHやmDNSは立ち上がるまで少し時間がかかるみたいなので、<br />\n起動後数十秒程度待ってから接続した方が良い。</p>\n</blockquote>\n\n<h2 id=\"ssh接続がタイムアウトする対策\">SSH接続がタイムアウトする対策</h2>\n<p>SSH接続したターミナルを触らずにしばらく置いておくと、タイムアウトしてクローズされてしまう。\nこれを防ぐにはクライアント側からkeep-aliveパケットを定期的に送信してやれば良いらしい。</p>\n\n<p>Teratermの場合、「設定」→「SSH」→「ハートビート(keep-alive)」を「8」とかに設定し、保存。\n次回接続時はこの保存した設定ファイルを読み込む</p>\n\n<h1 id=\"初期設定\">初期設定</h1>\n<h2 id=\"bashrcの修正\">.bashrcの修正</h2>\n<p>.bashrcの修正をお好みで。<br />\n以下は設定例</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> resize <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># numpy 1.19.5 のimportでcore dumpする対策</span>\n<span class=\"nb\">export </span><span class=\"nv\">OPENBLAS_CORETYPE</span><span class=\"o\">=</span>ARMV8\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"c\"># export PYTHON_CONFIGURE_OPTS=\"--enable-ipv6\\</span>\n    <span class=\"c\">#     --enable-unicode=ucs4\\</span>\n    <span class=\"c\">#     --enable-shared\\</span>\n    <span class=\"c\">#     --with-dbmliborder=bdb:gdbm\\</span>\n    <span class=\"c\">#     --with-system-expat\\</span>\n    <span class=\"c\">#     --with-system-ffi\\</span>\n    <span class=\"c\">#     --with-fpectl\"</span>\n    <span class=\"c\"># Ubuntu向け対策</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vim\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># venvの仮想環境名を表示するための設定</span>\n    show_virtual_env<span class=\"o\">()</span> <span class=\"o\">{</span>\n      <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"s2\">)\"</span>\n      <span class=\"k\">fi</span>\n    <span class=\"o\">}</span>\n    <span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s1\">'$(show_virtual_env)'</span><span class=\"nv\">$PS1</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># DISPLAYが未定義なら設定する</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-z</span> <span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n    <span class=\"k\">fi\nfi</span>\n</code></pre></div></div>\n\n<h2 id=\"不要なソフトのアンインストール\">不要なソフトのアンインストール</h2>\n<p>使わないのでアンインストールしておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\n</code></pre></div></div>\n\n<h2 id=\"guiの動作の設定変更をお好みで\">GUIの動作の設定変更をお好みで</h2>\n<!--\n「ウィンドウが勝手に最大化するのをやめる」はOK\n「ウィンドウにマウスを乗せるとフォーカスされるようにする」で \"focus-mode\" は 'mouse' ではなく 'sloppy'\n「デスクトップからゴミ箱とホームを消す」は項目としてないらしい\n「Dockのカスタマイズ」は設定できるけど有効でない?\n「マウスカーソルを大きくする」は設定できるけど有効でない?リブートすると元に戻る?\nwindowの閉じるボタンなどを右に移動するにはgnome-tweaskでWindowsのTitlebar Buttons を設定する → 反映されず\n「CAPSキーをCtrlキーに変更」はOK\n-->\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.mutter auto-maximize\ngsettings get org.gnome.mutter edge-tiling\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.desktop.wm.preferences auto-raise \ngsettings get org.gnome.desktop.wm.preferences focus-mode \ngsettings get org.gnome.desktop.wm.preferences raise-on-click\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode sloppy\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"capsキーをctrlキーに変更\">CAPSキーをCtrlキーに変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.input-sources xkb-options\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.input-sources xkb-options <span class=\"se\">\\[\\'</span>ctrl:nocaps<span class=\"se\">\\'\\]</span>\n\n<span class=\"c\"># 設定を有効にするにはGUIでのlogout&再loginが必要</span>\n\n</code></pre></div></div>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>IPv6を無効化したい場合は、\n/<code class=\"language-plaintext highlighter-rouge\">boot/extlinux/extlinux.conf</code>の<code class=\"language-plaintext highlighter-rouge\">APPEND</code>の行の最後に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加してリブートする<br />\n参考: <a href=\"https://www.rough-and-cheap.jp/ubuntu/ubuntu18_04_howto_diseable_ipv6/\" target=\"_blank\">Ubuntu 18.04 で ipv6 を無効にする</a></p>\n<blockquote>\n  <p>[!NOTE]\ngrubではなく、U-Bootなので設定するところが違う</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSysctl の設定ではうまくいかなかった。</p>\n</blockquote>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work\n</code></pre></div></div>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<h3 id=\"インストール\">インストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<h3 id=\"設定ファイル\">設定ファイル</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<h3 id=\"ユーザの追加と再起動\">ユーザの追加と再起動</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"vncサーバvinoの設定\">VNCサーバ(vino)の設定</h2>\n<p>参考: <a href=\"https://zenn.dev/tunefs/articles/9774eb8f229e1bf97a8c\">https://zenn.dev/tunefs/articles/9774eb8f229e1bf97a8c</a>\n以下、参考先をベースに説明</p>\n\n<h3 id=\"vinoのインストール\">Vinoのインストール</h3>\n<p>インストール済みなので不要</p>\n\n<h3 id=\"vinoの自動起動の設定\">Vinoの自動起動の設定</h3>\n<p>コピー先ディレクトリは作成済み</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> /usr/share/applications/vino-server.desktop ~/.config/autostart/\n</code></pre></div></div>\n\n<h3 id=\"vinoのコンフィグレーション\">Vinoのコンフィグレーション</h3>\n<p>実行は以下のみでOK</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.Vino prompt-enabled <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false</span>\n</code></pre></div></div>\n<p>以下は不要</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>set org.gnome.Vino authentication-methods は \"['vnc']\" でなく \"['none']\"   デフォルトと同じなので不要\ngsettings set org.gnome.Vino vnc-password $(echo -n 'thepassword'|base64) は不要\n</code></pre></div></div>\n\n<h3 id=\"自動loginの設定\">自動loginの設定</h3>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定する</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h3 id=\"解像度の設定\">解像度の設定</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n\n<h3 id=\"リブートする\">リブートする</h3>\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続する。</p>\n\n<h3 id=\"設定メニューを表示できるようにする\">設定メニューを表示できるようにする</h3>\n<p>上記だけで設定は完了するが、設定メニュー(Settings)から設定しようとするとエラーになるので、\nそれを修正しておく(やらなくても設定メニュー使わなければ問題ない)。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml</code>に以下のパッチを当てる</li>\n</ul>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  /tmp/a.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- org.gnome.Vino.gschema.xml.org      2020-10-19 06:21:32.034728957 +0900\n</span><span class=\"gi\">+++ org.gnome.Vino.gschema.xml  2020-10-19 06:22:30.887994965 +0900\n</span><span class=\"p\">@@ -154,5 +154,14 @@</span>\n       </description>\n       <default>true</default>\n     </key>\n<span class=\"gi\">+    <key name='enabled' type='b'>\n+      <summary>Enable remote access to the desktop</summary>\n+        <description>\n+          If true, allows remote access to the desktop via the RFB\n+          protocol. Users on remote machines may then connect to the\n+          desktop using a VNC viewer.\n+        </description>\n+      <default>false</default>\n+    </key>\n</span>   </schema>\n </schemalist>\n</code></pre></div></div>\n\n<ul>\n  <li>パッチを当てるコマンド\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>patch /usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml /tmp/a.patch\n</code></pre></div>    </div>\n  </li>\n  <li>さらにコンパイルが必要\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>glib-compile-schemas /usr/share/glib-2.0/schemas\n</code></pre></div>    </div>\n  </li>\n  <li>これで「settings」から「Desktop Sharing」が実行できるようになる</li>\n</ul>\n\n<h2 id=\"使用率等の確認ツールのインストールと起動\">使用率等の確認ツールのインストールと起動</h2>\n\n<p>pyenvインストール済みのときは念のため<code class=\"language-plaintext highlighter-rouge\">pyenv shell system</code>しておく。<br />\nvenv環境使用時はデアクティベートしておく。<br />\n(sudo付きで実行してるのでsystemのpython3が使用されるハズだけど)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip\n<span class=\"nb\">sudo </span>pip3 <span class=\"nb\">install </span>jetson-stats\n<span class=\"nb\">sudo </span>jtop \n</code></pre></div></div>\n<p>一度再起動したあとは、<code class=\"language-plaintext highlighter-rouge\">sudo</code>なしの<code class=\"language-plaintext highlighter-rouge\">jtop</code>のみで実行可能。</p>\n<blockquote>\n  <p>[!NOTE]\njtopは結構CPUパワーを喰うので、性能評価等の間は止めておくのが無難と思われる。</p>\n</blockquote>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"sdカードのイメージファイル化\">SDカードのイメージファイル化</h1>\n<p><a href=\"/memoBlog/2021/07/18/sd_image_2.html\" target=\"_blank\">Raspbian SDカードイメージファイルの作成(改訂版)</a>を参照。</p>\n\n<h1 id=\"イメージのコピーからの起動\">イメージのコピーからの起動</h1>\n<h2 id=\"縮小されたパーティションを拡張する\">縮小されたパーティションを拡張する</h2>\n<p>バックアップはパーティションが縮小されているので、拡張する。<br />\n上記参照先の拡張方法ではうまくいかない(JetsonはパーティションがGPTだから?)。<br />\nなので、GUIツールのgpartedを使用して拡張する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gparted\n<span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0       <span class=\"c\"># sshから実行するときはXserverが起動しているマシンをDISPLAY変数に設定</span>\n<span class=\"nb\">sudo </span>gparted /dev/mmcblk0\n</code></pre></div></div>\n\n<ul>\n  <li>Libparted Warning ダイアログで”Not all of the space available to ~”と出たらFixをクリック</li>\n  <li>Libparted Warning ダイアログで”The backup GPT table is corrupt, but the primary appears OK, so that will be used.”と出たらOKをクリック</li>\n  <li>以降も何度か出るが、以下の操作がすべて終わればbackup GPTが新たに作成されるので問題なし。\n    <ul>\n      <li>(これは、ディスクイメージを縮小したときにgdiskコマンドを実行しなかった場合に出ます)</li>\n    </ul>\n  </li>\n  <li>図の«SDカードのパーティション» を右クリック→「Resize/Move」をクリック\n    <ul>\n      <li>「New size」の欄に上にある「Maximum size」以下の値を入力(「Free space following」 に残したいサイズを入れても可)</li>\n      <li>他の入力欄をクリックして自動計算を反映</li>\n      <li>「Resize」をクリック\n-「Edit」→「Apply All Operations」をクリック</li>\n      <li>「Are you sure you want to apply the pending operations?」と聞かれるので、「Apply」をクリック</li>\n    </ul>\n  </li>\n  <li>処理が完了したら閉じるボタンでプログラム終了</li>\n</ul>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"venvによるpython-仮想環境の構築\">venvによるpython 仮想環境の構築</h1>\n<p>いつもはpyenv + virtualenv で環境構築しているが、この環境ではプリインストールされた opencv を使用できないらしい(core dumpする)。<br />\nなので、system上のpythonを使用してvenvで仮想環境を構築して使用するようにしてみた。<br />\n(これ、↓のnumpyの問題かも。でもtensorflowはpython3.6でないとダメだから、pyenv引っ張ってこなくてもいいか。)</p>\n\n<h2 id=\"venvのインストール\">venvのインストール</h2>\n<p>venv使用のためのプログラムをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-venv\n</code></pre></div></div>\n\n<h2 id=\"仮想環境の構築\">仮想環境の構築</h2>\n<p>仮想環境を構築する。<br />\nここで実行したpythonが仮想環境で実行されるpythonになる。<br />\n<code class=\"language-plaintext highlighter-rouge\">--system-site-packages</code> を付加しておくと元のパッケージも参照される。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> «venv_dir»\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">pip list/freeze</code> でも参照される。pipのバージョンが新しければ、<code class=\"language-plaintext highlighter-rouge\">pip -v list</code>と オプション<code class=\"language-plaintext highlighter-rouge\">-v</code>を付けることで インストール先を見分けることでどちらにインストールされているかが判別できる。</p>\n\n<p>例えばこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/TF2.5\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート\">仮想環境のアクティベート</h2>\n<p>pyenvではlocalで指定してあればディレクトリ移動で自動的に仮想環境を切り替えられたが、<br />\nvenvでは逐一仮想環境をアクティベートしなければならない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> «venv_dir»/bin/bin/activate\n</code></pre></div></div>\n\n<h2 id=\"お約束\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"仮想環境の終了\">仮想環境の終了</h2>\n<p>仮想環境を終了するときは以下のコマンドでデアクティベートする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>deactivate\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">deactivate</code>はアクティベート時に関数として登録されている<br />\n下記のようにdirenvで設定した場合は<code class=\"language-plaintext highlighter-rouge\">deactivate</code>は使えないが、ディレクトリから移動すれば元にもどるので問題ない</p>\n</blockquote>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"direnvのインストールと設定\">direnvのインストールと設定</h1>\n<p>仮想環境管理をvenvで行うようにしたが、venvだと逐一activateしないといけないので、pyenvに慣れたカラダでは なかなか 使いにくい。<br />\nそこで、direnvを使ってpyenvに近い使い勝手を実現してみる。</p>\n\n<p>参考:<a href=\"https://yoshitaku-jp.hatenablog.com/entry/2018/07/29/070000\">direnvを使って、source bin/activateを自動化する</a></p>\n\n<h2 id=\"インストール-1\">インストール</h2>\n<p>インストールは<code class=\"language-plaintext highlighter-rouge\">apt</code>でイッパツ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>direnv\n</code></pre></div></div>\n\n<h2 id=\"初期設定-1\">初期設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code> に以下の内容を追記。(上記<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>例では記載済み)<br />\nエディタはvimに設定してあるが、別のものを使いたければ設定変更のこと。<br />\n(direnv 未インストール時は設定はスキップされる)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vim\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># venvの仮想環境名を表示するための設定</span>\n    show_virtual_env<span class=\"o\">()</span> <span class=\"o\">{</span>\n      <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"s2\">)\"</span>\n      <span class=\"k\">fi</span>\n    <span class=\"o\">}</span>\n    <span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s1\">'$(show_virtual_env)'</span><span class=\"nv\">$PS1</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">source ~/.bashrc</code> するか、terminalを開きなおす。</p>\n\n<h2 id=\"対象ディレクトリに処理を登録する\">対象ディレクトリに処理を登録する</h2>\n<p>対象ディレクトリに移動して<code class=\"language-plaintext highlighter-rouge\">direnv edit .</code> を実行して中身を作成するか、 <code class=\"language-plaintext highlighter-rouge\">.envrc</code>を直接生成する。</p>\n\n<p>中身は以下の通り<br />\n他にも設定したい環境変数があれば設定しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> «venv_dir»/bin/activate\n</code></pre></div></div>\n<p>例えばこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/TF2.5/bin/activate\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">direnv: error .envrc is blocked. Run `direnv allow` to approve its content.</code>と言われたら、以下のように実行する。<br />\n(直接編集した時に言われるらしい)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>direnv allow\n</code></pre></div></div>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"tensorflow2-のインストール\">tensorflow2 のインストール</h1>\n<h2 id=\"仮想環境の構築-1\">仮想環境の構築</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/TF2.5\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート-1\">仮想環境のアクティベート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/TF2.5/bin/activate\n</code></pre></div></div>\n<p>またはdirenvで上記が実行されるように設定しておく</p>\n\n<h2 id=\"お約束-1\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<p>tensorflowをimportしたとき(具体的にはその中でnumpyをimportしたとき)に\n<code class=\"language-plaintext highlighter-rouge\">Illegal instruction (core dumped)</code>が発生する。<br />\nこれを回避するため、以下を<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に設定しておく(上記<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>例では記載済み) 。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">OPENBLAS_CORETYPE</span><span class=\"o\">=</span>ARMV8\n</code></pre></div></div>\n\n<p>tensoorflowはpypiではなく、nvidiaのサイトからダウンロードしてインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>https://developer.download.nvidia.com/compute/redist/jp/v46/tensorflow/tensorflow-2.5.0+nv21.7-cp36-cp36m-linux_aarch64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nn5pyインストールでエラーになった時は以下の手順で回避する。  <br />\nミソはh5pyのインストール時点でnumpy 1.19.5がインストールされているとエラーになるので、<br />\n一時的にnumpyのそれ以前のバージョンをインストールしてh5pyをインストールし、その後numpyを本来のバージョンに戻す。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libhdf5-serial-dev hdf5-tools libhdf5-dev\npip <span class=\"nb\">install </span>cython\n<span class=\"c\"># numpyのバージョン下げる  </span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">numpy</span><span class=\"o\">==</span>1.19.3\npip <span class=\"nb\">install </span><span class=\"nv\">h5py</span><span class=\"o\">==</span>2.10.0\n<span class=\"c\"># h5pyのインストールのためにインストールしたnumpyを本来のバージョンに更新  </span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">numpy</span><span class=\"o\">==</span>1.19.5\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"tensorflowなどのありか\">Tensorflowなどのありか</h2>\n<p>以下に色々まとめられている。<br />\n<a href=\"https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime\">https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime</a></p>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"onnx-runtimeのインストール\">onnx-runtimeのインストール</h1>\n<h2 id=\"仮想環境の構築-2\">仮想環境の構築</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/onnx\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート-2\">仮想環境のアクティベート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/onnx/bin/activate\n</code></pre></div></div>\n<p>またはdirenvで上記が実行されるように設定しておく</p>\n\n<h2 id=\"お約束-2\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"インストールファイルのダウンロード\">インストールファイルのダウンロード</h2>\n<p><a href=\"https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime\" target=\"_blank\">Jetson Zoo</a>\nから使用環境に対応するインストールファイルをダウンロードする。<br />\n表の下にあるコマンド例の<code class=\"language-plaintext highlighter-rouge\">wget</code>ではうまくダウンロードできないのでブラウザでダウンロードしてコピっておく。<br />\n以下、onnxruntime 1.8.0/Python 3.6 を選択したものとする。</p>\n\n<h2 id=\"インストール-2\">インストール</h2>\n\n<p>システムにインストールされたprotobufのバージョンが古くてエラーになるので、\nあらかじめ最新版にアップデートしておく。<br />\n(venv環境なので、システムのprotobufには影響ない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> protobuf\n</code></pre></div></div>\n\n<p>ダウンロードしたonnx-runtimeをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>onnxruntime_gpu-1.8.0-cp36-cp36m-linux_aarch64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian SDカードイメージファイルの作成(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian SDカードイメージファイルの作成(改訂版)</h1>\n      <p>Raspbian SDカードイメージファイルの縮小</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/07/17/raspios_20210507.html\" target=\"_blank\">Raspberry Pi OS(May 7th 2021)のインストール</a> \nでセットアップしたSDカードをバックアップしておけば逐一セットアップ作業を行わなくても環境を復元できます。</p>\n\n<p>ただ、そのままSDカードをイメージファイル化しただけでは復元するSDカードのサイズが微妙に小さい場合などは、復元できなくなってしまいます。<br />\nそこで、バックアップしtイメージファイル内のパーティションサイズを縮小し、イメージファイルを小さくして保存します。</p>\n\n<p>以前、<a href=\"/memoBlog/2019/09/15/sd_image.html\" target=\"_blank\">Raspbian SDカードイメージファイルの縮小</a>、\n<a href=\"/memoBlog/2020/10/25/Jetson_nano_backup.html\" target=\"_blank\">Jetson nano のSDカードをバックアップする</a>\nでも書いていますが、今回はSDカード上でパーティションを縮小する方法にしてみました。<br />\nこれだと、不要な部分のバックアップを行わなくて済むので、ディスク領域/時間敵に有利かと思います。</p>\n\n<p>Windowsでは出来ない操作があるので、Ubuntu PCが必要です。<br />\nWSLではたぶん出来ません。<br />\nVirtualboxだと出来そうな気がしますが、試していません。</p>\n\n<h1 id=\"事前準備\">事前準備</h1>\n<h2 id=\"raspberrypiの準備\">RaspberryPiの準備</h2>\n<p>コピーしたSDカードで初回Boot時にパーティションを拡張するためのスクリプト<code class=\"language-plaintext highlighter-rouge\">expand_partition.sh</code>を\n<a href=\"/memoBlog/misc/stock/diskimage_shrink.sh\" target=\"_blank\">ここ</a> \nから適当なディレクトリにダウンロードしておきます。<br />\n(SDカードのコピーからブートしたあとに実行するので、コピーからブートした環境でダウンロードしても良いですが、\nマスタにダウンロードしておけばコピーの度にダウンロードしなくて済むので。)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/first_boot_settings\n<span class=\"nb\">cd</span>  ~/first_boot_settings\nwget https://ippei8jp.github.io/memoBlog/misc/stock/expand_partition.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPiの場合は<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>でパーティション拡張できるので、このスクリプトはなくても良い。</p>\n</blockquote>\n\n<p>RaspberryPiの電源をOFFし、SDカードを取り外してubuntu PCに挿入しておきます。</p>\n\n<h1 id=\"ubuntu-pcでの操作\">Ubuntu PCでの操作</h1>\n\n<p>以下、SDカードは<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0</code>に割り当てられているものとします。</p>\n\n<blockquote>\n  <p>[!NOTE]\nSDカードが自動マウントされている場合はアンマウントしておいてください。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount /dev/mmcblk0p1\n<span class=\"nb\">sudo </span>umount /dev/mmcblk0p2\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"gpartedのインストール\">gpartedのインストール</h2>\n<p>パーティション操作を行うため、gpartedがインストールされていなければインストールしておきます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gparted\n</code></pre></div></div>\n\n<h2 id=\"gpartedによりパーティションを縮小\">gpartedによりパーティションを縮小</h2>\n<ul>\n  <li>goartedを起動</li>\n  <li>対象デバイスとして<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0</code>を選択。</li>\n  <li>配置図またはパーティション一覧で<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0p2</code>を右クリックし、「リサイズ/移動」を選択</li>\n  <li>ダイアログで「新しいサイズ」に縮小したサイズを設定。 ダイアログ左上に表示されている「最小サイズ」よりも少し多めに。<br />\n(後方の空き領域は自動計算されます)</li>\n  <li>メニューの「編集」→「保留中の全ての操作を適用する」を選択し、パーティションを縮小する</li>\n  <li>gpartedを終了</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\ngpartedによるパーティションの縮小はマウントしたままではできません。<br />\nしたがって、RaspberryPiでは作業できず、Ubuntu PCで行う必要があります。</p>\n</blockquote>\n\n<h2 id=\"データサイズを確認\">データサイズを確認</h2>\n<p>以下のコマンドを実行し、コピーすべきデータサイズを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>parted /dev/mmcblk0 unit MiB print\n</code></pre></div></div>\n<p>以下が実行結果例。<br />\nここで、パーティション2の終了位置をメモ(ここでは<code class=\"language-plaintext highlighter-rouge\">3760</code>)しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>モデル: SD SA16G <span class=\"o\">(</span>sd/mmc<span class=\"o\">)</span>\nディスク /dev/mmcblk0: 14772MiB\nセクタサイズ <span class=\"o\">(</span>論理/物理<span class=\"o\">)</span>: 512B/512B\nパーティションテーブル: msdos\nディスクフラグ: \n\n番号  開始     終了     サイズ   タイプ   ファイルシステム  フラグ\n 1    4.00MiB  260MiB   256MiB   primary  fat32             lba\n 2    260MiB   3760MiB  3500MiB  primary  ext4\n</code></pre></div></div>\n\n<h2 id=\"イメージファイルの作成\">イメージファイルの作成</h2>\n<p>以下のコマンドでSDカードのデータをイメージファイルに保存します。<br />\nここで、<code class=\"language-plaintext highlighter-rouge\">of=</code>で指定しているのが作成するイメージファイル名、<br />\n<code class=\"language-plaintext highlighter-rouge\">count=</code>は上で調べたパーティションの終了位置をしていします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>/dev/mmcblk0 <span class=\"nv\">of</span><span class=\"o\">=</span>hoge1.img <span class=\"nv\">bs</span><span class=\"o\">=</span>1M <span class=\"nv\">count</span><span class=\"o\">=</span>3760 <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div></div>\n\n<p>必要ならzip圧縮しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>zip hoge1.zip hoge1.img \n</code></pre></div></div>\n\n<h1 id=\"新しい環境での起動\">新しい環境での起動</h1>\n\n<h2 id=\"新しいsdカードにバックアップを復元\">新しいSDカードにバックアップを復元</h2>\n\n<p>上で作成したイメージファイルをSDカードに書き込み(WindowsでもUbuntuでもお好きにどうぞ)、</p>\n\n<h2 id=\"最初のブート\">最初のブート</h2>\n<p>RaspberryPiに挿入しBootします(特別な手順は特にありません)。</p>\n\n<h2 id=\"新しいsdカードのパーティションを拡張\">新しいSDカードのパーティションを拡張</h2>\n\n<p>Boot完了したらlog inしてパーティションサイズを変更するために\n以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash first_boot_settings/expand_partition.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nまたは、RaspberryPiにgpartedをインストールして、<br />\nパーティションを縮小したときと同様に最大サイズまでパーティションサイズを拡大しても良いです。<br />\nパーティションの拡大はマウントしたままでも可能。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPiの場合は<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>でパーティション拡張できる</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config --expand-rootfs  \n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">Please reboot</code>と言われたらrebootする。</p>\n</blockquote>\n\n<h2 id=\"その他\">その他</h2>\n<p>必要であれば、ホスト名など必要な変更を行います。</p>\n\n<h2 id=\"リブート\">リブート</h2>\n<p>リブートします。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(May 7th 2021)のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(May 7th 2021)のインストール</h1>\n      <p>Raspberry Pi OS(May 7th 2021)のインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>前にやった <a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\" target=\"_blank\">Raspbian Busterのインストール</a>\nからあまり違わないけど、微妙に違いもあるので、もう一度メモしておく。</p>\n\n<h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspberry Pi OS with desktop」 の 「Download」でダウンロードしてSDカードに書き込む。<br />\n(「・・・ and recommended software」 の方ではない)<br />\n以下の手順は、RaspberryPi4 model B で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の <code class=\"language-plaintext highlighter-rouge\">[pi4]</code>の行の前に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\nシリアルコンソールの送信改行コードは<code class=\"language-plaintext highlighter-rouge\">CR</code>にしておくこと。<br />\nそうしないと、ビミョーに悲しいことが起こる場合がある。</p>\n</blockquote>\n\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>の <code class=\"language-plaintext highlighter-rouge\">[pi4]</code>の行の前に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group</code>と<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>については使用するモニタに合わせる。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group=2</code>はモニタ種別でDMT(一般的にモニタディスプレイ)、<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_mode=82</code>が 1920x1080 60Hz(1080p)を示している。<br />\n設定値の内容については、<a href=\"https://www.raspberrypi.org/documentation/configuration/config-txt/video.md\" target=\"_blank\">Video options in config.txt</a>\nを参照。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>はテキストモードで表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nhdmi_group=2\nhdmi_mode=82\nframebuffer_width=1920\nframebuffer_height=1080\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nHDMIディスプレイを常に接続しているなら設定しなくても問題ないが、<br />\nHDMIディスプレイをはずしてVNCでリモート接続だけする場合は設定しておかないと<br />\n解像度が1024x768までしか設定できなくなるので注意。</p>\n</blockquote>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S7 Splash Screen\n            Would you like to show the splash screen at boot? \n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nこの操作で<code class=\"language-plaintext highlighter-rouge\">/boot/cmdline.txt</code>が書き換えられるらしい。</p>\n</blockquote>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\" target=\"_blank\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n            B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    3 Interfacing Options        \n        P3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>    \n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n<p>Windows側のクライアントは、<br />\n<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a> \nから VNC Viewerをダウンロード。<br />\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。<br />\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。<br />\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。<br />\n日本語化の手順はこちらを参考に。 <a href=\"http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。<br />\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"--enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マウスフォーカスの変更\">マウスフォーカスの変更</h1>\n\n<p>ウィンドウをクリックしないとフォーカスが移動しないのはイライラするので x-mouse相当の設定をする。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/xdg/openbox/lxde-pi-rc.xml</code>の以下の部分をnoからyesに変更。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><followMouse>yes</followMouse>\n</code></pre></div></div>\n\n<h1 id=\"ipv6の無効化\">IPv6の無効化</h1>\n<p>IPv6を無効化したい場合は以下を設定。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/sysctl.conf</code>に以下を追加する\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Disable IPv6\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\n</code></pre></div>    </div>\n  </li>\n  <li>以下を実行する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sysctl <span class=\"nt\">-p</span>\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>UbuntuをNative環境にインストールする(20.04)</title>\n  </head>\n  <body>\n    <header>\n      <h1>UbuntuをNative環境にインストールする(20.04)</h1>\n      <p>Ubunt(20.04)をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"インストール\">インストール</h1>\n<p>最初の起動まではこちらに詳しく書かれています。<br />\n<a href=\"https://qiita.com/koba-jon/items/019a3b4eac4f60ca89c9\" target=\"_blank\">Ubuntu 20.04 LTS インストール方法(外付けドライブ用)</a></p>\n\n<blockquote>\n  <p>[!WARNING]\nEFIシステムパーティションを作成するのを忘れがち。<br />\n外付けだと作成忘れると内蔵HDDのEFIシステムパーティションに追記されちゃうので注意。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\nユーザ名に英数字以外を含むとChrome remote desktop の インストール&設定でエラーになることがあるので、<br />\n英数字以外を含まないユーザ名を設定することをおススメします。</p>\n</blockquote>\n\n<h1 id=\"その後の設定手順\">その後の設定手順</h1>\n\n<h2 id=\"最新版にアップデート\">最新版にアップデート</h2>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h2 id=\"ipアドレス確認したいとき\">IPアドレス確認したいとき</h2>\n<p>SSHのクライアントからの接続先が分からないと困るので、\nIPアドレスを確認するためにnet-toolsをインストールして\nifconfigで確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\nifconfig\n</code></pre></div></div>\n\n<h2 id=\"sshのインストール\">sshのインストール</h2>\n<p>WindowsPCにあるデータをubuntuPCにキーボードで打ち込むのは効率が悪いので、最も簡単なsshでリモートログインできるようにしてみる。</p>\n\n<p>以下のコマンドでsshサーバをインストールし、サーバを開始する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n\n<p>クライアントからTeraTermなどでsshで対象マシンのポート22に接続する</p>\n\n<h2 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面ロック を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h2 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h2>\n\n<p>とりあえず入れとこう</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\n</code></pre></div></div>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが…</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h3 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>NFSサーバの再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.XX.XX:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"bashの設定変更\">bashの設定変更</h2>\n\n<p>~/.bashrcに以下を追記</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h2 id=\"guiの動作の設定変更をお好みで\">GUIの動作の設定変更をお好みで</h2>\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.mutter auto-maximize\ngsettings get org.gnome.mutter edge-tiling\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.desktop.wm.preferences auto-raise \ngsettings get org.gnome.desktop.wm.preferences focus-mode \ngsettings get org.gnome.desktop.wm.preferences raise-on-click\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.shell.extensions.desktop-icons show-home\ngsettings get org.gnome.shell.extensions.desktop-icons show-trash\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。<br />\ndconf-editorでも良いよ(しつこい…)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 ==================================</span>\n<span class=\"c\"># Dockバー上のゴミ箱表示有無</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock show-trash\n\n<span class=\"c\"># アプリケーションのDockバー上の表示位置</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock show-apps-at-top\n\n<span class=\"c\"># Dockバー表示位置</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock dock-position\n\n<span class=\"c\"># Dockバー上のアイコンサイズ</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock dash-max-icon-size\n\n<span class=\"c\"># 設定 ==================================</span>\n<span class=\"c\"># Dockバー上のゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># Dockバー上のアイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.interface cursor-size\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"capsキーをctrlキーに変更\">CAPSキーをCtrlキーに変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.input-sources xkb-options\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.input-sources xkb-options <span class=\"se\">\\[\\'</span>ctrl:nocaps<span class=\"se\">\\'\\]</span>\n\n<span class=\"c\"># 設定を有効にするにはGUIでのlogout&再loginが必要</span>\n\n</code></pre></div></div>\n\n<h2 id=\"日本語入力\">日本語入力</h2>\n<p>前は設定必要だったけど、なんか大丈夫になったみたい</p>\n<blockquote>\n  <p>[!NOTE]\n以前の設定手順<br />\n右上の「A」または「あ」と書かれたアイコンをクリック→「テキスト入力設定」を選択\n一番下の「インストールされている言語の管理」をクリック\n「言語サポートが完全にはインストールされていません」と出るので「インストール」をクリック\n一旦log offして再log in\n右上のJaまたはMoと書かれたアイコンをクリック\n    Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)\nキーボードの全角/半角キーで切り替えられるようになる</p>\n</blockquote>\n\n<h2 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h2>\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nUbuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>IPv6が動いてるとうまく行かない環境のときは無効化しておく。<br />\n参考:<a href=\"https://www.server-memo.net/ubuntu/ubuntu_disable_ipv6.html#IPv6-4\" target=\"_blank\">UbuntuでIPv6を無効化する方法</a></p>\n\n<p>sysctlで設定するのがお手軽かな?</p>\n\n<h2 id=\"システムバックアップ\">システムバックアップ</h2>\n<p>Nativeならバックアップしといた方がいいかな。<br />\n参考:<a href=\"https://gihyo.jp/admin/serial/01/ubuntu-recipe/0588\">第588回 TimeShiftでUbuntuをホットバックアップする 2019年版</a> <br />\n<code class=\"language-plaintext highlighter-rouge\">add-apt-repository</code> でリポジトリを追加しなくても大丈夫。標準リポジトリにも入ってるから。</p>\n\n<h2 id=\"chrome-remote-desktopインストール\">chrome remote desktopインストール</h2>\n\n<p>remote desktop使いたいので、インストールする。</p>\n\n<h3 id=\"chromeのインストール\">chromeのインストール</h3>\n<p><a href=\"https://www.google.com/chrome/\">Google Chrome - Google の高速で安全なブラウザをダウンロード</a>からダウンロードしてインストール。</p>\n\n<h3 id=\"おまじない\">おまじない</h3>\n<p>remote desktopのインストール時にエラーが発生するので、以下のディレクトリを作成しておく。<br />\n(インストーラのバグらしい)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/.config/chrome-remote-desktop\n</code></pre></div></div>\n\n<h3 id=\"remote-desktopのインストール\">remote desktopのインストール</h3>\n<p>以下参考ページ</p>\n<ul>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>パソコンでリモート アクセスを設定する</li>\n      <li>パソコンにリモート アクセスする</li>\n    </ul>\n  </li>\n</ul>\n\n<p>接続すると、開始するセッションの選択画面になるので、「Ubuntu」を選択。</p>\n\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。<br />\nこのダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></li>\n</ul>\n\n<p>要約すると\n<code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下の内容で作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tensorflowの転移学習に関するメモ</title>\n  </head>\n  <body>\n    <header>\n      <h1>tensorflowの転移学習に関するメモ</h1>\n      <p>tensorflowの転移学習を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"tensorflow-1xでのssdの転移学習の例\">tensorflow 1.XでのSSDの転移学習の例</h1>\n\n<p><a href=\"https://github.com/ippei8jp/tf1_TransferLearning\" target=\"_blank\">https://github.com/ippei8jp/tf1_TransferLearning</a></p>\n\n<h1 id=\"tensorflow-2xでのssdの転移学習の例\">tensorflow 2.XでのSSDの転移学習の例</h1>\n\n<p><a href=\"https://github.com/ippei8jp/tf2_TransferLearning\" target=\"_blank\">https://github.com/ippei8jp/tf2_TransferLearning</a></p>\n\n<h1 id=\"pascal-voc-で転移学習\">Pascal VOC で転移学習</h1>\n\n<p>ローカルマシン(Core-i7/Win10/WSL2/Ubuntu20.04/Tensorflow2.4)で試してみた手順が以下。<br />\nかなり時間がかかるけど、GPUなくても24時間もあればそれなりの回数がこなせる(5000回くらい?)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA  To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.</code> と言われているので、これらを有効にしてTensorflowを再構築すればもうちっと速くなるはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nずいぶん前にtensorflow 1.1.0でAVXを有効にしたら、MNISTの学習で実行時間が半分になった記憶もあるが、<br />\ntensorflow 1.6以降でAVXは有効になってて、AVX2,FMAの有無では10%くらいしか違わないらしい。<br />\n参考:<a href=\"https://www.acceluniverse.com/blog/developers/2019/05/tensorflowavx2-fma.html\" target=\"_blank\">TensorFlowのAVX2, FMAの有無で性能の比較をする</a><br />\ntensorflowのbuildに十何時間もかかることを考えたら 「ま、いっか」となっちゃうな…</p>\n</blockquote>\n\n<h2 id=\"実行手順\">実行手順</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">BASE_DIR</span><span class=\"o\">=</span>/work/test\n<span class=\"nv\">MODELS_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>/models\n<span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>/voc\n\n<span class=\"c\"># modelsリポジトリのclone</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>\ngit clone <span class=\"nt\">--depth</span> 1 https://github.com/tensorflow/models.git\n<span class=\"c\"># object_detectionモジュール未インストールならインストールすること</span>\n\n<span class=\"c\"># Pascal VOC データ取得</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>\nwget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar <span class=\"nt\">-O</span> - | <span class=\"nb\">tar </span>xvf -\n\n<span class=\"c\"># 学習データ(tf-record)の作成</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython create_pascal_tf_record.py <span class=\"nt\">--label_map_path</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"nt\">--data_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/VOCdevkit <span class=\"nt\">--year</span> VOC2007 <span class=\"nt\">--set</span> train <span class=\"nt\">--output_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pascal_train.record\npython create_pascal_tf_record.py <span class=\"nt\">--label_map_path</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"nt\">--data_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/VOCdevkit <span class=\"nt\">--year</span> VOC2007 <span class=\"nt\">--set</span> val <span class=\"nt\">--output_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pascal_val.record\n\n<span class=\"c\"># 元となるモデルのダウンロード</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/\nwget http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8.tar.gz <span class=\"nt\">-O</span> - | <span class=\"nb\">tar </span>xzvf -\n<span class=\"nb\">cp </span>ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/pipeline.config <span class=\"nb\">.</span>\n\n<span class=\"c\"># pipeline.config を編集(下記参照)</span>\n\n<span class=\"c\"># 学習実行</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython model_main_tf2.py <span class=\"nt\">--pipeline_config_path</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--model_dir</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--alsologtostderr</span>\n</code></pre></div></div>\n\n<h3 id=\"object_detectionモジュールのインストール方法\">object_detectionモジュールのインストール方法</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models/research\nprotoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n<span class=\"nb\">cp </span>object_detection/packages/tf2/setup.py <span class=\"nb\">.</span> \n<span class=\"c\"># ↑ tf1の場合はtf1ディレクトリを指定する</span>\n\npip <span class=\"nb\">install</span> <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"pipelineconfig-の修正例\">pipeline.config\tの修正例</h3>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/pipeline.config\t2020-07-11 09:16:11.000000000 +0900\n</span><span class=\"gi\">+++ pipeline.config\t2021-05-11 05:22:30.943865000 +0900\n</span><span class=\"p\">@@ -1,6 +1,6 @@</span>\n model {\n   ssd {\n<span class=\"gd\">-    num_classes: 90\n</span><span class=\"gi\">+    num_classes: 20\n</span>     image_resizer {\n       fixed_shape_resizer {\n         height: 320\n<span class=\"p\">@@ -132,7 +132,7 @@</span>\n   }\n }\n train_config {\n<span class=\"gd\">-  batch_size: 128\n</span><span class=\"gi\">+  batch_size: 64\n</span>   data_augmentation_options {\n     random_horizontal_flip {\n     }\n<span class=\"p\">@@ -162,19 +162,19 @@</span>\n     }\n     use_moving_average: false\n   }\n<span class=\"gd\">-  fine_tune_checkpoint: \"PATH_TO_BE_CONFIGURED\"\n-  num_steps: 50000\n</span><span class=\"gi\">+  fine_tune_checkpoint: \"/work/test/voc/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/checkpoint/ckpt-0\"\n+  num_steps: 2000\n</span>   startup_delay_steps: 0.0\n   replicas_to_aggregate: 8\n   max_number_of_boxes: 100\n   unpad_groundtruth_tensors: false\n<span class=\"gd\">-  fine_tune_checkpoint_type: \"classification\"\n</span><span class=\"gi\">+  fine_tune_checkpoint_type: \"detection\"\n</span>   fine_tune_checkpoint_version: V2\n }\n train_input_reader {\n<span class=\"gd\">-  label_map_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+  label_map_path: \"/work/test/models/research/object_detection/data/pascal_label_map.pbtxt\"\n</span>   tf_record_input_reader {\n<span class=\"gd\">-    input_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+    input_path: \"/work/test/voc/pascal_train.record\"\n</span>   }\n }\n eval_config {\n<span class=\"p\">@@ -182,10 +182,10 @@</span>\n   use_moving_averages: false\n }\n eval_input_reader {\n<span class=\"gd\">-  label_map_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+  label_map_path: \"/work/test/models/research/object_detection/data/pascal_label_map.pbtxt\"\n</span>   shuffle: false\n   num_epochs: 1\n   tf_record_input_reader {\n<span class=\"gd\">-    input_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+    input_path: \"/work/test/voc/pascal_val.record\"\n</span>   }\n }\n</code></pre></div></div>\n\n<h2 id=\"学習の中断\">学習の中断</h2>\n\n<p>学習処理を中断したい場合は、CTRL+cを入力する。<br />\nただし、中断した時点でのチェックポイントの保存は行われないので、それまでに保存されたチェックポイントが有効。<br />\nデフォルトではチェックポイントの保存は1000回毎なので、1000回未満で中断すると学習してないのと同じ(たぶん)。</p>\n\n<h2 id=\"追加学習学習の再開\">追加学習/学習の再開</h2>\n\n<p>中断した学習を再開したい場合や設定した学習回数では十分ではなかった場合の追加学習を行うには<br />\n<code class=\"language-plaintext highlighter-rouge\">model_main_tf2.py</code>を再度実行すればOK。<br />\nそれまで実行した学習結果の続きを実行してくれます。<br />\n(特に設定ファイル類を変更する必要はないみたい)</p>\n\n<p>追加学習の場合や学習回数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--num_train_steps</code>オプションで新しい学習回数を指定するか、\n<code class=\"language-plaintext highlighter-rouge\">pipeline.config</code>ファイル内の<code class=\"language-plaintext highlighter-rouge\">num_steps</code>の項目を変更します。</p>\n\n<p>また、デフォルトでは学習結果は1000回毎にセーブされるので、学習回数が1000回未満の場合や端数が出る場合、結果がセーブされません。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">--checkpoint_every_n</code>オプションで何回毎にセーブするかを指定する必要があります。</p>\n\n<p>以下に例を示します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python model_main_tf2.py <span class=\"nt\">--pipeline_config_path</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--model_dir</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--alsologtostderr</span> <span class=\"nt\">--checkpoint_every_n</span><span class=\"o\">=</span>100 <span class=\"nt\">--num_train_steps</span><span class=\"o\">=</span>2300\n</code></pre></div></div>\n<h2 id=\"モデルのエクスポート\">モデルのエクスポート</h2>\n\n<p>学習を行った結果をエクスポートしてsaved_modelを作成します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython exporter_main_v2.py <span class=\"nt\">--trained_checkpoint_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--pipeline_config_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--output_directory</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/inference_voc\n<span class=\"c\"># ラベルファイルもコピーしておく</span>\n<span class=\"nb\">cp</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/inference_voc/\n</code></pre></div></div>\n\n<h1 id=\"学習データtf-recordの確認方法\">学習データ(tf-record)の確認方法</h1>\n<h2 id=\"セットアップ\">セットアップ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tfrecord\n<span class=\"nb\">cd</span>  /work/tfrecord\n<span class=\"c\"># 仮想環境の準備</span>\npyenv virtualenv 3.8.9 tfrecord\npyenv <span class=\"nb\">local </span>tfrecord \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n<span class=\"c\"># 必要なモジュールのインストール</span>\npip <span class=\"nb\">install </span><span class=\"nv\">tensorflow</span><span class=\"o\">==</span>2.<span class=\"k\">*</span>\npip <span class=\"nb\">install </span>flask\npip <span class=\"nb\">install </span>pillow\npip <span class=\"nb\">install </span>tqdm\n</code></pre></div></div>\n\n<h2 id=\"リポジトリのclone\">リポジトリのclone</h2>\n\n<p>以下のリポジトリから</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/sulc/tfrecord-viewer.git\n<span class=\"nb\">cd </span>tfrecord-viewer/\n</code></pre></div></div>\n<h2 id=\"viewerの実行\">Viewerの実行</h2>\n\n<p>webサーバを起動する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfviewer.py «tf-recordファイル» \n</code></pre></div></div>\n\n<p>例:</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfviewer.py /work/test/train.record \n</code></pre></div></div>\n\n<p>ブラウザで以下に接続する(ポート番号は実行環境によって変わるかも)<br />\n<code class=\"language-plaintext highlighter-rouge\">http://localhost:5000/</code></p>\n\n<p>表示下部にサムネイルが表示されるので、クリックすると中央に拡大表示される。</p>\n\n<h2 id=\"元画像データの抽出\">元画像データの抽出</h2>\n\n<p>以下のパッチを当てる<br />\n(元のファイル名がディレクトリ名を含んでいるとファイル作成エラーになるので)</p>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tfrecord_to_imfolder.py b/tfrecord_to_imfolder.py\nindex 81bb764..7a0e269 100644\n</span><span class=\"gd\">--- a/tfrecord_to_imfolder.py\n</span><span class=\"gi\">+++ b/tfrecord_to_imfolder.py\n</span><span class=\"p\">@@ -41,6 +41,7 @@</span> def parse_tfrecord(record):\n     feat = example.features.feature\n\n     filename = feat[args.filename_key].bytes_list.value[0].decode(\"utf-8\")\n<span class=\"gi\">+    filename = os.path.basename(filename)\n</span>     img =  feat[args.image_key].bytes_list.value[0]\n     label = feat[args.class_label_key].bytes_list.value[0].decode(\"utf-8\")\n</code></pre></div></div>\n\n<p>以下のコマンドを実行<br />\n<code class=\"language-plaintext highlighter-rouge\">--class-label-key</code> には他にも指定できるものがあるけど、これくらいしか使わないと思う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfrecord_to_imfolder.py <span class=\"se\">\\</span>\n  <span class=\"nt\">--output_path</span> «ファイル出力ディレクトリ» <span class=\"se\">\\</span>\n  <span class=\"nt\">--class-label-key</span> image/object/class/text <span class=\"se\">\\</span>\n  <span class=\"nt\">-v</span> <span class=\"se\">\\</span>\n   «tf-recordファイル»\n</code></pre></div></div>\n\n<p>実行すると、«ファイル出力ディレクトリ»/«クラス名»/の下に画像ファイルが生成される。<br />\n(画像中に複数のクラスが含まれる場合は、一番最初のクラスが使用される)</p>\n\n<p>例:</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfrecord_to_imfolder.py <span class=\"se\">\\</span>\n  <span class=\"nt\">--output_path</span> ./hogehoge <span class=\"se\">\\</span>\n  <span class=\"nt\">--class-label-key</span> image/object/class/text <span class=\"se\">\\</span>\n  <span class=\"nt\">-v</span> <span class=\"se\">\\</span>\n  /work/test/train.record\n</code></pre></div></div>\n\n<h1 id=\"参考になるかもしれないページ\">参考になるかもしれないページ</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8c3197d11f61812546a9?fbclid=IwAR35TFl3mOK9XxXcZChP8wNkxp8cF6HZwnrWiTborZqETz7LJBZ88Dehvvs\">TensorFlowでの物体検出が超手軽にできる「Object Detection Tools」をTensorFlow 2.xに対応しました</a></p>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50?fbclid=IwAR35TFl3mOK9XxXcZChP8wNkxp8cF6HZwnrWiTborZqETz7LJBZ88Dehvvs\">Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Visual Studio Code で Jupyter Notebook</title>\n  </head>\n  <body>\n    <header>\n      <h1>Visual Studio Code で Jupyter Notebook</h1>\n      <p>Visual Studio Code で Jupyter Notebookを実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Visual Studio CodeでJupyter Notebookを実行する。</p>\n\n<p>サンプルプログラムがJupyter Notebookだったりするとブラウザで動かすのめんどいので、Visual Studio Codeで動かしてみた。<br />\n参考:このあたりかな? <a href=\"https://codeaid.jp/vscode-jupyter/\" target=\"_blank\">Visual Studio CodeでJupyter Notebookを使う方法</a></p>\n\n<p>以下では、<a href=\"https://www.koi.mashykom.com/tensorflow.html\" target=\"_blank\">SSD と YOLO を用いた物体検出</a> の「Object Detection APIを用いた物体検出」を参考に進めてみる。</p>\n\n<h1 id=\"前準備\">前準備</h1>\n<p>作業ディレクトリとツール類のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Tensorflow\n<span class=\"nb\">cd</span> /work/Tensorflow\n\n<span class=\"c\"># pyenvの仮想環境作成と切り替え</span>\npyenv virtualenv 3.7.10 tensorflow\npyenv <span class=\"nb\">local </span>tensorflow\n<span class=\"c\"># お約束</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># Protocol buffers コンパイラのインストール(Jupyter Notebookの実行には関係ない)</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n\n<span class=\"c\"># Jupyter Notebook のモジュールインストール</span>\npip <span class=\"nb\">install </span>notebook\n</code></pre></div></div>\n\n<h1 id=\"modelsリポジトリのクローン\">modelsリポジトリのクローン</h1>\n<p>実行するプログラムの準備</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git\n</code></pre></div></div>\n\n<h1 id=\"visual-studio-codeの起動\">Visual Studio Codeの起動</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models/\ncode <span class=\"nb\">.</span>\n</code></pre></div></div>\n<p><strong>*** Visual Studio Code起動 ***</strong></p>\n\n<h1 id=\"visual-studio-codeでの作業\">Visual Studio Codeでの作業</h1>\n<p>以下、Visual Studio Codeで作業する</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>拡張機能から「Jupyter」と「Python」を選択し、対象マシンにインストール</p>\n\n<h2 id=\"使用するpythonを選択その1\">使用するpythonを選択その1</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n<ul>\n  <li>Python: インタプリター選択\n    <ul>\n      <li>これはどこで有効なんだろうか?念のため設定しておこう。</li>\n    </ul>\n  </li>\n  <li>Jupyter: Select interpreter to start jupyter server\n    <ul>\n      <li>たぶん、Jupyter Notebookそのものを実行するためのPython<br />\njupyter-notebookモジュールがインストールされている必要がある</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"対象ファイルをオープン\">対象ファイルをオープン</h2>\n<p>エクスプローラから<br />\n<code class=\"language-plaintext highlighter-rouge\">research/object_detection/colab_tutorials/object_detection_tutorial.ipynb</code>\nを開く<br />\n<code class=\"language-plaintext highlighter-rouge\">a notebook could execute harmful code when opened. ~</code>\nと言われるので、<code class=\"language-plaintext highlighter-rouge\">Trust</code> をクリック</p>\n\n<h2 id=\"使用するpythonを選択その2\">使用するpythonを選択その2</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する<br />\n(ipynbファイルを開かないと選べない)</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n\n<ul>\n  <li>Jupyter: Select a Kernel\n    <ul>\n      <li>たぶん、Notebook内のpythonスクリプトを実行するためのPython<br />\nシステムコマンド(!を行頭につけて指定)として実行したり、<code class=\"language-plaintext highlighter-rouge\">%%bash</code> で指定したCode cell で実行した<br />\npython スクリプト(pipコマンドなども含む)を実行した場合もこのバージョンが使用される</li>\n      <li>ipykernelモジュールをインストールしておく必要があるが、入ってなければVSCodeからインストールできるので気にしなくても大丈夫。<br />\n(Jupyter Notebook のモジュールがインストールされていれば同時にインストールされている)</li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nその1、その2で選択するバージョンはそれぞれ異なるバージョンを設定できるが、<br />\n上でpyenvで選択したバージョンで統一しておくのが混乱しなくて良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSelect a Kernel の設定内容は以下のファイルに保存されるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.vscode-server/data/User/globalStorage/ms-toolsai.jupyter/kernelSpecPaths.json</code><br />\nこの設定はシステム(ターゲットマシン)で1つのようなので、他のプロジェクトで設定を変更した場合は再度確認しておくのが良いと思う。</p>\n</blockquote>\n\n<h2 id=\"エラーになる部分の対策\">エラーになる部分の対策</h2>\n\n<h3 id=\"その1\">その1</h3>\n<p>「Get tensorflow/models or cd to parent directory of the repository.」\nの下のCode cellの最後に以下を追加</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n<span class=\"n\">cwd</span><span class=\"o\">=</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getcwd</span><span class=\"p\">()</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research/slim\"</span><span class=\"p\">)</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research\"</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"その2\">その2</h3>\n<p>以下のcellを削除(エラーになる)<br />\n(おそらく、その1で追加している処理に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>%%bash \ncd models/research\npip install .\n</code></pre></div></div>\n\n<h3 id=\"その3\">その3</h3>\n<p>「Instance Segmentation」以下はエラーになる(RCNNのモデル形状が変更された?)ので削除しておく。<br />\n(手順の本筋に関係ないので)</p>\n\n<h2 id=\"実行\">実行</h2>\n<p>最初のCode cell(Installの下)で▶(Run)をクリック<br />\nあとは、続くcellで▶(Run)をクリックしていく。</p>\n\n<p>または、ツールバーの⏩(Run all cells)をクリックする</p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<h2 id=\"ipynbファイルをpythonファイルにエクスポートする\">ipynbファイルをpythonファイルにエクスポートする。</h2>\n\n<p>Visual Studio Codeのエクスプローラペインで対象のipynbファイルを右クリックして<br />\n<code class=\"language-plaintext highlighter-rouge\">Convert a Notebook to Python Script</code>を選択すると、変換結果が新しいファイルとしてエディタに開かれる。<br />\nこれを名前を付けて保存する。</p>\n\n<p>または、コマンドラインから以下のコマンドを実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>jupyter nbconvert «対象ファイル».ipynb <span class=\"nt\">--to</span> python\n</code></pre></div></div>\n<p>デフォルトの出力ファイル名は«対象ファイル名».py(拡張子をipynb→pyに変えたもの)になる。</p>\n\n<p>ただし、単独で動かす場合は <code class=\"language-plaintext highlighter-rouge\">get_ipython()</code> で始まる行(システムコマンドを実行する部分)はエラーになるので、コメントアウトしておくこと。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Keras on tensorflow2 で SSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>Keras on tensorflow2 で SSD</h1>\n      <p>Tensorflow2上のKerasでSSDを実行を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>※ 2021.05.21 kerasをtensorflow.kerasに変更</p>\n\n<h1 id=\"概要\">概要</h1>\n\n<p>Kerasを使ってSSDを実行してみようと思ったら、Tensorflow1.x上の情報ばかり出てきて、Tensorflow2で実行するのに手間取ったのでメモ。<br />\n(最終的にopenVINOに持っていきたいなぁ、と思って試し始めたんだけど、openVINOにサクッと変換できるのはcaffeだった😅)<br />\nということで、やったけど 続きはないかも。実行遅いし…😩💨</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p><a href=\"https://smilerobo.com/papero/tips_keras_tf_ssd/\" target=\"_blank\">【実験】学習済のSSDを使ってPaPeRo i に複数種類の物体を数えさせる</a>\nを参考に、KerasをTensorflow2で動かしてみる。</p>\n\n<p>Pythonは3.8を使用した(念のため明記しておく)。</p>\n\n<p>Anaconda使ってないし、Paperoじゃないので、そのまんまじゃないけど、<br />\nとりあえずSSDを動かしてみよう。</p>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n\n<p>まずは、python仮想環境の準備をする。<br />\npyenv環境前提。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースディレクトリとpython仮想環境の準備</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/keras2/\n<span class=\"nb\">cd</span> /work/keras2/\npyenv virtualenv 3.8.8 keras2\npyenv <span class=\"nb\">local </span>keras2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># pythonモジュールのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n<span class=\"c\"># kerasはtensorflow内を直接参照にしたので不要  </span>\n<span class=\"c\"># pip install keras</span>\npip <span class=\"nb\">install </span>matplotlib\npip <span class=\"nb\">install </span>imageio\n</code></pre></div></div>\n\n<p>インストールされているpythonモジュールは以下の通り</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.2\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.4.0\ngoogle-auth==1.30.0\ngoogle-auth-oauthlib==0.4.4\ngoogle-pasta==0.2.0\ngrpcio==1.34.1\nh5py==3.1.0\nidna==2.10\nimageio==2.9.0\nkeras-nightly==2.5.0.dev2021032900\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.4.2\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.2.52\nopt-einsum==3.3.0\nPillow==8.2.0\nprotobuf==3.17.0\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nsix==1.15.0\ntensorboard==2.5.0\ntensorboard-data-server==0.6.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.5.0\ntensorflow-estimator==2.5.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==2.0.1\nwrapt==1.12.1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nKeras修正以前の状態は以下</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.1\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.3.3\ngoogle-auth==1.28.0\ngoogle-auth-oauthlib==0.4.3\ngoogle-pasta==0.2.0\ngrpcio==1.32.0\nh5py==2.10.0\nidna==2.10\nimageio==2.9.0\nKeras==2.4.3\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.3.4\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.1.48\nopt-einsum==3.3.0\nPillow==8.1.2\nprotobuf==3.15.6\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nPyYAML==5.4.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nscipy==1.6.1\nsix==1.15.0\ntensorboard==2.4.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.4.1\ntensorflow-estimator==2.4.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==1.0.1\nwrapt==1.12.1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"patchファイルの準備\">patchファイルの準備</h2>\n\n<p>参照先には色々手順が書いてあるが、めんどくさいので パッチファイル用意した(足りない修正もあるし)。<br />\n以下の内容を<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code> <code class=\"language-plaintext highlighter-rouge\">ssd_keras_2.patch</code>のファイル名で保存しておく。</p>\n\n<h3 id=\"ssd_keraspatch\">ssd_keras.patch</h3>\n\n<p>参照先の情報によるpatch</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/ssd.py b/ssd.py\nindex c0049d8..656cd83 100644\n</span><span class=\"gd\">--- a/ssd.py\n</span><span class=\"gi\">+++ b/ssd.py\n</span><span class=\"p\">@@ -2,14 +2,15 @@</span>\n \n import keras.backend as K\n from keras.layers import Activation\n<span class=\"gd\">-from keras.layers import AtrousConvolution2D\n</span><span class=\"gi\">+#from keras.layers import AtrousConvolution2D\n</span> from keras.layers import Convolution2D\n from keras.layers import Dense\n from keras.layers import Flatten\n from keras.layers import GlobalAveragePooling2D\n from keras.layers import Input\n from keras.layers import MaxPooling2D\n<span class=\"gd\">-from keras.layers import merge\n</span><span class=\"gi\">+#from keras.layers import merge\n+from keras.layers.merge import concatenate\n</span> from keras.layers import Reshape\n from keras.layers import ZeroPadding2D\n from keras.models import Model\n<span class=\"p\">@@ -34,109 +35,115 @@</span> def SSD300(input_shape, num_classes=21):\n     input_tensor = input_tensor = Input(shape=input_shape)\n     img_size = (input_shape[1], input_shape[0])\n     net['input'] = input_tensor\n<span class=\"gd\">-    net['conv1_1'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    net['conv1_1'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_1')(net['input'])\n<span class=\"gd\">-    net['conv1_2'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    \n+    net['conv1_2'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_2')(net['conv1_1'])\n<span class=\"gd\">-    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+\n+    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool1')(net['conv1_2'])\n     # Block 2\n<span class=\"gd\">-    net['conv2_1'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+    net['conv2_1'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_1')(net['pool1'])\n<span class=\"gd\">-    net['conv2_2'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+\n+    net['conv2_2'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_2')(net['conv2_1'])\n<span class=\"gd\">-    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool2')(net['conv2_2'])\n<span class=\"gi\">+\n</span>     # Block 3\n<span class=\"gd\">-    net['conv3_1'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_1'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_1')(net['pool2'])\n<span class=\"gd\">-    net['conv3_2'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_2'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_2')(net['conv3_1'])\n<span class=\"gd\">-    net['conv3_3'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_3'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_3')(net['conv3_2'])\n<span class=\"gd\">-    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool3')(net['conv3_3'])\n     # Block 4\n<span class=\"gd\">-    net['conv4_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_1')(net['pool3'])\n<span class=\"gd\">-    net['conv4_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_2')(net['conv4_1'])\n<span class=\"gd\">-    net['conv4_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_3')(net['conv4_2'])\n<span class=\"gd\">-    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool4')(net['conv4_3'])\n<span class=\"gd\">-    # Block 5\n-    net['conv5_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+# Block 5\n+    net['conv5_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_1')(net['pool4'])\n<span class=\"gd\">-    net['conv5_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_2')(net['conv5_1'])\n<span class=\"gd\">-    net['conv5_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_3')(net['conv5_2'])\n<span class=\"gd\">-    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), border_mode='same',\n</span><span class=\"gi\">+    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), padding='same',\n</span>                                 name='pool5')(net['conv5_3'])\n     # FC6\n<span class=\"gd\">-    net['fc6'] = AtrousConvolution2D(1024, 3, 3, atrous_rate=(6, 6),\n-                                     activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['fc6'] = Convolution2D(1024, (3, 3), dilation_rate=(6, 6),\n+                                     activation='relu', padding='same',\n</span>                                      name='fc6')(net['pool5'])\n     # x = Dropout(0.5, name='drop6')(x)\n     # FC7\n<span class=\"gd\">-    net['fc7'] = Convolution2D(1024, 1, 1, activation='relu',\n-                               border_mode='same', name='fc7')(net['fc6'])\n</span><span class=\"gi\">+    net['fc7'] = Convolution2D(1024, (1, 1), activation='relu',\n+                               padding='same', name='fc7')(net['fc6'])\n</span>     # x = Dropout(0.5, name='drop7')(x)\n     # Block 6\n<span class=\"gd\">-    net['conv6_1'] = Convolution2D(256, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv6_1'] = Convolution2D(256, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv6_1')(net['fc7'])\n<span class=\"gd\">-    net['conv6_2'] = Convolution2D(512, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+\n+\n+    net['conv6_2'] = Convolution2D(512, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv6_2')(net['conv6_1'])\n<span class=\"gd\">-    # Block 7\n-    net['conv7_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+        # Block 7\n+    net['conv7_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv7_1')(net['conv6_2'])\n     net['conv7_2'] = ZeroPadding2D()(net['conv7_1'])\n<span class=\"gd\">-    net['conv7_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='valid',\n</span><span class=\"gi\">+    net['conv7_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='valid',\n</span>                                    name='conv7_2')(net['conv7_2'])\n     # Block 8\n<span class=\"gd\">-    net['conv8_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv8_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv8_1')(net['conv7_2'])\n<span class=\"gd\">-    net['conv8_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['conv8_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv8_2')(net['conv8_1'])\n     # Last Pool\n     net['pool6'] = GlobalAveragePooling2D(name='pool6')(net['conv8_2'])\n     # Prediction from conv4_3\n     net['conv4_3_norm'] = Normalize(20, name='conv4_3_norm')(net['conv4_3'])\n     num_priors = 3\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv4_3_norm_mbox_loc')(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_loc'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_loc_flat')\n<span class=\"p\">@@ -144,7 +151,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv4_3_norm_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_conf'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_conf_flat')\n<span class=\"p\">@@ -155,16 +162,16 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv4_3_norm_mbox_priorbox'] = priorbox(net['conv4_3_norm'])\n     # Prediction from fc7\n     num_priors = 6\n<span class=\"gd\">-    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, 3, 3,\n-                                        border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, (3, 3),\n+                                        padding='same',\n</span>                                         name='fc7_mbox_loc')(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_loc_flat')\n     net['fc7_mbox_loc_flat'] = flatten(net['fc7_mbox_loc'])\n     name = 'fc7_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, 3, 3,\n-                                         border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, (3, 3),\n+                                         padding='same',\n</span>                                          name=name)(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_conf_flat')\n     net['fc7_mbox_conf_flat'] = flatten(net['fc7_mbox_conf'])\n<span class=\"p\">@@ -174,7 +181,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['fc7_mbox_priorbox'] = priorbox(net['fc7'])\n     # Prediction from conv6_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv6_2_mbox_loc')(net['conv6_2'])\n     net['conv6_2_mbox_loc'] = x\n     flatten = Flatten(name='conv6_2_mbox_loc_flat')\n<span class=\"p\">@@ -182,7 +189,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv6_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv6_2'])\n     net['conv6_2_mbox_conf'] = x\n     flatten = Flatten(name='conv6_2_mbox_conf_flat')\n<span class=\"p\">@@ -193,7 +200,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv6_2_mbox_priorbox'] = priorbox(net['conv6_2'])\n     # Prediction from conv7_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv7_2_mbox_loc')(net['conv7_2'])\n     net['conv7_2_mbox_loc'] = x\n     flatten = Flatten(name='conv7_2_mbox_loc_flat')\n<span class=\"p\">@@ -201,7 +208,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv7_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv7_2'])\n     net['conv7_2_mbox_conf'] = x\n     flatten = Flatten(name='conv7_2_mbox_conf_flat')\n<span class=\"p\">@@ -212,7 +219,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv7_2_mbox_priorbox'] = priorbox(net['conv7_2'])\n     # Prediction from conv8_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv8_2_mbox_loc')(net['conv8_2'])\n     net['conv8_2_mbox_loc'] = x\n     flatten = Flatten(name='conv8_2_mbox_loc_flat')\n<span class=\"p\">@@ -220,7 +227,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv8_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv8_2'])\n     net['conv8_2_mbox_conf'] = x\n     flatten = Flatten(name='conv8_2_mbox_conf_flat')\n<span class=\"p\">@@ -241,7 +248,7 @@</span> def SSD300(input_shape, num_classes=21):\n     priorbox = PriorBox(img_size, 276.0, max_size=330.0, aspect_ratios=[2, 3],\n                         variances=[0.1, 0.1, 0.2, 0.2],\n                         name='pool6_mbox_priorbox')\n<span class=\"gd\">-    if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+    if K.image_data_format() == 'channels_last':\n</span>         target_shape = (1, 1, 256)\n     else:\n         target_shape = (256, 1, 1)\n<span class=\"p\">@@ -249,42 +256,47 @@</span> def SSD300(input_shape, num_classes=21):\n                                     name='pool6_reshaped')(net['pool6'])\n     net['pool6_mbox_priorbox'] = priorbox(net['pool6_reshaped'])\n     # Gather all predictions\n<span class=\"gd\">-    net['mbox_loc'] = merge([net['conv4_3_norm_mbox_loc_flat'],\n</span><span class=\"gi\">+    net['mbox_loc'] = concatenate([net['conv4_3_norm_mbox_loc_flat'],\n</span>                              net['fc7_mbox_loc_flat'],\n                              net['conv6_2_mbox_loc_flat'],\n                              net['conv7_2_mbox_loc_flat'],\n                              net['conv8_2_mbox_loc_flat'],\n                              net['pool6_mbox_loc_flat']],\n<span class=\"gd\">-                            mode='concat', concat_axis=1, name='mbox_loc')\n-    net['mbox_conf'] = merge([net['conv4_3_norm_mbox_conf_flat'],\n</span><span class=\"gi\">+                            axis=1,\n+                                  name='mbox_loc')\n+    net['mbox_conf'] = concatenate([net['conv4_3_norm_mbox_conf_flat'],\n</span>                               net['fc7_mbox_conf_flat'],\n                               net['conv6_2_mbox_conf_flat'],\n                               net['conv7_2_mbox_conf_flat'],\n                               net['conv8_2_mbox_conf_flat'],\n                               net['pool6_mbox_conf_flat']],\n<span class=\"gd\">-                             mode='concat', concat_axis=1, name='mbox_conf')\n-    net['mbox_priorbox'] = merge([net['conv4_3_norm_mbox_priorbox'],\n</span><span class=\"gi\">+                              axis=1,\n+                              name='mbox_conf')\n+    net['mbox_priorbox'] = concatenate([net['conv4_3_norm_mbox_priorbox'],\n</span>                                   net['fc7_mbox_priorbox'],\n                                   net['conv6_2_mbox_priorbox'],\n                                   net['conv7_2_mbox_priorbox'],\n                                   net['conv8_2_mbox_priorbox'],\n                                   net['pool6_mbox_priorbox']],\n<span class=\"gd\">-                                 mode='concat', concat_axis=1,\n</span><span class=\"gi\">+                                 axis=1,\n</span>                                  name='mbox_priorbox')\n     if hasattr(net['mbox_loc'], '_keras_shape'):\n         num_boxes = net['mbox_loc']._keras_shape[-1] // 4\n     elif hasattr(net['mbox_loc'], 'int_shape'):\n<span class=\"gd\">-        num_boxes = K.int_shape(net['mbox_loc'])[-1] // 4\n</span><span class=\"gi\">+        num_boxes = net['mbox_loc'].int_shape()[-1] // 4\n+    elif hasattr(net['mbox_loc'], 'get_shape'):\n+        num_boxes = net['mbox_loc'].get_shape()[-1] // 4\n</span>     net['mbox_loc'] = Reshape((num_boxes, 4),\n                               name='mbox_loc_final')(net['mbox_loc'])\n     net['mbox_conf'] = Reshape((num_boxes, num_classes),\n                                name='mbox_conf_logits')(net['mbox_conf'])\n     net['mbox_conf'] = Activation('softmax',\n                                   name='mbox_conf_final')(net['mbox_conf'])\n<span class=\"gd\">-    net['predictions'] = merge([net['mbox_loc'],\n</span><span class=\"gi\">+    net['predictions'] = concatenate([net['mbox_loc'],\n</span>                                net['mbox_conf'],\n                                net['mbox_priorbox']],\n<span class=\"gd\">-                               mode='concat', concat_axis=2,\n</span><span class=\"gi\">+                               axis=2,\n+                               #axis = 0,\n</span>                                name='predictions')\n     model = Model(net['input'], net['predictions'])\n     return model\n<span class=\"gh\">diff --git a/ssd_layers.py b/ssd_layers.py\nindex 5e10478..41ee510 100644\n</span><span class=\"gd\">--- a/ssd_layers.py\n</span><span class=\"gi\">+++ b/ssd_layers.py\n</span><span class=\"p\">@@ -29,7 +29,8 @@</span> class Normalize(Layer):\n         Add possibility to have one scale for all features.\n     \"\"\"\n     def __init__(self, scale, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n+\n</span>             self.axis = 3\n         else:\n             self.axis = 1\n<span class=\"p\">@@ -41,7 +42,7 @@</span> class Normalize(Layer):\n         shape = (input_shape[self.axis],)\n         init_gamma = self.scale * np.ones(shape)\n         self.gamma = K.variable(init_gamma, name='{}_gamma'.format(self.name))\n<span class=\"gd\">-        self.trainable_weights = [self.gamma]\n</span><span class=\"gi\">+        self._trainable_weights = [self.gamma]\n</span> \n     def call(self, x, mask=None):\n         output = K.l2_normalize(x, self.axis)\n<span class=\"p\">@@ -81,7 +82,7 @@</span> class PriorBox(Layer):\n     \"\"\"\n     def __init__(self, img_size, min_size, max_size=None, aspect_ratios=None,\n                  flip=True, variances=[0.1], clip=True, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n</span>             self.waxis = 2\n             self.haxis = 1\n         else:\n<span class=\"p\">@@ -108,7 +109,7 @@</span> class PriorBox(Layer):\n         self.clip = True\n         super(PriorBox, self).__init__(**kwargs)\n \n<span class=\"gd\">-    def get_output_shape_for(self, input_shape):\n</span><span class=\"gi\">+    def compute_output_shape(self, input_shape):\n</span>         num_priors_ = len(self.aspect_ratios)\n         layer_width = input_shape[self.waxis]\n         layer_height = input_shape[self.haxis]\n<span class=\"gh\">diff --git a/ssd_utils.py b/ssd_utils.py\nindex 0a9ffb1..4fc7a49 100644\n</span><span class=\"gd\">--- a/ssd_utils.py\n</span><span class=\"gi\">+++ b/ssd_utils.py\n</span><span class=\"p\">@@ -1,7 +1,8 @@</span>\n \"\"\"Some utils for SSD.\"\"\"\n \n import numpy as np\n<span class=\"gd\">-import tensorflow as tf\n</span><span class=\"gi\">+import tensorflow.compat.v1 as tf\n+tf.disable_v2_behavior()\n</span> \n \n class BBoxUtility(object):\n<span class=\"gh\">diff --git a/testing_utils/videotest.py b/testing_utils/videotest.py\nindex 0cbae3c..7b2ff4f 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest.py\n</span><span class=\"p\">@@ -3,13 +3,14 @@</span>\n import cv2\n import keras\n from keras.applications.imagenet_utils import preprocess_input\n<span class=\"gd\">-from keras.backend.tensorflow_backend import set_session\n</span><span class=\"gi\">+# from keras.backend.tensorflow_backend import set_session\n</span> from keras.models import Model\n from keras.preprocessing import image \n import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-from scipy.misc import imread, imresize\n</span><span class=\"gi\">+# from scipy.misc import imread, imresize\n+from imageio import imread\n</span> from timeit import default_timer as timer\n \n import sys\n<span class=\"p\">@@ -84,8 +85,8 @@</span> class VideoTest(object):\n             \"trying to open a webcam, make sure you video_path is an integer!\"))\n         \n         # Compute aspect ratio of video     \n<span class=\"gd\">-        vidw = vid.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)\n-        vidh = vid.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)\n</span><span class=\"gi\">+        vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)\n+        vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)\n</span>         vidar = vidw/vidh\n         \n         # Skip frames until reaching start_frame\n<span class=\"gh\">diff --git a/testing_utils/videotest_example.py b/testing_utils/videotest_example.py\nindex fb4d873..27ec148 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest_example.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest_example.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import os\n+# GPU不使用を設定\n+os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n+\n</span> import keras\n import pickle\n from videotest import VideoTest\n<span class=\"p\">@@ -9,16 +13,38 @@</span> from ssd import SSD300 as SSD\n input_shape = (300,300,3)\n \n # Change this if you run with other classes than VOC\n<span class=\"gd\">-class_names = [\"background\", \"aeroplane\", \"bicycle\", \"bird\", \"boat\", \"bottle\", \"bus\", \"car\", \"cat\", \"chair\", \"cow\", \"diningtable\", \"dog\", \"horse\", \"motorbike\", \"person\", \"pottedplant\", \"sheep\", \"sofa\", \"train\", \"tvmonitor\"];\n</span><span class=\"gi\">+class_names = [ \n+                \"background\", \n+                \"aeroplane\", \n+                \"bicycle\", \n+                \"bird\", \n+                \"boat\", \n+                \"bottle\", \n+                \"bus\", \n+                \"car\", \n+                \"cat\", \n+                \"chair\", \n+                \"cow\", \n+                \"diningtable\", \n+                \"dog\", \n+                \"horse\", \n+                \"motorbike\", \n+                \"person\", \n+                \"pottedplant\", \n+                \"sheep\", \n+                \"sofa\", \n+                \"train\", \n+                \"tvmonitor\"\n+            ];\n</span> NUM_CLASSES = len(class_names)\n \n model = SSD(input_shape, num_classes=NUM_CLASSES)\n \n # Change this path if you want to use your own trained weights\n<span class=\"gd\">-model.load_weights('../weights_SSD300.hdf5') \n</span><span class=\"gi\">+model.load_weights('../../weights_SSD300.hdf5') \n</span>         \n vid_test = VideoTest(class_names, model, input_shape)\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('path/to/your/video.mkv')\n</span><span class=\"gi\">+vid_test.run('../../testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h3 id=\"ssd_keras_2patch\">ssd_keras_2.patch</h3>\n\n<p>keras修正対応</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras_2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd.py ssd_keras.tmp/ssd.py\n</span><span class=\"gd\">--- ssd_keras/ssd.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd.py\t2021-05-21 07:06:44.970000000 +0900\n</span><span class=\"p\">@@ -1,19 +1,17 @@</span>\n \"\"\"Keras implementation of SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.layers import Activation\n-#from keras.layers import AtrousConvolution2D\n-from keras.layers import Convolution2D\n-from keras.layers import Dense\n-from keras.layers import Flatten\n-from keras.layers import GlobalAveragePooling2D\n-from keras.layers import Input\n-from keras.layers import MaxPooling2D\n-#from keras.layers import merge\n-from keras.layers.merge import concatenate\n-from keras.layers import Reshape\n-from keras.layers import ZeroPadding2D\n-from keras.models import Model\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.keras.layers import Activation\n+from tensorflow.keras.layers import Convolution2D\n+from tensorflow.keras.layers import Dense\n+from tensorflow.keras.layers import Flatten\n+from tensorflow.keras.layers import GlobalAveragePooling2D\n+from tensorflow.keras.layers import Input\n+from tensorflow.keras.layers import MaxPooling2D\n+from tensorflow.keras.layers import concatenate\n+from tensorflow.keras.layers import Reshape\n+from tensorflow.keras.layers import ZeroPadding2D\n+from tensorflow.keras.models import Model\n</span> \n from ssd_layers import Normalize\n from ssd_layers import PriorBox\n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd_layers.py ssd_keras.tmp/ssd_layers.py\n</span><span class=\"gd\">--- ssd_keras/ssd_layers.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd_layers.py\t2021-05-21 06:31:11.780000000 +0900\n</span><span class=\"p\">@@ -1,8 +1,8 @@</span>\n \"\"\"Some special pupropse layers for SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.engine.topology import InputSpec\n-from keras.engine.topology import Layer\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.python.keras.engine.input_spec import InputSpec\n+from tensorflow.python.keras.engine.base_layer import Layer\n</span> import numpy as np\n import tensorflow as tf\n \n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest.py ssd_keras.tmp/testing_utils/videotest.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest.py\t2021-05-21 07:08:24.680000000 +0900\n</span><span class=\"p\">@@ -1,15 +1,13 @@</span>\n \"\"\" A class for testing a SSD model on a video file or webcam \"\"\"\n \n import cv2\n<span class=\"gd\">-import keras\n-from keras.applications.imagenet_utils import preprocess_input\n-# from keras.backend.tensorflow_backend import set_session\n-from keras.models import Model\n-from keras.preprocessing import image \n</span><span class=\"gi\">+import tensorflow.keras as keras\n+from tensorflow.keras.applications.imagenet_utils import preprocess_input\n+from tensorflow.keras.models import Model\n+from tensorflow.keras.preprocessing import image \n</span> import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-# from scipy.misc import imread, imresize\n</span> from imageio import imread\n from timeit import default_timer as timer\n \n<span class=\"p\">@@ -179,6 +177,7 @@</span>\n             cv2.putText(to_draw, fps, (3,10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0,0,0), 1)\n             \n             cv2.imshow(\"SSD result\", to_draw)\n<span class=\"gd\">-            cv2.waitKey(10)\n-            \n-        \n</span><span class=\"gi\">+            key = cv2.waitKey(1)\n+            if key == 27:\n+                # ESCキー\n+                break\n</span><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest_example.py ssd_keras.tmp/testing_utils/videotest_example.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest_example.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest_example.py\t2021-05-21 07:04:24.320000000 +0900\n</span><span class=\"p\">@@ -2,7 +2,7 @@</span>\n # GPU不使用を設定\n os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n \n<span class=\"gd\">-import keras\n</span><span class=\"gi\">+import tensorflow.keras as keras\n</span> import pickle\n from videotest import VideoTest\n \n<span class=\"p\">@@ -47,4 +47,4 @@</span>\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('../../testvideo3.mp4')\n</span><span class=\"gi\">+vid_test.run('../../images/testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h2 id=\"学習済み重みファイルのダウンロード\">学習済み重みファイルのダウンロード</h2>\n\n<p>参照先の記載にしたがって、重み学習済み重みファイルをダウンロードする。</p>\n\n<p>wgetでは取得できなかったので、ブラウザで↓ここ から weights_SSD300.hdf5 をダウンロード。<br />\n<a href=\"https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA\" target=\"_blank\">https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA</a><br />\nで、ZIPファイルをカレントディレクトリに解凍しておく。</p>\n\n<h2 id=\"ソースのダウンロードパッチをあてる\">ソースのダウンロード&パッチをあてる</h2>\n\n<p>githubからソースをダウンロードする。<br />\nこのままではエラーになるので、先ほど作成したパッチファイル<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code>でパッチをあてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/rykov8/ssd_keras.git\n<span class=\"nb\">cd </span>ssd_keras\npatch <span class=\"nt\">-p1</span> < ../ssd_keras.patch \n<span class=\"c\"># Keras修正対応パッチ</span>\npatch <span class=\"nt\">-p1</span> < ../ssd_keras_2.patch \n</code></pre></div></div>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>testing_utils/\npython videotest_example.py\n</code></pre></div></div>\n\n<p>おー。<br />\nしかし遅い…. <br />\nKerasは遅いみたい。。。orz…</p>\n\n<h1 id=\"こんなんもある\">こんなんもある</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50\" target=\"_blank\">「Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PyPiからopenVINOをインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>PyPiからopenVINOをインストール</h1>\n      <p>PyPiで配布されているopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>openVINOを使いたいが、SDKをインストールするのは面倒というズボラさんのためのTips😅<br />\nNCS2を使うためのドライバをインストールするにはSDK必要だが(WSLだとそもそもNCS2は使えないけど)、CPUだけでさくっと使いたいときなんかは有効かな?<br />\nあと、SDKインストール済みだけど、別のバージョン試したいときとか。</p>\n\n<p>対象はWindwos(試してないけど)、Ubuntu(x86_64 の 18.04、20.04)。(macOSも対象らしいけど使ったことないのでよーわからん😅)<br />\nPython は3.6、3.7、3.8<br />\nRasoberryPiは現在のところ対象外。</p>\n\n<h1 id=\"pypiのページ\">PyPiのページ</h1>\n\n<p>PyPiは以下にページがある。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino/\" target=\"_blank\">openvino · PyPI</a></li>\n</ul>\n\n<p>ただし、現状はUbuntuでPython3.8を使用する場合は以下を使用(Ubuntu Python3.7は両方用意されているらしい)。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino-ubuntu20/\" target=\"_blank\">openvino-ubuntu20 · PyPI</a></li>\n</ul>\n\n<h1 id=\"pythonモジュールのインストール\">pythonモジュールのインストール</h1>\n<p>上記ページに記載された通りだが、大抵openCVも必要になるので、インストールしておく。 <br />\n最近はopenCVも<code class=\"language-plaintext highlighter-rouge\">pip</code>コマンドイッパツでインストールできるのでラクチン😊</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOのインストール</span>\npip <span class=\"nb\">install </span>openvino\n<span class=\"c\"># またはこちら</span>\n<span class=\"c\"># pip install openvino-ubuntu20</span>\n\n<span class=\"c\"># openCVのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<p>インストールすると、現状、以下のモジュールがインストールされる(ubuntuでpython3.7/3.8の場合)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>numpy==1.20.1\nopencv-python==4.5.1.48\nopenvino==2021.2\ntbb==2020.3.254\n</code></pre></div></div>\n\n<h1 id=\"実行前の準備\">実行前の準備</h1>\n\n<p>openVINOモジュールは<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>の設定が必要なので、\nシステムのpythonを使用するときは上記ページに記載された通りに<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>を設定する。<br />\nただし、pyenvを使用している場合は、以下のように設定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"k\">}</span>:<span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/versions/<span class=\"sb\">`</span>pyenv version-name<span class=\"sb\">`</span>/lib\n</code></pre></div></div>\n\n<p>pyenvで環境を切り替えることを考えると、<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>で設定するより、スクリプト実行ラッパで設定した方が無難かも。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2でX-serverへの表示</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2でX-serverへの表示</h1>\n      <p>WindowsTerminal上のWSL2コンソールからGUIプログラムを起動する場合の設定メモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>MobaXtermを使えば何もしなくてもGUIプログラムを表示できるけど、\nWindowsTerminalなどから表示したい場合に対応してみた。</p>\n\n<h1 id=\"windows側の設定\">Windows側の設定</h1>\n<p>VcXsrvをインストールして起動しておく。<br />\n参考:<a href=\"/memoBlog/2019/11/26/VcXsrv.html\" target=\"_blank\">WindowsでX-serve</a></p>\n\n<h1 id=\"linux側の設定\">Linux側の設定</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">.bashrc</code>に以下を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># HOSTのIPアドレス取得</span>\n<span class=\"c\"># export HOST_IP_ADDR=$(host `hostname`.mshome.net | sed -r 's/.*address (.*)$/\\1/')</span>\n<span class=\"c\"># HOSTのIPアドレス取得(アドレスが2つ以上返ってきたときは1個目だけ取り出す)</span>\n<span class=\"nb\">export </span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"o\">=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-n</span> 1p<span class=\"si\">)</span>\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"k\">}</span>:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n他の用途でホストのIPアドレス(名前でなく)を使いたいときのために別に変数作っておいた。<br />\n以下のように名前で書いて指定しても良い。<br />\nマシン名は<code class=\"language-plaintext highlighter-rouge\">hostname</code>コマンドで得られるので、別のマシンに移動しても変更の必要はない。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net:0.0\n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">.mshome.net</code>ドメインを指定するとホスト側のIPアドレスが得られるらしい。<br />\nドメインなしだと<code class=\"language-plaintext highlighter-rouge\">localhost</code>になっちゃうから注意。<br />\nぐぐると<code class=\"language-plaintext highlighter-rouge\">/etc/resolv.conf</code>を<code class=\"language-plaintext highlighter-rouge\">awk</code>でごちょごちょやるのが流行っているが<br />\n本来の設定値ではない(結果的に同じだけど)のでちゃんと設定しておくことにする。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nドメイン<code class=\"language-plaintext highlighter-rouge\">mshome.net</code>はHyper-Vのネットワークのドメインらしい。<br />\n要はWSL-Windows間の仮想ネットワークのドメイン名みたい。<br />\nちなみに、WSL2上から<code class=\"language-plaintext highlighter-rouge\">nslookup <<ホストのIPアドレス>></code>とやったら出てきた。</p>\n</blockquote>\n\n<h1 id=\"x-windowを使用するプログラムを起動\">X-Windowを使用するプログラムを起動</h1>\n<p>なんか起動してちょ。\nとりあえず<code class=\"language-plaintext highlighter-rouge\">xeyes</code>とか。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">xeyes</code> は <code class=\"language-plaintext highlighter-rouge\">sudo apt install x11-apps</code>でインストールできる。</p>\n\n<h1 id=\"wslからのgui表示が行えない場合の対処\">WSLからのGUI表示が行えない場合の対処</h1>\n\n<h2 id=\"原因\">原因</h2>\n<p>WSLのネットワークがパブリックネットワークになっており、<br />\nWSLネットワークからの接続要求がファイアウォールで はじかれている。</p>\n\n<h2 id=\"ファイアウォールの設定変更による回避\">ファイアウォールの設定変更による回避</h2>\n\n<p>VcXsrvをパブリックネットワークからの接続も受け付けるようにする \n以下手順。</p>\n\n<ul>\n  <li>コントロール パネル  →  Windows Defender ファイアウォール</li>\n  <li>左側上から2番目「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック</li>\n  <li>名前の欄から「VcXsrv windows xserver」を探す</li>\n  <li>その横のチェックボックスの「パブリック」側(右側)にもチェックを入れる(プライベート側は既にチェックが入っているはず。そっちはそのまま)。</li>\n  <li>OKボタンをクリックして終了</li>\n  <li>コントロールパネルは閉じてOK</li>\n</ul>\n\n<h2 id=\"ちなみに\">ちなみに</h2>\n\n<p>以下のような回避方法もある。</p>\n\n<h3 id=\"display変数を変更して回避\">DISPLAY変数を変更して回避</h3>\n<p>一旦WSLネットワークから外に出て接続すれば接続できる。<br />\n具体的には、DISPLAY変数をWSL側のIPアドレス(172.xxx.xxx.xxx)ではなく、<br />\nWi-Fiやイーサネットに割り当てられたアドレス(一般に 192.168.xxx.xxx)を指定する。<br />\n → WSL側から自動的にアドレスを取得できないのであまりおススメできない。<br />\n    VcXsrvがちゃんと動いているかを確認するには有効な手段かも。</p>\n\n<h3 id=\"根本的回避\">根本的回避</h3>\n<p><a href=\"https://daizo3.tumblr.com/post/150523393217/%E5%82%99%E5%BF%98%E9%8C%B2-%E5%85%88%E6%97%A5%E3%81%AE%E7%B6%9A%E3%81%8D-%E8%AD%98%E5%88%A5%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF-%E3%82%92%E3%83%97%E3%83%A9%E3%82%A4%E3%83%99%E3%83%BC%E3%83%88%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AB%E3%81%99%E3%82%8B\">備忘録 - (先日の続き) 識別されていないネットワーク をプライベートネットワークにする</a><br />\nによると、<br />\n<a href=\"https://www.atmarkit.co.jp/ait/articles/1012/24/news127.html\">Windowsで、「識別されていないネットワーク」の種類を「パブリック ネットワーク」から「プライベート ネットワーク」に変更する</a><br />\nの「レジストリによる設定」に記載された方法でも出来るらしいけど(こっちの方が根本的解決な気がする)、<br />\nレジストリ弄るのは気が引けるので、小手先対処にて。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu20.04 on WSL2 で openVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu20.04 on WSL2 で openVINO</h1>\n      <p>WSL2上のUbuntu20.04でopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"環境構築\">環境構築</h1>\n\n<p>WSL環境ではNCS2は使えないが、CPU演算での実行は可能。<br />\n以下インストール~デモ実行までのメモ。</p>\n\n<p>基本は以下を参考に。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></li>\n  <li><a href=\"/memoBlog/2020/10/18/openVINO_ubuntu_3.html\">openVINO フルパッケージ(2021.1)をインストール(追加)</a></li>\n</ul>\n\n<p>WSLのインストールメモはこちら:<a href=\"/memoBlog/2021/03/03/WSL_memo.html\">WSL2 メモ</a><br />\nUbuntuは20.04。<br />\n今回はopenVINO 2021.2を使用した。</p>\n\n<h2 id=\"pyenvの仮想環境を作成\">pyenvの仮想環境を作成</h2>\n<p>まずは、pythonの環境を準備。<br />\n以下ではpythonは3.7.10を使用。(3.8を使えばTensorflow2を使えるらしい(?))</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.10 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n\n<p>ubuntuのライブラリ類をインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev \n<span class=\"c\"># 他にもあるかもしれんけど、とりあえずこれだけ。</span>\n</code></pre></div></div>\n\n<p>WSLでは以下も必要(グラフィック系処理が入ってないので)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgtk-3-0\n</code></pre></div></div>\n<h2 id=\"ダウンロードしたopenvinoアーカイブの展開とインストール\">ダウンロードしたopenVINOアーカイブの展開とインストール</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/mnt/f/Download/</code>にダウンロードしたファイルがあるとして。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\n<span class=\"nb\">tar </span>xzvf /mnt/f/Download/l_openvino_toolkit_p_2021.2.185.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2021.2.185/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n<span class=\"c\"># なぜかXwindow設定しててもテキストベースになる...</span>\n<span class=\"c\"># てきとーに答えていく。</span>\n</code></pre></div></div>\n\n<p>スクリプト終了したら、以下に従い進めていく。<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html</a></p>\n\n<h2 id=\"後半のコマンド一覧と注意事項\">後半のコマンド一覧と注意事項</h2>\n\n<ul>\n  <li>環境変数の設定とpythonモジュールのインストール</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># このコマンド、~/.bashrcにも書いておくこと</span>\n<span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n\n<span class=\"c\"># このコマンド実行すると、pyenvでなくsystemのpipでモジュールがインストールされるので実行しない</span>\n<span class=\"c\"># しかも、systemのpip3が壊れる...すごい罠😡</span>\n<span class=\"c\"># cd /opt/intel/openvino_2021/deployment_tools/model_optimizer/install_prerequisites/</span>\n<span class=\"c\"># sudo -E ./install_prerequisites.sh </span>\n\n<span class=\"c\"># 代わりに以下を実行(上記スクリプトは結局これを実行しているだけなので)</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npython 3.7で実行すると、</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version >= \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われるけど、無視して良い。<br />\nこれはPython3.8未満か以上で異なるバージョンのTensorflowがインストールされるように設定されているため。<br />\nちなみに、python 3.8でやると</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version < \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nもし、<code class=\"language-plaintext highlighter-rouge\">install_prerequisites.sh</code>を実行してしまい、pip3が壊れてしまった場合は\n以下で復旧する(一旦アンインストールしてから再インストール)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove python3-pip \n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip \n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"デモ実行\">デモ実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino_2021/deployment_tools/demo\n<span class=\"nb\">sudo cp</span> /work/.python-version <span class=\"nb\">.</span>\n\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/demo1.log\n\n<span class=\"c\"># このデモはグラフィック表示可能環境で実行する必要がある。  </span>\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/dem2.log\n</code></pre></div></div>\n\n<h1 id=\"別の仮想環境を用意する場合\">別の仮想環境を用意する場合</h1>\n\n<p>別の仮想環境を用意するときは以下で新しい仮想環境下にモジュールをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2 メモ</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2 メモ</h1>\n      <p>WSL2に関するメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <blockquote>\n  <p>[!NOTE]\n<strong><a href=\"https:///memoBlog/2024/07/24/WSL_memo2.html\" target=\"_blank\">改訂版</a>があります。</strong></p>\n</blockquote>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"wsl2のインストール\">WSL2のインストール</h2>\n<p>参考: <a href=\"https://itengine.seesaa.net/article/479688577.html\" target=\"_blank\">WSL2をインストールしてみた</a></p>\n\n<h2 id=\"virtualboxとの共存\">Virtualboxとの共存</h2>\n<p>参考: <a href=\"https://qiita.com/hibohiboo/items/c17459e0af84d2059d21\" target=\"_blank\">Vagrant + Virtualbox 6.1.16 と WSL2 を同時に動かしたメモ</a></p>\n\n<h1 id=\"セットアップ\">セットアップ</h1>\n\n<h2 id=\"アップデート\">アップデート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n</code></pre></div></div>\n\n<h2 id=\"日本語化\">日本語化</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 日本語ランゲージパック</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>language-pack-ja\n<span class=\"c\"># ロケールの設定</span>\n<span class=\"nb\">sudo </span>update-locale <span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF8\n<span class=\"c\"># 日本語manページのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>manpages-ja manpages-ja-dev\n</code></pre></div></div>\n\n<h2 id=\"beepを消す\">BEEPを消す</h2>\n<p>鬱陶しいのでBEEPを消しておく。<br />\n参考: <a href=\"https://linuxfan.info/bow-stop-beep\" target=\"_blank\">Bash on Windowsでビープ音を消す方法</a></p>\n\n<ul>\n  <li>ターミナルのbeepを消して画面フラッシュにする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"set bell-style visible\"</span> <span class=\"o\">>></span> ~/.inputrc\n</code></pre></div>    </div>\n  </li>\n  <li>vimのbeepを消す\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"set visualbell t_vb=\"</span> <span class=\"o\">>></span> ~/.vimrc\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalの場合、<code class=\"language-plaintext highlighter-rouge\">settings.json</code>に各プロファイルの設定に\n以下の設定を追加すればbash、vim、その他一括して変更できる。</p>\n  <div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\"> </span><span class=\"nl\">\"bellStyle\"</span><span class=\"w\"> </span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visual\"</span><span class=\"err\">,</span><span class=\"w\">\n</span></code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"デフォルトshをbashに変更\">デフォルトshをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"ツール類インストール\">ツール類インストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> /proj /work\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n<p>参考:<a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a></p>\n\n<h2 id=\"nodenvのインストール\">nodenvのインストール</h2>\n<p>参考:<a href=\"/memoBlog/2019/06/28/nodenv.html\" target=\"_blank\">nodenvのインストール</a></p>\n\n<h2 id=\"bashrcの設定\">.bashrcの設定</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\[\\e</span><span class=\"s2\">[36m</span><span class=\"se\">\\]</span><span class=\"nv\">$WSL_DISTRO_NAME</span><span class=\"se\">\\[\\e</span><span class=\"s2\">[0m</span><span class=\"se\">\\]</span><span class=\"s2\">:</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n        <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n        <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"nb\">export </span><span class=\"nv\">VIRTUAL_ENV_DISABLE_PROMPT</span><span class=\"o\">=</span>1\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h1 id=\"起動時の初期ディレクトリをホームディレクトリにするための設定\">起動時の初期ディレクトリをホームディレクトリにするための設定</h1>\n\n<p>起動時の初期ディレクトリがホームディレクトリにならないので(SSHの場合は大丈夫なはず)、以下の方法で指定する。</p>\n\n<h3 id=\"windows-terminalのsettingjsonでの設定\">Windows TerminalのSetting.jsonでの設定</h3>\n<p><a href=\"https://ryotatake.hatenablog.com/entry/2019/08/15/windows_terminal_wsl\" target=\"_blank\">Windows Terminal + WSLでターミナル起動時のディレクトリをホームディレクトリにする</a></p>\n\n<h3 id=\"wtexeのコマンドラインで指定する場合\">wt.exeのコマンドラインで指定する場合</h3>\n\n<p>settings.jsonで設定してない場合や設定とは別のディレクトリを指定する場合は-dオプションで指定する。<br />\nホームディレクトリを指定する場合は以下。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">C:\\Users\\</span><span class=\"err\"><<ユーザ名>></span><span class=\"nx\">\\AppData\\Local\\Microsoft\\WindowsApps\\wt.exe</span><span class=\"w\"> </span><span class=\"nt\">-p</span><span class=\"w\"> </span><span class=\"s2\">\"«環境登録名»\"</span><span class=\"w\"> </span><span class=\"nt\">-d</span><span class=\"w\"> </span><span class=\"s2\">\"\\\\wsl</span><span class=\"err\">$</span><span class=\"s2\">\\«仮想環境名»\\home\\<<ユーザ名>>\"</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ -p で指定するのは仮想環境名ではなく、WindowsTerminal に登録した環境名(ドロップダウンリストに表示される名前)。 -d で指定するのは仮想環境名。同一でない場合は間違えないように注意。</p>\n\n<h3 id=\"wsl-コマンドで起動する場合\">wsl コマンドで起動する場合</h3>\n\n<p>使用中のターミナルを使って起動する場合はwslコマンドで起動する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">c:\\WINDOWS\\system32\\wsl.exe</span><span class=\"w\"> </span><span class=\"nx\">~</span><span class=\"w\"> </span><span class=\"nt\">-d</span><span class=\"w\"> </span><span class=\"s2\">\"仮想環境名\"</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ wsl コマンドのパラメータに <code class=\"language-plaintext highlighter-rouge\">~</code> を追加</p>\n\n<h1 id=\"pathにwindowsのpathを引き継がせない設定\">PATHにWindowsのPATHを引き継がせない設定</h1>\n<p>仮想マシン起動語、PATHにWindows環境のPATHが引き継がれる。<br />\n便利な半面、コマンド名補完でサーチに行くと かなりの時間をくってしまい 不便。<br />\nWindowsのコマンドを仮想マシン上から起動することはあまりない(私の場合)ので、、<br />\nWindows環境のPATHを引き継がせないようにする。</p>\n\n<p>設定方法は <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に 以下の設定を追加する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>interop]\nappendWindowsPath <span class=\"o\">=</span> <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>参考: <a href=\"https://zenn.dev/o2z/articles/zenn-20210524-01\" target=\"_blank\">WSL2でWindowsのPATH設定が引き継がれるのを解除する</a></p>\n\n<h1 id=\"guiアプリを使用する\">GUIアプリを使用する</h1>\n<p>参考: <a href=\"https://qiita.com/vega77/items/f00323e8ce64bfa1fdd6\" target=\"_blank\">WSL2でGUIアプリを起動</a></p>\n\n<h1 id=\"wsl2上のサーバプログラムへのアクセス\">WSL2上のサーバプログラムへのアクセス</h1>\n<p>参考:<a href=\"https://www.atmarkit.co.jp/ait/articles/1909/09/news020.html\" target=\"_blank\">Linuxがほぼそのまま動くようになった「WSL2」のネットワーク機能</a></p>\n\n<table>\n  <thead>\n    <tr>\n      <th>向き</th>\n      <th>可否</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>HOST → WSL2</td>\n      <td>localhost でアクセスできる</td>\n    </tr>\n    <tr>\n      <td>WSL2 → HOST</td>\n      <td>localhost でアクセスできない。<br /> IPアドレス指定ならアクセスできる。</td>\n    </tr>\n  </tbody>\n</table>\n\n<h1 id=\"仮想マシンの複製\">仮想マシンの複製</h1>\n\n<h2 id=\"手順\">手順</h2>\n<p>仮想マシンは元になる仮想マシンをエクスポートして、別のディレクトリにインポートすれば複製できる。</p>\n\n<h3 id=\"仮想マシン一覧の確認\">仮想マシン一覧の確認</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>対象の仮想マシンが停止していることを確認。<br />\n停止してない場合はそれぞれのターミナルを終了するか、以下のコマンドで。<br />\nターミナルを終了してから実際に仮想マシンが停止するまで少し時間がかかる(数十秒くらい?)。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"err\">«対象の仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"エクスポート\">エクスポート</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--export</span><span class=\"w\"> </span><span class=\"err\">«エクスポート元仮想環境名»</span><span class=\"w\"> </span><span class=\"err\">«エクスポートファイル名»</span><span class=\"o\">.</span><span class=\"nf\">tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>例</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--export</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04</span><span class=\"w\"> </span><span class=\"nx\">F:\\WSL_VMs\\_Backup\\Ubuntu-20.04.tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"インポート\">インポート</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"err\">«新しい仮想環境名»</span><span class=\"w\"> </span><span class=\"err\">«インストール先ディレクトリ»</span><span class=\"w\"> </span><span class=\"err\">«エクスポートファイル名»</span><span class=\"o\">.</span><span class=\"nf\">tar</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ インストール先ディレクトリは自動で作成される</p>\n\n<p>例:</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04-1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">/Ubuntu-20.04-1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">\\_Backup\\Ubuntu-20.04.tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"削除\">削除</h3>\n<p>不要になった仮想環境は削除する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"err\">«削除する仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04-2</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"参考\">参考</h2>\n<ul>\n  <li>同一ディストリビューションの複製<br />\n<a href=\"https://qiita.com/souyakuchan/items/9f95043cf9c4eda2e1cc\" target=\"_blank\">WSL 上で同一ディストリビューションの環境を複数インストール・管理する</a></li>\n  <li>仮想環境をCドライブ以外に変更する<br />\n<a href=\"https://nosubject.io/windowsdocker-desktop-move-disk-image/\" target=\"_blank\">[Windows] Docker Desktop の ディスク領域 を Cドライブから別のドライブへ移動する方法</a></li>\n</ul>\n\n<h2 id=\"インポートした環境のデフォルトユーザを変更する\">インポートした環境のデフォルトユーザを変更する</h2>\n<p>インポートした環境では、デフォルトユーザがrootになっているため、自分に変更しておく。<br />\n方法は2つ。  <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>のほうがお手軽かな? エクスポート元で書いておけば逐一書かなくてもいいし。<br />\n両方設定した場合は<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>の設定が優先される(らしい)。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>で指定する方法。<br />\nインポートした環境を起動して、 <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>を以下の内容で作成\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>user]\n<span class=\"nv\">default</span><span class=\"o\">=</span>«デフォルトユーザ名» \n</code></pre></div>    </div>\n    <p>参考:<a href=\"https://github.com/Microsoft/WSL/issues/3974#issuecomment-576782860\" target=\"_blank\">github Microsoft/WSL/issues/3974</a>\n参考:<a href=\"https://roy-n-roy.github.io/Windows/WSL%EF%BC%86%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A/wslconfig/\" target=\"_blank\">wsl.conf と .wslconfig - roy-n-roy メモ</a></p>\n  </li>\n  <li>レジストリで設定する方法\n    <ul>\n      <li>Windowsでレジストリエディタを起動</li>\n      <li><strong><em>コンピューター\\HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Lxss</em></strong> 下の<br />\n各エントリで <strong><em>DistributionName</em></strong> が対象の名前になっているエントリを探す</li>\n      <li>そのエントリの<strong><em>DefaultUid</em></strong> を 対象のユーザIDに変更する。<br />\n対象のユーザIDはコピー元の<strong><em>DefaultUid</em></strong> に合わせれば良い。 あるいは、一旦ログインして/etc/passwd で調べる。 (大抵、1000( = 0x3e8 )のはず)</li>\n    </ul>\n  </li>\n</ul>\n\n<p>参考:<a href=\"https://roy-n-roy.github.io/Windows/WSL%EF%BC%86%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A/centos/#wsl\" target=\"_blank\">WSLでCentOS/Fedoraを利用する - roy-n-roy メモ</a></p>\n\n<h1 id=\"なんかのときに使うかも\">なんかのときに使うかも</h1>\n\n<p>試してないけど、メモっておく。</p>\n<ul>\n  <li>仮想ディスクが肥大化した場合の対処方法<br />\n<del><a href=\"https://qiita.com/386jp/items/e469333c5a74789db46d\" target=\"_blank\">WSL2を使っているパソコンのディスク容量が枯渇したときにやってみるべきこと</a></del><br />\nこっちの方が分かりやすかった。<br />\n<a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1271vhdexpcmd/vhdexpcmd.html\">仮想ディスクをコマンドラインから拡大/縮小する</a></li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>PS: XXXX> diskpart                                                 ← コマンド起動\n\nMicrosoft DiskPart バージョン 10.0.19041.964\n\nCopyright (C) Microsoft Corporation.\nコンピューター: XXXXXX\n\nDISKPART> select vdisk file=\"f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\" ← 圧縮したいvhdxファイル\n\nDiskPart により、仮想ディスク ファイルが選択されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   20 GB\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART> compact vdisk                                            ← 縮小の実行\n\n  100% 完了しました                       ← ちょっと時間がかかる\n\nDiskPart により、仮想ディスク ファイルは正常に圧縮されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   12 GB                      ← 小さくなった\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART>exit                                                      ← 終了\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 20.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 20.04のインストール</h1>\n      <p>Ubuntu 20.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>VirtualBox へのインストール前提で書いてます。<br />\nでも、仮想マシンの作成以外は同じかな。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2004-インストール媒体の入手\">Ubuntu 20.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら:\n<a href=\"https://www.ubuntulinux.jp/products/JA-Localized/download\" target=\"_blank\">Ubuntu Desktop 日本語 Remixのダウンロード</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを2048MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<p>以下の説明が図付きで分かりやすい:\n<a href=\"https://qiita.com/HirMtsd/items/225c20b77a7cd5194834\" target=\"_blank\">Windows10上のVirtualBoxにUbuntu20.04をインストール</a></p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面ロック を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから「デバイス」→「クリップボードの共有」→「双方向」<br />\nを選択。\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h3 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h2>\n<blockquote>\n  <p>[!NOTE]\n前のバージョンまでは、WMをGnome Flashbackに変更してたけど、<br />\n日本語入力とかと相性悪いみたいなので、やめといた方が無難<br />\nインストールする場合はここを参考に: <a href=\"https://goto-linux.com/ja/2020/3/13/ubuntu-20.04-gnome-flashback%E3%83%86%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%95%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB/\" target=\"_blank\">Ubuntu 20.04 Gnome Flashbackデスクトップのインストール</a></p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-session-flashback\n</code></pre></div>  </div>\n  <p>「GNOME Flashback(Compiz)」はなくなったらしい</p>\n</blockquote>\n\n<h2 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h2>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nUbuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h2>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"bashの設定変更\">bashの設定変更</h2>\n\n<p>~/.bashrcに以下を追記</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h2 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h2 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h2 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nFlashbackの場合は以下らしい。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.gnome-flashback.desktop.icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.gnome-flashback.desktop.icons show-trash <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h2>\n<p>なんとなく使いにくいので好みのデザインに変更。<br />\ndconf-editorでも良いよ(しつこい…)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h2 id=\"日本語入力\">日本語入力</h2>\n<p>前は設定必要だったけど、なんか大丈夫になったみたい</p>\n<blockquote>\n  <p>[!NOTE]\n以前の設定手順<br />\n右上の「A」または「あ」と書かれたアイコンをクリック→「テキスト入力設定」を選択\n一番下の「インストールされている言語の管理」をクリック\n「言語サポートが完全にはインストールされていません」と出るので「インストール」をクリック\n一旦log offして再log in\n右上のJaまたはMoと書かれたアイコンをクリック\n    Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)\nキーボードの全角/半角キーで切り替えられるようになる</p>\n</blockquote>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h2 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h2>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h2 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h2>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a></p>\n\n<p>リブート必要だが、以下のIPv6無効化とまとめてリブートでも可。</p>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>grubメニューの更新</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hosts は書き換えられないので、手動で書き換える</p>\n</blockquote>\n\n<p>IPアドレスの変更(固定アドレスにしたい場合)</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<p>まとめて実行するならこちら。<br />\n接続名があってるかは確認しておくこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># マシン番号の設定とホスト名の設定</span>\n<span class=\"nv\">number</span><span class=\"o\">=</span>30\n<span class=\"nv\">new_hostname</span><span class=\"o\">=</span>skull<span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span>\n\n<span class=\"c\"># HOSTNAMEの変更</span>\n<span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/ubuntu-20.*</span><span class=\"nv\">$/</span><span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span><span class=\"s2\">/\"</span> /etc/hosts\n\n<span class=\"c\"># HOST ONLY ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n\n<span class=\"c\"># BRIDGE ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Apps Script で メール送信</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Apps Script で メール送信</h1>\n      <p>Google Apps Script から メールを送信する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Google Apps Script(GAS)からメールを送信してみます。</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは<a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> で新しいGoogle Apps Scriptのプロジェクトを作成します。</p>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n\n<ul>\n  <li>新しいウィンドウでスクリプトエディタが開きます。</li>\n  <li>コード.gs に以下のコードを入力してください。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * テスト用関数\n */</span>\n <span class=\"kd\">function</span> <span class=\"nx\">myFunction</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">sendGmail</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">XXXX@gmail.com</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">TEST</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">テストだよ~ん</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n\n<span class=\"cm\">/**\n * Gmail送信処理\n *\n * @param {string|string[]} address    - 送信先アドレス\n * @param {string} subject  - サブジェクト(最大250文字)\n * @param {string} message  - 送信するメッセージ\n * \n * @note 送信先アドレスが間違っていてもここではエラーにならず、送信元アドレスにエラーメールが返る\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">sendGmail</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">,</span> <span class=\"nx\">subject</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n\n  <span class=\"c1\">// アドレスが配列だったらカンマ区切りの文字列に変換する</span>\n  <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nb\">Array</span><span class=\"p\">.</span><span class=\"nx\">isArray</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n    <span class=\"nx\">address</span> <span class=\"o\">=</span> <span class=\"nx\">address</span><span class=\"p\">.</span><span class=\"nx\">join</span><span class=\"p\">(</span><span class=\"dl\">'</span><span class=\"s1\">,</span><span class=\"dl\">'</span><span class=\"p\">);</span>\n  <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// そのまま</span>\n  <span class=\"p\">}</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">options</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"na\">name</span><span class=\"p\">:</span> <span class=\"dl\">\"</span><span class=\"s2\">てすと</span><span class=\"dl\">\"</span>        <span class=\"c1\">// 送信者名を指定したい場合は入れる</span>\n    <span class=\"c1\">// , replyTo: \"ZZZZ@gmail.com\"     // Reply-To を指定したい場合は入れる</span>\n  <span class=\"p\">};</span>\n\n  <span class=\"c1\">// メール送信</span>\n  <span class=\"nx\">GmailApp</span><span class=\"p\">.</span><span class=\"nx\">sendEmail</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">,</span> <span class=\"nx\">subject</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">,</span> <span class=\"nx\">options</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n</code></pre></div></div>\n\n<ul>\n  <li>「実行する関数」に<code class=\"language-plaintext highlighter-rouge\">myFunction</code>を選択(エディタの上、「実行ログ」の左の▼をクリックして選ぶ)</li>\n  <li>「実行」をクリック</li>\n  <li>送信先アドレスへメールが送信されます</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n送信元アドレスにはこのスクリプトを実行しているGoogleユーザ(デプロイ設定によってはそのとき実行しているGoogleユーザ)が使用されます。<br />\noptionsで「from」フィールドを指定する事が出来ますが、このアドレスは送信元アドレスのaliasである必要があります。<br />\nそうでない場合は例外 Invalid argument がthrowされます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n送信先アドレスが間違っていてもここではエラーになりません。<br />\n送信元アドレスにエラーメール(subject:「Delivery Status Notification (Failure)」)が送られてきます。</p>\n</blockquote>\n\n<h1 id=\"最後に\">最後に</h1>\n\n<p>関数化する必要もないくらい簡単ですが😅</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Apps Script で LINE Notify</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Apps Script で LINE Notify</h1>\n      <p>Google Apps Script から LINE に通知を送る</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Google Apps Script(GAS)からリアルタイムな通知を送る方法としてLINEにメッセージを送ってみる。</p>\n\n<p>LINE Notify を使うとアクセストークンを取得すれば、REST APIで簡単にメッセージを送れるので、これを使うことにした。</p>\n\n<h1 id=\"前準備\">前準備</h1>\n\n<p><a href=\"https://qiita.com/iitenkida7/items/576a8226ba6584864d95\" target=\"_blank\">[超簡単]LINE notify を使ってみる</a>  を参考に、\nLINEの設定 および LINE Notifyのアクセストークンの取得を行っておいてください。</p>\n<blockquote>\n  <p>[!NOTE]\nトークルームでなく、『1:1でLINE Notifyから通知を受け取る』を選択した場合は、ID検索で「@linenotify」を検索して友だちに追加してください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://notify-bot.line.me/ja/\" target=\"_blank\">LINE Notifyホーム</a> <br />\n<a href=\"https://notify-bot.line.me/doc/ja/\" target=\"_blank\">ドキュメント</a></p>\n</blockquote>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは<a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> で新しいGoogle Apps Scriptのプロジェクトを作成します。</p>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n\n<ul>\n  <li>新しいウィンドウでスクリプトエディタが開きます。</li>\n  <li>コード.gs に以下のコードを入力してください。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">// アクセストークン </span>\n<span class=\"kd\">const</span> <span class=\"nx\">ACCESS_TOKEN</span> <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">«取得したアクセストークン»</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n\n<span class=\"cm\">/**\n * テスト用関数\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">myFunction</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 時刻文字列取得</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">date_str</span> <span class=\"o\">=</span> <span class=\"nx\">Utilities</span><span class=\"p\">.</span><span class=\"nx\">formatDate</span><span class=\"p\">(</span><span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">(),</span><span class=\"dl\">\"</span><span class=\"s2\">JST</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">yyyy/MM/dd hh:mm:ss</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">token</span> <span class=\"o\">=</span> <span class=\"nx\">ACCESS_TOKEN</span><span class=\"p\">;</span>\n  <span class=\"nx\">LINE_notify</span><span class=\"p\">(</span><span class=\"nx\">token</span><span class=\"p\">,</span> <span class=\"nx\">date_str</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">    てすとぉぉぉ</span><span class=\"dl\">\"</span> <span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n<span class=\"cm\">/**\n * メッセージ送信処理\n *\n * @param {string} token    - アクセストークン\n * @param {string} message  - 送信するメッセージ\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">LINE_notify</span><span class=\"p\">(</span><span class=\"nx\">token</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">){</span>\n    <span class=\"kd\">const</span> <span class=\"nx\">url</span> <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">https://notify-api.line.me/api/notify</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n    <span class=\"kd\">var</span> <span class=\"nx\">headers</span> <span class=\"o\">=</span> <span class=\"p\">{</span> \n      <span class=\"dl\">'</span><span class=\"s1\">Authorization</span><span class=\"dl\">'</span><span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">Bearer </span><span class=\"dl\">'</span> <span class=\"o\">+</span> <span class=\"nx\">token</span> \n    <span class=\"p\">};</span>\n    <span class=\"kd\">var</span> <span class=\"nx\">options</span> <span class=\"o\">=</span> <span class=\"p\">{</span> \n      <span class=\"dl\">'</span><span class=\"s1\">headers</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"nx\">headers</span> <span class=\"p\">,</span>\n      <span class=\"dl\">'</span><span class=\"s1\">method</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">post</span><span class=\"dl\">'</span> <span class=\"p\">,</span>\n      <span class=\"c1\">// encodeURIComponent()はなくても大丈夫っぽい...</span>\n      <span class=\"c1\">// 'payload' : 'message=' + encodeURIComponent(message)</span>\n      <span class=\"dl\">'</span><span class=\"s1\">payload</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">message=</span><span class=\"dl\">'</span> <span class=\"o\">+</span> <span class=\"nx\">message</span><span class=\"p\">,</span> \n      <span class=\"dl\">'</span><span class=\"s1\">muteHttpExceptions</span><span class=\"dl\">'</span><span class=\"p\">:</span> <span class=\"kc\">true</span>        <span class=\"c1\">// エラーが返ってきても例外発生させない</span>\n     <span class=\"p\">};</span> \n    <span class=\"kd\">var</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n\n    <span class=\"k\">try</span> <span class=\"p\">{</span>\n      <span class=\"c1\">// メッセージを送信 </span>\n      <span class=\"kd\">var</span> <span class=\"nx\">res</span> <span class=\"o\">=</span> <span class=\"nx\">UrlFetchApp</span><span class=\"p\">.</span><span class=\"nx\">fetch</span><span class=\"p\">(</span><span class=\"nx\">url</span> <span class=\"p\">,</span><span class=\"nx\">options</span><span class=\"p\">);</span>\n\n      <span class=\"kd\">var</span> <span class=\"nx\">resCode</span> <span class=\"o\">=</span> <span class=\"nx\">res</span><span class=\"p\">.</span><span class=\"nx\">getResponseCode</span><span class=\"p\">();</span>              <span class=\"c1\">// HTTP レスポンスステータスコード</span>\n      <span class=\"kd\">var</span> <span class=\"nx\">resBody</span> <span class=\"o\">=</span> <span class=\"nx\">JSON</span><span class=\"p\">.</span><span class=\"nx\">parse</span><span class=\"p\">(</span><span class=\"nx\">res</span><span class=\"p\">.</span><span class=\"nx\">getContentText</span><span class=\"p\">());</span>   <span class=\"c1\">// レスポンス本体はJSONなのでパースする</span>\n\n      <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nx\">resCode</span> <span class=\"o\">===</span> <span class=\"mi\">200</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// レスポンスが200 → 正常終了</span>\n        <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">SUCCESS: %s</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"nx\">resBody</span><span class=\"p\">.</span><span class=\"nx\">message</span><span class=\"p\">);</span>\n      <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// それ以外→エラーレスポンス</span>\n        <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"nx\">Utilities</span><span class=\"p\">.</span><span class=\"nx\">formatString</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">ERROR: status:%d  body:%s</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"nx\">resCode</span><span class=\"p\">,</span> <span class=\"nx\">resBody</span><span class=\"p\">.</span><span class=\"nx\">message</span><span class=\"p\">));</span>\n      <span class=\"p\">}</span>\n    <span class=\"p\">}</span> <span class=\"k\">catch</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n      <span class=\"c1\">// その他のエラー(DNSエラー、タイムアウトなど)は例外が発生する</span>\n      <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">ERROR: </span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">e</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<ul>\n  <li>「実行する関数」に<code class=\"language-plaintext highlighter-rouge\">myFunction</code>を選択(エディタの上、「実行ログ」の左の▼をクリックして選ぶ)\nー 「実行」をクリック</li>\n  <li>LINEに通知が届きます</li>\n</ul>\n\n<h1 id=\"最後に\">最後に</h1>\n\n<p>これだけだと大したことできないけど、ライブラリ化して他のサービスと組み合わせて使えばなんかのPUSH通知っぽく使えるかな?</p>\n\n<blockquote>\n  <p>[!NOTE]\nSpreadsheetの時のように、ウェブアプリにしようかと思ったら、もともとREST APIだから全然意味ないので関数作るだけにしておいた。<br />\n(POST使えない場合にGETで受け付けるラッパみたいなのは考えられなくはないけど)</p>\n</blockquote>\n\n<h1 id=\"参考\">参考</h1>\n\n<p>通知回数の上限は1000回/1時間/アクセストークンです。(そんなに送ったら鬱陶しいでしょうから問題ないかな?)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google spreadsheet にREST APIを追加(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google spreadsheet にREST APIを追加(その2)</h1>\n      <p>Google Apps Scriptのライブラリ化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">Google spreadsheet にREST APIを追加 その1</a>   では\nSpreadsheetに埋め込んだスクリプトにすべて記述しましたが、 新しいSpreadsheetを作成する度にコードをコピーするのは大変ですし、\n何らかの不具合が見つかったときに複数のファイルをメンテナンスしなければならないのは現実的ではありません。<br />\nそこで、スプレッドシートにデータを登録する部分をライブラリ化し、Spreadsheetに埋め込んだスクリプトには最低限のコードだけ記載するようにしてみます。</p>\n\n<h1 id=\"手順\">手順</h1>\n<p>まずはスクリプトライブラリを作成します</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a>   を開く</li>\n  <li>左側「新規」→ 「その他」→「Google Apps Script」で新しいスクリプトエディタが開く\n    <ul>\n      <li>「無題のプロジェクト」をクリックして名前を入力</li>\n      <li>コード.gsに以下を入力(<a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">その1</a>  の<code class=\"language-plaintext highlighter-rouge\">AddDataToSeet()</code>と同一)</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストで渡されたデータをスプレッドシートの最終行に追加する\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">AddDataToSeet start</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n\n  <span class=\"c1\">// 記録するシート(現在のスプレッドシートのアクティブなシート)</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">sheet</span> <span class=\"o\">=</span> <span class=\"nx\">SpreadsheetApp</span><span class=\"p\">.</span><span class=\"nx\">getActiveSheet</span><span class=\"p\">();</span>\n\n  <span class=\"kd\">var</span> <span class=\"nx\">dt</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>    <span class=\"c1\">// 日付</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>            <span class=\"c1\">// デフォルト値</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv0が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv1が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv2が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n\n  <span class=\"c1\">// スプレッドシートの最終行に追加</span>\n  <span class=\"nx\">sheet</span><span class=\"p\">.</span><span class=\"nx\">appendRow</span><span class=\"p\">([</span><span class=\"nx\">dt</span><span class=\"p\">,</span> <span class=\"nx\">v0</span><span class=\"p\">,</span> <span class=\"nx\">v1</span><span class=\"p\">,</span> <span class=\"nx\">v2</span><span class=\"p\">]);</span>\n\n  <span class=\"c1\">// HTML表示データを生成</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">createTextOutput</span><span class=\"p\">();</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setMimeType</span><span class=\"p\">(</span><span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">MimeType</span><span class=\"p\">.</span><span class=\"nx\">TEXT</span><span class=\"p\">);</span>\n  <span class=\"c1\">// メッセージボディ</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setContent</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">set data:</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">date=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">dt</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v0=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v0</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v1=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v1</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v2=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v2</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<ul>\n  <li>右上の青いボタン「デプロイ」→「新しいデプロイ」をクリック\n    <ul>\n      <li>「デプロイタイプを選択してください」と言われるので、\n        <ul>\n          <li>「種類の選択」横の歯車アイコンをクリック → 「ライブラリ」をクリック</li>\n          <li>「説明」に説明文を入力(省略可)</li>\n          <li>「デプロイ」をクリック</li>\n        </ul>\n      </li>\n      <li>新しいデプロイウィンドウが表示されるので、「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>画面左の歯車アイコン「プロジェクトの設定」をクリック\n    <ul>\n      <li>「プロジェクトの設定」の真ん中あたりの「スクリプトID」をメモしておく</li>\n    </ul>\n  </li>\n</ul>\n\n<p>次に操作されるspreadsheetを作成します。</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a>   を開く</li>\n  <li>左側「新規」→ 「Googleスプレッドシート」で新しいスプレッドシートが開く</li>\n  <li>無題のスプレッドシート」をクリックして名前を入力</li>\n  <li>SpreadsheetにGoogle Apps Script(GAS)を追加します。\n    <ul>\n      <li>メニューの「ツール」→「スクリプトエディタ」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<p>新しいウィンドウでスクリプトエディタが開きます。</p>\n<ul>\n  <li>「ライブラリ」の横の+マーク(ライブラリを追加)をクリック</li>\n  <li>「ライブラリの追加」ウィンドウが開くので、「スクリプトID」の欄に上でメモしたスクリプトIDを入力し、「検索」をクリック</li>\n  <li>バージョンで使用するバージョンを選択(HAEAD(開発モード)を選択すると、デプロイするまえの最新ソースが使用される)</li>\n  <li>ID を設定します。\n    <blockquote>\n      <p>[!NOTE]\nID は node.jsで言うところの、以下の部分の「変数名」に相当する</p>\n      <div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">var</span> <span class=\"nx\">変数名</span> <span class=\"o\">=</span> <span class=\"nx\">require</span><span class=\"p\">(</span><span class=\"dl\">'</span><span class=\"s1\">モジュール名</span><span class=\"dl\">'</span><span class=\"p\">)</span>\n</code></pre></div>      </div>\n    </blockquote>\n  </li>\n  <li>コード.gs に以下のコードを入力</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストの処理\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">doGet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 処理本体</span>\n  <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">MySpreadsheetLib</span><span class=\"p\">.</span><span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>以降、(<a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">その1</a> のデプロイ作業と同一です。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google spreadsheet にREST APIを追加(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google spreadsheet にREST APIを追加(その1)</h1>\n      <p>HTTP GETリクエストでGoogle spreadsheetに追記する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2019/10/01/spreadsheet.html\" target=\"_blank\">Node.jsでGoogle spreadsheet にデータを書き込む</a> で\nGoogle Drive APIでGoogle spreadsheet にデータを書き込む方法を紹介しましたが、\nクライアント側の処理をもっと簡単にするためにREST APIを追加してHTTP GETリクエストでデータを書き込めるようにしてみました。</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは操作されるspreadsheetを作成します。</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> を開く</li>\n  <li>左側「新規」→ 「Googleスプレッドシート」で新しいスプレッドシートが開く</li>\n  <li>無題のスプレッドシート」をクリックして名前を入力</li>\n</ul>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n<ul>\n  <li>メニューの「ツール」→「スクリプトエディタ」をクリック</li>\n</ul>\n\n<p>新しいウィンドウでスクリプトエディタが開きます。</p>\n<ul>\n  <li>コード.gs に以下のコードを入力</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストで渡されたデータをスプレッドシートの最終行に追加する\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">AddDataToSeet start</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n\n  <span class=\"c1\">// 記録するシート(現在のスプレッドシートのアクティブなシート)</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">sheet</span> <span class=\"o\">=</span> <span class=\"nx\">SpreadsheetApp</span><span class=\"p\">.</span><span class=\"nx\">getActiveSheet</span><span class=\"p\">();</span>\n\n  <span class=\"kd\">var</span> <span class=\"nx\">dt</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>    <span class=\"c1\">// 日付</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>            <span class=\"c1\">// デフォルト値</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv0が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv1が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv2が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n\n  <span class=\"c1\">// スプレッドシートの最終行に追加</span>\n  <span class=\"nx\">sheet</span><span class=\"p\">.</span><span class=\"nx\">appendRow</span><span class=\"p\">([</span><span class=\"nx\">dt</span><span class=\"p\">,</span> <span class=\"nx\">v0</span><span class=\"p\">,</span> <span class=\"nx\">v1</span><span class=\"p\">,</span> <span class=\"nx\">v2</span><span class=\"p\">]);</span>\n\n  <span class=\"c1\">// HTML表示データを生成</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">createTextOutput</span><span class=\"p\">();</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setMimeType</span><span class=\"p\">(</span><span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">MimeType</span><span class=\"p\">.</span><span class=\"nx\">TEXT</span><span class=\"p\">);</span>\n  <span class=\"c1\">// メッセージボディ</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setContent</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">set data:</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">date=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">dt</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v0=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v0</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v1=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v1</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v2=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v2</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"cm\">/**\n * GETリクエストの処理\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">doGet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 処理本体</span>\n  <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ndoGet関数のパラメータ<code class=\"language-plaintext highlighter-rouge\">e</code>については、<a href=\"https://developers.google.com/apps-script/guides/web\" target=\"_blank\">このへん</a>を参照してください。</p>\n</blockquote>\n\n<ul>\n  <li>右上の青いボタン「デプロイ」→「新しいデプロイ」をクリック\n    <ul>\n      <li>「デプロイタイプを選択してください」と言われるので、「種類の選択」横の歯車アイコンをクリック → 「ウェブアプリ」をクリック\n        <ul>\n          <li>「説明」に説明文を入力(省略可)</li>\n          <li>「ウェブアプリ」の「次のユーザとして実行」で「自分」を選択</li>\n          <li>「アクセスできるユーザ」を適切な範囲に設定  (「全員」にすればパスワードなしでアクセスできる)\n            <blockquote>\n              <p>[!NOTE]\ncurlなどでアクセスしたい場合は、「全員」にしておかないと、認証画面に飛んでしまい、アクセスが完了しません。</p>\n            </blockquote>\n          </li>\n          <li>「デプロイ」をクリック</li>\n        </ul>\n      </li>\n      <li>「このウェブ アプリケーションを使用するには、データへのアクセスを許可する必要があります。」と言われるので「アクセスを承認」をクリック</li>\n      <li>「アカウントの選択」が表示されるので、使用するアカウントを選択</li>\n      <li>「このアプリは Google で確認されていません」と言われるので、左下「詳細」をクリック\n        <ul>\n          <li>「無題のプロジェクト(安全ではないページ)に移動」をクリック</li>\n          <li>「無題のプロジェクトがGoogle アカウントへのアクセスをリクエストしています」と言われるので、「許可」をクリック</li>\n          <li>「新しいデプロイ」が表示される</li>\n          <li>一番下の「ウェブアプリ」のUARLをコピーして使用</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<p>例えば以下のコマンドでアクセスする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>curl <span class=\"nt\">-L</span> <span class=\"s2\">\"«上でコピーしたURL»?v0=1&v1=2&v2=3\"</span>\n</code></pre></div></div>\n\n<p>実行すると、対象のスプレッドシートの最終行に以下のデータが追加されます。</p>\n<ul>\n  <li>A列: 日付と時刻</li>\n  <li>B列: v0で指定した値</li>\n  <li>C列: v1で指定した値</li>\n  <li>D列: v2で指定した値</li>\n</ul>\n\n<p>スクリプトを修正した場合、再度「新しいデプロイ」を実行する必要がある。</p>\n\n<p>または、「デプロイ」→「デプロイをテスト」で表示されるURLを使用すると、デプロイせずに現在の最新ソースで実行できる。<br />\nただし、この場合、ユーザ認証が必須になってしまうので、ブラウザ等でアクセスする必要がある。<br />\nどうしてもcurlでアクセスしたい場合は、ヘッダに<code class=\"language-plaintext highlighter-rouge\">Authorization: Bearer «アクセストークン»</code>を追加してやれば良い。(あまりおススメはしないけど)<br />\nやり方は<a href=\"https://www.ka-net.org/blog/?p=12258\" target=\"_blank\">ここらへん</a>を参考にしてください。</p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>時刻の文字列を取得した場合、知らないタイムゾーンになっていて困ったときはタイムゾーンを変更すれば良い。</p>\n\n<p>タイムゾーンを変更するにはこちら。</p>\n<ul>\n  <li>画面左の歯車アイコン「プロジェクトの設定」をクリック\n    <ul>\n      <li>「「appsscript.json」マニフェスト ファイルをエディタで表示する」にチェックを入れる</li>\n    </ul>\n  </li>\n  <li>画面左の<>アイコン「エディタ」をクリックしてエディタに戻る\n    <ul>\n      <li>ファイル一覧に「appsscript.json」が追加されているのでクリック</li>\n      <li>タイムゾーンを指定している部分を   <code class=\"language-plaintext highlighter-rouge\">\"timeZone\": \"Asia/Tokyo\",</code> に変更</li>\n      <li>保存して再度デプロイ</li>\n    </ul>\n  </li>\n</ul>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano に pyenv をインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano に pyenv をインストールする</h1>\n      <p>Jetson nano に pyenvをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>systemのpythonを使うのはちょっと嫌なので、仮想環境を使えるようにしておく。<br />\n<code class=\"language-plaintext highlighter-rouge\">venv</code>でもいいけど、やっぱり使い慣れた<code class=\"language-plaintext highlighter-rouge\">pyenv</code>+<code class=\"language-plaintext highlighter-rouge\">vertualenv</code>で。<br />\n基本的に<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a>と同じだけど、<br />\nJetpackでインストール済みで、<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできないパッケージがあるなど、<br />\nJetson nano 固有の設定等があるので、メモ。</p>\n\n<h1 id=\"手順再掲を含む\">手順(再掲を含む)</h1>\n\n<h2 id=\"pyenvをインストールする\">pyenvをインストールする</h2>\n<ul>\n  <li>必要なパッケージのインストール\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>pyenvとプラグインをダウンロード\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git            <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone git://github.com/pyenv/pyenv-update.git      <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境からJetpackでインストール済みのパッケージを参照できるようにしておく。<br />\n(pipでインストールできないみたいなので、お手軽な方法で解決)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/cv2          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/graphsurgeon <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/tensorrt     <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/uff          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>\n、とやりたいけど、ARM版は非対応らしいので…</p>\n    </blockquote>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>の修正<br />\n以下を追加しておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n<span class=\"c\">#jetson専用のインストール済みパッケージをコピっておく</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHONPATH</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span><span class=\"s2\">/jetson_pythonlib:</span><span class=\"nv\">$PYTHONPATH</span><span class=\"s2\">\"</span>\n</code></pre></div>    </div>\n  </li>\n  <li>ターミナル開きなおし or <code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を再読み込み</li>\n</ul>\n\n<h2 id=\"ベースとなるpythonのインストール\">ベースとなるpythonのインストール</h2>\n<p>バージョンは3.6.xでないとダメっぽい</p>\n\n<h2 id=\"python-のインストール\">python のインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.12\npyenv global 3.6.12\n</code></pre></div></div>\n<p>pip と setuptools のアップデート</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n<h2 id=\"その他\">その他</h2>\n<p>wheelが入ってると仮想環境を変えて同じモジュールをインストールするときに早いので、<br />\nインストールしておきたいが、各仮想環境に逐一インストールするのも面倒なので<br />\n共通に参照できるディレクトリにインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>wheel <span class=\"nt\">-t</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をUSBドライブからブートできるようにする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をUSBドライブからブートできるようにする</h1>\n      <p>Jetson nano をUSBドライブからブートできるようにする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>本稿はJetoack4.4での手順です。<br />\nJetpack4.6のときのメモは<a href=\"/memoBlog/2021/09/14/Jetson_usb_boot.html\" target=\"_blank\">Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</a> にあります。</p>\n\n<h1 id=\"概要\">概要</h1>\n<p>SDカードからブートすると、かなりディスクアクセスが遅いのと、ディスク容量を結構喰うので、<br />\nUSBドライブ(HDD/SSD)からブートできるようにする手順。<br />\n例によって、先人の知恵を借りるだけだけど(パクりとも言う)…(^^ゞ</p>\n\n<p>めんどくさそうだったけど、ほとんどスクリプト化されているので、意外と簡単。</p>\n\n<h1 id=\"参考\">参考</h1>\n<ul>\n  <li><a href=\"https://www.miki-ie.com/nvidiajetsonnano/nvidia-jetson-nano-usb-root/\">NVIDIA Jetson Nano USB ディスクをルート構成</a></li>\n  <li><a href=\"https://qiita.com/sgrowd/items/87d65383c0b74306ea7d\">Jetson Nanoの/をUSBドライブにしてSDカードを長生きさせる</a></li>\n  <li><a href=\"https://www.jetsonhacks.com/2019/09/17/jetson-nano-run-from-usb-drive/\">Jetson Nano – Run From USB Drive</a></li>\n</ul>\n\n<h1 id=\"手順を再掲しとく\">手順を再掲しとく</h1>\n\n<ul>\n  <li>SDカードからブート</li>\n  <li>USBドライブを接続&フォーマット</li>\n  <li>USBドライブをマウント</li>\n  <li>ツールのダウンロード\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/JetsonHacksNano/rootOnUSB.git\n<span class=\"nb\">cd </span>rootOnUSB/\n</code></pre></div>    </div>\n  </li>\n  <li>USBドライブからbootするためのinitrdを作成する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./addUSBToInitramfs.sh\n</code></pre></div>    </div>\n  </li>\n  <li>SDカードからUSBドライブへファイルをコピーする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./copyRootToUSB.sh <span class=\"nt\">-p</span> «コピー先パーティション»\n  <span class=\"c\"># 例: ./copyRootToUSB.sh -p /dev/sda1</span>\n</code></pre></div>    </div>\n  </li>\n  <li>実際にUSBドライブからブートするための設定\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/boot/extlinux/extlinux.conf</code>のバックアップをとっておく\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv</span> /boot/extlinux/extlinux.conf /boot/extlinux/extlinux.conf.org\n</code></pre></div>        </div>\n      </li>\n      <li>USBドライブのUUIDを調べる\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./diskUUID.sh\n</code></pre></div>        </div>\n        <p>→ <code class=\"language-plaintext highlighter-rouge\">XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</code>として得られる。</p>\n      </li>\n      <li><code class=\"language-plaintext highlighter-rouge\">sample-extlinux.conf</code> の <code class=\"language-plaintext highlighter-rouge\">APPEND</code>の行のUUID部分を以下のように変更する\n        <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    APPEND ${cbootargs} root=UUID=dc21871e-9db4-434c-98b4-713f55f807eb rootwait rootfstype=ext4\n                                     ↓↓↓↓↓\n    APPEND ${cbootargs} root=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rootwait rootfstype=ext4\n</code></pre></div>        </div>\n      </li>\n      <li>変更した<code class=\"language-plaintext highlighter-rouge\">sample-extlinux.conf</code>を<code class=\"language-plaintext highlighter-rouge\">/boot/extlinux/extlinux.conf</code>をコピー\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp </span>sample-extlinux.conf /boot/extlinux/extlinux.conf\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>リーブート</li>\n</ul>\n\n<p>リブート完了したらUSBドライブがrootにマウントされていることを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">mount</code>で確認しても良いけど、いっぱい出てきて鬱陶しいので<code class=\"language-plaintext highlighter-rouge\">df</code>で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">df</span> <span class=\"nt\">-h</span> /\n</code></pre></div></div>\n<p>こんな感じで行頭にマウント元が表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Filesystem      Size  Used Avail Use% Mounted on\n/dev/sda1       110G   14G   91G  13% /\n</code></pre></div></div>\n\n<h1 id=\"注意\">注意</h1>\n<p>USBドライブからブートできるようになっても、SDカードは取り外してはいけない。<br />\nu-bootからinitrdをロードするのはSDカードなので。</p>\n\n<p>ということは、<code class=\"language-plaintext highlighter-rouge\">apt update</code>でカーネルアップデートされても古いカーネルが使われちゃうなぁ…<br />\nそれはそのとき考えよう…<br />\nそんなに変わるもんでもないだろう。</p>\n\n<h1 id=\"独り言\">独り言</h1>\n<p>u-bootの環境変数見ると、そのままUSBブート出来そうな感じだったけど、<br />\n実際に<code class=\"language-plaintext highlighter-rouge\">usb start</code>してみたらエラーになる。<br />\nどうやらu-bootにはUSBドライバが入ってないらしい…<br />\nそんな環境変数残しとくな!!</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano のSDカードをバックアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano のSDカードをバックアップする</h1>\n      <p>Jetson nano のSDカードをバックアップする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2020/10/23/Jetson_nano_install.html\">Jetson nano をセットアップする</a> \nでセットアップしたSDカードをバックアップしておけば逐一セットアップ作業を行わなくても環境を復元できます。</p>\n\n<p>ただ、そのままSDカードをイメージファイル化しただけでは復元するSDカードのサイズが微妙に小さい場合などは、復元できなくなってしまいます。<br />\nそこで、バックアップしtイメージファイル内のパーティションサイズを縮小し、イメージファイルを小さくするスクリプトを用意しました。</p>\n\n<p>この作業はubuntu PC上で行います。</p>\n\n<p>この方法、およびスクリプトはRaspberryPi用SDカードでも使用できます。</p>\n\n<h1 id=\"sdカードのバックアップ\">SDカードのバックアップ</h1>\n<blockquote>\n  <p>[!WARNING]\nJetson用SDカードはFATパーティションが存在しないため、<br />\nWindowsPCではバックアップツールがSDカードを認識できず、バックアップできません。</p>\n</blockquote>\n\n<ul>\n  <li>ubuntu PCにバックアップしたいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>SDカードイメージをファイルにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">of</span><span class=\"o\">=</span>«出力ファイル» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n  <li>ubuntu PCからSDカードを抜去</li>\n</ul>\n\n<h1 id=\"ディスクイメージファイルの縮小\">ディスクイメージファイルの縮小</h1>\n\n<p>バックアップしたイメージファイルはSDカード容量と同じサイズになっています。<br />\nディスクイメージを縮小するために <a href=\"/memoBlog/misc/stock/diskimage_shrink.sh\">このスクリプト</a> をダウンロードして実行します。</p>\n\n<p>まず、必要なツールをインストールしておきます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install </span>kpartx\n</code></pre></div></div>\n\n<p>ダウンロードしたスクリプトを実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash diskimage_shrink.sh «入力イメージファイル» «出力イメージファイル» \n</code></pre></div></div>\n<p>出力イメージファイルが既に存在する場合は、上書きするか聞かれますので、yまたはnで指定してください。</p>\n\n<p>最初に入力イメージファイルから出力イメージファイルへコピーを行います。<br />\nコピーが終了すると、<code class=\"language-plaintext highlighter-rouge\">sudo</code>実行するためのパスワードを聞かれますので、入力してください。<br />\n縮小するパーティションサイズを計算した後、\n現在のパーティションサイズと縮小後のパーティションサイズが表示されます。<br />\n各サイズが正しければ、yを入力してパーティションサイズの修正を行いますが、\n一般的に危険な処理なので、「警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?」と再度確認されます。<br />\nyを入力して実行してください。</p>\n\n<p>その後、さらに ファイルサイズを切り詰めます。</p>\n\n<p>処理が終了すると、以下のメッセージが表示されますので、これにしたがって後の処理を行ってください。<br />\nRaspberryPi用SDカードはMBRパーティションなので<code class=\"language-plaintext highlighter-rouge\">gdisk</code>の処理は不要です。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n<p>実行例を以下に示します。<br />\n入力コマンドは<code class=\"language-plaintext highlighter-rouge\"># =========</code>で囲んであります。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># =========================================================================\n/work2$ bash diskimage_shrink.sh jetson_sd_20201022_2.img XXXX.img\n# =========================================================================\nCopy image file...\n>f+++++++++ jetson_sd_20201022_2.img\n 30,953,963,520 100%   26.97MB/s    0:18:14 (xfr#1, to-chk=0/1)\nGet partition info...\n対象パーティション番号 : 1\nImage file mapping...\n[sudo] <<ユーザ>> のパスワード: «パスワードを入力»\nadd map loop18p1 (253:0): 0 60313600 linear 7:18 28672\nadd map loop18p2 (253:1): 0 256 linear 7:18 2048\nadd map loop18p3 (253:2): 0 896 linear 7:18 4096\nadd map loop18p4 (253:3): 0 1152 linear 7:18 6144\nadd map loop18p5 (253:4): 0 128 linear 7:18 8192\nadd map loop18p6 (253:5): 0 384 linear 7:18 10240\nadd map loop18p7 (253:6): 0 768 linear 7:18 12288\nadd map loop18p8 (253:7): 0 128 linear 7:18 14336\nadd map loop18p9 (253:8): 0 896 linear 7:18 16384\nadd map loop18p10 (253:9): 0 896 linear 7:18 18432\nadd map loop18p11 (253:10): 0 1536 linear 7:18 20480\nadd map loop18p12 (253:11): 0 128 linear 7:18 22528\nadd map loop18p13 (253:12): 0 160 linear 7:18 24576\nadd map loop18p14 (253:13): 0 256 linear 7:18 26624\nLOOP device : /dev/mapper/loop18p1\n現在のパーティションサイズ   : 29450MiB\n縮小後のパーティションサイズ : 15637MiB\nパーティションを縮小しますか? [y/N]: y\nPartition shrinking...\ne2fsck 1.44.1 (24-Mar-2018)\nPass 1: Checking iノードs, blocks, and sizes\nPass 2: Checking ディレクトリ structure\nPass 3: Checking ディレクトリ connectivity\nPass 4: Checking reference counts\nPass 5: Checking グループ summary information\n/dev/mapper/loop18p1: 199065/1881264 files (0.2% non-contiguous), 3701166/7539200 blocks\nresize2fs 1.44.1 (24-Mar-2018)\nResizing the filesystem on /dev/mapper/loop18p1 to 4003167 (4k) blocks.\nBegin pass 2 (max = 55)\nRelocating blocks             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nBegin pass 3 (max = 231)\nScanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nThe filesystem on /dev/mapper/loop18p1 is now 4003167 (4k) blocks long.\n\n警告: 管理者権限がありません。パーミッションに注意してください。\n警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?\nはい(Y)/Yes/いいえ(N)/No? y                                               \nTruncate image file size...\nReleas image file mapping...\nloop deleted : /dev/loop18\n******** Done!! ********\n\n\n\n対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\n\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n\n\n\n# =========================================================================\n/work2$ gdisk XXXX.img \n# =========================================================================\nGPT fdisk (gdisk) version 1.0.3\n\nWarning! Disk size is smaller than the main header indicates! Loading\nsecondary header from the last sector of the disk! You should use 'v' to\nverify disk integrity, and perhaps options on the experts' menu to repair\nthe disk.\nCaution: invalid backup GPT header, but valid main header; regenerating\nbackup header from main header.\n\nWarning! Error 25 reading partition table for CRC check!\nWarning! One or more CRCs don't match. You should repair the disk!\n\nPartition table scan:\n  MBR: protective\n  BSD: not present\n  APM: not present\n  GPT: damaged\n\n****************************************************************************\nCaution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\nverification and recovery are STRONGLY recommended.\n****************************************************************************\n\nCommand (? for help): b\nEnter backup filename to save: backup.gpt\nThe operation has completed successfully.\n\nCommand (? for help): r\n\nRecovery/transformation command (? for help): d\n\nRecovery/transformation command (? for help): w\nCaution! Secondary header was placed beyond the disk's limits! Moving the\nheader, but other problems may occur!\n\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\nPARTITIONS!!\n\nDo you want to proceed? (Y/N): y\nOK; writing new GUID partition table (GPT) to XXXX.img.\nWarning: The kernel is still using the old partition table.\nThe new table will be used at the next reboot or after you\nrun partprobe(8) or kpartx(8)\nThe operation has completed successfully.\n\n\n\n# =========================================================================\n/work2$ sudo parted -m XXXX.img unit GiB print\n# =========================================================================\nBYT;\n/work2/XXXX.img:15.3GiB:file:512:512:gpt::;\n2:0.00GiB:0.00GiB:0.00GiB::TBC:;\n3:0.00GiB:0.00GiB:0.00GiB::RP1:;\n4:0.00GiB:0.00GiB:0.00GiB::EBT:;\n5:0.00GiB:0.00GiB:0.00GiB::WB0:;\n6:0.00GiB:0.01GiB:0.00GiB::BPF:;\n7:0.01GiB:0.01GiB:0.00GiB::BPF-DTB:;\n8:0.01GiB:0.01GiB:0.00GiB::FX:;\n9:0.01GiB:0.01GiB:0.00GiB::TOS:;\n10:0.01GiB:0.01GiB:0.00GiB::DTB:;\n11:0.01GiB:0.01GiB:0.00GiB::LNX:;\n12:0.01GiB:0.01GiB:0.00GiB::EKS:;\n13:0.01GiB:0.01GiB:0.00GiB::BMP:;\n14:0.01GiB:0.01GiB:0.00GiB::RP4:;\n1:0.01GiB:15.3GiB:15.3GiB:ext4:APP:;\n\n\n\n# =========================================================================\n/work2$ ls -la jetson_sd_20201022_2.img y.img \n# =========================================================================\n-rw-r--r-- 1 user  user 30953963520 10月 22 15:42 jetson_sd_20201022_2.img\n-rw-r--r-- 1 user  user 16422139904 10月 25 07:00 y.img\n</code></pre></div></div>\n\n<h1 id=\"新しいsdカードにバックアップを復元\">新しいSDカードにバックアップを復元</h1>\n\n<p>イメージファイルからSDカードへのコピーはWindowsマシンで行っても良いですが、ここではubuntu PCで行う方法について記載します。</p>\n\n<ul>\n  <li>ubuntu PCに新しいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>バックアップしたイメージファイルをSDカードにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«入力ファイル» <span class=\"nv\">of</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h1 id=\"新しいsdカードのパーティションを拡張\">新しいSDカードのパーティションを拡張</h1>\n\n<p>バックアップした際にパーティションサイズを縮小してあるため、そのままのSDカードではディスクの残り容量がわずかしかありません。<br />\nそこで、パーティションサイズを拡張して容量を増加させます。</p>\n\n<p>この作業はubuntu PCであらかじめ行うか、またはターゲットマシンでブートした後に行います。</p>\n\n<p>パーティション操作プログラム<code class=\"language-plaintext highlighter-rouge\">gparted</code>を使用します。<br />\nインストールされていない場合は、<code class=\"language-plaintext highlighter-rouge\">sudo apt install gparted</code>でインストールしておいてください。</p>\n\n<ul>\n  <li>gpartedを起動\n    <ul>\n      <li>Libparted Warning ダイアログで”Not all of the space available to ~”と出たらFixをクリック</li>\n      <li>Libparted Warning ダイアログで”The backup GPT table is corrupt, but the primary appears OK, so that will be used.”と出たらOKをクリック<br />\n以降も何度か出るが、以下の操作がすべて終わればbackup GPTが新たに作成されるので問題なし。<br />\n(これは、ディスクイメージを縮小したときにgdiskコマンドを実行しなかった場合に出ます)</li>\n      <li>Gparted→デバイスで<code class=\"language-plaintext highlighter-rouge\">«SDカードデバイス»</code>`を選択</li>\n      <li>図の<code class=\"language-plaintext highlighter-rouge\">«SDカードのパーティション»</code> を右クリック→「リサイズ/移動」をクリック\n        <ul>\n          <li>「新しいサイズ」の欄に上にある「最大サイズ」以下の値を入力</li>\n          <li>「リサイズ」をクリック</li>\n        </ul>\n      </li>\n      <li>「編集(E)」→「保留中の全ての操作を適用する(A)」をクリック\n        <ul>\n          <li>「本当に保留中の操作を適用してもよろしいですか?」と聞かれるので、「適用」をクリック</li>\n        </ul>\n      </li>\n      <li>処理が完了したら「閉じる」をクリック</li>\n    </ul>\n  </li>\n  <li>gpartedを終了</li>\n</ul>\n\n<p>ターゲットマシンで実行している場合は、そのまま使用できます。<br />\nubuntuマシンで実行した場合は、SDカードを取り外してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をセットアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をセットアップする</h1>\n      <p>Jetson nano をセットアップする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>本稿はJetoack4.4での手順です。<br />\nJetpack4.6のときのメモは<a href=\"/memoBlog/2021/09/13/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする(Jetpack4.6)</a> にあります。</p>\n\n<p>Nvidiaの<a href=\"https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/\">Jetson nano</a>をセットアップしたときのメモ</p>\n\n<h1 id=\"参照先\">参照先</h1>\n<ul>\n  <li><a href=\"https://monoist.atmarkit.co.jp/mn/articles/1905/30/news029.html\">「Jetson Nano」の電源を入れて立ち上げる</a>\n    <ul>\n      <li>わりと詳しく書いてある</li>\n    </ul>\n  </li>\n  <li><a href=\"https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit\">Getting Started With Jetson Nano Developer Kit </a>\n    <ul>\n      <li>本家</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"sdカードの作成\">SDカードの作成</h1>\n<p>参照先の通り。</p>\n\n<p>ただし、参照先のSDカードイメージへのリンクは古いので、は以下から最新版をダウンロードする(古いのも下の方を探せば出てくる)</p>\n<ul>\n  <li><a href=\"https://developer.nvidia.com/embedded/downloads\">Jetson Download Center</a></li>\n</ul>\n\n<p>SDカード書き込みは記事に書かれた balenaEtcher でなく WIN32DiskImager でも大丈夫だが、<br />\nbalenaEtcher は zipファイルを解凍せずにSDカードに書き込めるので便利。<br />\nちなみに、<em>balena</em> はイタリア語で <em>鯨</em> の意味らしい…全然関係ないけど…</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストール先のSDカードは32GB必須みたい。<br />\n16GBだとインストールしただけで「残り少ない」と言われてしまう。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSDカードスロットが分かりにくいところにある(開発ボード側ではなく、モジュール側の裏側)。<br />\nシリアルコンソール繋いでるとケーブルが邪魔で特に挿抜しにくい…</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\n一度このイメージを書き込んだSDカードは、以後Windowsから認識されなくなる。<br />\nよって、SDフォーマッタやディスクイメージ書き込みツールから新たに書き込みできなくなってしまう。\nこれは書き込んだSDカードにFATのパーティションが存在しないためのよう。<br />\n(RaspberryPiはbootパーティションとしてFATパーティションを持っているので認識されるようだ)</p>\n\n  <p>コントロールパネル→管理ツール→コンピュータの管理を起動して、<br />\n記憶域の下のディスクの管理からSDカード上の不明なパーティションを解放し、<br />\nそこに新たにFATパーティションを作成すればWindowsから認識されるようになる。<br />\nもちろん、他のUbuntuマシンで書き換えちゃうのもアリだけど。。。</p>\n</blockquote>\n\n<h1 id=\"シリアルコンソールの使用\">シリアルコンソールの使用</h1>\n<p>シリアルコンソールが必要なら接続できる。<br />\n特に設定等は必要ない。  <br />\n接続端子は以下を参照</p>\n<ul>\n  <li><a href=\"https://www.jetsonhacks.com/2019/04/19/jetson-nano-serial-console/\">Jetson Nano – Serial Console</a>\nの 「Wiring」の下の「Jetson Nano B01」を参照。</li>\n</ul>\n\n<p>シリアルポートの設定は115200bps/8bit/none/1bit/none</p>\n\n<blockquote>\n  <p>[!WARNING]\nJ41(RaspberryPi互換の40pinヘッダ)のUART端子はコンソールとして動作していないみたい。<br />\ngettyが動いてないみたいなので。  <br />\nたぶん、<code class=\"language-plaintext highlighter-rouge\">/etc/systemd/nvgetty.sh</code> に<code class=\"language-plaintext highlighter-rouge\">ttyTHS2</code>の設定を追加すればできるようになる感じだけど、試してないので詳細不明。<br />\nJ41のUARTを汎用UARTとして使用するには、以下を参照。</p>\n  <ul>\n    <li><a href=\"https://www.jetsonhacks.com/2019/10/10/jetson-nano-uart/\">Jetson Nano – UART</a></li>\n  </ul>\n</blockquote>\n\n<p>その他、コネクタ類の配置が分かりにくい場合は、\n<a href=\"https://developer.download.nvidia.com/assets/embedded/secure/jetson/Nano/docs/NV_Jetson_Nano_Developer_Kit_User_Guide.pdf?yIbsUqvBKxI1G6r3WW7cOdheZGv2-eSfaFW_kMt3dSgi0NJ7h77OwFHr5b-rquc3IX7Tyrt8FV6IKD4DHqvP4_LzhWt55tb071gqXlNGwBPYCOC5pnEKAla8D-B82bPjhQMykANFyn-EhxZRHC8AIBYWuVwwwXVPWtCOjs34Tg50oBdN0vBNoyUlZMRFXLNJ2to\">JETSON NANO DEVELOPER KIT</a>\nのP22 に<strong>Developer kit module and carrier board: rev B01 top view</strong>として配置図が掲載されているので参照のこと。</p>\n\n<h1 id=\"firstboot\">FirstBoot</h1>\n<p>最初のブートでUbuntuのセットアップを行う。<br />\nこれも参照先の通り。<br />\n終わったら、何はともあれ最新版にアップデート。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ここで一旦リブートしておく。</p>\n\n<p>その他こまごました設定はこちらが参考になるかも。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/05/08/ubuntu_native.html\">UbuntuをNative環境にインストールする(18.04)</a></li>\n</ul>\n\n<p>インストールしたパッケージ\ngnome-tweaks\ndconf-editor\nsamba</p>\n<blockquote>\n  <p>[!NOTE]\nmin/max/closeボタンがウィンドウ右側に移動できない…\nちょっとストレス…</p>\n</blockquote>\n\n<h1 id=\"その他設定\">その他設定</h1>\n<h2 id=\"ウィンドウマネージャをunityからubuntuに変更する\">ウィンドウマネージャをUnityからubuntuに変更する</h2>\n<p>Unityは使いにくくて嫌(個人の見解デス)なので、Ubuntuに変更する(変更しなくても良い)。\n自動ログインしている場合は、一旦ログアウトして、<br />\n再ログインする際に、「サインイン」ボタンの左にある歯車アイコンをクリック→Ubuntuを選択してから<br />\nログインすると、ウィンドウマネージャがUbuntuに変更されている。<br />\n次回ログイン(自動ログインでも)は何もしなくても前回のウィンドウマネージャが選択される。</p>\n<blockquote>\n  <p>[!NOTE]\nUbuntuに変えると min/max/closeボタンがウィンドウ右側に移動できてる。<br />\n結果オーライ😅</p>\n</blockquote>\n\n<h2 id=\"sshでの接続\">SSHでの接続</h2>\n<p>特に設定などは必要ない。<br />\nTeraTermなどで接続すれば良い。\nUbuntuではmDNSが動いているので、«マシン名».localでアクセスできる。</p>\n\n<p>コマンドは以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\"C:\\Program Files (x86)\\teraterm\\ttermpro.exe\" /auth=password /user=«ユーザ名» /passwd=«パスワード» «JetsonのIPアドレス or マシン名.local»\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nSSHやmDNSは立ち上がるまで少し時間がかかるみたいなので、<br />\n起動後数十秒程度待ってから接続した方が良い。</p>\n</blockquote>\n\n<h3 id=\"ssh接続がタイムアウトする対策\">SSH接続がタイムアウトする対策</h3>\n<p>SSH接続したターミナルを触らずにしばらく置いておくと、タイムアウトしてクローズされてしまう。\nこれを防ぐにはクライアント側からkeep-aliveパケットを定期的に送信してやれば良いらしい。</p>\n\n<p>Teratermの場合、「設定」→「SSH」→「ハートビート(keep-alive)」を「8」とかに設定し、保存。\n次回接続時はこの保存した設定ファイルを読み込む</p>\n\n<h3 id=\"シリアルコンソールssh接続でguiウィンドウを表示できるようにする\">シリアルコンソール/SSH接続でGUIウィンドウを表示できるようにする</h3>\n<p>シリアルコンソール/SSH接続でGUIウィンドウを表示できるようにするには、\nWindowsPCなどでX-Serverを動作させておき、<br />\nそこに出力するようにすればよい。<br />\nJetson側は<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加しておく。<br />\nここのIPアドレスはX-Serverが動作しているマシンのIPアドレスに変更すること。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XX.XX:0.0\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"リモートデスクトップの設定\">リモートデスクトップの設定</h1>\n<p>TigerVNC はちょっと動作があやしいので、やめておいて、Desktop Sharing(Vino)を使うことにする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f#%E6%96%B9%E6%B3%952-desktop-sharingvino%E3%82%92%E4%BD%BF%E3%81%86\">Jetson Nanoにリモートデスクトップ(VNC)環境を用意する</a></li>\n  <li><a href=\"https://www.hackster.io/news/getting-started-with-the-nvidia-jetson-nano-developer-kit-43aa7c298797\">Getting Started with the NVIDIA Jetson Nano Developer Kit</a> の 「Enabling Desktop Sharing」</li>\n</ul>\n\n<p>この手順はウィンドウマネージャがUnityで実行しています。 ウィンドウマネージャをUbuntuに変更していると少し手順が違うかもしれませんので、\nウィンドウマネージャをUbuntuに変更している場合はUnityに戻してから設定してください。<br />\n設定完了後はUbuntuに再変更しても問題ありません。</p>\n\n<p>以下手順の再掲。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml</code>に以下のパッチを当てる</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- org.gnome.Vino.gschema.xml.org      2020-10-19 06:21:32.034728957 +0900\n</span><span class=\"gi\">+++ org.gnome.Vino.gschema.xml  2020-10-19 06:22:30.887994965 +0900\n</span><span class=\"p\">@@ -154,5 +154,14 @@</span>\n       </description>\n       <default>true</default>\n     </key>\n<span class=\"gi\">+    <key name='enabled' type='b'>\n+      <summary>Enable remote access to the desktop</summary>\n+        <description>\n+          If true, allows remote access to the desktop via the RFB\n+          protocol. Users on remote machines may then connect to the\n+          desktop using a VNC viewer.\n+        </description>\n+      <default>false</default>\n+    </key>\n</span>   </schema>\n </schemalist>\n</code></pre></div></div>\n<ul>\n  <li>以下のコマンドを実行(これで「システム設定」に「デスクトップの共有」アイコンが表示されるようになる)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>glib-compile-schemas /usr/share/glib-2.0/schemas\n</code></pre></div>    </div>\n  </li>\n  <li>GUI画面から「システム設定」→「デスクトップの共有」(ユーザ向けカテゴリの中にある)\n    <ul>\n      <li>「Sharing」カテゴリ\n        <ul>\n          <li>「Allow other users to view your desktop」にチェックを<em>入れる</em></li>\n          <li>「Allow other users to control your desktop」にチェックを<em>入れる</em></li>\n        </ul>\n      </li>\n      <li>「セキュリティ」カテゴリ\n        <ul>\n          <li>「You must confirm each access to this machine」のチェックを<em>はずす</em></li>\n          <li>「Requwire the user to enter this password」にチェックを<em>入れて</em>パスワード設定</li>\n          <li>「Automatically configure UPnP router to open and forward ports」のチェックを<em>はずす</em></li>\n        </ul>\n      </li>\n      <li>「Show Notification Area Icon」カテゴリ\n        <ul>\n          <li>「Only when someone is connected」を選択\n            <blockquote>\n              <p>[!NOTE]\nウィンドウマネージャがUbuntuの時は「設定」で設定する。\n左側の「共有」カテゴリを選択、「画面共有」をクリック</p>\n              <ul>\n                <li>「このスクリーンの操作する接続を許可する」をチェック</li>\n                <li>「アクセスオプション」で「パスワードを要求する」を選択し、パスワード設定</li>\n                <li>「ネットワーク」で「有線接続1」のスライドスイッチで「オン」を選択\n左上のスライドスイッチで「オン」を選択\nで出来ると思うけど、出来なかったらUnityで上の方法で設定した後、再度Ubuntuに切り替えてちょ。</li>\n              </ul>\n            </blockquote>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>「自動起動するアプリケーション」を起動\n    <blockquote>\n      <p>[!NOTE]\n「コンピュータを検索」で「自動」または「session」と入力すると出てくる\n日本語環境だと「startup」で出てこないみたい…</p>\n    </blockquote>\n    <ul>\n      <li>「追加」ボタンをクリック\n        <ul>\n          <li>名前に「Vino」</li>\n          <li>コマンドに「/usr/lib/vino/vino-server」</li>\n          <li>説明に「VNC server」\nー と入力して「追加」をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>以下のコマンドを実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.Vino prompt-enabled <span class=\"nb\">false</span>\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\nこれはVinoの暗号化方式がWindowsと互換性がないための措置で、<br />\n暗号化を無効化しているらしい。<br />\ndconf-editorでも設定できる。</p>\n    </blockquote>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nVNC使う場合は自動ログインをONしておかないといけない<br />\n設定箇所はぐぐってちゃぶだい…😅</p>\n</blockquote>\n\n<ul>\n  <li>リブートする</li>\n  <li>ホストPCからRealVNCのVNC ViewerやUltraVNC viewerなどで接続する</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nVNCは反応速度が鈍いので、ちょっと使いにくい。<br />\n普段はSSHとsambaとホスト側のX-Serverで動かすのが良いかも…</p>\n</blockquote>\n\n<h1 id=\"追加情報\">追加情報</h1>\n<p>ipv6を無効にしたい(ネットワーク環境によっては無効にした方が良い)場合は、<br />\n<a href=\"/memoBlog/2020/05/26/ubuntu_koneta.html\">ubuntu 小ネタ集</a>の\n「ubuntu 18.04 で IPv6を無効にする方法」 にしたがって設定する。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージ(2021.1)をインストール(追加)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージ(2021.1)をインストール(追加)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2021.1対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a>で\nubuntuへopenVINO 2020.3のインストールしたが、今回は 2021.1 を追加インストールしたのでメモ。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>前に登録したときに通知されたURLから「Choose Version」でバージョン選んでダウンロードできる。<br />\n新しく登録しなても大丈夫(登録方法は<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>参照)。</p>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>これは前回と同じ。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫だが、<br />\ncmakeは<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたバージョンだと古くてNGといわれてしまうので、<br />\n別途本家からダウンロードしてインストールする(ubuntu 18.04の場合。20.04だとたぶん<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたので大丈夫)。</p>\n\n<ul>\n  <li>既に<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストール済みの場合は、アンインストールする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt purge <span class=\"nt\">--auto-remove</span> cmake\n</code></pre></div>    </div>\n  </li>\n  <li>本家からダウンロードして展開\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/Kitware/CMake/releases/download/v3.18.4/cmake-3.18.4-Linux-x86_64.tar.gz  \n<span class=\"nb\">tar </span>xzvf cmake-3.18.4-Linux-x86_64.tar.gz \n</code></pre></div>    </div>\n  </li>\n  <li>/opt ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv </span>cmake-3.18.4-Linux-x86_64 /opt/\n</code></pre></div>    </div>\n  </li>\n  <li>/usr/bin ディレクトリにシンボリックリンク作成\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /opt/cmake-3.18.4-Linux-x86_64/bin/<span class=\"k\">*</span> /usr/bin/\n</code></pre></div>    </div>\n  </li>\n  <li>バージョン確認\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">--version</span> \n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>インストール手順も<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫。</p>\n\n<p>完了したらこれが表示されるページのURLは以下に変更されている。<br />\n<a href=\"https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<p>2020.3インストール済みだと端折っても大丈夫かと思ったけど、微妙にパッケージ増えてたりするので、再度やった方が良い。<br />\n環境変数の設定のために、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に記述する処理は以下に変更(<code class=\"language-plaintext highlighter-rouge\">openvino</code>→<code class=\"language-plaintext highlighter-rouge\">openvino_2021</code>)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\n<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を実行すると、再度<code class=\"language-plaintext highlighter-rouge\">apt</code>で<code class=\"language-plaintext highlighter-rouge\">cmake</code>がインストールされてしまいます。<br />\nopenVINOのインストール完了後であれば<code class=\"language-plaintext highlighter-rouge\">cmake</code>のバージョンが古くても大丈夫ですが、<br />\n気になるなら、再度アンインストールとシンボリックリンクの作成を行います。<br />\n(実行前に<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を編集してcmake消しておいても良いけど)</p>\n</blockquote>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>これは2020.3インストール済みだと端折ってもOK。<br />\n初めてインストールなら<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>を参照。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順はWiresharkで色々操作しないといけないのがめんどっちいので、スクリプトで自動化してみた。</p>\n\n<p>WiresharkのCUI版である、tsharkを使うと出来るらしいとの情報があったので、試してみたときのメモ。<br />\n今回はRaspberryPiだけ。Windowsは対応してません。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_1.html\">WiresharkでUSBパケットをキャプチャするときの注意事項</a> \nの準備は出来ているものとする。(Wiresharkは入ってなくても大丈夫。もちろん 入ってても良いよ。)</p>\n\n<p>tsharkは以下のコマンドイッパツでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tshark \n</code></pre></div></div>\n\n<p>で、あとは以下のスクリプトを\n<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの<code class=\"language-plaintext highlighter-rouge\">json_read.py</code>と同じディレクトリに作成し、実行するだけ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cap.sh\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/usr/bin/env bash</span>\n\n<span class=\"c\"># 第一引数でキャプチャ期間(sec)</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-z</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n  <span class=\"c\"># 引数なしだと2secに設定</span>\n  <span class=\"nv\">period</span><span class=\"o\">=</span>2\n<span class=\"k\">else</span>\n  <span class=\"c\"># 引数のチェック</span>\n  <span class=\"k\">if </span><span class=\"nb\">expr</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> : <span class=\"s1\">'[0-9]*'</span> <span class=\"o\">></span> /dev/null <span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># 数値</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nv\">$1</span> <span class=\"nt\">-lt</span> 1 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n      <span class=\"c\"># 1未満の数値</span>\n      <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n      <span class=\"nb\">exit\n    </span><span class=\"k\">else</span>\n      <span class=\"c\"># 1以上の数値(OK)</span>\n      <span class=\"nv\">period</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span>\n    <span class=\"k\">fi\n  else</span>\n    <span class=\"c\"># 数値でない</span>\n    <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n    <span class=\"nb\">exit\n  </span><span class=\"k\">fi\nfi</span>\n\n<span class=\"c\"># 現在時刻</span>\n<span class=\"nv\">cur_time</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">date</span> <span class=\"s2\">\"+%y%m%d_%H%M%S\"</span><span class=\"sb\">`</span>\n<span class=\"c\"># ファイル名生成</span>\n<span class=\"nv\">fname_base</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span>_<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># USBパケットキャプチャ</span>\n<span class=\"nb\">echo</span> <span class=\"s2\">\"Capture USB packets for </span><span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span><span class=\"s2\"> second from </span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\ntshark <span class=\"nt\">-i</span> usbmon1 <span class=\"nt\">-w</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-a</span> duration:<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># バス番号、デバイス番号の抽出</span>\n<span class=\"nv\">tmp_str</span><span class=\"o\">=</span><span class=\"sb\">`</span>lsusb | <span class=\"nb\">grep </span>WebCam<span class=\"sb\">`</span>\n<span class=\"nv\">bus_and_dev</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">tmp_str</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/Bus </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">Device </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">: ID.*/</span><span class=\"se\">\\1</span><span class=\"s2\"> </span><span class=\"se\">\\2</span><span class=\"s2\">/g\"</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">bus</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[0]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">dev</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[1]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">endpoint</span><span class=\"o\">=</span>1\n<span class=\"nv\">addr</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">bus</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">dev</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">endpoint</span><span class=\"k\">}</span>\n<span class=\"c\"># echo ${addr}</span>\n\n<span class=\"c\"># JSONファイルをエクスポート</span>\n<span class=\"nb\">echo </span>JSON data save to <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json...\ntshark <span class=\"nt\">-r</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-Y</span> <span class=\"s2\">\"usb.src==</span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">addr</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span> <span class=\"nt\">-T</span> json <span class=\"o\">></span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json\n\n<span class=\"c\"># JSON->CSV 変換</span>\npython json_read.py <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.csv\n\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。キャプチャ時間を秒で設定する。省略時は2秒。<br />\n出力されるファイル名は実行時の時刻で作成された文字列に各拡張子を付加したもの。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash cap.sh <span class=\"o\">[</span>キャプチャ時間<span class=\"o\">(</span>sec<span class=\"o\">)]</span>\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>なんかパラメータチェックが一番長いなぁ…😅</p>\n\n<p>33行目でパケットキャプチャ実行。</p>\n\n<p>35~41行目で対象USB機器のアドレス(バス番号、デバイス番号)を取得している。<br />\n36行目の<code class=\"language-plaintext highlighter-rouge\">grep</code>のパラメータは対象となるUSB機器に合わせて変更してちょ。<br />\nエンドポイント番号は対象機器によって固定なので、調べてね。\n分からなかったら、キャプチャしたデータをWiresharkで読み込んで確認してちょ。</p>\n\n<p>46行目でキャプチャしたファイルをJSONファイルにエクスポート。</p>\n\n<p>49行目でJSON→CSV変換。</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>これで<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順をスクリプトイッパツで完了できる。<br />\nま、特定環境でしか試してないから、どんな環境でも使えるとは限らないけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要--背景\">概要 & 背景</h1>\n\n<p>WiresharkでUSBパケットをキャプチャしたとき、実際に転送されてるデータの中身が見たいというニッチな要求があった。<br />\n(送ったデータがちゃんとUSBバスに出てるよね~、という確認がしたいなどの用途)</p>\n\n<p>Wiresharkのセーブデータ渡して「Wiresharkで見てね~」と言ったら「見方が分からん!」と…<br />\nで、Excelで一覧表にしてあげようと思い、エクスポートできんかな~と探してみるも、適当な機能が見つからず…<br />\nしかたなく、変換スクリプトかましてCSVに出力してExcelで読み込んでみよう、と試した時のメモ。</p>\n\n<p>今回はisochronous転送のデータの中身をダンプしている。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<ol>\n  <li>最初に解析したいパケットをキャプチャしておく(これをやらなきゃ始まらん…)。</li>\n  <li>必要なら表示フィルタで解析したいパケットだけ選び出す。</li>\n  <li>それらのパケットの一部だけ(最初の1秒だけ など)解析したい場合はそのパケット群を選択する。<br />\n   RaspberryPiでのやり方が分からん…Windows版なら他のアプリ同様、先頭で左クリック→最後でshift押しながら左クリックでOK。<br />\n   どうしても出来なかったら、RaspberryPiでキャプチャしたのを保存して、そのファイル(pcapngファイル)をWindowsにコピーして、\n   Windows上のWiresharkで読み込んでくだされ…😅</li>\n  <li>メニューの「ファイル」→「パケット解析をエクスポート」→「JSONとして」を選択</li>\n  <li>ファイル操作ダイアログが表示される\n    <ul>\n      <li>真ん中の「ファイル名」を入力</li>\n      <li>左下の「パケットの範囲」で\n        <ul>\n          <li>「表示されたパケット」を選択</li>\n          <li>「すべてのパケット」または「選択されたパケットのみ」を選択<br />\n (ここで「範囲」を選んで入力すれば選択しなくてもいいのかな?試してないので不明)</li>\n        </ul>\n      </li>\n      <li>「保存」をクリック</li>\n    </ul>\n  </li>\n</ol>\n\n<p>これでJSONファイルが保存される。</p>\n\n<h1 id=\"csvファイルに変換\">CSVファイルに変換</h1>\n\n<p>さぁ、このJSONファイルを読み込んで必要な部分を取り出すスクリプトを書けばOKじゃん?と思ったが、<br />\nそうは問屋がおろしてくれない😢<br />\nじつはWiresharkがエクスポートするJSONファイルはJSONファイルの文法からはずれた部分があるのだ…<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">/_source/layers/usb</code> の配下に複数のキー<code class=\"language-plaintext highlighter-rouge\">usb</code>があって、すべてのUSBデータを読み込めない。<br />\n(JSONの仕様では同一階層に複数の同じキーの存在を許さない。pythonのJSONモジュールでは複数あるデータのうち、一つだけが読み込まれる)<br />\nここが配列になってればOKだと気が付いて、チカラワザで変換する処理を追加してみた。</p>\n\n<p>で、pyshonで書いたスクリプトがこちら。<br />\nWindows/RaspberryPi どっちでも大丈夫と思うけど、Windowsでしか試してない。<br />\npythonは3.6以降が必要。3.7.7で動作確認。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  json_read.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"c1\"># テンポラリファイル名\n</span><span class=\"n\">tmp_file</span> <span class=\"o\">=</span> <span class=\"s\">'tmp.json'</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'==== USAGE ========================='</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'    </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> <JSON file> <CSV file>'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'===================================='</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">json_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">csv_file</span>  <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'Error: JSON file not exist!!'</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># \"usb\" キーが複数あるので、これをリストに変換したJSONファイルを作成する\n# かなり力技...\n</span><span class=\"k\">def</span> <span class=\"nf\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_json</span><span class=\"p\">,</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_tmp</span><span class=\"p\">:</span>\n        <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        \n        <span class=\"k\">while</span> <span class=\"n\">line</span><span class=\"p\">:</span>\n            <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"n\">line_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>           <span class=\"c1\"># 行番号\n</span>            <span class=\"c1\"># line = line.rstrip('\\r\\n')              # CRLFを削除\n</span>            <span class=\"k\">if</span> <span class=\"n\">find_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">'\"usb\": '</span><span class=\"p\">,</span> <span class=\"s\">''</span><span class=\"p\">)</span>      <span class=\"c1\"># key名称 \"usb\"を削除\n</span>                <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'START: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          \"usb_data\": [</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">+</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'{'</span><span class=\"p\">)</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">-</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'}'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">brackets</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'END: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          ]</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb.iso.numdesc\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">f_pos</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">tell</span><span class=\"p\">()</span>\n                    <span class=\"n\">next_line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>        <span class=\"c1\"># 次の行を読み込んで\n</span>                    <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"n\">f_pos</span><span class=\"p\">)</span>                   <span class=\"c1\"># ファイル位置を戻す\n</span>                    <span class=\"k\">if</span> <span class=\"n\">next_line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                    <span class=\"c1\"># 括弧の数\n</span>            <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">line</span><span class=\"p\">)</span>\n            <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># JSONファイルの修正\n</span><span class=\"n\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># パケット解析用変数\n</span><span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n<span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># JSONファイルの読み込み\n</span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n    <span class=\"n\">json_load</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(json_load)\n</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">csv_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_csv</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ヘッダの出力\n</span>    <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">'PacketNo,Date,Relative_time,Delta_time,Packet Size,Video Stream Size,Video Stream offset,Frame No,Stream No,Stream Data</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">json_data</span> <span class=\"ow\">in</span> <span class=\"n\">json_load</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フレームデータ\n</span>        <span class=\"n\">frame_data</span>          <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"frame\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_index</span>         <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.number\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_epoc</span>     <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_epoch\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_delta</span>    <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_delta_displayed\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_relative</span> <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_relative\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_dt</span>       <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">fromtimestamp</span><span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">frame_time_epoc</span><span class=\"p\">))</span>\n        <span class=\"n\">frame_time</span>          <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_time_dt</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_len</span>           <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.len\"</span><span class=\"p\">]</span>\n        <span class=\"c1\"># print(f'{frame_index},\"\\'{frame_time}\",{frame_len},', end='')\n</span>        <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_index</span><span class=\"si\">}</span><span class=\"s\">,\"</span><span class=\"se\">\\'</span><span class=\"si\">{</span><span class=\"n\">frame_time</span><span class=\"si\">}</span><span class=\"s\">\",</span><span class=\"si\">{</span><span class=\"n\">frame_time_relative</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_time_delta</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_len</span><span class=\"si\">}</span><span class=\"s\">,'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># USBデータ\n</span>        <span class=\"n\">usb_datas</span>  <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"usb\"</span><span class=\"p\">][</span><span class=\"s\">\"usb_data\"</span><span class=\"p\">]</span>\n        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"k\">for</span> <span class=\"n\">usb_data</span> <span class=\"ow\">in</span> <span class=\"n\">usb_datas</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f',,,,,', end='')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">',,,,,'</span><span class=\"p\">)</span>\n            <span class=\"n\">iso_len</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_len'</span><span class=\"p\">])</span>\n            <span class=\"n\">iso_off</span>  <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_off'</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">iso_len</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">\"usb.iso.data\"</span><span class=\"p\">]</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"s\">'0x'</span><span class=\"o\">+</span><span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">':'</span><span class=\"p\">,</span> <span class=\"s\">',0x'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">stream_number</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_number</span><span class=\"p\">)</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"s\">''</span>\n                \n                <span class=\"c1\"># print(f'{iso_len},{iso_off},{stream_number},{iso_data}')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_number_str</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">stream_number</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_data</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x02'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x03'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"n\">stream_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f'{iso_len},{iso_off},,')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,,</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># テンポラリファイルの削除\n</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。(RaspberryPiだと<code class=\"language-plaintext highlighter-rouge\">python3</code>にしてちょ)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python json_read.py «入力JSONファイル» «出力CSVファイル»\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>やっつけスクリプトなので、エラーチェックはかなりいい加減…</p>\n\n<p>関数<code class=\"language-plaintext highlighter-rouge\">modify_json()</code> が 前述のJSONファイルの不具合をチカラワザで修正する処理。</p>\n\n<p>テンポラリファイルとしてカレントディレクトリに<code class=\"language-plaintext highlighter-rouge\">tmp.json</code>を作成するので、注意。\nファイル名を変更したければ、8行目の<code class=\"language-plaintext highlighter-rouge\">tmp_file</code>を変更。<br />\nこのファイルはスクリプトの最後で削除している。<br />\n作成したテンポラリファイルを残しておきたければ最後の<code class=\"language-plaintext highlighter-rouge\">os.remove(tmp_file)</code>をコメントアウト。</p>\n\n<p>71~72行目で修正したJSONファイルを読み込み。</p>\n\n<p>75行目で書き出すCSVファイルをオープン。</p>\n\n<p>78行目~のforループで各JSONレコードを読み込みながら処理。</p>\n\n<p>82,85~86行目でframe.time_epochから時刻文字列を作成。<br />\n時刻は<code class=\"language-plaintext highlighter-rouge\">frame.time</code>を使用する手もあるが、ここはプラットフォームによって変化するらしいので同じ表示にするためにエポックタイムから生成している。<br />\nその他時刻関連データでは、<code class=\"language-plaintext highlighter-rouge\">frame.time_delta_displayed</code>で「前のパケットからの相対時間」、\n<code class=\"language-plaintext highlighter-rouge\">frame.time_relative</code>で「最初のパケットからの相対時間」を取得している。</p>\n\n<p>94行目~のforループがデータを取り出す部分。<br />\nisochronous転送のデータではないデータを取り出したい場合は、所望のデータのキーに置き換えて取り出せば良い。<br />\n<code class=\"language-plaintext highlighter-rouge\">frame_number</code>と<code class=\"language-plaintext highlighter-rouge\">stream_number</code>は私の解析用の補助データなので気にしないでネ。</p>\n\n<p>あとは、エクスポートされたJSONファイルとスクリプトを見比べてちゃぶだい。(^^ゞ</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>あとは、csvファイルをExcelで読み込むなり、pandasとかを使った別のスクリプトで加工するなりしてちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットをキャプチャするときの注意事項</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットをキャプチャするときの注意事項</h1>\n      <p>WiresharkでUSBパケットをキャプチャしようとしてちょっとハマったのでメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>WiresharkでUSBパケットをキャプチャするための準備(Linux版)<br />\nWindows版はちょっと異なると思うけど試してないので、ググってね😅。</p>\n\n<h1 id=\"wiresharkのインストール実行\">Wiresharkのインストール&実行</h1>\n\n<p>ふつーに<code class=\"language-plaintext highlighter-rouge\">apt install</code>するだけ。<br />\nWindows版と異なり、USBパケットキャプチャのために別途USBキャプチャプログラムをインストールする必要はない。<br />\nついでに<code class=\"language-plaintext highlighter-rouge\">sudo</code>しなくても実行できるように自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>グループを追加しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>wireshark\n<span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> wireshark \n</code></pre></div></div>\n\n<p>ここで一旦ログアウト&再ログイン or 再起動。</p>\n\n<p>このままだとUSBパケットキャプチャのためのプログラム(<code class=\"language-plaintext highlighter-rouge\">usbmon</code>)が動いてないので、動かす必要がある。<br />\n<strong>起動の度に</strong>ターミナルから以下のコマンドを実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbmon\n</code></pre></div></div>\n\n<p>Wiresharkの実行は、ターミナルから<code class=\"language-plaintext highlighter-rouge\">wireshark</code>を実行するか、メニューの「インターネット」→「Wireshark」を選択します。<br />\n(自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>`グループを追加してあるので、メニューからでも実行できます)</p>\n\n<p>起動の度に<code class=\"language-plaintext highlighter-rouge\">usbmon</code>を起動するのは面倒な場合は、以下の手順で自動化できます。</p>\n\n<ol>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/udev/rules.d/99-usbmon.rules</code>を以下の内容で作成\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>SUBSYSTEM==\"usbmon\", GROUP=\"wireshark\", MODE=\"640\"\n</code></pre></div>    </div>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/modules</code> に以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbmon\n</code></pre></div>    </div>\n  </li>\n  <li>リブート</li>\n</ol>\n\n<h1 id=\"wiresharkの使い方\">Wiresharkの使い方</h1>\n\n<p>あちこちのホームページに詳しく解説されているので、ぐぐってちょ(←なんて他力本願…😅)。<br />\nRaspberryPi4の場合、USBのインタフェースはusbmon1とusbmon2があるが、どっちをキャプチャするかは、接続した機器がUSB2.0かUSB3.0による。<br />\nたぶん、usbmon1がUSB2.0(外側/内側)、usbmon2がUSB3.0(内側のみ)だと思う。<br />\n<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)がusbmonYのYにあたるとだと推測。</p>\n\n<h1 id=\"wiresharkでパケット解析\">Wiresharkでパケット解析</h1>\n\n<p>USBのパケットの表示フィルタの書き方がネット上でもなかなか見つからなかったので、簡単なものだけメモ。</p>\n\n<h2 id=\"特定のusb機器のパケットだけ表示\">特定のUSB機器のパケットだけ表示</h2>\n\n<p>実際にはエンドポイントまで指定しているので、複数のエンドポイントを同時に表示したければ、OR(<code class=\"language-plaintext highlighter-rouge\">||</code>)で条件つなげてください。\n(<code class=\"language-plaintext highlighter-rouge\">1.5.*</code>みたいな書き方が出来るのかは不明 )</p>\n\n<p>この例の<code class=\"language-plaintext highlighter-rouge\">1.5.1</code>の<br />\n左の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)、 <br />\n中央の<code class=\"language-plaintext highlighter-rouge\">5</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のデバイス番号(<code class=\"language-plaintext highlighter-rouge\">Device YYY</code>の部分の数字)(<strong>挿抜の度に変わる</strong>)、 <br />\n右の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb -D /dev/bus/usb/XXX/YYY</code>(XXX、YYYは上記のバス番号、デバイス番号。0は省略不可) で表示される情報の <br />\n<code class=\"language-plaintext highlighter-rouge\">bEndpointAddress</code>で確認できるけど、これは機器内部で固定されてるはず。<br />\nと、難しく調べんでも、一度全部キャプチャしたものを表示して欲しいパケットを探してみてそこのアドレスを見れば分かる。</p>\n\n<p>USBホストの吐合は<code class=\"language-plaintext highlighter-rouge\">\"host\"</code>になる。</p>\n\n<h3 id=\"特定の機器の送信パケットだけ表示\">特定の機器の送信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\"\n</code></pre></div></div>\n<h3 id=\"特定の機器の受信パケットだけ表示\">特定の機器の受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n<h3 id=\"特定の機器の送受信パケットだけ表示\">特定の機器の送受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\" || usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>githubによるセキュリティチェック</title>\n  </head>\n  <body>\n    <header>\n      <h1>githubによるセキュリティチェック</h1>\n      <p>githubによるセキュリティチェックによるpullリクエストが来た場合の対処方法</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>githubによるセキュリティチェックによるpullリクエストが来た場合の対処方法</p>\n\n<p>例えば、tensorflow 1.15 を使用するような設定が書かれていた場合、2.1.0に変更しろと言ってくる。<br />\nでも、変更したら動かなくなるし…</p>\n\n<h1 id=\"対処方法\">対処方法</h1>\n\n<p>こんな場合は しかたないので、アラート無視するよう言い訳する。<br />\nやり方:<a href=\"https://blog.tmd45.jp/entry/2019/11/26/162157\">GitHub Security Alert の Dismiss 言い訳</a></p>\n\n<p>でもって、自動で作成されたpullリクエストをcloseすると勝手に作成されたブランチも消えるらしい。<br />\nやり方: <a href=\"https://help.github.com/ja/github/collaborating-with-issues-and-pull-requests/closing-a-pull-request\">プルリクエストをクローズする</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのバグ??</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのバグ??</h1>\n      <p>pyenvのバグ??</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>バグかどうかわからんけど、思った通りの動作をしなかったので、メモ。</p>\n\n<h1 id=\"現象\">現象</h1>\n\n<p>pyenv を使う環境で、</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    python script.py <span class=\"nt\">--option</span> /path/to/file\n</code></pre></div></div>\n\n<p>と実行した場合、カレントディレクトリと<code class=\"language-plaintext highlighter-rouge\">/path/to/file</code>の存在するディレクトリで使用するpythonのバージョンが異なる場合、<br />\n(どちらか片方 or 両方で <code class=\"language-plaintext highlighter-rouge\">pyenv local</code>が指定されている)<br />\nカレントディレクトリではなく、/path/to/fileの存在するディレクトリで使用するpythonのバージョンが指定されてしまうらしい。</p>\n\n<p>問題が発生するシチュエーションは そんなに多くないと思うけど、 双方のバージョンでインストールしてるモジュールが違ったりすると困ったことになる。</p>\n\n<h1 id=\"原因\">原因</h1>\n\n<p>色々試行錯誤してみてわかったことを結論だけ。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> を見ると、<br />\nコマンドラインをサーチして最初に見つかったファイルの属する<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読むらしい。<br />\n(以下の部分)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    ・・・\n    <span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"k\">in</span>\n        <span class=\"nt\">-c</span><span class=\"k\">*</span> <span class=\"p\">|</span> <span class=\"nt\">--</span> <span class=\"p\">)</span> <span class=\"nb\">break</span> <span class=\"p\">;;</span>\n        <span class=\"k\">*</span>/<span class=\"k\">*</span> <span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-f</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n                </span><span class=\"nb\">export </span><span class=\"nv\">PYENV_FILE_ARG</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span>\n                <span class=\"nb\">break\n            </span><span class=\"k\">fi</span>\n            <span class=\"p\">;;</span>\n    <span class=\"k\">esac</span>\n    ・・・\n</code></pre></div></div>\n<p>本来ならスクリプトファイルのあるディレクトリの<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読んでほしいはずなのに…<br />\n<code class=\"language-plaintext highlighter-rouge\">*/* )</code> でなく、<code class=\"language-plaintext highlighter-rouge\">*)</code> じゃないのかな? なんか深い訳があるのかもしれんけど…</p>\n\n<h1 id=\"対処方法\">対処方法</h1>\n\n<p>で、以下のいずれかの方法で対処できる。</p>\n\n<ul>\n  <li>オプションの場合は、オプションとオプションパラメータの間をスペースでなく、<code class=\"language-plaintext highlighter-rouge\">=</code>にする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  python script.py <span class=\"nt\">--option</span><span class=\"o\">=</span>/path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>ただし、パーサが<code class=\"language-plaintext highlighter-rouge\">argparse.ArgumentParser</code>など、オプションとオプションパラメータの区切りに<code class=\"language-plaintext highlighter-rouge\">=</code>が使えるものでなければダメ。</li>\n      <li>しかも、そもそもオプションパラメータでなくコマンドパラメータだったらどうしようもない…orz…</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pyenv shell</code>で使用するバージョンを指定する\n    <ul>\n      <li>メンドクサイ…</li>\n    </ul>\n  </li>\n  <li>スクリプトファイルの前に<code class=\"language-plaintext highlighter-rouge\">--</code>を追加してやる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">--</span> script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> では<code class=\"language-plaintext highlighter-rouge\">-c</code>か<code class=\"language-plaintext highlighter-rouge\">--</code>が見つかったら<code class=\"language-plaintext highlighter-rouge\">PYENV_FILE_ARG</code>を探すループを抜けてくれるので。</li>\n      <li>ちょっとめんどくさい…</li>\n    </ul>\n  </li>\n  <li>スクリプト名の前に./を追加する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ./script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>これが一番シンプルかな?</li>\n      <li>てか、コレしかないっしょ。 常に<code class=\"language-plaintext highlighter-rouge\">./</code>付けるクセ付ければいいし。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"免責のツモリ\">免責(のツモリ)</h1>\n\n<p>あくまで自分のメモなんで、、、  ゴニョゴニョ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ガラクタ置き場</title>\n  </head>\n  <body>\n    <header>\n      <h1>ガラクタ置き場</h1>\n      <p>COCO データセットから適当にファイルを取得する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ガラクタ\">ガラクタ</h1>\n<p>SSDなどの動作確認に使えるかなぁ~?と思ってCOCO データセットから適当にいくつかの画像ファイルを取得するスクリプトを作ってみた。<br />\n結局使わなかったけど、せっかくなのでガラクタ置き場に置いておく。(^^ゞ</p>\n\n<p>今回はリポジトリ作るほどではないので、ここにソース貼っとく。<br />\n解説するほどでもないので、使い方はソース見てチョ!←   テヌキ…</p>\n\n<h2 id=\"ソース\">ソース</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"s\">'''\nCOCOデータセットから適当にファイルを取得する\n'''</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">glob</span>\n<span class=\"kn\">import</span> <span class=\"nn\">shutil</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">RawTextHelpFormatter</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">urllib.request</span>\n<span class=\"kn\">import</span> <span class=\"nn\">zipfile</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n\n<span class=\"n\">COCO_2014</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>       <span class=\"c1\"># COCO 2014のminivalデータセット を使用する場合はTrueにする\n</span>\n<span class=\"c1\"># パラメータ\n</span><span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n    <span class=\"n\">DOWNLOAD_URL</span> <span class=\"o\">=</span> <span class=\"s\">'https://dl.dropboxusercontent.com/s/o43o90bna78omob/instances_minival2014.json.zip?dl=0'</span>\n    <span class=\"n\">JSON_FILE</span>    <span class=\"o\">=</span> <span class=\"s\">'instances_minival2014.json'</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">DOWNLOAD_URL</span> <span class=\"o\">=</span> <span class=\"s\">'http://images.cocodataset.org/annotations/image_info_test2017.zip'</span>\n    <span class=\"n\">JSON_FILE</span>    <span class=\"o\">=</span> <span class=\"s\">'annotations/image_info_test2017.json'</span>\n\n<span class=\"c1\"># zipファイル展開のための一時ファイル\n</span><span class=\"n\">TEMP_ZIP</span>     <span class=\"o\">=</span> <span class=\"s\">'temp.zip'</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">formatter_class</span><span class=\"o\">=</span><span class=\"n\">RawTextHelpFormatter</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--num'</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロードするファイル数\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--margin'</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">30</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロードエラーのためのマージン数\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--clean'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロード済みのファイルを削除して終了します</span><span class=\"se\">\\n</span><span class=\"s\">(ダウンロードは行いません)\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n\n<span class=\"c1\"># コマンドラインパーサの生成&解析\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">clean</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"==== CLEAN!! ====\"</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">):</span>\n        <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n            <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">shutil</span><span class=\"p\">.</span><span class=\"n\">rmtree</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">dirname</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">),</span> <span class=\"n\">ignore_errors</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">for</span> <span class=\"nb\">file</span> <span class=\"ow\">in</span> <span class=\"n\">glob</span><span class=\"p\">.</span><span class=\"n\">glob</span><span class=\"p\">(</span><span class=\"s\">'*.jpg'</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">):</span>\n            <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ファイル数設定\n</span><span class=\"n\">num_files</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num</span>\n<span class=\"n\">num_margin</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">margin</span>\n\n<span class=\"c1\"># JSONファイルがなければダウンロードする\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ダウンロードを実行\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">DOWNLOAD_URL</span><span class=\"si\">}</span><span class=\"s\"> をダウンロード中...'</span><span class=\"p\">)</span>\n    <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">urlretrieve</span><span class=\"p\">(</span><span class=\"n\">DOWNLOAD_URL</span><span class=\"p\">,</span> <span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 展開\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">TEMP_ZIP</span><span class=\"si\">}</span><span class=\"s\"> を展開中...'</span><span class=\"p\">)</span>\n    <span class=\"k\">with</span> <span class=\"n\">zipfile</span><span class=\"p\">.</span><span class=\"n\">ZipFile</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">zf</span><span class=\"p\">:</span>\n        <span class=\"n\">zf</span><span class=\"p\">.</span><span class=\"n\">extractall</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># テンポラリファイルの削除\n</span>    <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># JSONファイルの読み込み\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">JSON_FILE</span><span class=\"si\">}</span><span class=\"s\">の読み込み中...'</span><span class=\"p\">)</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_json</span> <span class=\"p\">:</span>\n    <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f_json</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ個数(5000のハズ)\n</span><span class=\"n\">data_len</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">])</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'DATA_LENGTH = </span><span class=\"si\">{</span><span class=\"n\">data_len</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 内容をダンプ\n# print(json.dumps(data[\"images\"], indent=2))\n</span>\n<span class=\"c1\"># ダウンロード数のチェック\n</span><span class=\"k\">if</span> <span class=\"n\">num_files</span> <span class=\"o\">+</span> <span class=\"n\">num_margin</span> <span class=\"o\">></span> <span class=\"n\">data_len</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'ERROR : ファイル数とマージンの合計がデータ個数を超えています'</span><span class=\"p\">)</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ダウンロードするインデックスを乱数で決定(エラー発生時のためにマージンを積んどく)\n</span><span class=\"n\">download_indexs</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">(</span><span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">data_len</span><span class=\"p\">),</span> <span class=\"n\">num_files</span> <span class=\"o\">+</span> <span class=\"n\">num_margin</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># ダウンロード完了個数\n</span><span class=\"n\">num_downloaded</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n<span class=\"n\">num_error</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># ダウンロードループ\n</span><span class=\"k\">for</span> <span class=\"nb\">id</span> <span class=\"ow\">in</span> <span class=\"n\">download_indexs</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ファイル名\n</span>    <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"file_name\"</span><span class=\"p\">]</span>\n    <span class=\"c1\"># URL\n</span>    <span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n        <span class=\"n\">url</span>      <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"url\"</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">url</span>      <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"coco_url\"</span><span class=\"p\">]</span>\n    <span class=\"c1\"># ダウンロード\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">filename</span><span class=\"si\">}</span><span class=\"s\">をダウンロード中...'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'ID : </span><span class=\"si\">{</span><span class=\"nb\">id</span><span class=\"si\">:</span><span class=\"mi\">3</span><span class=\"si\">}</span><span class=\"se\">\\t</span><span class=\"s\">NAME : </span><span class=\"si\">{</span><span class=\"n\">filename</span><span class=\"si\">}</span><span class=\"se\">\\t</span><span class=\"s\">URL : </span><span class=\"si\">{</span><span class=\"n\">url</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">try</span> <span class=\"p\">:</span> \n        <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">urlretrieve</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">)</span>\n    <span class=\"k\">except</span> <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">.</span><span class=\"n\">HTTPError</span> <span class=\"k\">as</span> <span class=\"n\">e</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># エラー発生\n</span>        <span class=\"n\">num_error</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'**** skip!! ****  </span><span class=\"si\">{</span><span class=\"n\">e</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ダウンロード完了\n</span>        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'---- DONE!! ----'</span><span class=\"p\">)</span>\n        <span class=\"n\">num_downloaded</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"c1\"># 所望の数に達したら終了\n</span>        <span class=\"k\">if</span> <span class=\"n\">num_downloaded</span> <span class=\"o\">>=</span> <span class=\"n\">num_files</span> <span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'ダウンロード数 : </span><span class=\"si\">{</span><span class=\"n\">num_downloaded</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'エラー数       : </span><span class=\"si\">{</span><span class=\"n\">num_error</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">num_error</span> <span class=\"o\">></span> <span class=\"n\">num_margin</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'warning : エラー数がマージンを越えました'</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<p>今後、なんかに使えると良いなぁ~(笑)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git の差分比較ツールにWinMergeを使用する</title>\n  </head>\n  <body>\n    <header>\n      <h1>git の差分比較ツールにWinMergeを使用する</h1>\n      <p>git の差分比較ツールに WinMerge を使用する方法</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows上のgit-の差分比較ツールに-winmerge-を使用する方法\">Windows上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows限定だが、git の差分比較ツールに WinMerge を使用する方法のメモ<br />\n参考: <a href=\"https://qiita.com/kobake@github/items/fb317b4fdacad718a4b2?fbclid=IwAR1eO6ENMKDeeY3PmGJWrKLf_n1rgC8NVPBF60xKMiG02yAFgCFS6ceC7IE\">git の差分比較・マージを WinMerge で行う</a><br />\n↑参考というよりパクリだが(^^ゞ</p>\n\n<p>git の差分比較の <code class=\"language-plaintext highlighter-rouge\">git diff</code> で見ると見難いので、WinmMergeを使えるようにしてみた。<br />\n普段はVS Code 使ってるけど…</p>\n\n<p>手順は、 <code class=\"language-plaintext highlighter-rouge\">C:\\Users\\〇〇\\.gitconfig</code> に以下を追記するだけ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n[difftool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -f \\\"*.*\\\" -e -u -r \\\"$LOCAL\\\" \\\"$REMOTE\\\"\n[merge]\n    tool = WinMerge\n[mergetool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -e -u \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$MERGED\\\"\n[alias]\n    windiff = difftool -y -d -t WinMerge\n    winmerge = mergetool -y -t WinMerge\n</code></pre></div></div>\n\n<p>差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力すれば良い。</p>\n\n<p>差分はファイル書き換えても自動的にアップデートされなので、都度<code class=\"language-plaintext highlighter-rouge\">git windiff</code> する必要がある。<br />\n(あくまでスナップショットでの比較を表示してるだけ)</p>\n\n<p>比較対象の指定とか、マージとかもできるみたいだけど、使ってないので、詳しくは↑の参考先を見てね。(^^ゞ</p>\n\n<h1 id=\"wsl上のgit-の差分比較ツールに-winmerge-を使用する方法\">WSL上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows上の場合とほぼ同じ。<code class=\"language-plaintext highlighter-rouge\">~/.gitconfig</code>に以下を追加しておき、差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力する。<br />\nマージは使わないので、diffだけ設定。<br />\n(上の方法をwslpathでLinux上のpath→Windows上のpath 変換してるだけ、かな?)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n\n[difftool]\n    prompt = false\n\n[difftool \"WinMerge\"]\n    cmd = '/mnt/c/Program Files/WinMerge/WinMergeU.exe' -e -r -u -wl -dl Local -wr -dr Remote \\\"`wslpath -wa $LOCAL`\\\" \\\"`wslpath -wa $REMOTE`\\\"\n    trustExitCode = false\n\n[alias]\n    windiff = difftool -y -d --no-symlinks -t WinMerge\n</code></pre></div></div>\n<p>参考:<a href=\"https://qiita.com/forest1/items/334b5d756b5696c63331\">WSL(Ubuntu 18.04)環境のgitでWinMergeを使う方法</a></p>\n\n<p>参考先ではUbuntu18.04となっているが、20.04でも問題なし。<br />\nまた、<code class=\"language-plaintext highlighter-rouge\">/mnt/c/Users/username</code>以下で作業と書いてあるが、どこで作業しても大丈夫。テンポラリパスの変更も不要。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>csvファイルをエクセルファイルに変換する</title>\n  </head>\n  <body>\n    <header>\n      <h1>csvファイルをエクセルファイルに変換する</h1>\n      <p>pythonでcsvファイルをエクセルファイルに変換する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonでcsvファイルをエクセルファイルに変換する方法。<br />\nぐぐったらすぐ出てくるけど、自分のとこにもメモしとく。<br />\nついでに、おまけとしてcsvファイルを読んで、各列の平均値を出力する処理も載せとく。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p>必要なモジュールをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>pandas openpyxl\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pandas</span> <span class=\"k\">as</span> <span class=\"n\">pd</span>\n\n<span class=\"c1\"># コマンドラインパラメータ\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span>\n\n<span class=\"c1\"># エラーチェックは省略\n# 入力ファイル(csv形式、拡張子は任意)の拡張子をxlsxに変更したファイルとして出力する\n</span>\n<span class=\"n\">input_file</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>                                        <span class=\"c1\"># 入力ファイル名\n</span><span class=\"n\">output_file</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">input_file</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".xlsx\"</span>     <span class=\"c1\"># 出力ファイル名\n</span> \n<span class=\"c1\"># CSVファイルの読み込み\n</span><span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">pd</span><span class=\"p\">.</span><span class=\"n\">read_csv</span><span class=\"p\">(</span><span class=\"n\">input_file</span><span class=\"p\">,</span> <span class=\"n\">index_col</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>     <span class=\"c1\"># 1行目がヘッダ、1列目がインデックスとする\n</span>\n<span class=\"c1\"># Excel形式で出力\n</span><span class=\"n\">data</span><span class=\"p\">.</span><span class=\"n\">to_excel</span><span class=\"p\">(</span><span class=\"n\">output_file</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s\">'utf-8'</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<p>csvファイルを読んで、各列の平均値を出力する処理をワンライナーで。<br />\n(前提:1行目がヘッダ、1列目がインデックス)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import sys; import pandas as pd; data = pd.read_csv(sys.argv[1], index_col=0); ave=data.mean(); print(ave)\"</span> «csvファイル»\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その6</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その6</h1>\n      <p>tensorflow lite で色々なSSDモデルを使う手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はソースが大半なので、githubにリポジトリ作った。<br />\n内容は各ディレクトリのREADME.mdを見てチョ。<br />\n<a href=\"https://github.com/ippei8jp/tflite_trial\">https://github.com/ippei8jp/tflite_trial</a></p>\n\n<p>順序は <code class=\"language-plaintext highlighter-rouge\">download_models</code> → <code class=\"language-plaintext highlighter-rouge\">mk_tflite_ssd</code> → <code class=\"language-plaintext highlighter-rouge\">images</code> → <code class=\"language-plaintext highlighter-rouge\">ssd</code> が良いと思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール(改訂版)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2020.3対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a>で\nubuntuへのインストール手順を書いたが、今読み返すと結構分かりにくかったので改訂版を書いとく。<br />\n今回はNCS2をubuntuで使えるようにしたので、その手順も追加。<br />\nついでに、今日(2020/06/16)現在の最新版Ver.2020.3での手順確認したので、反映しておく。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<p>参考 :<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">AIを始めよう!OpenVINOのインストールからデモの実行まで[R4対応]</a></p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>何やら登録しないとダウンロードさせてくれないらしい。</p>\n<ul>\n  <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download.html\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a> <br />\nLinux* (supports Ubuntu, CentOS, and Yocto Project)を選択\n    <ul>\n      <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download/linux.html\">Free Download</a>  <br />\n<span style=\"border: 1px solid;\">Register & Download</span>をクリック\n        <ul>\n          <li><a href=\"https://software.seek.intel.com/openvino-toolkit?os=linux\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a><br />\n必要事項を記入して<span style=\"border: 1px solid;\">Submit</span>をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>openVINO用のpython環境を用意しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work1/\npyenv virtualenv 3.7.7 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p>あとで「入ってない」って言われるので先にインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev\n</code></pre></div></div>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>ダウンロードしたファイルを展開してインストールスクリプトを実行する。<br />\n今回はバージョン 2020.3 で確認した。<br />\n最新版は <a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html</a> を参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf l_openvino_toolkit_p_<version>.tgz\n<span class=\"nb\">cd </span>l_openvino_toolkit_p_<version>/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n<p>GUIで次へを押していく。</p>\n\n<p>完了したらこれが表示されるので、したがって進める。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<h3 id=\"install-external-software-dependencies\">Install External Software Dependencies</h3>\n<p>依存パッケージのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh \n</code></pre></div></div>\n\n<h3 id=\"set-the-environment-variables\">Set the Environment Variables</h3>\n<p>環境変数の設定<br />\n~/.bashrc に以下の一文を追加。これでこの後開くコンソールでは環境変数が設定される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>source /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<p>現在のターミナルでも使えるように以下のコマンドを実行しておく。コンソール開きなおしてもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<h3 id=\"configure-the-model-optimizer\">Configure the Model Optimizer</h3>\n<p>モデルオプティマイザのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh \n</code></pre></div></div>\n\n<p>上記スクリプトではsystemのpython3にpipモジュールがインストールされてしまうので、<br />\npyenv環境にも必要なpipモジュールをインストールしておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell openVINO                       <span class=\"c\"># python環境を固定したいので</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\npyenv shell <span class=\"nt\">--unset</span>                        <span class=\"c\"># python環境を戻しておく</span>\n</code></pre></div></div>\n\n<h3 id=\"run-the-verification-scripts-to-verify-installation\">Run the Verification Scripts to Verify Installation</h3>\n<p>デモ実行<br />\n「Verify Installation」って書いてあるけど、実行必須。</p>\n\n<ul>\n  <li>デモ用ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo/\n</code></pre></div>    </div>\n  </li>\n  <li>sudoでpyenvが使えないので、代わりに <code class=\"language-plaintext highlighter-rouge\">/work1</code>  で作成した <code class=\"language-plaintext highlighter-rouge\">.python-version</code>をコピーしておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /work1/.python-version <span class=\"nb\">.</span>\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境にデモ環境で必要なpipモジュールをインストールしておく 。Systemのpython使うときは↓のスクリプト実行時にインストールされる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その1\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/demo1.log\n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その2\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/dem2.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"steps-for-intel-processor-graphics-gpu\">Steps for Intel® Processor Graphics (GPU)</h3>\n<p>今回はGPUを使わないのでスキップ</p>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>NCS2の準備<br />\n色々書いてあるけど、これ一発でOK。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n中ではこんなことをやってます。<br />\nグループusersに自分を追加<br />\n(ログアウト & 再ログインするまで追加は反映されません)<br />\nudevルールの作成と再ロード</p>\n</blockquote>\n\n<p>NCS2をUSBポートにブッ挿すして認識したか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下があったら認識できてる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ID 03e7:2485\n</code></pre></div></div>\n\n<h3 id=\"steps-for-intel-vision-accelerator-design-with-intel-movidius-vpus\">Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPUs</h3>\n<p>今回はVPUを使わないのでスキップ</p>\n\n<p>デモプログラムの実行で動作確認</p>\n\n<p>で、Run a Sample Application に行く前に、ログアウト&再ログインでいいはずだけど、念のためリブート。</p>\n\n<h3 id=\"run-a-sample-application\">Run a Sample Application</h3>\n<p>リブートして開いてたページが分からなくなるといけないので、念のためURL貼っとく。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample</a></p>\n\n<ul>\n  <li>デモ実行ディレクトリに移動。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~/inference_engine_samples_build/intel64/Release\n</code></pre></div>    </div>\n  </li>\n  <li>CPUでデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> CPU\n</code></pre></div>    </div>\n  </li>\n  <li>NCS2でデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> MYRIAD\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>このページの手順はここでおしまい。</p>\n\n<h1 id=\"他のサンプルも試してみよう\">他のサンプルも試してみよう。</h1>\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n<h3 id=\"前準備\">前準備</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work1/NCS/sample <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work1/NCS/sample/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release /opt/intel/openvino_2020.3.194/deployment_tools/inference_engine/samples/cpp/\n</code></pre></div></div>\n\n<h3 id=\"ssdを試してみよう\">SSDを試してみよう</h3>\n<h4 id=\"build\">build</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">-j2</span> object_detection_sample_ssd\n</code></pre></div></div>\n<h4 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R4/20200117_150000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n</code></pre></div></div>\n\n<h4 id=\"実行\">実行</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./intel64/Release/object_detection_sample_ssd <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> /work/data/data2/z_20141013051441.jpg \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nコマンド実行時の<code class=\"language-plaintext highlighter-rouge\">-i</code>オプションは入力画像ファイル。<br />\n人の顔が写っているjpegファイルを指定しましょう。 \n顔が写ってなければ顔検出できません(^^ゞ</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[ INFO ] Execution successful</code>と表示されたら実行成功だと思う。</p>\n\n<h4 id=\"結果画像を表示してみる\">結果画像を表示してみる。</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>eog out_0.bmp \n</code></pre></div></div>\n\n<h4 id=\"おーーーー\"><strong><em>おーーーー</em></strong></h4>\n\n<h1 id=\"ここまでの作業でインストールしたpipパッケージ一覧\">ここまでの作業でインストールしたpipパッケージ一覧</h1>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.9.0\nastor==0.8.1\ncertifi==2020.4.5.2\nchardet==3.0.4\ndecorator==4.4.2\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.2.0\ngraphviz==0.8.4\ngrpcio==1.29.0\nh5py==2.10.0\nidna==2.9\nimportlib-metadata==1.6.1\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.2\nMarkdown==3.2.2\nmxnet==1.5.1\nnetworkx==2.4\nnumpy==1.18.5\nonnx==1.7.0\nopt-einsum==3.2.1\nprotobuf==3.6.1\nPyYAML==5.3.1\nrequests==2.23.0\nsix==1.15.0\ntensorboard==1.15.0\ntensorflow==1.15.3\ntensorflow-estimator==1.15.1\ntermcolor==1.1.0\ntyping-extensions==3.7.4.2\nurllib3==1.25.9\nWerkzeug==1.0.1\nwrapt==1.12.1\nzipp==3.1.0\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その5</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その5</h1>\n      <p>Tensorflow v1.15のインストールとソースからのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はUbuntuだけ。</p>\n\n<h1 id=\"tensorflow-115-のインストール\">Tensorflow 1.15 のインストール</h1>\n\n<p>Tensorflow1系でないと動かない環境とかサンプルとかあるので、<br />\nTensorflow v1.15をインストールする。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_1.15.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_1.15.0\n<span class=\"nb\">cd</span> /work/tf_1.15.0\npyenv <span class=\"nb\">local </span>tf_1.15.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"tensorflow-115-ライブラリのインストール\">Tensorflow 1.15 ライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>1.15\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nGPU使わないので-cpu付きパッケージを選択する</p>\n</blockquote>\n\n<h1 id=\"tensorflow-115-のbuild\">Tensorflow 1.15 のbuild</h1>\n\n<p>Tensorflowのpythonライブラリは<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできるが、\nソースからbuildしないと使えないツールもあるのでbuild環境を整える。</p>\n\n<p>参考: <a href=\"https://www.tensorflow.org/install/source?hl=ja\">ソースからのビルド | Tensorflow</a></p>\n\n<h2 id=\"bazelのインストール\">Bazelのインストール</h2>\n\n<p>Tensorflow をソースからbuildするには<code class=\"language-plaintext highlighter-rouge\">bazel</code>が必要なので、インストールしておく。</p>\n<blockquote>\n  <p>[!NOTE]\nBazelはVer.0.26.1 以下 を使用しないといけない<br />\nVer. 0.26.1はaptでインストールできない</p>\n</blockquote>\n\n<p>参考: <a href=\"https://docs.bazel.build/versions/0.26.0/install-ubuntu.html\">Installing Bazel on Ubuntu</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/bazelbuild/bazel/releases/download/0.26.1/bazel-0.26.1-installer-linux-x86_64.sh\n<span class=\"nb\">chmod</span> +x bazel-0.26.1-installer-linux-x86_64.sh\n./bazel-0.26.1-installer-linux-x86_64.sh <span class=\"nt\">--user</span>\n</code></pre></div></div>\n\n<p>実行ファイルは、<code class=\"language-plaintext highlighter-rouge\">~/bin/bazel</code> になるので、pathが~/binに通ってない場合は、一旦 ログアウトして 再ログイン\n(pathが通ってない場合、configureでエラーになる)</p>\n\n<h2 id=\"必要なpipパッケージのインストール\">必要なpipパッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>six numpy wheel mock <span class=\"s1\">'future>=0.17.1'</span>\npip <span class=\"nb\">install </span>keras_applications <span class=\"nt\">--no-deps</span>\npip <span class=\"nb\">install </span>keras_preprocessing <span class=\"nt\">--no-deps</span>\n</code></pre></div></div>\n\n<h2 id=\"tennsorflowのソースを取得\">tennsorflowのソースを取得</h2>\n\n<p>githubからcloneして V1.15.3 をチェックアウトしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/\ngit clone https://github.com/tensorflow/tensorflow.git\n<span class=\"nb\">cd </span>tensorflow\ngit checkout <span class=\"nt\">-b</span> v1.15.3 refs/tags/v1.15.3\n</code></pre></div></div>\n\n<h1 id=\"buildの設定\">buildの設定</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\n./configure\n<span class=\"c\"># いくつか質問されるので、すべてデフォルト(リターン)を入力</span>\n</code></pre></div></div>\n\n<h1 id=\"buildの実行\">buildの実行</h1>\n<h2 id=\"実行のひな形\">実行のひな形</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build //《対象ディレクトリ》:《ターゲット》\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n※ 対象ディレクトリはカレントディレクトリからの相対パス<br />\n※ ターゲットは対象ディレクトリのBUILDファイルで確認</p>\n</blockquote>\n\n<h2 id=\"例えばこんな感じ\">例えばこんな感じ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel build //tensorflow/lite/toco:toco\nbazel build //tensorflow/python/tools:freeze_graph\nbazel build //tensorflow/tools/graph_transforms:summarize_graph\nbazel build //tensorflow/tools/graph_transforms:transform_graph\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRAMは4GB以上必要かな?<br />\nオプション<code class=\"language-plaintext highlighter-rouge\">--local_ram_resources=2048</code>を指定すると使用するRAMを2GBに限定できる(指定する数値はMB単位)。<br />\n使用するPCのスペックによってかかる時間はマチマチ。<br />\nNativeなUbuntuで4コア8スレッドでも3~4時間程度かかる。<br />\nVirtualboxで1コア使用だと24時間とかかかることも。</p>\n</blockquote>\n\n<h2 id=\"buildしたファイルの実行\">buildしたファイルの実行</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">bazel run</code> で実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nオプションをbazelではなく実行するコマンドに渡すため、<code class=\"language-plaintext highlighter-rouge\">--</code> を入れる必要がある。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel run //tensorflow/lite/toco:toco <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:summarize_graph <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:transform_graph <span class=\"nt\">--</span> «オプション»\n</code></pre></div></div>\n\n<p>絶対パスで実行するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph «オプション»\n</code></pre></div></div>\n\n<p>パスが長いので、以下を設定しておくと便利。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">alias            </span><span class=\"nv\">toco</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">summarize_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">transform_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph'</span>\n</code></pre></div></div>\n\n<h2 id=\"おまけ\">おまけ</h2>\n\n<p>フツーはこっちがメインだが…(^^ゞ<br />\npipでインストールすれば必要ないが、Tensorflowのpipパッケージを作成するにはこちら。<br />\n(オプション変更したいときとか)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build <span class=\"nt\">--config</span><span class=\"o\">=</span>v1 //tensorflow/tools/pip_package:build_pip_package\n./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg\npip <span class=\"nb\">install</span> /tmp/tensorflow_pkg/tensorflow-1.15.3-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その4</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その4</h1>\n      <p>tensorflowのモデルファイル(*.pbや*.tflite)の可視化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>tensorflowのモデルファイル( <code class=\"language-plaintext highlighter-rouge\">*.pb</code> や <code class=\"language-plaintext highlighter-rouge\">*.tflite</code> )を可視化する方法について。<br />\n<code class=\"language-plaintext highlighter-rouge\">tensorboard</code> を使う方法などもあるが、最もお手軽と思われる <code class=\"language-plaintext highlighter-rouge\">netron</code> を使用する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれやらなくても、<a href=\"https://lutzroeder.github.io/netron/\">https://lutzroeder.github.io/netron/</a> にアクセスすれば使える。</p>\n</blockquote>\n\n<h1 id=\"netron-の-インストール\">netron の インストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code>をインストールする。<br />\n<code class=\"language-plaintext highlighter-rouge\">netron</code> はtensorflowのバージョンに依存しない(そもそもtensorflow自体に依存してない)のでTensorflow1系、Tenorflow2系 どちらの環境にインストールしてもよい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>netron\n</code></pre></div></div>\n\n<h1 id=\"netron-の-実行\">netron の 実行</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code> を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>netron <span class=\"nt\">--host</span> 0.0.0.0 <span class=\"o\">[</span><span class=\"nt\">--port</span> xxxx]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--host</code> オプションを指定しないとlocalhostからしか接続できないので、他のマシンから接続するときは指定する。<br />\n<code class=\"language-plaintext highlighter-rouge\">--port</code> オプションのデフォルトは8080なので、変更したいときは指定する。</p>\n\n<h1 id=\"モデルファイルの表示\">モデルファイルの表示</h1>\n\n<p>ブラウザ(Winマシンからで可)で実行したマシンのポート8008(またはオプションで指定したxxxx)に接続。<br />\n例:<code class=\"language-plaintext highlighter-rouge\">http://ncc-1701u.local:8080/</code></p>\n\n<p>表示された画面でOpen Model…をクリックして表示するモデルファイルを選ぶ。<br />\nしばらく待つと表示される。<br />\nモデルファイルはブラウザからアップロードするので、ブラウザから参照できる場所になければならない(サーバ側にあってもダメ)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">*.pb</code> ファイルが大きいとうまく表示できないみたい。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その3</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その3</h1>\n      <p>Tensorflow 2.2.0をインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Edge-TPUを直接操作するわけではないが、Tensorflowで作成されたモデルファイルをtflite用に変換する準備として<br />\ntensorflowをインストールする。<br />\nここではVersion 2.2.0を使用する。</p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<p>coral環境に追加インストールでも良いが、今回は別の環境を用意する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_2.2.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_2.2.0\n<span class=\"nb\">cd</span> /work/tf_2.2.0\npyenv <span class=\"nb\">local </span>tf_2.2.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"tensorflow-220-のインストール\">tensorflow 2.2.0 のインストール</h1>\n\n<p>インストールするパッケージはGPUを使わないので-cpu付きパッケージを選択する。<br />\nTensorflowはバージョンによって機能差が激しいので、インストールするバージョンを指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>2.2.0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その2</h1>\n      <p>Google Coral USB Accelerator で SSD(Single Shot MultiBox Detector)を実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n一部を除き、基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<h1 id=\"tflite-の-モデルファイルをedgetpu使用モデルに変換する方法\">tflite の モデルファイルをEdgeTPU使用モデルに変換する方法</h1>\n<p>通常のtfliteのモデルファイルはCPUのみ(またはCPU+GPU)を使用するように構成されていて、\nそのまま実行してもEdge-TPUは使用されない。<br />\nそこで、Edge-TPU使用モデルに変換するため、edgetpu_compilerを使用する必要がある。<br />\n(ただし、Ubuntuのみ。RasPi不可。)</p>\n\n<h2 id=\"edgetpu_compiler-のインストール\">edgetpu_compiler のインストール</h2>\n\n<p>CPU使用モデルからEdge-TPU使用モデルに変換するツール<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code>をインストールする。<br />\naptリポジトリの登録はTPUライブラリインストール時に行っているので不要(以下ではコメントアウトしてある)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -</span>\n<span class=\"c\"># echo \"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list</span>\n<span class=\"c\"># sudo apt update</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>edgetpu-compiler\n</code></pre></div></div>\n\n<h2 id=\"使用方法\">使用方法</h2>\n<p>基本的に以下。<br />\ntfliteファイルを喰わせるとファイル名に<code class=\"language-plaintext highlighter-rouge\">_edgetpu</code>を付加したファイルが作成される。<br />\nこれがEdge-TPU使用するモデルファイル。<br />\n詳細は<a href=\"https://coral.ai/docs/edgetpu/compiler/\">Edge TPU Compiler</a> を参照。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>edgetpu_compiler [options] model...\n</code></pre></div></div>\n\n<h1 id=\"事前準備\">事前準備</h1>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n\n<p>openCVをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"ssdを実行してみる\">SSDを実行してみる</h1>\n\n<h2 id=\"作業用ディレクトリの作成移動\">作業用ディレクトリの作成&移動</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral/ssd/\n<span class=\"nb\">cd</span> /work/coral/ssd/\n</code></pre></div></div>\n\n<h2 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h2>\n\n<p>用意されているSSDのモデルをダウンロードし、Edge-TPU使用モデルを作成する。<br />\n実行が終了すると、<code class=\"language-plaintext highlighter-rouge\">models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite</code> ができる。</p>\n\n<ul>\n  <li>ダウンロード元: <a href=\"https://www.tensorflow.org/lite/models/object_detection/overview\">Object detection</a>\nの 「Get Started」の「Download starter model and labels」</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl <span class=\"nt\">-O</span> https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip\nunzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip \n<span class=\"nb\">mv </span>detect.tflite coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># リネームしなくてもいいけど、後でわからなくならないようにリネームしておく</span>\n<span class=\"nb\">mv </span>labelmap.txt coco_ssd_mobilenet_v1_1.0_quant.labels   <span class=\"c\"># 同上</span>\nedgetpu_compiler coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># EdgeTPU使用モデルに変換</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"テスト用画像の準備\">テスト用画像の準備</h2>\n\n<p>適当な画像を<code class=\"language-plaintext highlighter-rouge\">image</code>ディレクトリに用意しておく。<br />\n使用できるファイル形式は<code class=\"language-plaintext highlighter-rouge\">jpg</code>と<code class=\"language-plaintext highlighter-rouge\">mp4</code></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>images\n<span class=\"nb\">cd </span>images/\n<span class=\"c\"># 適当な画像ファイルをダウンロードする</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"ssdのプログラムソース\">SSDのプログラムソース</h2>\n\n<p>以下の内容を<code class=\"language-plaintext highlighter-rouge\">object_detection_demo_ssd.py</code>として保存しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">tflite_runtime.interpreter</span> <span class=\"k\">as</span> <span class=\"n\">tflite</span>\n\n<span class=\"c1\"># shared library\n</span><span class=\"n\">EDGETPU_SHARED_LIB</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n  <span class=\"s\">'Linux'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.so.1'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Darwin'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.1.dylib'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Windows'</span><span class=\"p\">:</span> <span class=\"s\">'edgetpu.dll'</span>\n<span class=\"p\">}[</span><span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">system</span><span class=\"p\">()]</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># interpreter の生成\n</span><span class=\"k\">def</span> <span class=\"nf\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">):</span>\n    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"o\">=</span><span class=\"n\">model_file</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span>\n                <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">model_file</span><span class=\"p\">,</span>\n                <span class=\"n\">experimental_delegates</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n                    <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">load_delegate</span><span class=\"p\">(</span><span class=\"n\">EDGETPU_SHARED_LIB</span><span class=\"p\">)</span>\n                <span class=\"p\">])</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    \n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">output_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_output_details</span><span class=\"p\">()</span>\n    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n\n    <span class=\"n\">tflite_results1</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Locations (Top, Left, Bottom, Right)\n</span>    <span class=\"n\">tflite_results2</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Classes (0=Person)\n</span>    <span class=\"n\">tflite_results3</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Scores\n</span>    <span class=\"n\">tflite_results4</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Number of detections\n</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">tflite_results4</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])):</span>\n        <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        \n        <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>        <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n\n        <span class=\"n\">prob</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results3</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">prob</span> <span class=\"o\">>=</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'Class=</span><span class=\"si\">{</span><span class=\"n\">class_name</span><span class=\"si\">:</span><span class=\"mi\">15</span><span class=\"si\">}</span><span class=\"s\">    Probability=</span><span class=\"si\">{</span><span class=\"n\">prob</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    Location=(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)-(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n            <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span>    <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span>   <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span>  <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 表示色\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 対象物の枠とラベルの描画\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"n\">bottom</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">20</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"o\">+</span><span class=\"mi\">160</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"s\">\"{} ({:.3f})\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">class_name</span><span class=\"p\">,</span> <span class=\"n\">prob</span><span class=\"p\">),</span>\n                        <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># interpreterの構築\n</span>    <span class=\"n\">interpreter</span> <span class=\"o\">=</span> <span class=\"n\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">allocate_tensors</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">input_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()</span>\n    \n    <span class=\"c1\"># 入力データ\n</span>    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">org_frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>                 <span class=\"c1\"># オリジナルのフレームレート\n</span>    <span class=\"n\">org_frame_time</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span> <span class=\"o\">/</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>                <span class=\"c1\"># オリジナルのフレーム時間\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">org_frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルの読み込み\n</span>        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルがない場合\n</span>        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># フレーム数\n</span>    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 実行時間測定用変数の初期化\n</span>    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n    <span class=\"c1\"># フレーム測定用タイマ\n</span>    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># モデルの入力サイズ\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># 画像の前処理 =============================================================================\n</span>        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                          <span class=\"c1\"># 前処理開始時刻\n</span>        \n        <span class=\"c1\"># 画像の読み込み\n</span>        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレームを作成\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># モデル入力用にリサイズ\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>   <span class=\"c1\"># input size of coco ssd mobilenet?\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">]]</span>                          <span class=\"c1\"># BGR -> RGB\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">in_frame</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>                 <span class=\"c1\"># 3D -> 4D\n</span>        \n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>     <span class=\"c1\"># 前処理にかかった時間\n</span>        \n        <span class=\"c1\"># 推論実行 =============================================================================\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"c1\"># 推論本体\n</span>        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">set_tensor</span><span class=\"p\">(</span><span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">],</span> <span class=\"n\">in_frame</span><span class=\"p\">)</span>\n        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">invoke</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>                          <span class=\"c1\"># 推論処理にかかった時間\n</span>        \n        <span class=\"c1\"># 検出結果の解析 =============================================================================\n</span>        <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                               <span class=\"c1\"># 解析処理開始時刻\n</span>        <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n        <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>                    <span class=\"c1\"># 解析処理にかかった時間\n</span>        \n        <span class=\"c1\"># 結果の表示 =============================================================================\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 表示処理開始時刻\n</span>        \n        <span class=\"c1\"># 測定データの表示\n</span>        <span class=\"n\">frame_number_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'frame_number   : </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span>\n        <span class=\"k\">if</span> <span class=\"n\">frame_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span>  <span class=\"s\">'Frame time     : ---'</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Frame time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms    </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> fps'</span>\n        <span class=\"n\">inf_time_message</span>        <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Inference time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">render_time_message</span>     <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Rendering time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">parsing_time_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'parse time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        \n        <span class=\"c1\"># 結果の書き込み\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_number_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>     <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>   <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像の保存\n</span>        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>                 <span class=\"c1\"># 表示処理にかかった時間\n</span>        \n        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"c1\"># フレーム処理終了 =============================================================================\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_key_code</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"make_interpretermodel_file\">make_interpreter(model_file)</h3>\n\n<p>interpreter(認識エンジン)を構築する処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>モデルファイル内に<code class=\"language-plaintext highlighter-rouge\">\"edgetpu-custom-op\"</code>という文字列が含まれていたらTPU使用モデルと判定してTPU使用のための共有ライブラリをダウンロードして初期化する。<br />\nそうでなければCPUのみ使用モデルなので、 共有ライブラリなしで初期化する。</p>\n\n<p>もっと単純にモデルファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>が含まれていたらTPU使用モデルと判定しても良いかもしれない(<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code> は出力ファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>を付加するので)。</p>\n\n<h3 id=\"parse_resultinterpreter-frame-labels_map-args\">parse_result(interpreter, frame, labels_map, args)</h3>\n\n<p>認識結果の解析と結果の表示(検出枠とラベルの描画)</p>\n\n<p>認識結果から検出した座標、クラスID、スコアを取得し、出力画像に描画している。</p>\n\n<p>出力データの構成は<a href=\"https://www.tensorflow.org/lite/models/object_detection/overview#output\">ここ</a>を参照。</p>\n\n<p>どうやらこのモデルは検出個数が10個に設定されているようだ。</p>\n\n<h3 id=\"main\">main()</h3>\n\n<p>メインルーチン</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>タイミング調整部分は、認識処理が速かった場合に結果表示画像の表示時間を実際の入力画像の表示時間に合わせるため、ちょっと小細工を入れてある。</p>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--help</span>\nusage: object_detection_demo_ssd.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT <span class=\"o\">[</span><span class=\"nt\">-l</span> LABELS]\n                                    <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> LABELS, <span class=\"nt\">--labels</span> LABELS\n                        Optional. Labels mapping file\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合edge-tpu使用\">静止画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合edge-tpu使用\">動画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n再生が終了するか、画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n<h2 id=\"静止画の場合cpuのみ\">静止画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合cpuのみ\">動画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その1</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その1</h1>\n      <p>Google Coral USB Acceleratorのインストールメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<p>参考サイト:\n<a href=\"https://qiita.com/rhene/items/7b34f60b73645d430789\">RaspberryPi 4でCoral USB TPU Accelerator(EdgeTPU)をとりあえず使う</a></p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<h2 id=\"edgetpu用ライブラリのインストール\">EdgeTPU用ライブラリのインストール</h2>\n\n<p>下記コマンドを実行して、EdgeTPU用ライブラリ(ドライバ類)をインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/coral-edgetpu.list\ncurl https://packages.cloud.google.com/apt/doc/apt-key.gpg | <span class=\"nb\">sudo </span>apt-key add -\n\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># 通常版をインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libedgetpu1-std\n<span class=\"c\"># または、最大クロック版</span>\n<span class=\"c\"># sudo apt install libedgetpu1-max</span>\n</code></pre></div></div>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 coral\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral\n<span class=\"nb\">cd</span> /work/coral\npyenv <span class=\"nb\">local </span>coral \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<p>numpyのinstallで失敗するので、以下を実行しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n</code></pre></div></div>\n\n<h2 id=\"tfliteモジュールのインストール\">TFLiteモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install  </span>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nどれをインストールするかは<a href=\"https://www.tensorflow.org/lite/guide/python\">Python quickstart</a>で確認<br />\n========= 例えば、ubuntu/raspbianのときはpythonのバージョンに応じて以下のどれかを指定 ==============</p>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (x86-64)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl</td>\n      </tr>\n    </tbody>\n  </table>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (ARM 32)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl</td>\n      </tr>\n    </tbody>\n  </table>\n</blockquote>\n\n<h2 id=\"coral-usb-acceleratorの接続と確認\">Coral USB Acceleratorの接続と確認</h2>\n\n<p>USBポートに Coral USB Accelerator を接続する</p>\n\n<p>認識されたことを確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下の表示があったら正常に認識されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>«省略»\nBus XXX Device YYY: ID 1a6e:089a Global Unichip Corp. \n«省略»\n</code></pre></div></div>\n\n<h1 id=\"動作確認サンプルプログラム\">動作確認(サンプルプログラム)</h1>\n\n<h2 id=\"サンプルソースのインストール\">サンプルソースのインストール</h2>\n\n<p>Githubからソースをダウンロードする</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/\ngit<span class=\"k\">**</span> clone https://github.com/google-coral/tflite.git\n</code></pre></div></div>\n\n<h2 id=\"サンプルプログラムの実行その1-classification\">サンプルプログラムの実行(その1) classification</h2>\n\n<h3 id=\"プログラムディレクトリへの移動\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/classification/\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh \n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py \n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n<p>結果の例は以下。<br />\n結果は「Ara macao(コンゴウインコ)」と表示されている。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference on Edge TPU is slow because it includes loading the model into Edge TPU memory.\n12.4ms\n4.2ms\n4.1ms\n4.2ms\n4.2ms\n-------RESULTS--------\nAra macao (Scarlet Macaw): 0.77734\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n\n<p><a id=\"CPUonlydiff\"> </a></p>\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合もCoral USB Acceleratorを接続しておかないとエラーになる。<br />\n接続しなくても実行できるようにするには以下のパッチを適用し、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">-cpu</code>オプションを指定する。</p>\n\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/python/examples/classification/classify_image.py b/python/examples/classification/\n</span><span class=\"gi\">> classify_image.py\n</span><span class=\"gh\">index 75f1d76..44fb798 100644\n</span><span class=\"gd\">--- a/python/examples/classification/classify_image.py\n</span><span class=\"gi\">+++ b/python/examples/classification/classify_image.py\n</span><span class=\"p\">@@ -12,7 +12,7 @@</span>\n<span class=\"err\">#</span> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n # See the License for the specific language governing permissions and\n # limitations under the License.\n<span class=\"gd\">-r\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span><span class=\"gi\">+\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span>\n    To run this code, you must attach an Edge TPU attached to the host and\n    install the Edge TPU runtime (`libedgetpu.so`) and `tflite_runtime`. For\n<span class=\"p\">@@ -64,9 +64,12 @@</span> def load_labels(path, encoding='utf-8'):\n       return {index: line.strip() for index, line in enumerate(lines)}\n\n\n<span class=\"gd\">-def make_interpreter(model_file):\n</span><span class=\"gi\">+def make_interpreter(model_file, cpu=False):\n</span>   model_file, *device = model_file.split('@')\n<span class=\"gd\">-  return tflite.Interpreter(\n</span><span class=\"gi\">+  if cpu :\n+    return tflite.Interpreter(model_path=model_file)\n+  else :\n+    return tflite.Interpreter(\n</span>       model_path=model_file,\n       experimental_delegates=[\n           tflite.load_delegate(EDGETPU_SHARED_LIB,\n<span class=\"p\">@@ -92,11 +95,19 @@</span> def main():\n   parser.add_argument(\n       '-c', '--count', type=int, default=5,\n       help='Number of times to run inference')\n<span class=\"gi\">+  parser.add_argument(\n+      '--cpu', action='store_true',\n+      help='use cpu only(default:use with TPU)')\n</span>   args = parser.parse_args()\n\n+  if args.cpu :\n<span class=\"gi\">+    print('**** USE CPU ONLY!! ****')\n+  else :\n+    print('**** USE WITH TPU ****')\n+\n</span>   labels = load_labels(args.labels) if args.labels else {}\n\n-  interpreter = make_interpreter(args.model)\n<span class=\"gi\">+  interpreter = make_interpreter(args.model, args.cpu)\n</span>   interpreter.allocate_tensors()\n\n   size = classify.input_size(interpreter)\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"サンプルプログラムの実行その2-detection\">サンプルプログラムの実行(その2) detection</h2>\n\n<h3 id=\"プログラムディレクトリへの移動-1\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/detection\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール-1\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh\n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行-1\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<p>結果の例は以下。<br />\n以下の表示と同時に認識結果の画像が別ウィンドウで表示される。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference is slow because it includes loading the model into Edge TPU memory.\n27.90 ms\n11.59 ms\n11.36 ms\n11.89 ms\n11.10 ms\n-------RESULTS--------\ntie\n  id:     31\n  score:  0.83984375\n  bbox:   BBox(xmin=226, ymin=417, xmax=290, ymax=539)\nperson\n  id:     0\n  score:  0.83984375\n  bbox:   BBox(xmin=2, ymin=5, xmax=507, ymax=590)\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行-1\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションを指定すると、結果画像を保存するとともに、表示を行う。<br />\n指定しなければ認識だけ行う(結果の画像表示もしない)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションによる出力ファイルの形式は指定した拡張子で決定される。jpgやbmpなど。<br />\nrawデータで出力した場合(拡張子rgb)は、以下のコマンドでjpgやbmpに変換できる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.jpg\n</code></pre></div>  </div>\n\n  <p>または</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.bmp\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合でCoral USB Acceleratorを接続していなくてエラーになる場合は<br />\n<a href=\"#CPUonlydiff\">こちら</a>を参照</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>UbuntuをNative環境にインストールする(18.04)</title>\n  </head>\n  <body>\n    <header>\n      <h1>UbuntuをNative環境にインストールする(18.04)</h1>\n      <p>Ubunt(18.04)をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntu-をnative環境virtualboxではなくにインストールする\">Ubuntu をNative環境(Virtualboxではなく)にインストールする</h1>\n\n<p><a href=\"/memoBlog/2019/06/26/install1804.html\">Ubuntu 18.04のインストール</a>ではVirtualbox環境にUbuntuをインストールする手順を書いたが、ここではNative環境にインストールする手順を説明する。</p>\n\n<p>ハードウェア構成としては、Ubuntuを外付けHDDにインストールし、内蔵ディスクのWindowsは消さずにデュアルブート環境にする。<br />\n手順はPCはNECのLavie all-in-oneタイプ(ちょっと古い奴)で確認している。<br />\nBIOS関連など、PC固有の機能に左右される部分は機種によって異なるので注意。</p>\n\n<h2 id=\"前準備\">前準備</h2>\n\n<h3 id=\"hddをgpt化\">HDDをGPT化</h3>\n<p>インストールするHDDのパーティションがMBRだとEFIブートができないので、<br />\n対象ハードディスクのパーテイションテーブルをGPTに変更<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://pc-karuma.net/windows-10-convert-mbr-gpt-disk/\">Windows10 - MBRディスク ⇔ GPTディスクに変換(変更)</a></li>\n</ul>\n\n<h3 id=\"インストールメディアでインストーラ起動\">インストールメディアでインストーラ起動</h3>\n<p>インストールメディアはブータブルUSBメモリを作成すると便利<br />\nブータブルUSBメモリの作成は以下を参照</p>\n<ul>\n  <li><a href=\"https://forest.watch.impress.co.jp/library/software/rufus/?fbclid=IwAR0Ry5oRt3jOegmkkswUQmudtvuleLCkH44-Tx8brnS0VYQJLQLBmGtT5Lw\">窓の杜 Rufus</a></li>\n  <li><a href=\"https://pc-freedom.net/software/how-to-use-rufus/?fbclid=IwAR1bXsLVQviiwpcQSZapci1vgJKF4rFv1nmIh7knZkrdQDJkGh7BLTrcXi4\">RufusでLinuxのインストールメディアを作る</a></li>\n  <li><a href=\"https://rufus.ie/\">本家</a></li>\n</ul>\n\n<p>ダウンロードしたファイルはインストーラではなく、ポータブル版の実行ファイル。<br />\n大体直感的に使えるけど、<strong><em>UEFI モードで起動できるようにするにはパーティション構成でGPTを選択しないといけない</em></strong>らしい。<br />\nGPT にしておけば、UEFI モードでブートするPCのbootデバイスの優先順位をUSBをHDDより高くしておけば対象のHDDからブートできる。</p>\n\n<p>これで逐一CD-Rを焼かなくて済む。<br />\nまた、起動もCD-Rより高速。</p>\n\n<h2 id=\"対象ハードディスクにインストール\">対象ハードディスクにインストール</h2>\n<p>以下を参照。</p>\n<ul>\n  <li><a href=\"https://linuxfan.info/ubuntu-18-04-install-guide\">Ubuntu 18.04 LTSインストールガイド【スクリーンショットつき解説】</a></li>\n</ul>\n\n<h2 id=\"再起動してbiosセットアップメニューを起動\">再起動してBIOSセットアップメニューを起動</h2>\n<p>NEC LAVIEの場合、電源ON時にF2キーを連打し、BIOSセットアップメニューを表示<br />\n「Boot」の「Boot Priority Order」の起動順序で「Ubuntu」を「Windows」の上に持ってくる。<br />\nその後、 saveしてreset。</p>\n\n<h2 id=\"基本的な初期設定\">基本的な初期設定</h2>\n<p>Virtualbox版の手順の<a href=\"/memoBlog/2019/06/26/install1804.html\">Ubuntu 18.04のインストール</a>を参照。<br />\n基本的にこれと同じで大丈夫(GuestAdditionのインストール、grub-pcのインストール先情報の変更を除く)</p>\n\n<h3 id=\"もっと簡単に設定する方法があった\">もっと簡単に設定する方法があった</h3>\n<p>以下の項目はもっと簡単に設定する方法があったのでメモ。</p>\n\n<ul>\n  <li>「ウィンドウが勝手に最大化するのをやめる」</li>\n  <li>「ウィンドウにマウスを乗せるとフォーカスされるようにする」</li>\n  <li>「デスクトップからゴミ箱とホームを消す」</li>\n</ul>\n\n<p>これらの設定はdconf-editorでなく、gnome-tweaksを使うと簡単(dconf-editorでもOK)</p>\n\n<p>gnome-tweaksのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\ngnome-tweaks\n</code></pre></div></div>\n<ul>\n  <li>「ウィンドウにマウスを乗せるとフォーカスされるようにする」\n    <ul>\n      <li>「ウィンドウ」で「ウィンドウフォーカス」を「Sloppy」にする</li>\n    </ul>\n  </li>\n  <li>「デスクトップからゴミ箱とホームを消す」\n    <ul>\n      <li>「デスクトップ」で選択</li>\n    </ul>\n  </li>\n  <li>「CTRLとCapsLockの入れ替えを行う」(Virtualboxではホスト側で入れ替えてたので不要だった)\n    <ul>\n      <li>「キーボードとマウス」で「追加のレイアウトオプション」をクリック\n        <ul>\n          <li>Ctrl position」の「CapsLockをCtrlとして扱う」を選択する。\n            <ul>\n              <li>「CtrlとCapsLockを入れ替える」だとうまく動かないので注意。</li>\n              <li>UnityとGNOME Flashbackでは設定は別らしい。</li>\n              <li>GNOME Flashbackでは「CtrlとCapsLockを入れ替える」でもOK。</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>「ウィンドウが勝手に最大化するのをやめる」\n    <ul>\n      <li>設定項目が見当たらないので、dconf editorで設定する。\n        <ul>\n          <li>dconf editor起動して以下を変更\n            <ul>\n              <li>/org/gnome/metacity/edge-tiling false</li>\n              <li>/org/gnome/mutter/edge-tiling false</li>\n              <li>/org/gnome/shell/overrides/edge-tiling false</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"sshのインストール\">sshのインストール</h1>\n<p>WindowsPCにあるデータをubuntuPCにキーボードで打ち込むのは効率が悪いので、最も簡単なsshでリモートログインできるようにしてみる。</p>\n\n<p>以下のコマンドでsshサーバをインストールし、サーバを開始する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n<p>クライアントからTeraTermなどでsshで対象マシンのポート22に接続する</p>\n\n<h1 id=\"vncで画面共有する\">vncで画面共有する</h1>\n\n<p>sshリモートログインよりもうちょっと使いやすくしたいので、vncで画面共有するようにしてみる。</p>\n\n<p>chrome リモートデスクトップ等とは異なり、コンソールに表示している画面を共有して操作するもの。<br />\n使用したクライアント(VNC-Viewer)がヘボいからなのか、ちょっと反応鈍いけど、<br />\nコンソールで作業していた実行状況を確認したり<br />\n会社でトラブった人のリモートサポートなんかに使えるかも。</p>\n\n<p>やり方自体はとてもシンプル。<br />\n特にインストールとかも必要ない。<br />\n(クライアント側はVNC viewerなどを実行する必要があるけど、こっちもインストールは不要(単体実行))</p>\n\n<p>例によって手順の説明は他力本願(^^ゞ<br />\n参照:</p>\n<ul>\n  <li><a href=\"https://www.yokoweb.net/2019/12/09/ubuntu-18_04-desktop-vnc-remote/\">【Ubuntu 18.04 Desktop】WinやMacパソコンからVNCでリモート接続し画面共有する </a></li>\n</ul>\n\n<p>そのままトレースすればできるけど、ちょっと「ん?」と思ってしまうエラーが。<br />\n同じページの<a href=\"https://www.yokoweb.net/2019/12/09/ubuntu-18_04-desktop-vnc-remote/#toc5\">ココ</a>に解決策がかかれているけど、ちゃんと前もって書いておいてほしいもんだ(笑)。<br />\n解決策の要約は以下の通り。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false</span>\n<span class=\"c\"># 実行後再起動必要</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ndconf editor でも設定可能。<br />\nなので、dconf editorとの設定操作とバッティングしないように注意<br />\ndconf editorで設定する場合は以下<br />\n   /org/gnome/desktop/remote-access/require-encryption</p>\n</blockquote>\n\n<p>あくまで共有なのでコンソール側でGUIログインしてないとつながらない。<br />\n反応鈍いので、普段使いにはちょっとストレスかも。<br />\nchrome リモートデスクトップ使えるならそっち使ったほうがいいかな。</p>\n\n<h1 id=\"chromeリモートデスクトップのインストール\">chromeリモートデスクトップのインストール</h1>\n\n<p>chromeリモートデスクトップ による接続は画面の共有ではなく、新しいセッションによる接続となる(Xclientみたいなもん?)。<br />\nwindowsマシンに接続した場合は表示画面のミラーリングだったが。</p>\n\n<p>chromeのインストール&リモートデスクトップのインストールはWindowsとほぼ同じ。<br />\n以下参考ページ</p>\n<ul>\n  <li><a href=\"https://www.google.com/chrome/\">Google Chrome フェブブラウザ</a></li>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>パソコンでリモート アクセスを設定する</li>\n      <li>パソコンにリモート アクセスする</li>\n    </ul>\n  </li>\n</ul>\n\n<p>接続すると、開始するセッションの選択画面になるので、「Ubuntu」を選択。GNOME Flashbackだとつながらない…なんで??</p>\n\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。このダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></li>\n</ul>\n\n<p>要約すると\n<code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下を入力</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n<h2 id=\"コンソール画面を共有したい場合\">コンソール画面を共有したい場合</h2>\n\n<p>chromeリモートデスクトップでvnc同様のコンソール画面の共有をすることも可能。<br />\n設定方法は以下を参照。</p>\n<ul>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>他のユーザとパソコンを共有する</li>\n    </ul>\n  </li>\n</ul>\n\n<p>この方法だと、アクセスコードの生成(コンソール側)/アクセスコードの入力(リモート側)/アクセス許可(コンソール側)と手続きが少々煩雑(毎回必要)。<br />\n画面共有で操作するにはvncのほうが簡単かな?</p>\n\n<h1 id=\"biosセットアップメニューでのブートマネージャの表示名を変更する\">BIOSセットアップメニューでのブートマネージャの表示名を変更する</h1>\n\n<p>ubuntu をインストールした後、BIOSセットアップメニューでブート優先順位を指定しようとすると<br />\nubuntuのブートマネージャが2つ表示されて、どちらを選べばよいのか見分けがつかない。<br />\n(機種によってはpathが表示されて見分けられるものもあるらしいが、私のPCはそうなってない)</p>\n\n<p>そこで、表示名を変更して見分けがつくようにしてみる。</p>\n\n<p>以下、参考ページ</p>\n<ul>\n  <li><a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1383uefinvnm/uefinvnm.html\">bcdeditでUEFIのブート・エントリの名前を変更する</a></li>\n</ul>\n\n<p>まず、Windowsを起動し、管理者権限でコマンドプロンプト(cmd.exe)を実行する。\nPowerShellではちょっとテクニックが要る(というほど大げさではないが)みたいなので、\nコマンドプロンプトで実行するのが無難。</p>\n\n<p>現在の状態の確認</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /enum firmware\n</code></pre></div></div>\n\n<p>実行結果</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ファームウェアのブート マネージャー\n--------------------------------\nidentifier              {fwbootmgr}\ndisplayorder            {bootmgr}\n                        {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\n                        {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ntimeout                 1\n\nWindows ブート マネージャー\n--------------------------------\n《省略》\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\ubuntu\\shimx64.efi\ndescription             ubuntu\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\Ubuntu\\grubx64.efi\ndescription             ubuntu\n</code></pre></div></div>\n\n<p>表示名を変更する<br />\n指定するuuidは現状の確認で確認したuuidに置き換えること。<br />\ndescriptionが表示名なので、これを好みの名前に変更する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /set {9b7f627e-7edc-11ea-84b2-806e6f6e6963} description  \"ubuntu shimx64\"\nbcdedit /set {9b7f627f-7edc-11ea-84b2-806e6f6e6963} description  \"ubuntu grubx64\"\n</code></pre></div></div>\n\n<p>結果を確認する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /enum firmware\n</code></pre></div></div>\n\n<p>実行結果</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ファームウェアのブート マネージャー\n--------------------------------\nidentifier              {fwbootmgr}\ndisplayorder            {bootmgr}\n                        {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\n                        {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ntimeout                 1\n\nWindows ブート マネージャー\n--------------------------------\n《省略》\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\ubuntu\\shimx64.efi\ndescription             ubuntu shimx64\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\Ubuntu\\grubx64.efi\ndescription             ubuntu grubx64\n</code></pre></div></div>\n\n<p>ちなみに、shimx64.efi と grubx64.efi の違いは、セキュアブートの対応/非対応の違いである。<br />\n通常(セキュアブート有効のハズ)はshimx64.efiで良いと思われる。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://netlog.jpn.org/r271-635/2019/08/uefi_windows10_ubuntu_install.html\">UEFIのWindows 10マシンにUbuntu 18.04を追加インストールしデュアルブート化する</a>\n    <ul>\n      <li>「UbuntuがUEFIのブートメニューに登録されていることを確認」のあたり</li>\n    </ul>\n  </li>\n</ul>\n\n<p>この設定はbuntuを再インストールすると上書きされてしまうので、再度変更する必要がある。</p>\n\n<h1 id=\"grubのboot-menuの表示などの変更方法\">GRUBのboot menuの表示などの変更方法</h1>\n\n<p>デフォルトのubuntuインストール状態では、GRUBのブートメニューが表示されない。<br />\nそこで、ブートメニューを表示するように変更してみる。<br />\nついでに、設定する箇所が同じなので、</p>\n\n<ul>\n  <li>タイムアウトまでの時間の変更(あっ?と思った瞬間にブートされちゃうと悲しいので)</li>\n  <li>スプラッシュスクリーンを表示しなくする(ちゃんとブートしてるか心配なので(笑))</li>\n</ul>\n\n<p>も設定しておく。</p>\n\n<p>まず、ubuntuを起動してターミナル起動</p>\n\n<p>rootでないとできないことなので、rootでbashを実行しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>bash                                     \n</code></pre></div></div>\n\n<p>設定ファイル <code class=\"language-plaintext highlighter-rouge\">/etc/default/grub</code> を以下の内容で変更する</p>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- grub.org\t2020-05-08 06:16:59.908079737 +0900\n</span><span class=\"gi\">+++ grub\t2020-05-08 06:17:13.540255464 +0900\n</span><span class=\"p\">@@ -3,11 +3,11 @@</span>\n # For full documentation of the options in this file, see:\n #   info -f grub -n 'Simple configuration'\n \n<span class=\"gd\">-GRUB_DEFAULT=0\n-GRUB_TIMEOUT_STYLE=hidden\n-GRUB_TIMEOUT=10\n</span><span class=\"gi\">+GRUB_DEFAULT=saved\n+GRUB_TIMEOUT_STYLE=menu\n+GRUB_TIMEOUT=30\n</span> GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`\n<span class=\"gd\">-GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash\"\n</span><span class=\"gi\">+GRUB_CMDLINE_LINUX_DEFAULT=\n</span> GRUB_CMDLINE_LINUX=\"\"\n \n # Uncomment to enable BadRAM filtering, modify to suit your needs\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">GRUB_DEFAULT</code> がデフォルトの選択項目。 <code class=\"language-plaintext highlighter-rouge\">saved</code> は前回選択項目。rebootのときだけ??動きがイマイチわからんかった。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_TIMEOUT_STYLE</code> がメニュー表示形式。<code class=\"language-plaintext highlighter-rouge\">hidden</code> は表示しない、<code class=\"language-plaintext highlighter-rouge\">menu</code> はメニューを表示する。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_TIMEOUT</code> がタイムアウトまでの時間。単位は秒。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_CMDLINE_LINUX_DEFAULT</code> がLinux起動時のコマンドラインオプション。<code class=\"language-plaintext highlighter-rouge\">quiet splash</code> を指定すると起動メッセージを表示せず、スプラッシュスクリーンを表示する。これを削除することで起動メッセージが表示される</p>\n\n<p>変更した設定をcfgファイルに反映する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>grub-mkconfig <span class=\"nt\">-o</span> /boot/grub/grub.cfg            \n</code></pre></div></div>\n\n<p>これで、次回起動時からGRUBのブートメニューが変更される</p>\n\n<p>以下、参考ページ:</p>\n<ul>\n  <li><a href=\"http://www.usupi.org/sysad/202.html\">いますぐ実践! Linux システム管理</a></li>\n</ul>\n\n<p>この項目と直接関係ないけど、起動時にのfsckを実行する方法の参考ページ。</p>\n<ul>\n  <li><a href=\"https://linux.just4fun.biz/?Linux%E7%92%B0%E5%A2%83%E8%A8%AD%E5%AE%9A/%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E9%96%93%E9%9A%94%E3%81%AE%E7%A2%BA%E8%AA%8D\">Linux環境設定/起動時のファイルシステムチェック間隔の確認 </a></li>\n</ul>\n\n<h1 id=\"usb-hdd接続-ubuntuのboot未接続windowsのbootにする方法\">USB-HDD接続→ Ubuntuのboot、未接続→Windowsのbootにする方法</h1>\n\n<p>ubuntuがインストールされたUSB-UDDが接続されていたらubuntuが、接続されていなければ内蔵HDDのWindowsが自動的に起動するようにしてみる。<br />\n(デフォルトのインストール状態だとブート優先順位を変更しないと切り替えられない)<br />\nちょうどFDDブートのような感じ。</p>\n\n<p>BIOSセットアップにより、ブートモードはUEFIブートで、ブート優先順位はubuntuの方を高く設定しておく。</p>\n\n<p>まず、ubuntuを起動する</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/boot/efi/EFI/ubuntu/grub.cfg</code> を以下のように変更する。<br />\nrootでないとアクセスできないので、<code class=\"language-plaintext highlighter-rouge\">sudo bash</code>  して rootでshellを動かして作業するのが良い。</p>\n\n<ul>\n  <li>元のファイル\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>search.fs_uuid 60c491cd-126d-4f4a-a321-84bb2e0d9068 root hd1,gpt1 \nset prefix=($root)'/boot/grub'\nconfigfile $prefix/grub.cfg\n</code></pre></div>    </div>\n  </li>\n  <li>変更後のファイル\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>if search.fs_uuid 60c491cd-126d-4f4a-a321-84bb2e0d9068 root hd1,gpt1 ;then\n set prefix=($root)'/boot/grub'\n configfile $prefix/grub.cfg\nelse\n set timeout_style=menu\n set timeout=0\n menuentry 'Windows Boot Manager (on /dev/sda2)' --class windows --class os $menuentry_id_option 'osprober-efi-2A43-3D28' {\n    insmod part_gpt\n    insmod fat\n    set root='hd0,gpt2'\n    if [ x$feature_platform_search_hint = xy ]; then\n       search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  2A43-3D28\n    else\n       search --no-floppy --fs-uuid --set=root 2A43-3D28\n    fi\n    chainloader /EFI/Microsoft/Boot/bootmgfw.efi\n}\nfi\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>メモ:</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">60c491cd-126d-4f4a-a321-84bb2e0d9068</code>  は ubuntuのインストールされたパーティションのuuidなので、接続したUSB-HDDDのuuidに合わせて変更する。\n    <ul>\n      <li>パーティションのuuidは以下で確認可能。\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"s1\">' \\/boot\\/efi '</span> /etc/mtab         <span class=\"c\"># デバイスファイルを確認する</span>\n<span class=\"nb\">sudo </span>blkid /dev/sda2                   <span class=\"c\"># 確認したデバイスファイルを指定する</span>\n</code></pre></div>        </div>\n      </li>\n      <li>あるいは、元のファイルのuuidをコピるのでもOK。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">2A43-3D28</code>はEFIシステムパーティションのuuidなので、環境に合わせて変更する。\n    <ul>\n      <li>パーティションのuuidは以下で確認可能。\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"s1\">' \\/ '</span> /etc/mtab                  <span class=\"c\"># デバイスファイルを確認する</span>\n<span class=\"nb\">sudo </span>blkid /dev/sdb1                   <span class=\"c\"># 確認したデバイスファイルをしてする</span>\n</code></pre></div>        </div>\n      </li>\n      <li>あるいは、<code class=\"language-plaintext highlighter-rouge\">/boot/grub/grub.cfg</code> の <code class=\"language-plaintext highlighter-rouge\">menuentry 'Windows Boot Manager ~</code>  の部分をパクってきても可。</li>\n    </ul>\n  </li>\n  <li>このファイルはbuntuを再インストールすると上書きされてしまうので、再度編集する必要がある。</li>\n</ul>\n\n<p>処理の解説:<br />\n元のgrub.cfgではUSB-HDDが接続されていなければ <code class=\"language-plaintext highlighter-rouge\">$prefix/grub.cfg</code>  が見つからないので、GRUBメニューが表示されない。<br />\nそこで、<code class=\"language-plaintext highlighter-rouge\">search.fs_uuid</code> の実行結果により、ディスクが見つかったら従来通りの処理、<br />\n見つからなかったらWindows Boot Managerを起動するようにしている。</p>\n\n<h3 id=\"参考情報\">参考情報</h3>\n<p>WindowsからEFIシステムパーティションのファイルを編集するには、このあたりを参考に。</p>\n<ul>\n  <li><a href=\"https://bi.biopapyrus.jp/os/win/dualboot-fix-bootmenu.html\">デュアルブートから Ubuntu を削除する方法</a><br />\nマウントする部分だけね。</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD(その2)</h1>\n      <p>openVINOのSSDのサンプルプログラムのモデルデータを変更してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> でSSDを動かしてみたが、\n検出できるオブジェクトの種類が少なくてちょっと寂しかったので、別のモデルがないか探してみた。</p>\n\n<p>で、調べてみると、openCVのopen_model_zoo以外にもTensorFlowの公式モデルなどをダウンロードして変換するスクリプトが用意されていた。<br />\nで、以下手順。</p>\n\n<h1 id=\"モデルのダウンロードモデルのirへの変換\">モデルのダウンロード&モデルのIRへの変換</h1>\n\n<h4 id=\"テンポラリディレクトリの作成移動\">テンポラリディレクトリの作成&移動</h4>\n\n<p>とりあえず作業用のディレクトリを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/temp\n<span class=\"nb\">cd</span> /work/temp\n</code></pre></div></div>\n\n<h3 id=\"使用できるモデルの一覧を表示\">使用できるモデルの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py  <span class=\"nt\">--print_all</span>\n</code></pre></div></div>\n\n<p>ちなみに、モデル毎の設定は以下にあるので、雰囲気で解読してちょ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>${INTEL_OPENVINO_DIR}/deployment_tools/open_model_zoo/models/public/${modelname}/model.yml\n</code></pre></div></div>\n\n<h3 id=\"このへんのモデルを使ってみる\">このへんのモデルを使ってみる</h3>\n\n<p>なんとなく、mobilenetが小さそうなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssd_mobilenet_v2_coco\n</code></pre></div></div>\n\n<p>または</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssdlite_mobilenet_v2\n</code></pre></div></div>\n\n<p>ssdlightの方がモデルデータが小さい。その分精度は落ちるらしい。<br />\n検出できるオブジェクトの種類は同じ。<br />\n出力は90種類だが、途中欠番があるみたいなので実質80種類くらい。<br />\n変わったところでは「テディベア」なんてのもある。試してみたらちゃんと認識した(あたりまえか…)。<br />\ncocoデータセット<a href=\"http://cocodataset.org/#home\">http://cocodataset.org/#home</a>なので、有名どころですね。<br />\nあ、「80 object categories 91 stuff categories」ってちゃんと書いてある…</p>\n\n<h3 id=\"ダウンロード\">ダウンロード</h3>\n\n<p>まずはダウンロード。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/</code>にモデルがダウンロードされる。</p>\n\n<h3 id=\"モデルデータをirファイルへ変換\">モデルデータをIRファイルへ変換</h3>\n\n<p>もとのモデルデータはTensorFlowで使用するProtocolBuffer形式なので、openVINOで使用できるIR形式に変換する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/converter.py <span class=\"nt\">--precisions</span> FP16 <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/FP16/</code>にIRモデルが出来る。</p>\n\n<h3 id=\"そのままの場所で使用しても良いが他のモデルとまとめておく\">そのままの場所で使用しても良いが、他のモデルとまとめておく</h3>\n\n<p>モデルがあちこちにあると管理しずらくなるので、他のモデルと同じところに置いておく。<br />\n必要なのはxmlとbin。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>public/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>/FP16/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>.<span class=\"o\">{</span>xml,bin<span class=\"o\">}</span> /work/NCS2/openvino_models/FP16/\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">.{xml,bin}</code>のところにスペースなどを入れてしまうとうまく動かないので注意。<br />\n結構「あとで読みやすいように」と入れてしまいがち(特にスクリプト書くとき)なので注意。</p>\n\n<h3 id=\"ラベルファイルの作成\">ラベルファイルの作成</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/work/NCS2/openvino_models/FP16/${modelname}.labels</code>にラベルデータを作成しておく。<br />\nなくても可。<br />\n作り方は後述。</p>\n\n<h3 id=\"実行\">実行</h3>\n\n<p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> の「デモ実行」と同じ手順で\nモデルファイルを差し替えて(<code class=\"language-plaintext highlighter-rouge\">--model</code>オプション)実行すれば良い。</p>\n\n<h1 id=\"ラベルファイルの作成方法\">ラベルファイルの作成方法</h1>\n\n<p>ラベルデータはモデルデータには含まれていないようなので、作成する方法を検討してみた。</p>\n\n<h3 id=\"tensorflowのmodelsモジュールをダウンロード\">tensorflowのmodelsモジュールをダウンロード</h3>\n\n<p>まず、モデルデータの作成情報のあるモジュールをダウンロードしておく。<br />\ngitでなくてもzipをダウンロードして展開しておいても可(ちょっとデカいので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git models_tf\n</code></pre></div></div>\n\n<h3 id=\"作業ディレクトリに移動\">作業ディレクトリに移動</h3>\n\n<p>あとでpythonプログラムを作成するときに色々面倒がないので、作業ディレクトリはココで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models_tf/research\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">object_detection/samples/configs</code>から対応するconfigファイルを探して(なんとなく雰囲気で探せ!)表示<br />\n<code class=\"language-plaintext highlighter-rouge\">label_map_path</code>に記載されたファイルがlabel_mapファイル<br />\nこのとき、PATH_TO_BE_CONFIGURED は <code class=\"language-plaintext highlighter-rouge\">object_detection/data</code> に読み替えること</p>\n\n<p>ssd_mobilenet_v2_cocoの場合は以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/samples/configs/ssd_mobilenet_v2_coco.config\n</code></pre></div></div>\n\n<p>上記ファイルの場合、label_mapは以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/data/mscoco_label_map.pbtxt\"\n</code></pre></div></div>\n\n<p>こにファイルにIDとラベルが定義されているが、そのままラベルファイルとしては認識できない。<br />\nIDには途中抜けがあるので注意(そのままgrepで抜き出してはダメ)</p>\n\n<h2 id=\"ラベルデータ変換プログラムを作成する\">ラベルデータ変換プログラムを作成する</h2>\n\n<p>label_map.pbtxtからラベル一覧を取得するのを手作業で行うのは大変なので、プログラムを作成する。</p>\n\n<h3 id=\"protocのインストール\">protocのインストール</h3>\n\n<p>まずは必要なモジュールのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n</code></pre></div></div>\n\n<h3 id=\"protoファイルからpythonモジュールを作成する\">protoファイルからpythonモジュールを作成する</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>protoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"変換プログラムのソース\">変換プログラムのソース</h3>\n\n<p>label_mapからテーブルを作成するスクリプト(labelmap2labels.py)をカレントディレクトリに作成する。<br />\nやっつけ仕事なので、かなりテキトー(笑)、、、</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">object_detection.utils</span> <span class=\"kn\">import</span> <span class=\"n\">label_map_util</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"==== USAGE ====\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"    python </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> label_map_file\"</span><span class=\"p\">)</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># パラメータが1個でない\n</span>    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_map_file = \"object_detection/data/mscoco_complete_label_map.pbtxt\"\n</span><span class=\"n\">label_map_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># 第一パラメータのファイルが存在しない\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"error: '</span><span class=\"si\">{</span><span class=\"n\">label_map_file</span><span class=\"si\">}</span><span class=\"s\">' not exist</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_mapからカテゴリインデックスを作成\n</span><span class=\"n\">category_index</span> <span class=\"o\">=</span> <span class=\"n\">label_map_util</span><span class=\"p\">.</span><span class=\"n\">create_category_index_from_labelmap</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span>\n\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># print(i)\n</span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">category_index</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">\"name\"</span><span class=\"p\">]</span>\n    <span class=\"k\">except</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'{name}\\t# {i}')\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n    \n<span class=\"c1\"># 個数確認のためにダミーを出力\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スクリプトの実行\">スクリプトの実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.py label_map_file\n</code></pre></div></div>\n\n<p>結果は標準出力へ出力されるので、ファイルにcastして使用する</p>\n\n<p>例:</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.pyobject_detection/data/mscoco_complete_label_map.pbtxt <span class=\"o\">></span> mscoco_complete.labels\n</code></pre></div></div>\n\n<p>出来上がったlabelsファイルを必要なところへコピーして使ってちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO で顔検出(特定人物識別)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO で顔検出(特定人物識別)</h1>\n      <p>openVINOの顔検出(特定人物識別)のサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOで顔検出(特定人物識別)するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"ソースをワークディレクトリにコピー\">ソースをワークディレクトリにコピー</h1>\n\n<p>ファイルのオーナがrootなので、編集しやすいようにワークディレクトリにソースをコピーし、そこで作業する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>face_recognition_demo/\n</code></pre></div></div>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p>いくつかのモデルデータが必要になるので、ダウンロードする。<br />\nワイルドカードでファイル指定したかったので、wgetでなくcurlを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/landmarks-regression-retail-0009/FP16/landmarks-regression-retail-0009.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-reidentification-retail-0095/FP16/face-reidentification-retail-0095.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\n<span class=\"nb\">cd</span> ..\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ncurlは「カレントディレクトリにターゲットと同じファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-O</code> と 「任意のファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-o</code>オプションしかなく、\nwgetの「ターゲットと同じファイル名で保存先ディレクトリを指定して保存」の<code class=\"language-plaintext highlighter-rouge\">-P</code>に相当するオプションがないので、\nカレントディレクトリを保存先に移動してから<code class=\"language-plaintext highlighter-rouge\">-O</code> オプションでコマンドを実行する。</p>\n</blockquote>\n\n<h1 id=\"足りないモジュールのインストール\">足りないモジュールのインストール</h1>\n\n<p>使用するモジュールでこれまでのお試しで未インストールのモジュールがあるのでインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>scipy\n</code></pre></div></div>\n\n<h1 id=\"ソースの修正\">ソースの修正</h1>\n\n<p>ソースはそのままで問題ないが、ちょっと修正しておく。</p>\n\n<p>主な変更内容は以下の通り。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code> オプションの追加と関連処理</li>\n  <li>Unknownと識別できた場合で検出枠の色を変える</li>\n  <li>入力ファイルを絶対パスに変換(不具合対策)</li>\n  <li>出力ファイルのフォーマットのmp4対応を追加(オリジナルはaviのみ対応)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur face_recognition_demo.org/face_recognition_demo.py face_recognition_demo/face_recognition_demo.py\n</span><span class=\"gd\">--- face_recognition_demo.org/face_recognition_demo.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/face_recognition_demo.py\t2019-11-27 06:29:07.507574900 +0900\n</span><span class=\"p\">@@ -62,6 +62,10 @@</span>\n     gallery.add_argument('--run_detector', action='store_true',\n                          help=\"(optional) Use Face Detection model to find faces\" \\\n                          \" on the face images, otherwise use full images.\")\n<span class=\"gi\">+    gallery.add_argument('--run_detector_no_save', action='store_true',\n+                         help=\"(optional) Use Face Detection model to find faces\" \\\n+                         \" on the face images, otherwise use full images.\" \\\n+                         \" not save detected face image.\")\n</span> \n     models = parser.add_argument_group('Models')\n     models.add_argument('-m_fd', metavar=\"PATH\", default=\"\", required=True,\n<span class=\"p\">@@ -142,7 +146,7 @@</span>\n         log.info(\"Building faces database using images from '%s'\" % (args.fg))\n         self.faces_database = FacesDatabase(args.fg, self.face_identifier,\n                                             self.landmarks_detector,\n<span class=\"gd\">-                                            self.face_detector if args.run_detector else None, args.no_show)\n</span><span class=\"gi\">+                                            self.face_detector if args.run_detector or args.run_detector_no_save else None, args.no_show, args.run_detector_no_save)\n</span>         self.face_identifier.set_faces_database(self.faces_database)\n         log.info(\"Database is built, registered %s identities\" % \\\n             (len(self.faces_database)))\n<span class=\"p\">@@ -261,9 +265,8 @@</span>\n             .face_identifier.get_identity_label(identity.id)\n \n         # Draw face ROI border\n<span class=\"gd\">-        cv2.rectangle(frame,\n-                      tuple(roi.position), tuple(roi.position + roi.size),\n-                      (0, 220, 0), 2)\n</span><span class=\"gi\">+        color1 = (0, 220, 0) if identity.id == FaceIdentifier.UNKNOWN_ID else (0, 0, 220)\n+        cv2.rectangle(frame, tuple(roi.position), tuple(roi.position + roi.size), color1, 2)\n</span> \n         # Draw identity label\n         text_scale = 0.5\n<span class=\"p\">@@ -398,19 +401,17 @@</span>\n         try:\n             stream = int(path)\n         except ValueError:\n<span class=\"gd\">-            pass\n</span><span class=\"gi\">+            # 数字でなければ絶対パスに変換\n+            stream = osp.abspath(path)\n</span>         return cv2.VideoCapture(stream)\n \n     @staticmethod\n     def open_output_stream(path, fps, frame_size):\n         output_stream = None\n         if path != \"\":\n<span class=\"gd\">-            if not path.endswith('.avi'):\n-                log.warning(\"Output file extension is not 'avi'. \" \\\n-                        \"Some issues with output can occur, check logs.\")\n</span><span class=\"gi\">+            forcc = cv2.VideoWriter.fourcc(*'mp4v') if path.endswith('.mp4') else cv2.VideoWriter.fourcc(*'MJPG')\n</span>             log.info(\"Writing output to '%s'\" % (path))\n<span class=\"gd\">-            output_stream = cv2.VideoWriter(path,\n-                                            cv2.VideoWriter.fourcc(*'MJPG'), fps, frame_size)\n</span><span class=\"gi\">+            output_stream = cv2.VideoWriter(path, forcc, fps, frame_size)\n</span>         return output_stream\n \n \n<span class=\"gh\">diff -ur face_recognition_demo.org/faces_database.py face_recognition_demo/faces_database.py\n</span><span class=\"gd\">--- face_recognition_demo.org/faces_database.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/faces_database.py\t2019-11-20 06:31:13.481819754 +0900\n</span><span class=\"p\">@@ -36,10 +36,11 @@</span>\n         def cosine_dist(x, y):\n             return cosine(x, y) * 0.5\n \n<span class=\"gd\">-    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False):\n</span><span class=\"gi\">+    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False, no_db_save=False):\n</span>         path = osp.abspath(path)\n         self.fg_path = path\n         self.no_show = no_show\n<span class=\"gi\">+        self.no_db_save = no_db_save\n</span>         paths = []\n         if osp.isdir(path):\n             paths = [osp.join(path, f) for f in os.listdir(path) \\\n<span class=\"p\">@@ -96,7 +97,7 @@</span>\n                     self.add_item(descriptor, label)\n \n     def ask_to_save(self, image):\n<span class=\"gd\">-        if self.no_show:\n</span><span class=\"gi\">+        if self.no_show or self.no_db_save:\n</span>             return None\n         save = False\n         label = None\n<span class=\"p\">@@ -209,12 +210,14 @@</span>\n             match = len(self.database)-1\n         else:\n             filename = \"{}-{}.jpg\".format(label, len(self.database[match].descriptors)-1)\n<span class=\"gd\">-        filename = osp.join(self.fg_path, filename)\n-\n-        log.debug(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n-        if osp.exists(filename):\n-            log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n-        cv2.imwrite(filename, image)\n</span><span class=\"gi\">+        \n+        if name :\n+            filename = osp.join(self.fg_path, filename)\n+            log.info(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n+            if osp.exists(filename):\n+                log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n+            else :\n+                cv2.imwrite(filename, image)\n</span>         return match\n \n     def add_item(self, desc, label):\n</code></pre></div></div>\n\n<h1 id=\"前準備\">前準備</h1>\n\n<p>識別したい顔の画像を適当なディレクトリに保存しておく。ファイル形式はjpgまたはpng。<br />\n一人ずつ1画像で顔部分のみ切り出しておく。<br />\n複数の人の顔を識別したい場合はそれぞれ別々に保存しておく。</p>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"実行用スクリプトの作成\">実行用スクリプトの作成</h2>\n\n<p>実行コマンドが長ったらしくて入力が面倒なので、以下のスクリプト(demo.sh)を作成しておく。<br />\nUbuntuとRaspberrypiを識別して自動でコマンドオプションを変更するようにしてある。 \n作成したら実行属性を付与しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/bin/bash</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"face_recognition_demo.py\"</span>\n\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"       -m_fd models/face-detection-retail-0004.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_lm models/landmarks-regression-retail-0009.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_reid models/face-reidentification-retail-0095.xml\"</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"o\">==</span> <span class=\"s2\">\"armv7l\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Raspberry Pi\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_fd MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_lm MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_reid MYRIAD\"</span>\n<span class=\"k\">else\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Ubuntu\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> --cpu_lib /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so\"</span>\n<span class=\"k\">fi\n\n\nif</span> <span class=\"o\">[</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 0 <span class=\"nt\">-o</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 1 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n\t<span class=\"c\"># パラメータなし/1個はエラー</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\n</span><span class=\"s2\">==== usage ====\"</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"nv\">$0</span><span class=\"s2\"> database_dir input_file [other option(s)]</span><span class=\"se\">\\n\\n\\n</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">exit </span>1\n<span class=\"k\">else\n    </span><span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -fg </span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\"> --input </span><span class=\"k\">${</span><span class=\"nv\">2</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    <span class=\"c\"># 3番目以降すべてのパラメータを追加</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"p\">@</span>:3:<span class=\"p\">(</span><span class=\"nv\">$#-2</span><span class=\"p\">)</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi\n</span><span class=\"nb\">echo</span> <span class=\"s2\">\"python </span><span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\npython <span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n\n<p>第1パラメータに識別子する顔画像を保存したディレクトリ、第2パラメータに入力ビデオファイル名を指定する。<br />\nこれらのパラメータは省略不可。<br />\n追加でオプションを指定したい場合は第3パラメータ以降に指定する。<br />\nたとえば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo.sh data data/video.mp4  <span class=\"nt\">--output</span> result.mp4\n</code></pre></div></div>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python face_recognition_demo.py <span class=\"nt\">-h</span>\nusage: face_recognition_demo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-i</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-o</span> PATH] <span class=\"o\">[</span><span class=\"nt\">--no_show</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-tl</span><span class=\"o\">]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-cw</span> CROP_WIDTH] <span class=\"o\">[</span><span class=\"nt\">-ch</span> CROP_HEIGHT] <span class=\"nt\">-fg</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">--run_detector</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--run_detector_no_save</span><span class=\"o\">]</span>\n                                <span class=\"nt\">-m_fd</span> PATH <span class=\"nt\">-m_lm</span> PATH <span class=\"nt\">-m_reid</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-l</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-c</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]]\n                                <span class=\"o\">[</span><span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]] <span class=\"o\">[</span><span class=\"nt\">-exp_r_fd</span> NUMBER]\n                                <span class=\"o\">[</span><span class=\"nt\">--allow_grow</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit\n\n</span>General:\n  <span class=\"nt\">-i</span> PATH, <span class=\"nt\">--input</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to the input video <span class=\"o\">(</span><span class=\"s1\">'0'</span> <span class=\"k\">for </span>the\n                        camera, default<span class=\"o\">)</span>\n  <span class=\"nt\">-o</span> PATH, <span class=\"nt\">--output</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to save the output video to\n  <span class=\"nt\">--no_show</span>             <span class=\"o\">(</span>optional<span class=\"o\">)</span> Do not display output\n  <span class=\"nt\">-tl</span>, <span class=\"nt\">--timelapse</span>      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Auto-pause after each frame\n  <span class=\"nt\">-cw</span> CROP_WIDTH, <span class=\"nt\">--crop_width</span> CROP_WIDTH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this width\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n  <span class=\"nt\">-ch</span> CROP_HEIGHT, <span class=\"nt\">--crop_height</span> CROP_HEIGHT\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this height\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n\nFaces database:\n  <span class=\"nt\">-fg</span> PATH              Path to the face images directory\n  <span class=\"nt\">--run_detector</span>        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images.\n  <span class=\"nt\">--run_detector_no_save</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images. not save\n                        detected face image.\n\nModels:\n  <span class=\"nt\">-m_fd</span> PATH            Path to the Face Detection model XML file\n  <span class=\"nt\">-m_lm</span> PATH            Path to the Facial Landmarks Regression model XML file\n  <span class=\"nt\">-m_reid</span> PATH          Path to the Face Reidentification model XML file\n\nInference options:\n  <span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Detection model\n                        <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Facial Landmarks\n                        Regression model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Reidentification\n                        model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> PATH, <span class=\"nt\">--cpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For MKLDNN <span class=\"o\">(</span>CPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to a shared library with custom layers\n                        implementations\n  <span class=\"nt\">-c</span> PATH, <span class=\"nt\">--gpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For clDNN <span class=\"o\">(</span>GPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to the XML file with descriptions of the\n                        kernels\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> Be more verbose\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_stats</span>     <span class=\"o\">(</span>optional<span class=\"o\">)</span> Output detailed per-layer performance stats\n  <span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Probability threshold <span class=\"k\">for </span>face\n                        detections<span class=\"o\">(</span>default: 0.6<span class=\"o\">)</span>\n  <span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Cosine distance threshold between two\n                        vectors <span class=\"k\">for </span>face identification <span class=\"o\">(</span>default: 0.3<span class=\"o\">)</span>\n  <span class=\"nt\">-exp_r_fd</span> NUMBER      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Scaling ratio <span class=\"k\">for </span>bboxes passed to face\n                        recognition <span class=\"o\">(</span>default: 1.15<span class=\"o\">)</span>\n  <span class=\"nt\">--allow_grow</span>          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Allow to grow faces gallery and to dump on\n                        disk. Available only <span class=\"k\">if</span> <span class=\"nt\">--no_show</span> option is off.\n</code></pre></div></div>\n\n<p>主なオプションの意味は以下の通り。</p>\n\n<h3 id=\"-m_fd\"><code class=\"language-plaintext highlighter-rouge\">-m_fd</code></h3>\n\n<p>必須。<br />\n顔位置検出モデルファイル</p>\n\n<h3 id=\"ーm_lm\"><code class=\"language-plaintext highlighter-rouge\">ーm_lm</code></h3>\n\n<p>必須。<br />\n顔特徴点検出モデルファイル</p>\n\n<h3 id=\"-m_reid\"><code class=\"language-plaintext highlighter-rouge\">-m_reid</code></h3>\n\n<p>必須。<br />\n顔識別モデルファイル</p>\n\n<h3 id=\"-d_fd\"><code class=\"language-plaintext highlighter-rouge\">-d_fd</code></h3>\n\n<p>顔位置検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_lm\"><code class=\"language-plaintext highlighter-rouge\">-d_lm</code></h3>\n\n<p>顔特徴点検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_reid\"><code class=\"language-plaintext highlighter-rouge\">-d_reid</code></h3>\n\n<p>顔識別に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"--cpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--cpu_lib</code></h3>\n\n<p>CPU用カスタムレイヤライブラリ(?)ファイル</p>\n\n<h3 id=\"--gpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--gpu_lib</code></h3>\n\n<p>GPU用カスタムレイヤライブラリ(?)ファイル(使ったことないからワカラン)</p>\n\n<h3 id=\"-fg\"><code class=\"language-plaintext highlighter-rouge\">-fg</code></h3>\n\n<p>必須。<br />\n識別する顔画像を格納したディレクトリ<br />\nこのディレクトリ内のjpg、pngファイルのみ抽出してくれるので、他のファイルが混在しても大丈夫。</p>\n\n<h3 id=\"--input\"><code class=\"language-plaintext highlighter-rouge\">--input</code></h3>\n\n<p>必須。<br />\n入力ファイル(動画ファイル)を指定する。 <br />\n静止画でもエラーにならないが、一瞬で消えるので、オプション –timelapse でキー入力待ちにするか、\nオプション –outputでファイル出力すると確認できる。<br />\n省略時はカメラが指定される。</p>\n\n<h3 id=\"--output\"><code class=\"language-plaintext highlighter-rouge\">--output</code></h3>\n\n<p>認識結果をファイルに出力する。<br />\n指定しなければファイルは作成されない(表示のみ)。 \n拡張子がmp4のときはMP4(追加した処理)。<br />\nそれ以外はMJPEGで保存(aviにするのが望ましい。それ以外だとffmpegがなんか言うがファイルはできてるっぽい)。</p>\n\n<h3 id=\"--no_show\"><code class=\"language-plaintext highlighter-rouge\">--no_show</code></h3>\n\n<p>画像表示しない。<br />\n通常は–outputと組み合わせて使う。</p>\n\n<h3 id=\"--timelapse\"><code class=\"language-plaintext highlighter-rouge\">--timelapse</code></h3>\n\n<p>1フレーム表示するごとにキー入力待ちになる。</p>\n\n<h3 id=\"--crop_width--crop_height\"><code class=\"language-plaintext highlighter-rouge\">--crop_width</code>、<code class=\"language-plaintext highlighter-rouge\">--crop_height</code></h3>\n\n<p>入力画像を指定したサイズに切り取る。切り取る場所は元画像の中心。<br />\n両方指定しないと無効。</p>\n\n<h3 id=\"--run_detector\"><code class=\"language-plaintext highlighter-rouge\">--run_detector</code></h3>\n\n<p>オプションを指定するとデータベース作成時に顔検出して新たに顔画像を作成してくれる。<br />\nデータベースファイルが全身画像だったり、複数人数が一緒に写っていてもOK。<br />\n1回指定すれば画像が残っているので以降は指定しなくても良い。</p>\n\n<h3 id=\"--run_detector_no_save\"><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code></h3>\n\n<p>追加したオプション<br />\n指定するとデータベース作成時に顔検出するが、顔画像の保存はしない。</p>\n\n<h3 id=\"--verbose\"><code class=\"language-plaintext highlighter-rouge\">--verbose</code></h3>\n\n<p>指定するとloglevelがDEBUGになる</p>\n\n<h3 id=\"--perf_stats\"><code class=\"language-plaintext highlighter-rouge\">--perf_stats</code></h3>\n\n<p>指定するとフレーム毎にパフォーマンスステータスを表示する</p>\n\n<h3 id=\"-t_fd\"><code class=\"language-plaintext highlighter-rouge\">-t_fd</code></h3>\n\n<p>顔位置検出に使用する閾値。省略時は0.6。</p>\n\n<h3 id=\"-t_reid\"><code class=\"language-plaintext highlighter-rouge\">-t_reid</code></h3>\n\n<p>顔識別に使用する閾値。省略時は0.3。</p>\n\n<h3 id=\"-exp_r_fd\"><code class=\"language-plaintext highlighter-rouge\">-exp_r_fd</code></h3>\n\n<p>顔位置検出した枠のサイズを何倍にするか。ギリギリだとうまく行かないから?省略時は1.15</p>\n\n<h3 id=\"--allow_grow\"><code class=\"language-plaintext highlighter-rouge\">--allow_grow</code></h3>\n\n<p>認識画像で知らない顔が出てきたらその都度登録するか確認する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbianのディスクイメージのアーカイブ</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbianのディスクイメージのアーカイブ</h1>\n      <p>Raspbianのディスクイメージのアーカイブのありかをすぐ忘れてしまうのでメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"メモ\">メモ</h1>\n\n<p>Raspbianのディスクイメージのアーカイブは以下にある。<br />\n各バージョン(日付)別にディレクトリ分けされている。<br />\nミラーサイトが爆速なのでおススメ。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>項目</th>\n      <th>URL</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>最新版</td>\n      <td><a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(本家)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_armhf/images/\">https://downloads.raspberrypi.org/raspios_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Full版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_full_armhf/images/\">https://downloads.raspberrypi.org/raspios_full_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_lite_armhf/images/\">https://downloads.raspberrypi.org/raspios_lite_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(ミラーサイト)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Full版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(2020/02以前版)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspbian/images/\">https://downloads.raspberrypi.org/raspbian/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspbian_lite/images/\">https://downloads.raspberrypi.org/raspbian_lite/images/</a></td>\n    </tr>\n  </tbody>\n</table>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WindowsでX-serve</title>\n  </head>\n  <body>\n    <header>\n      <h1>WindowsでX-serve</h1>\n      <p>WindowsでX-serveを使用するためにVcXsrvを使う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>SSH ログインしたLinuxマシンからX-Windowプログラムを実行したときに、ウィンドウをWindoesマシンに表示する方法。<br />\nUbuntu、RaspberryPiともにOK。</p>\n\n<h1 id=\"vcxsrvのインストール\">VcXsrvのインストール</h1>\n\n<p>このあたりを参考に(といっても、ダウンロードしてインストーラ実行するだけだけど)。<br />\n<a href=\"https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html\">https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html</a></p>\n\n<h1 id=\"設定のメモ\">設定のメモ</h1>\n\n<h2 id=\"リモートマシンからの要求を受け付ける\">リモートマシンからの要求を受け付ける</h2>\n\n<p>リモートマシンからの要求を受け付けるには、起動時に3ページ目で”Disable access control” にチェックを入れる。</p>\n\n<blockquote>\n  <p>[!NOTE]\nC:\\Program Files\\VcXsrv\\X0.hosts にクライアント(Linuxマシン)のIPアドレスを書いておくと、”Disable access control”にチェックを入れなくても良いらしい。<br />\nしかし、サブネット全体を指定するために「192.168.1.」とやってもうまく動かない。。。<br />\n個別に「192.168.1.5」と書いておくとOK</p>\n</blockquote>\n\n<h2 id=\"逐一設定するのがめんどい\">逐一設定するのがめんどい</h2>\n\n<p>4ページ目で”Save configuration”\tをクリックして保存した設定ファイル(拡張子は”.xlaunch”)を実行すれば設定済みの状態で起動できる。</p>\n\n<h2 id=\"linux側の設定\">Linux側の設定</h2>\n\n<p>Linux側では~/.bashrcに以下を追加しておくと、SSHでlog inしたときに自動でDISPLAY変数を設定してくれる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n\t</span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XXX.XXX:0.0\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h2 id=\"その他注意事項\">その他注意事項</h2>\n\n<p>VcXsrvを起動するとキーボードが勝手に変わることがあるらしい。<br />\n日本語入力できなくなったらWindows+SPACEで確認すること。</p>\n\n<h2 id=\"愚痴\">愚痴</h2>\n\n<p>コマンドラインオプションで設定できないか調べてみたが、見つからない。<br />\n「Addituinal parameters」という設定項目があるので、何かしら設定できるはずなんだけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でYOLO(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でYOLO(その2)</h1>\n      <p>openVINOのYOLOのプログラムをちょこっと改変</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> のソースを\n<a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> のソースと形状を合わせたもの。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">math</span> <span class=\"kn\">import</span> <span class=\"n\">exp</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-iout\"</span><span class=\"p\">,</span> <span class=\"s\">\"--iou_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Intersection over union threshold for overlapping \"</span>\n                                                       <span class=\"s\">\"detections filtering\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-ni\"</span><span class=\"p\">,</span> <span class=\"s\">\"--number_iter\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Number of inference iterations\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pc\"</span><span class=\"p\">,</span> <span class=\"s\">\"--perf_counts\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Report performance counters\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span>\n                      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-r\"</span><span class=\"p\">,</span> <span class=\"s\">\"--raw_output_message\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Output inference results raw values showing\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">YoloParams</span><span class=\"p\">:</span>\n    <span class=\"c1\"># ------------------------------------------- Extracting layer parameters ------------------------------------------\n</span>    <span class=\"c1\"># Magic numbers are copied from yolo samples\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">param</span><span class=\"p\">,</span> <span class=\"n\">side</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"mi\">3</span> <span class=\"k\">if</span> <span class=\"s\">'num'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'num'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">=</span> <span class=\"mi\">4</span> <span class=\"k\">if</span> <span class=\"s\">'coords'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'coords'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">classes</span> <span class=\"o\">=</span> <span class=\"mi\">80</span> <span class=\"k\">if</span> <span class=\"s\">'classes'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'classes'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">10.0</span><span class=\"p\">,</span> <span class=\"mf\">13.0</span><span class=\"p\">,</span> <span class=\"mf\">16.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">33.0</span><span class=\"p\">,</span> <span class=\"mf\">23.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">61.0</span><span class=\"p\">,</span> <span class=\"mf\">62.0</span><span class=\"p\">,</span> <span class=\"mf\">45.0</span><span class=\"p\">,</span> <span class=\"mf\">59.0</span><span class=\"p\">,</span> <span class=\"mf\">119.0</span><span class=\"p\">,</span> <span class=\"mf\">116.0</span><span class=\"p\">,</span> <span class=\"mf\">90.0</span><span class=\"p\">,</span> <span class=\"mf\">156.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">198.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">373.0</span><span class=\"p\">,</span> <span class=\"mf\">326.0</span><span class=\"p\">]</span> <span class=\"k\">if</span> <span class=\"s\">'anchors'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"p\">[</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">a</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'anchors'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n\n        <span class=\"k\">if</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">:</span>\n            <span class=\"n\">mask</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">idx</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'mask'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">mask</span><span class=\"p\">)</span>\n\n            <span class=\"n\">maskedAnchors</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n            <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">mask</span><span class=\"p\">:</span>\n                <span class=\"n\">maskedAnchors</span> <span class=\"o\">+=</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"n\">maskedAnchors</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">=</span> <span class=\"n\">side</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"o\">=</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span>  <span class=\"c1\"># Weak way to determine but the only one.\n</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">log_params</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># params_to_print = {'classes': self.classes, 'num': self.num, 'coords': self.coords, 'anchors': self.anchors}\n</span>        <span class=\"c1\"># [log.info(\"         {:8}: {}\".format(param_name, param)) for param_name, param in params_to_print.items()]\n</span>        <span class=\"k\">pass</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">entry_index</span><span class=\"p\">(</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">coord</span><span class=\"p\">,</span> <span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">location</span><span class=\"p\">,</span> <span class=\"n\">entry</span><span class=\"p\">):</span>\n    <span class=\"n\">side_power_2</span> <span class=\"o\">=</span> <span class=\"n\">side</span> <span class=\"o\">**</span> <span class=\"mi\">2</span>\n    <span class=\"n\">n</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">//</span> <span class=\"n\">side_power_2</span>\n    <span class=\"n\">loc</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">%</span> <span class=\"n\">side_power_2</span>\n    <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">side_power_2</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">coord</span> <span class=\"o\">+</span> <span class=\"n\">classes</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">entry</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">loc</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"p\">,</span> <span class=\"n\">h_scale</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"p\">):</span>\n    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">w</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">y</span> <span class=\"o\">-</span> <span class=\"n\">h</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">w</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">+</span> <span class=\"n\">h</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"nb\">dict</span><span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"o\">=</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"o\">=</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"o\">=</span><span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"o\">=</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">blob</span><span class=\"p\">,</span> <span class=\"n\">resized_image_shape</span><span class=\"p\">,</span> <span class=\"n\">original_im_shape</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">threshold</span><span class=\"p\">):</span>\n    <span class=\"c1\"># ------------------------------------------ Validating output parameters ------------------------------------------\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    <span class=\"k\">assert</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">==</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"s\">\"Invalid size of output blob. It sould be in NCHW layout and height should \"</span> \\\n                                     <span class=\"s\">\"be equal to width. Current height = {}, current width = {}\"</span> \\\n                                     <span class=\"s\">\"\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ------------------------------------------ Extracting layer parameters -------------------------------------------\n</span>    <span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">orig_im_w</span> <span class=\"o\">=</span> <span class=\"n\">original_im_shape</span>\n    <span class=\"n\">resized_image_h</span><span class=\"p\">,</span> <span class=\"n\">resized_image_w</span> <span class=\"o\">=</span> <span class=\"n\">resized_image_shape</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">predictions</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">flatten</span><span class=\"p\">()</span>\n    <span class=\"n\">side_square</span> <span class=\"o\">=</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n\n    <span class=\"c1\"># ------------------------------------------- Parsing YOLO Region output -------------------------------------------\n</span>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">side_square</span><span class=\"p\">):</span>\n        <span class=\"n\">row</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">//</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"n\">col</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">%</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"k\">for</span> <span class=\"n\">n</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">num</span><span class=\"p\">):</span>\n            <span class=\"n\">obj_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">)</span>\n            <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">scale</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"n\">box_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n            <span class=\"c1\"># Network produces location predictions in absolute coordinates of feature maps.\n</span>            <span class=\"c1\"># Scale it to relative coordinates.\n</span>            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">col</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">0</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">row</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"c1\"># Value for exp is very big number in some cases so following construction is using here\n</span>            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">w_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n                <span class=\"n\">h_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">3</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n            <span class=\"k\">except</span> <span class=\"nb\">OverflowError</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"c1\"># Depends on topology we need to normalize sizes by feature maps (up to YOLOv3) or by input shape (YOLOv3)\n</span>            <span class=\"n\">w</span> <span class=\"o\">=</span> <span class=\"n\">w_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_w</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"n\">h</span> <span class=\"o\">=</span> <span class=\"n\">h_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_h</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">):</span>\n                <span class=\"n\">class_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span>\n                                          <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">+</span> <span class=\"n\">j</span><span class=\"p\">)</span>\n                <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"n\">scale</span> <span class=\"o\">*</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">class_index</span><span class=\"p\">]</span>\n                <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                    <span class=\"k\">continue</span>\n                <span class=\"n\">objects</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">=</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">=</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"o\">=</span><span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"o\">=</span><span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">j</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">,</span>\n                                          <span class=\"n\">h_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_w</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"n\">objects</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n    <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">height_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span>\n    <span class=\"k\">if</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">height_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">*</span> <span class=\"n\">height_of_overlap_area</span>\n    <span class=\"n\">box_1_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">box_2_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">area_of_union</span> <span class=\"o\">=</span> <span class=\"n\">box_1_area</span> <span class=\"o\">+</span> <span class=\"n\">box_2_area</span> <span class=\"o\">-</span> <span class=\"n\">area_of_overlap</span>\n    <span class=\"k\">if</span> <span class=\"n\">area_of_union</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"mi\">0</span>\n    <span class=\"k\">return</span> <span class=\"n\">area_of_overlap</span> <span class=\"o\">/</span> <span class=\"n\">area_of_union</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>                 <span class=\"c1\"># 冒頭でinputは一つでなければエラーになってるので決め打ちで[0]\n</span>    <span class=\"n\">in_frame_shape</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">:]</span>       <span class=\"c1\"># HWC→BCHWに変更してあるので、height/widthはshape[2:]で取得\n</span>    <span class=\"k\">for</span> <span class=\"n\">layer_name</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">.</span><span class=\"n\">items</span><span class=\"p\">():</span>\n        <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">parents</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]].</span><span class=\"n\">shape</span><span class=\"p\">)</span>\n        <span class=\"n\">layer_params</span> <span class=\"o\">=</span> <span class=\"n\">YoloParams</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n        <span class=\"c1\"># log.info(\"Layer {} parameters: \".format(layer_name))\n</span>        <span class=\"n\">layer_params</span><span class=\"p\">.</span><span class=\"n\">log_params</span><span class=\"p\">()</span>\n        <span class=\"n\">objects</span> <span class=\"o\">+=</span> <span class=\"n\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">out_blob</span><span class=\"p\">,</span> \n                                        <span class=\"n\">in_frame_shape</span><span class=\"p\">,</span>\n                                        <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">],</span> \n                                        <span class=\"n\">layer_params</span><span class=\"p\">,</span>\n                                        <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Filtering overlapping boxes with respect to the --iou_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">sorted</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">,</span> <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"k\">lambda</span> <span class=\"n\">obj</span> <span class=\"p\">:</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">reverse</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">iou_threshold</span><span class=\"p\">:</span>\n                <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># Drawing objects with respect to the --prob_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">obj</span> <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span> <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">Detected boxes for batch {}:\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">))</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\" Class ID | Confidence | XMIN | YMIN | XMAX | YMAX | COLOR \"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">origin_im_size</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Validation bbox of detected object\n</span>        <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"c1\"># color = (int(min(obj['class_id'] * 12.5, 255)),\n</span>        <span class=\"c1\">#          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span>        <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n        <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]]</span> <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"ow\">and</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">>=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]</span> <span class=\"k\">else</span> \\\n            <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">])</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span>\n                <span class=\"s\">\"{:^9} | {:10f} | {:4} | {:4} | {:4} | {:4} | {} \"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">det_label</span><span class=\"p\">,</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">color</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]),</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span>\n                    <span class=\"s\">\"#\"</span> <span class=\"o\">+</span> <span class=\"n\">det_label</span> <span class=\"o\">+</span> <span class=\"s\">' '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"s\">' %'</span><span class=\"p\">,</span>\n                    <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.6</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"c1\"># YOLOのoutputsは1ではない\n</span>    \n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Sample supports only YOLO V3 based single input topologies\"</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>     <span class=\"c1\"># inputは一つだけなので決め打ちで[0]\n</span>    \n    <span class=\"c1\">#  Defaulf batch_size is 1\n</span>    <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n    \n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n        \n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span> <span class=\"o\">=</span>      <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span> <span class=\"o\">=</span>   <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span>  <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_yolov3_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                             <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                             <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                             <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-iout</span> IOU_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-ni</span> NUMBER_ITER] <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-r</span><span class=\"o\">]</span>\n                                             <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG]\n                                             <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n  <span class=\"nt\">-iout</span> IOU_THRESHOLD, <span class=\"nt\">--iou_threshold</span> IOU_THRESHOLD\n                        Optional. Intersection over union threshold <span class=\"k\">for\n                        </span>overlapping detections filtering\n  <span class=\"nt\">-ni</span> NUMBER_ITER, <span class=\"nt\">--number_iter</span> NUMBER_ITER\n                        Optional. Number of inference iterations\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_counts</span>    Optional. Report performance counters\n  <span class=\"nt\">-r</span>, <span class=\"nt\">--raw_output_message</span>\n                        Optional. Output inference results raw values showing\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD</h1>\n      <p>openVINOのSSDのサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>YOLOとは別のアルゴリズムSSDで物体認識するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_ssd_async</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">models.list</code>によると、以下のモデルデータが使用できるらしい。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>face-detection-adas-????\nface-detection-adas-binary-????\nface-detection-retail-????\npedestrian-and-vehicle-detector-adas-????\npedestrian-detection-adas-????\npedestrian-detection-adas-binary-????\nperson-detection-retail-????\nvehicle-detection-adas-????\nvehicle-detection-adas-binary-????\nvehicle-license-plate-detection-barrier-????\n</code></pre></div></div>\n\n<p>ここでは、vehicle-detection-adas-binary-????を使ってみることにする。</p>\n\n<p>以下の手順でモデルデータをダウンロードする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/pedestrian-and-vehicle-detector-adas-0001/FP16/pedestrian-and-vehicle-detector-adas-0001\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>ラベルデータは用意されていないので、ラベルデータを以下の内容で、<code class=\"language-plaintext highlighter-rouge\">${models_diir}/pedestrian-and-vehicle-detector-adas-0001.labels</code>のファイル名で作成する。<br />\nオリジナルでは<code class=\"language-plaintext highlighter-rouge\">--label</code>オプションでラベルデータファイルを指定するようになっているが、\nモデルデータファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものをデフォルトのラベルデータファイルとして認識するように変更しておいた。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>UNKNOWN\nvehicles\npedestrians\nUNKNOWN\n</code></pre></div></div>\n\n<p>どのIDが何を示すか書いてる場所を見つけられなかったんだよなぁ~。<br />\nとりあえず、結果表示から推測するしかないか。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<p>ちょっとのつもりで改造してたら、結構たくさんの変更になったので、ソース全体を掲載しておく。<br />\n(RaspberryPiにはソース入ってないし)<br />\nおもな変更点は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--save</code> <code class=\"language-plaintext highlighter-rouge\">--log</code> <code class=\"language-plaintext highlighter-rouge\">--sync</code> <code class=\"language-plaintext highlighter-rouge\">--no_disp</code> オプションの追加</li>\n  <li>結果解析部分の関数化(後でYOLOと比較しやすいように)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># print(res[out_blob].shape)\n</span>    <span class=\"c1\">#  -> (1, 1, 200, 7)        200:バウンディングボックスの数\n</span>    <span class=\"c1\"># データ構成は\n</span>    <span class=\"c1\"># https://docs.openvinotoolkit.org/2019_R1/_pedestrian_and_vehicle_detector_adas_0001_description_pedestrian_and_vehicle_detector_adas_0001.html\n</span>    <span class=\"c1\"># の「outputs」を参照\n</span>    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"n\">out_blob</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]:</span>     <span class=\"c1\"># このループは200回まわる\n</span>        <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>                       <span class=\"c1\"># confidence for the predicted class(スコア)\n</span>        <span class=\"k\">if</span> <span class=\"n\">conf</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">:</span>      <span class=\"c1\"># 閾値より大きいものだけ処理\n</span>            <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n            <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 表示色\n</span>            <span class=\"c1\"># color = (min(class_id * 12.5, 255), min(class_id * 7, 255), min(class_id * 5, 255))\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>            <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># バウンディングボックスとラベル、スコアを表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">det_label</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">conf</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">%\"</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Demo supports only single output topologies\"</span>\n\n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"c1\"># SSDのinputsは1とは限らないのでスキャンする\n</span>    <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">for</span> <span class=\"n\">blob_name</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">:</span>\n        <span class=\"c1\"># print(f'{blob_name}   {net.inputs[blob_name].shape}')\n</span>        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">4</span><span class=\"p\">:</span>\n            <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">2</span><span class=\"p\">:</span>\n            <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"nb\">RuntimeError</span><span class=\"p\">(</span><span class=\"s\">\"Unsupported {}D input layer '{}'. Only 2D and 4D input layers are supported\"</span>\n                               <span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">),</span> <span class=\"n\">blob_name</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    <span class=\"k\">if</span> <span class=\"n\">img_info_input_blob</span><span class=\"p\">:</span>\n        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">img_info_input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n\n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span>     <span class=\"o\">=</span> <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span>  <span class=\"o\">=</span> <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span> <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_ssd_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                          <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                          <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO(C++版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO(C++版)</h1>\n      <p>tinyYOLOのC++版デモプログラムのbuildと実行</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nのpythonで実行したデモプログラムのC++版をbuild&実行してみる。</p>\n\n<h1 id=\"ubuntu環境での実行\">ubuntu環境での実行</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h2 id=\"デモのソースプログラム\">デモのソースプログラム</h2>\n\n<p>ドライバのインストール先 <code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/deployment_tools/open_model_zoo/demos</code> にあるので、そのまま参照しても良いが、\nソース修正に備えて、ソースをコピっておく(オーナーも変更)と何かと便利。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++/openvino_demo <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos <span class=\"nb\">.</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> demos/\n</code></pre></div></div>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>出力文字列のサイズと位置を調整</li>\n  <li>-saveオプションの追加と認識結果画像ファイルの保存処理の追加</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.hpp.org\t2019-10-31 14:39:14.757039048 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.hpp\t2019-10-31 06:16:49.178945707 +0900\n</span><span class=\"p\">@@ -93,6 +93,7 @@</span>\n /// \\brief Define a flag to disable showing processed video<br>\n /// It is an optional parameter\n DEFINE_bool(no_show, false, no_show_processed_video);\n<span class=\"gi\">+DEFINE_bool(save, false, \"Optional. save image file.\");\n</span> \n /**\n * \\brief This function shows a help message\n<span class=\"p\">@@ -115,4 +116,5 @@</span>\n     std::cout << \"    -iou_t                    \" << iou_thresh_output_message << std::endl;\n     std::cout << \"    -auto_resize              \" << input_resizable_message << std::endl;\n     std::cout << \"    -no_show                  \" << no_show_processed_video << std::endl;\n<span class=\"gi\">+    std::cout << \"    -save                     \" << \"Optional. save image file.\" << std::endl;\n</span> }\n</code></pre></div></div>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.org\t2019-10-31 05:46:38.515000000 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"p\">@@ -197,6 +197,21 @@</span>\n         }\n         // -----------------------------------------------------------------------------------------------------\n \n<span class=\"gi\">+        // =====================================================================================\n+        // 動画ファイルを書き出すためのオブジェクトを宣言する\n+        cv::VideoWriter writer;\n+        // =====================================================================================\n+        // =====================================================================================\n+        if (FLAGS_save) {\n+            double fps    = cap.get(cv::CAP_PROP_FPS);\t\t\t\t// フレームレートを取得\n+            int fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v');\t\t// MP4形式を指定\n+            // * エンコード形式 \"XVID\" = AVI, \"MP4V\" = MPEG4, \"WMV1\" = WMV\n+\n+            // 動画ファイルを書き出すためのファイルをオープンする\n+            writer.open(\"result.mp4\", fourcc, fps, cv::Size(width, height));\n+        }\n+        // =====================================================================================\n+\n</span>         // --------------------------- 1. Load inference engine -------------------------------------\n         slog::info << \"Loading Inference Engine\" << slog::endl;\n         Core ie;\n<span class=\"p\">@@ -356,17 +371,17 @@</span>\n                 std::ostringstream out;\n                 out << \"OpenCV cap/render time: \" << std::fixed << std::setprecision(2)\n                     << (ocv_decode_time + ocv_render_time) << \" ms\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 25), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 255, 0));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 15), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 255, 0));\n</span>                 out.str(\"\");\n                 out << \"Wallclock time \" << (isAsyncMode ? \"(TRUE ASYNC):      \" : \"(SYNC, press Tab): \");\n                 out << std::fixed << std::setprecision(2) << wall.count() << \" ms (\" << 1000.f / wall.count() << \" fps)\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 50), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 0, 255));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 30), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 0, 255));\n</span>                 if (!isAsyncMode) {  // In the true async mode, there is no way to measure detection time directly\n                     out.str(\"\");\n                     out << \"Detection time  : \" << std::fixed << std::setprecision(2) << detection.count()\n                         << \" ms (\"\n                         << 1000.f / detection.count() << \" fps)\";\n<span class=\"gd\">-                    cv::putText(frame, out.str(), cv::Point2f(0, 75), cv::FONT_HERSHEY_TRIPLEX, 0.6,\n</span><span class=\"gi\">+                    cv::putText(frame, out.str(), cv::Point2f(0, 45), cv::FONT_HERSHEY_TRIPLEX, 0.4,\n</span>                                 cv::Scalar(255, 0, 0));\n                 }\n \n<span class=\"p\">@@ -410,7 +425,7 @@</span>\n                         cv::putText(frame,\n                                 (label < static_cast<int>(labels.size()) ?\n                                         labels[label] : std::string(\"label #\") + std::to_string(label)) + conf.str(),\n<span class=\"gd\">-                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 1,\n</span><span class=\"gi\">+                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.4,\n</span>                                     cv::Scalar(0, 0, 255));\n                         cv::rectangle(frame, cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin)),\n                                       cv::Point2f(static_cast<float>(object.xmax), static_cast<float>(object.ymax)), cv::Scalar(0, 0, 255));\n<span class=\"p\">@@ -420,6 +435,11 @@</span>\n             if (!FLAGS_no_show) {\n                 cv::imshow(\"Detection results\", frame);\n             }\n<span class=\"gi\">+            // =====================================================================================\n+            if (FLAGS_save) {\n+                writer << frame;\n+            }\n+            // =====================================================================================\n</span> \n             t1 = std::chrono::high_resolution_clock::now();\n             ocv_render_time = std::chrono::duration_cast<ms>(t1 - t0).count();\n<span class=\"p\">@@ -457,6 +477,11 @@</span>\n         if (FLAGS_pc) {\n             printPerformanceCounts(*async_infer_request_curr, std::cout, getFullDeviceName(ie, FLAGS_d));\n         }\n<span class=\"gi\">+        // =====================================================================================\n+        if (FLAGS_save) {\n+            writer.release();\n+        }\n+        // =====================================================================================\n</span>     }\n     catch (const std::exception& error) {\n         std::cerr << \"[ ERROR ] \" << error.what() << std::endl;\n\n</code></pre></div></div>\n\n<h2 id=\"buildディレクトリの作成とbuild\">buildディレクトリの作成とbuild</h2>\n\n<p>cmakeの実行とbuild</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<p>ちょっと時間がかかる。</p>\n\n<h2 id=\"モデルデータ\">モデルデータ</h2>\n\n<p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nで作成したモデルデータをそのまま使用する。<br />\nラベルデータファイルのファイル名はモデルデータのxmlファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものに固定だが、モデルデータ作成時にコピー済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./intel64/Release/</code>に作成される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./intel64/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-l</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> ../../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>-save オプションを指定すると、認識結果の動画をresult.mp4(ファイル名は固定)に保存する。</p>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>デモプログラムはRasspberryPiでも動作させることができる。<br />\nソースはRaspberryPi側にはないので、ubuntuからコピーする。</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>ubuntuで作成した /work/NCS2/c++/openvino_demo/demos ディレクトリと/work/NCS2/openvino_models ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"buildディレクトリの作成とbuild-1\">buildディレクトリの作成とbuild</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a -Wno-psabi\"</span> ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./armv7l/Release/</code>に作成される。<br />\n入力ファイル(-i オプション)はフルパスで指定すること。相対パスだとファイルが見つからないと怒られる。<br />\n※ 下のパッチを当てると相対パスでも大丈夫になる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./armv7l/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-d</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> /work/NCS2/data/testvideo3.mp4 \n</code></pre></div></div>\n\n<p>なぜか-saveオプションが効かない。。。</p>\n\n<h2 id=\"入力ファイル名に相対パスを使用できるようにするためのパッチ\">入力ファイル名に相対パスを使用できるようにするためのパッチ</h2>\n\n<p>入力ファイル名をrealpath()で絶対パスに変換して使用することで対応。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.1\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-11-01 11:25:29.720856218 +0900\n</span><span class=\"p\">@@ -30,6 +30,9 @@</span>\n #include <ext_list.hpp>\n #endif\n \n<span class=\"gi\">+#include <limits.h>\n+#include <unistd.h>\n+\n</span> using namespace InferenceEngine;\n \n bool ParseAndCheckCommandLine(int argc, char *argv[]) {\n<span class=\"p\">@@ -180,7 +183,23 @@</span>\n \n         slog::info << \"Reading input\" << slog::endl;\n         cv::VideoCapture cap;\n<span class=\"gd\">-        if (!((FLAGS_i == \"cam\") ? cap.open(0) : cap.open(FLAGS_i.c_str()))) {\n</span><span class=\"gi\">+\n+        bool open_status;\n+        if (FLAGS_i == \"cam\") {\n+            open_status = cap.open(0);\n+        }\n+        else {\n+            std::string input_filename;\n+            char input_filename_char[PATH_MAX+1];\n+            if (!realpath(FLAGS_i.c_str(), input_filename_char)) {\n+                throw std::logic_error(\"Cannot get realpath\");\n+            }\n+            input_filename = input_filename_char;\n+            slog::info << \"input filename :\" + input_filename << slog::endl;\n+            open_status = cap.open(input_filename.c_str());\n+\n+        }\n+        if (!open_status) {\n</span>             throw std::logic_error(\"Cannot open input file or camera: \" + FLAGS_i);\n         }\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO</h1>\n      <p>darknetのモデルデータをopenVINOのモデルデータに変換し、tinyYOLOで画像認識を行う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOの2019 R3.1 がリリー(2019.10.29現在、ubuntu用のみ)スされ、YOLOのサンプルプログラムが用意されていたので、tinyYOLOを実行してみた。</p>\n\n<p>参考:<a href=\"https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html\">https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html</a></p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"darknetのモデルデータをopenvinoのモデルデータに変換\">darknetのモデルデータをopenVINOのモデルデータに変換</h1>\n\n<p>上記参考サイトの手順に従って、darknetのtinyYOLOモデルデータをopenVINOのモデルデータに変換する。</p>\n\n<h2 id=\"darknet--tensorflow-変換のためのプログラム取得\">darknet → tensorflow 変換のためのプログラム取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2\ngit clone https://github.com/mystic123/tensorflow-yolo-v3.git\n<span class=\"nb\">cd </span>tensorflow-yolo-v3/\ngit checkout ed60b90\n</code></pre></div></div>\n\n<h2 id=\"darknet-tinyyoloモデルデータ取得\">darknet tinyYOLOモデルデータ取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://raw.githubusercontent.com/pjreddie/darknet/master/data/coco.names\nwget https://pjreddie.com/media/files/yolov3-tiny.weights\n</code></pre></div></div>\n\n<h1 id=\"darknet--tensorflow-モデルデータ変換\">darknet → tensorflow モデルデータ変換</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python convert_weights_pb.py <span class=\"nt\">--class_names</span> coco.names <span class=\"nt\">--data_format</span> NHWC <span class=\"nt\">--weights_file</span> yolov3-tiny.weights <span class=\"nt\">--tiny</span>\n<span class=\"nb\">mv </span>frozen_darknet_yolov3_model.pb yolo_v3_tiny.pb\n</code></pre></div></div>\n\n<h2 id=\"モデルデータを変換\">モデルデータを変換</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP16 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div></div>\n\n<p>/work/NCS2/openvino_models/FP16ディレクトリに yolo_v3_tiny.bin yolo_v3_tiny.mapping yolo_v3_tiny.xml の3つが出来る</p>\n\n<blockquote>\n  <p>[!NOTE]\nFP32で計算する場合はこちら<br />\nNCStick使用時はFP16のみサポートなので、FP16で作っておくと使い回しできて楽。<br />\nそんなに認識精度が変わるわけでもなさそうだし。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP32\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP32 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"ラベルデータもコピー\">ラベルデータもコピー</h2>\n\n<p>pbファイルにはラベルデータが入っているはずだが、この後の変換でラベルデータは欠落するらしい。<br />\n後のプログラムのためにファイル名変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>coco.names <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels\n</code></pre></div></div>\n\n<h2 id=\"デモプログラムをコピー\">デモプログラムをコピー</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ..\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_yolov3_async <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>object_detection_demo_yolov3_async/\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>MP4ファイルのパスが絶対パスでないと正常にオープンできない対策(ubuntuではやらなくても大丈夫)</li>\n  <li>1フレームあたりの処理時間の計測と表示処理を追加</li>\n  <li>認識枠の表示色変更(ちょっと見難かったので)</li>\n  <li>計測データ表示処理の並べ替え(ソースが見難かったので。フレーム時間の追加以外の動作は変更なし)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py.org\t2019-10-29 05:08:34.982999999 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"p\">@@ -210,7 +210,8 @@</span>\n     else:\n         labels_map = None\n \n<span class=\"gd\">-    input_stream = 0 if args.input == \"cam\" else args.input\n</span><span class=\"gi\">+    # input_stream = 0 if args.input == \"cam\" else args.input\n+    input_stream = 0 if args.input == \"cam\" else os.path.abspath(args.input)\n</span> \n     is_async_mode = True\n     cap = cv2.VideoCapture(input_stream)\n<span class=\"p\">@@ -234,6 +235,8 @@</span>\n     next_request_id = 1\n     render_time = 0\n     parsing_time = 0\n<span class=\"gi\">+    frame_time = 0\n+    prev_time = time()\n</span> \n     # ----------------------------------------------- 6. Doing inference -----------------------------------------------\n     log.info(\"Starting inference...\")\n<span class=\"p\">@@ -263,6 +266,8 @@</span>\n \n         # Start inference\n         start_time = time()\n<span class=\"gi\">+        frame_time = start_time - prev_time         # 1フレームの処理時間\n+        prev_time = start_time\n</span>         exec_net.start_async(request_id=request_id, inputs={input_blob: in_frame})\n         det_time = time() - start_time\n \n<span class=\"p\">@@ -303,8 +308,9 @@</span>\n             # Validation bbox of detected object\n             if obj['xmax'] > origin_im_size[1] or obj['ymax'] > origin_im_size[0] or obj['xmin'] < 0 or obj['ymin'] < 0:\n                 continue\n<span class=\"gd\">-            color = (int(min(obj['class_id'] * 12.5, 255)),\n-                     min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span><span class=\"gi\">+            # color = (int(min(obj['class_id'] * 12.5, 255)),\n+            #          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n+            color = (255, 128, 128)\n</span>             det_label = labels_map[obj['class_id']] if labels_map and len(labels_map) >= obj['class_id'] else \\\n                 str(obj['class_id'])\n \n<span class=\"p\">@@ -322,16 +328,17 @@</span>\n         # Draw performance stats over frame\n         inf_time_message = \"Inference time: N\\A for async mode\" if is_async_mode else \\\n             \"Inference time: {:.3f} ms\".format(det_time * 1e3)\n<span class=\"gi\">+        frame_time_message = \"Frame time: {:.3f} ms\".format(frame_time * 1e3)\n</span>         render_time_message = \"OpenCV rendering time: {:.3f} ms\".format(render_time * 1e3)\n         async_mode_message = \"Async mode is on. Processing request {}\".format(cur_request_id) if is_async_mode else \\\n             \"Async mode is off. Processing request {}\".format(cur_request_id)\n         parsing_message = \"YOLO parsing time is {:.3f}\".format(parsing_time * 1e3)\n \n<span class=\"gd\">-        cv2.putText(frame, inf_time_message, (15, 15), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200, 10, 10), 1)\n-        cv2.putText(frame, render_time_message, (15, 45), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n-        cv2.putText(frame, async_mode_message, (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5,\n-                    (10, 10, 200), 1)\n-        cv2.putText(frame, parsing_message, (15, 30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n</span><span class=\"gi\">+        cv2.putText(frame, inf_time_message,    (15, 15),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, parsing_message,     (15, 30),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, render_time_message, (15, 45),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, frame_time_message,  (10, int(origin_im_size[0] - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, async_mode_message,  (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n</span> \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n</code></pre></div></div>\n\n<p>上のパッチ内容をa.patchとして保存したとして、以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch object_detection_demo_yolov3_async.py a.patch \n\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\n入力ファイルをmp4に変えるだけ。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしいが、カメラないので未確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>RaspberryPi用はopenVINO 2019R3のまま(2019.10.29現在、R3.1はリリースされていない)だけど、問題なし。</p>\n\n<p>ubuntuで作成した object_detection_demo_yolov3_async ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"静止画の場合-1\">静止画の場合</h2>\n\n<p>実行コマンドは以下。  ubuntuの実行コマンドと比べて、以下の変更がある。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--device MYRIAD</code>を追加</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">--cpu_extension</code>を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合-1\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\nこちらも入力ファイルをmp4に変えるだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p>openCVではMP4ファイルを保存することができる。<br />\nobject_detection_demo_yolov3_async.py に以下の変更を加えることで、認識結果をMP4ファイルに保存することができる。</p>\n\n<p>以下の修正ファイルは簡易的に保存する処理を追加したため、保存ファイル名は決め打ち。 <br />\n汎用的にするなら、オプションで指定できるようにしてもいいかもね。</p>\n\n<p>ただし、実際に保存するタイミングとMP4ファイルのタイムインデックスが一致するわけではないので、\n処理時の見た目と保存ファイルを再生したときの見た目は異なるので注意が必要。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"gi\">+++ record.py\t2019-10-29 11:35:37.296005608 +0900\n</span><span class=\"p\">@@ -218,6 +218,18 @@</span>\n     number_input_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n     number_input_frames = 1 if number_input_frames != -1 and number_input_frames < 0 else number_input_frames\n \n<span class=\"gi\">+    # =====================================================================================\n+    # 幅と高さを取得\n+    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n+    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n+    size = (width, height)\n+    # フレームレート(1フレームの時間単位はミリ秒)の取得\n+    frame_rate = int(cap.get(cv2.CAP_PROP_FPS))\n+    # フォーマット\n+    fmt = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')\n+    writer = cv2.VideoWriter('./outtest.mp4', fmt, frame_rate, size)\n+    # =====================================================================================\n+\n</span>     wait_key_code = 1\n \n     # Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n<span class=\"p\">@@ -342,6 +354,9 @@</span>\n \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n<span class=\"gi\">+        # =====================================================================================\n+        writer.write(frame)\n+        # =====================================================================================\n</span>         render_time = time() - start_time\n \n         if is_async_mode:\n<span class=\"p\">@@ -359,6 +374,10 @@</span>\n             is_async_mode = not is_async_mode\n             log.info(\"Switched to {} mode\".format(\"async\" if is_async_mode else \"sync\"))\n \n<span class=\"gi\">+    # =====================================================================================\n+    writer.release()\n+    # =====================================================================================\n+\n</span>     cv2.destroyAllWindows()\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>YOLOv3を試す</title>\n  </head>\n  <body>\n    <header>\n      <h1>YOLOv3を試す</h1>\n      <p>Native & python でYOLOv3を実行してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"yolov3を試す\">YOLOv3を試す</h1>\n\n<p>YOLOv3をubuntu上で実行してみた。<br />\nopneVINOやNCStickは使用していない。<br />\n単にYOLOv3の動作確認したかった&python実装を探してたら見つかったサイトをトレースしてみただけの話。<br />\npyhton のバージョンは3.7.4</p>\n\n<p>元ネタはこちら→ <a href=\"https://qiita.com/massie_g/items/a2bcfac4fed66b1b0717#yolo-v3-tiny-%E3%83%A2%E3%83%87%E3%83%AB\">https://qiita.com/massie_g/items/a2bcfac4fed66b1b0717#yolo-v3-tiny-%E3%83%A2%E3%83%87%E3%83%AB</a></p>\n\n<p>とりあえず動かしてみた後にpythonのソース読んでみた。<br />\nイメージの読み込みも、結果の描画も、保存もNativeなライブラリをコールしてるだけだ… <br />\n完全なwrapperだ。。。<br />\nやりたかったこととちょっと違う。。。orz….</p>\n\n<p>darknetは色々な処理(jpegファイルの操作とか)を自前で実装しているので、\n色々ライブラリをインストールしなくて良いのは助かるんだけど、\n他の処理系に移植するのはめんどくさそうなんだな。。。</p>\n\n<p>ということで、さくっと試した手順だけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">WORKDIR</span><span class=\"o\">=</span>/work1/YOLO\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>\ngit clone https://github.com/pjreddie/darknet.git\n<span class=\"nb\">cd </span>darknet\nwget https://pjreddie.com/media/files/yolov3.weights\nwget https://pjreddie.com/media/files/yolov3-tiny.weights\n<span class=\"nb\">cd</span> ..\ngit clone https://github.com/mganeko/python3_yolov3.git\n<span class=\"nb\">cp</span> ./python3_yolov3/darknet-tiny-label.py ./darknet/python/\n<span class=\"nb\">cd </span>darknet\nmake\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>/darknet/libdarknet.so /usr/lib/libdarknet.so\n\n<span class=\"c\"># YOLOv3 native版の実行</span>\n./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg\n<span class=\"c\"># predictions.jpg が認識結果</span>\n<span class=\"nb\">mv </span>predictions.jpg predictions_yolo.jpg \n\n<span class=\"c\"># tinyYOLOv3 native版の実行</span>\n./darknet detect cfg/yolov3-tiny.cfg yolov3-tiny.weights data/dog.jpg\n<span class=\"c\"># predictions.jpg が認識結果</span>\n<span class=\"nb\">mv </span>predictions.jpg predictions_tiny.jpg\n\n<span class=\"c\"># tinyYOLOv3 python版の実行</span>\npython python/darknet-tiny-label.py \n<span class=\"c\"># detect_result.jpg が認識結果</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openCV で MPEG再生</title>\n  </head>\n  <body>\n    <header>\n      <h1>openCV で MPEG再生</h1>\n      <p>python + openCV でMPEGファイルを再生する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>python + openCV で MPEGファイルを再生するには、以下のようにread→imshowを繰り返せば良い。<br />\nしかし、これではフレームレートを考慮していないため、実際の時間とは異なる速度で再生されてしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n<span class=\"k\">while</span> <span class=\"n\">true</span><span class=\"p\">:</span>\n    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"k\">break</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>そこで、フレーム間に待ち時間を確保し、実際の時間と同じになるように再生する方法を考える。</p>\n\n<h1 id=\"フレーム間の待ち時間を決め打ちで待つパターン一番シンプルなパターン\">フレーム間の待ち時間を決め打ちで待つパターン(一番シンプルなパターン)</h1>\n\n<p>最も簡単な方法は、フレーム間に決め打ちでwait処理を挿入する方法である。<br />\nフレームレートは一定であるため、待ち時間も一定になる。<br />\n再生中にキー入力による中止を検出したいので、<code class=\"language-plaintext highlighter-rouge\">time.sleep()</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">cv2.waitKey(delay)</code>を使用している。<br />\n試した環境では、<code class=\"language-plaintext highlighter-rouge\">cv2.waitKey()</code> は 25くらいを指定すると大体30fpsに合うくらいの間隔になる(ちょっと早いかも)。<br />\n設定値はトライ&エラーで設定値を探るしかない。</p>\n\n<p>しかし、MPEG再生しか行わない場合はこれでも問題ないが、フレーム間に他の処理を行うと待ち時間が変わってきてしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./video.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 現在時刻\n</span>    <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"n\">index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># delay = 1         # 最速再生\n</span>    <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"mi\">25</span>          <span class=\"c1\"># それっぽい再生速度になるように決め打ちで\n</span>    \n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">delay</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"前回の時刻からフレーム間の待ち時間を決めるパターン\">前回の時刻からフレーム間の待ち時間を決めるパターン</h1>\n\n<p>前回の表示時刻を覚えておき、今回の表示時刻との間隔がフレームレートに一致するように待ち時間を調整する。<br />\nこれなら、フレーム間に他の処理を挿入しても(その処理時間が一定でなくても)、その処理時間を除いて待ち時間を設定できる。</p>\n\n<p>しかし、挿入した処理がフレームレートを超えてしまうと、回復する術がなく、どんどん遅れていってしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./video.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n        <span class=\"n\">tmp_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 現在時刻\n</span>    <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"n\">index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># 待ち時間計算用起点からの差分とsec/frameから待ち時間決定\n</span>    <span class=\"n\">delta_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">tmp_time</span>\n    <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">sec_per_frame</span> <span class=\"o\">-</span> <span class=\"n\">delta_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(f'delta =  {int(delta_time*1000)}    {delay}')\n</span>    <span class=\"c1\"># 待ち時間がsec/frameを超えてたら最小値に設定\n</span>    <span class=\"k\">if</span> <span class=\"n\">delay</span> <span class=\"o\"><</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n\n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">delay</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># 待ち時間計算用起点\n</span>    <span class=\"n\">tmp_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"経過時間から表示すべきフレームを求めて移動しながら表示するパターン\">経過時間から表示すべきフレームを求めて移動しながら表示するパターン</h1>\n\n<p>現在時刻と再生開始時刻の差から表示すべきフレーム番号を求め、必要であれば<code class=\"language-plaintext highlighter-rouge\">cap.set(cv2.CAP_PROP_POS_FRAMES, index)</code>で読み込みフレームを移動して現在時刻とフレームの同期をとる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">cap.set()</code>は処理に時間がかかるので、無条件で実行すると再生フレームレートが遅くなるため、フレーム飛びが発生したときのみ実行するようにする。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n# filepath = os.path.abspath(\"./video.mp4\") \n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./stopwatch.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 前回表示フレーム番号の更新\n</span>    <span class=\"n\">prev_index</span> <span class=\"o\">=</span> <span class=\"n\">index</span>\n    \n    <span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 現在時刻\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        \n        <span class=\"c1\"># 表示するフレーム位置の取得\n</span>        <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">sec_per_frame</span><span class=\"p\">)</span>\n        <span class=\"c1\"># print(f\"{prev_time}    {cur_time}    {prev_index}    {index}\")\n</span>        <span class=\"k\">if</span> <span class=\"n\">prev_index</span> <span class=\"o\">==</span> <span class=\"n\">index</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 前回と同じフレーム番号ならちょっと待つ\n</span>            <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.001</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"k\">break</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># 表示するフレーム位置が連続するフレームでなければ移動\n</span>    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">!=</span> <span class=\"n\">prev_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># 動作確認0.5秒待ってみる\n</span>    <span class=\"c1\"># time.sleep(0.5)\n</span>\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>改訂版はこちら→<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></p>\n\n<p>caffeモデルなどをopenVINOへ変換するには、フルパッケージが必要らしい。<br />\nでもって、フルパッケージはRaspberryPiでは使用できなくて、WindowsやLinux、macOSが必要。<br />\nということで、openVINO フルパッケージをubuntu 18.04にインストールする。 <br />\n(16.04でも大丈夫かもしれないけど、今回は18.04を使う。LTSじゃないのはやめといた方が良さそう)</p>\n\n<h1 id=\"ダウンロード--インストール前半\">ダウンロード & インストール前半</h1>\n\n<p>ダウンロードはこの辺を参考に。。。<br />\n<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758</a><br />\nなにやら登録しないといけないらしい。</p>\n\n<p>ダウンロードしたら、てきとーなところに展開して、インストーラを実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\n2910.10 「2019 R3.1」がリリースされた。ファイル名は「l_openvino_toolkit_p_2019.3.376.tgz」</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf /Share/l_openvino_toolkit_p_2019.3.334.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2019.3.334\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n\n<p>nextをクリックしていけば大丈夫(Agreeするとこはあるけど)。<br />\nあとで色々インストールしろと言われるけど、あとでやるので無視して大丈夫<br />\n・・・・しばらく待つ・・・・<br />\nいったんFinishするとブラウザが表示される<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h1 id=\"インストール後半--動作確認\">インストール後半 & 動作確認</h1>\n\n<h2 id=\"install-external-software-dependenciesとな\">「Install External Software Dependencies」とな?</h2>\n\n<p>なんか実行してインストールしろってことらしい。<br />\nroot権限で実行しないとエラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh\n</code></pre></div></div>\n\n<p>なんか色々インストールされるっぽい。<br />\n中身はOSのディストリビューションとバージョンでインストールパッケージを切り替えてインストールしてるらしい。</p>\n\n<h2 id=\"set-the-environment-variablesとな\">「Set the Environment Variables」とな?</h2>\n\n<p>環境変数の設定らしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<p>~/.bashrcに追加しておくと良いとのことなので、そうする。</p>\n\n<h2 id=\"configure-the-model-optimizerとな\">「Configure the Model Optimizer」とな?</h2>\n\n<p>モデルオプティマイザの設定。<br />\nこれが欲しかったのよ。</p>\n\n<p>必要なpipモジュールをインストールするらしい。<br />\n必要なものだけインストールすることもできるけど、一括でインストールしといた方が手間がかからないでしょう。</p>\n\n<p>pyenvを使ってると、<code class=\"language-plaintext highlighter-rouge\">sudo pip3</code>されると、systemのpip3が動いてしまい、pyenv環境にモジュールがインストールされない。<br />\nスクリプトの中で必要なコマンドだけ実行する(随分スッキリしちゃったなぁ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\n</code></pre></div></div>\n\n<p>バージョン不一致とか言われたら、適宜バージョン合わせてアップグレードorダウングレードしてちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nsetuptoolsは<code class=\"language-plaintext highlighter-rouge\">pip install -U setuptools</code>でOKなはず。<br />\nnumpyは<code class=\"language-plaintext highlighter-rouge\">mxnet 1.3.1 has requirement numpy<1.15.0,>=1.8.2, but you'll have numpy 1.17.3 which is incompatible.</code>と言われるのだけど、tensorflow 1.15.0だとnumpy 1.16.0以上を要求する。<br />\nとりあえず、tenssorflowを1.13.1にしてnumpyを1.14.6にしてみて様子見。<br />\n現状のバージョン一覧は以下。これを<code class=\"language-plaintext highlighter-rouge\">requirements.txt</code>として保存し、<code class=\"language-plaintext highlighter-rouge\">pip install -r requirements.txt</code>するとこのバージョンでそろえてくれるはず。</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.8.1\nastor==0.8.0\ncertifi==2019.9.11\nchardet==3.0.4\ndecorator==4.4.0\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.1.7\ngraphviz==0.8.4\ngrpcio==1.24.3\nh5py==2.10.0\nidna==2.8\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.0\nMarkdown==3.1.1\nmock==3.0.5\nmxnet==1.3.1\nnetworkx==2.3\nnumpy==1.14.6\nonnx==1.6.0\nopt-einsum==3.1.0\npipdeptree==0.13.2\nprotobuf==3.6.1\nrequests==2.22.0\nsix==1.12.0\ntensorboard==1.13.1\ntensorflow==1.13.1\ntensorflow-estimator==1.13.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4\nurllib3==1.25.6\nWerkzeug==0.16.0\nwrapt==1.11.2\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nオリジナルの方法はこちら</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"run-the-verification-scripts-to-verify-installationとな\">「Run the Verification Scripts to Verify Installation」とな?</h2>\n\n<p>なになに、実行必須?たしかにapt installが実行される。<br />\nなら、タイトルに “to Verify Installation” とか書くなよ!</p>\n\n<p>build前に<code class=\"language-plaintext highlighter-rouge\">apt install</code> と <code class=\"language-plaintext highlighter-rouge\">pip install</code>が走る。</p>\n\n<p>こっちもpyenv使ってるとpipで悲しいことになるので、先にpipだけ実行しておく。<br />\nスクリプト側でもpipが走ってsystemのモジュールが追加されるが、悪影響はないと思うので、そのままにしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div></div>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n./demo_squeezenet_download_convert_run.sh\n</code></pre></div></div>\n\n<p>・・・・こんなことをやってるらしい・・・・</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">target_precision</code> は FP16 になっている</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">apt install</code> で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pip install</code>で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/open_model_zoo/tools/downloaderdownloader.py</code>でモデルのダウンロードを行う\n    <ul>\n      <li>ダウンロード済みならスキップ»</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/model_optimizer/mo.py</code>でモデル変換を行う\n    <ul>\n      <li>変換済みならスキップ»</li>\n    </ul>\n  </li>\n  <li>サンプルプログラムのbuild</li>\n  <li>サンプルプログラム(classification_sample_async)の実行<br />\n  実行結果はこんな感じ</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./classification_sample_async -d CPU -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/openvino_models/ir/FP16//public/squeezenet1.1/squeezenet1.1.xml \n\n[ INFO ] InferenceEngine: \n\tAPI version ............ 2.1\n\tBuild .................. custom_releases/2019/R3_cb6cad9663aea3d282e0e8b3e0bf359df665d5d0\n\tDescription ....... API\n[ INFO ] Parsing input parameters\n[ INFO ] Parsing input parameters\n[ INFO ] Files were added: 1\n[ INFO ]     /opt/intel/openvino/deployment_tools/demo/car.png\n[ INFO ] Creating Inference Engine\n\tCPU\n\tMKLDNNPlugin version ......... 2.1\n\tBuild ........... 30677\n\n[ INFO ] Loading network files\n[ INFO ] Preparing input blobs\n[ WARNING ] Image is resized from (787, 259) to (227, 227)\n[ INFO ] Batch size is 1\n[ INFO ] Loading model to the device\n[ INFO ] Create infer request\n[ INFO ] Start inference (10 asynchronous executions)\n[ INFO ] Completed 1 async request execution\n[ INFO ] Completed 2 async request execution\n[ INFO ] Completed 3 async request execution\n[ INFO ] Completed 4 async request execution\n[ INFO ] Completed 5 async request execution\n[ INFO ] Completed 6 async request execution\n[ INFO ] Completed 7 async request execution\n[ INFO ] Completed 8 async request execution\n[ INFO ] Completed 9 async request execution\n[ INFO ] Completed 10 async request execution\n[ INFO ] Processing output blobs\n\nTop 10 results:\n\nImage /opt/intel/openvino/deployment_tools/demo/car.png\n\nclassid probability label\n------- ----------- -----\n817     0.8364176   sports car, sport car\n511     0.0945683   convertible\n479     0.0419195   car wheel\n751     0.0091233   racer, race car, racing car\n436     0.0068038   beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon\n656     0.0037315   minivan\n586     0.0025940   half track\n717     0.0016044   pickup, pickup truck\n864     0.0012045   tow truck, tow car, wrecker\n581     0.0005833   grille, radiator grille\n\n[ INFO ] Execution successful\n\n[ INFO ] This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool\n</code></pre></div></div>\n\n<ul>\n  <li>終了</li>\n</ul>\n\n<p>もういっちょでも実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh\n</code></pre></div></div>\n\n<p>やってることは前のと同じ。<br />\nこっちはopenVINOのモデルをダウンロードするので、モデル変換はない。<br />\n最終的に実行しているデモプログラムはこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./security_barrier_camera_demo -d CPU -d_va CPU -d_lpr CPU -i /opt/intel/openvino/deployment_tools/demo/car_1.bmp -m ~/openvino_models/ir/FP16/intel/vehicle-license-plate-detection-barrier-0106/FP16/vehicle-license-plate-detection-barrier-0106.xml -m_lpr ~/openvino_models/ir/FP16/intel/license-plate-recognition-barrier-0001/FP16/license-plate-recognition-barrier-0001.xml -m_va ~/openvino_models/ir/FP16/intel/vehicle-attributes-recognition-barrier-0039/FP16/vehicle-attributes-recognition-barrier-0039.xml \n</code></pre></div></div>\n\n<h2 id=\"gpuやncstick使わないから以下スキップ\">GPUやNCStick使わないから以下スキップ</h2>\n\n<!--\n## 「Run a Sample Application」\n\nNCStickなどVPUベースの環境で実行するにはFP16モデルが必要\nデフォルトはFP32\n\nFP16: 16bit浮動小数点\nFP32: 32bit浮動小数点\n====\nmkdir ~/squeezenet1.1_FP16\ncd ~/squeezenet1.1_FP16\npython3 /opt/intel/openvino/deployment_tools/model_optimizer/mo.py --input_model ~/openvino_models/models/FP32/classification/squeezenet/1.1/caffe/squeezenet1.1.caffemodel --data_type FP16 --output_dir .\n\n====\n\n\n\n\n./classification_sample_async -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/squeezenet1.1_FP16/squeezenet1.1.xml -d CPU\n-->\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PythonでIntel NCStick2</title>\n  </head>\n  <body>\n    <header>\n      <h1>PythonでIntel NCStick2</h1>\n      <p>PythonでIntel NCStick2を操作する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"事前準備\">事前準備</h1>\n<p>何はなくともPythonが必要。<br />\n実際には3.7.4を使用して動作確認。</p>\n\n<p>Pythonはpyenvでインストールしておくのが便利。インストール方法は \n<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a> を参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\npyenvとの相性が悪いらしく、pyenvで3.7.xがインストールされていると\n(python3.7コマンド自体は存在するので;実行自体はエラーで返ってくるが)、\nsetupvars.shでPYTHONPATHにpython3.7用pathが設定されてしまう。\nプログラム中で<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>でpathを追加しても、sys.pathの末尾に追加されてしまい、\n先に設定された3.7用モジュールがインポートされてしまう。\nもし、他のバージョンのpythonで実行する場合は<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">sys.path.insert</code>で\npathの先頭に追加するようにしないといけないようだ(試してないけど)。</p>\n\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n    <span class=\"err\">↓</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>ということで、下のプログラムソースの<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>の行は不要。</p>\n</blockquote>\n\n<h2 id=\"モジュールのインストール\">モジュールのインストール</h2>\n\n<p>必要なモジュール類をインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgfortran-6-dev\npip <span class=\"nb\">install </span>numpy\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h2 id=\"ワークディレクトリ\">ワークディレクトリ</h2>\n\n<p>色々共通で使いたいサイズのでっかいファイルがあるので、ワークディレクトリを以下の構成で作成しておく。<br />\n以降のopenVINO関連の投稿もこのディレクトリ構成を使うようにする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># C++プログラム湯尾</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++\n<span class=\"c\"># pythonプログラム用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/python\n<span class=\"c\"># モデルデータ用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP16\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP32\n</code></pre></div></div>\n\n<h1 id=\"参考\">参考</h1>\n\n<p><del>パクった</del> 参考にしたのは以下のあたり<br />\n解説や実行方法などはこっちを参照してちょ(相変わらずの他力本願ぶり…))</p>\n\n<ul>\n  <li><a href=\"http://jellyware.jp/openvino/\">JELLYWARE ゼロから学ぶディープラーニング推論</a>\n    <ul>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c07_ie_emotion.html\">Inference Engineを学んで感情分類</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c08_face_detection.html\">リアルタイム顔検出</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c09_emotion_app.html\">リアルタイム感情分析アプリ</a></li>\n    </ul>\n  </li>\n</ul>\n\n<p>顔検出+感情分類の参照元はカメラキャプチャした画像を処理しているけど、手元に適当なカメラがなかったので、JPEGファイルで実行するようにしてある(こっちの方が余計な処理なくて分かりやすいかな、と思ったのもある)。</p>\n\n<h1 id=\"感情分類\">感情分類</h1>\n\n<p>感情分類のプログラムを試す。</p>\n\n<h3 id=\"準備\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/emotions-recognition-retail-0003/FP16/emotions-recognition-retail-0003\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する顔画像(顔部分のみ切り出し)をPHOTO/face.jpgとして保存しておく。</p>\n\n<h3 id=\"プログラム\">プログラム</h3>\n\n<p>試したソースはこちら。<br />\nPCのubuntuで実行するための処理も追加済み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/face.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 結果取り出し\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>\n<span class=\"c1\"># 結果の最大値を持つインデックスを取得\n</span><span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 結果表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">結果'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">index_max</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"c1\"># 結果の詳細表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">詳細'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'スコア:</span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出\">顔検出</h1>\n\n<p>顔検出のプログラムを試す。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-1\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-1\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n\n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-1\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_detect.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_detect.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_detect.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出感情分類\">顔検出+感情分類</h1>\n\n<p>上の2つを合体させ、顔検出した結果に感情分類を実行する。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-2\">準備</h3>\n\n<p>モデルデータは上の2つをそのまま使用。</p>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-2\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出 + 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n# 日本語表示にはPillow使うとかしないといけないので、英語で。\n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# バウンティングボックスとラベルを表示する関数\n</span><span class=\"k\">def</span> <span class=\"nf\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ラベル領域サイズ\n</span>    <span class=\"n\">LABEL_W</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">12</span>    <span class=\"c1\"># 等幅フォントじゃないので正確ではないけど、大体こんな感じ\n</span>    <span class=\"n\">LABEL_H</span> <span class=\"o\">=</span> <span class=\"mi\">14</span>                <span class=\"c1\"># こっちもトライアンドエラーで微調整\n</span>    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">IMAGE_W</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">IMAGE_H</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># バウンディングボックス表示 \n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ラベル表示位置(X)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">IMAGE_W</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">IMAGE_W</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_W</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">xmin</span>\n    \n    <span class=\"c1\"># ラベル表示位置(Y)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span>\n    \n    <span class=\"c1\"># 文字列背景描画(塗りつぶし)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">label_x</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 文字列描画(座標は文字の左下)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX_SMALL</span><span class=\"p\">,</span> <span class=\"mf\">0.8</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n    \n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。特にminは補正しないとエラーになる\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 顔領域のみ切り出し \n</span>    <span class=\"n\">frame_face</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">[</span> <span class=\"n\">ymin</span><span class=\"p\">:</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">:</span><span class=\"n\">xmax</span> <span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 入力データフォーマットへ変換 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame_face</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span>   <span class=\"c1\"># サイズ変更 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">img_face</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img_face</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>    \n    <span class=\"c1\"># 推論実行 \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img_face</span><span class=\"p\">})</span>\n    \n    <span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>    \n    <span class=\"c1\"># 出力値が最大のインデックスを得る \n</span>    <span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"c1\"># print(list_emotion[index_max])\n</span>    <span class=\"n\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-2\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<h1 id=\"考察\">考察</h1>\n\n<p>基本パターンはこんな感じ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># モジュールのロード\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># 初期化\n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"s\">\"MYRIAD\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み\n</span><span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"s\">'xmlファイル'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"s\">'binファイル'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 推論実行 \n# imgは入力データ、Numpy配列 ndarray型\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># outが出力データ、Numpy配列 ndarray型\n</span>\n</code></pre></div></div>\n\n<p>入出力データの並びは読み込んだモデルに依存する。<br />\n入力データのサイズやRGB並び順などを合わせる。<br />\n(モデルに入力する際にリサイズすれば、元の画像ファイルのサイズは任意で良い。)<br />\n出力データはそのままでは「何のこっちゃ?」なので、きちんと整形してやる必要がある。</p>\n\n<p>ここに学習済みデータが色々登録されているらしい。<br />\n<a href=\"https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html\">https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html</a></p>\n\n<p>TensorflowやCaffeで作成した学習済みデータを変換することもできるらしいが、やり方はこれから調査。</p>\n\n<h1 id=\"参考情報\">参考情報</h1>\n<p><a href=\"https://software.intel.com/en-us/articles/OpenVINO-RelNotes\">openVINO toolkit リリースノート</a><br />\n<a href=\"https://git.uni-paderborn.de/rnagle/dldt/tree/noctua_plugin_develop\">openVINO toolkit リポジトリ</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その9)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その9)</h1>\n      <p>Node-REDのメモ 応用編 Google spreadsheet Read</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGoogle spreadsheet からデータを取得したときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><strong>その8</strong> に従って準備済みであるものとする。</p>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で作成済みの認証情報を選択するか、「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に操作対象のスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:zzz」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n          <li>Rangeのフォーマットはシート名!開始セル:終了セル\n            <ul>\n              <li>開始セルと終了セルを両方省略することは可能(片方のみ省略は不可のよう)。<br />\nこの場合、シート全体が取得される。ただし、↑のように特定のシート名はダメかもしれない。</li>\n              <li>開始セル/終了セルはカラム名と行番号で構成されるが、カラム名か行番号は省略可能。\nたぶん、こんな感じ。\n                <ul>\n                  <li>開始カラム名を省略するとAが指定されたとみなす</li>\n                  <li>開始行番号を省略すると1が指定されたとみなす</li>\n                  <li>終了カラム名を省略すると最終カラム(zzz?)が指定されたとみなす</li>\n                  <li>終了行番号を省略すると最終行が指定されたとみなす</li>\n                </ul>\n              </li>\n              <li>大きな範囲を指定しても、以降空白セルであった場合は無視される(有効なデータがある範囲だけ読み込まれる)</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n          <li>プロパティ名はシート名_開始セル_終了セル</li>\n          <li>globalに記録しておけば、キャッシュとして使用出来て、なんども同じデータを読まなくて済む、という使い方かな?</li>\n        </ul>\n      </li>\n      <li>\n        <p>「Action」に「Get Data」を選択し、その右は「By line」を選択</p>\n      </li>\n      <li>「Labels」の「First line for labels」を選択しすると、outputの型がDictionaryになる。指定したセル範囲の開始カラム(シート全体の開始カラムではない)がキー名となる。<br />\n 選択しなければ、outputの型がArrayになる</li>\n      <li>「Labels」の「First column for labels」を選択しすると、outputの各要素の型がDictionaryになる。指定したセル範囲の開始行(シート全体の開始行ではない)の内容がキー名となる。<br />\n 選択しなければ、outputの各要素の型がArrayになる</li>\n      <li>\n        <p>この2つ、なんか逆な気もするけど…</p>\n      </li>\n      <li>outputにリード結果が入る。とりあえず「msg」を選択し、「_output」にしておく\n内容は「Labels」の設定内容によって変わる</li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>設定内容と取得内容の関係はよくワカランので、色々試してみてください。<br />\n現実的には、細かくデータを取得してどうこうするより、シート全体を取得して処理するような使い方になるのかな??</p>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、スプレッドシートの内容が取得されるハズ。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"5eb2475f.ea747\",\n        \"type\": \"tab\",\n        \"label\": \"spreadsheet_read\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"60d62f37.80a8a\",\n        \"type\": \"inject\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"bba510f2.5bb2d8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e183b4f0.c372f\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"37bd743e.1ca96c\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"bba510f2.5bb2d8\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"spreadsheet read\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:zzz\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"get\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": true,\n        \"fields\": \"all\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"\",\n        \"output\": \"_output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 290,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"e183b4f0.c372f\"\n            ],\n            [\n                \"37bd743e.1ca96c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その8)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その8)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Google spreadsheet</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをGoogle spreadsheet に記録するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"google-spreadsheet用ノードのインストール\">Google spreadsheet用ノードのインストール</h2>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-contrib-viseo-google-」と入力</li>\n  <li>下に検索結果が出るので、「node-red-contrib-viseo-google-authentication」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら続けて「node-red-contrib-viseo-google-spreadsheet」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h2 id=\"googleの準備\">Googleの準備</h2>\n\n<p><a href=\"https://techblog.lclco.com/entry/2018/11/30/120000\">具体的な手順はこちらを参考にしてくだされ。</a> (コードの実装の手前まで)  <br />\nただし、<span style=\"color: red; \">有効にするAPI</span>は「Google Drive API」ではなく、「<span style=\"color: red; \">Google Sheets API</span>」なので、注意!!</p>\n\n<h3 id=\"認証情報の作成\">認証情報の作成</h3>\n\n<ul>\n  <li><a href=\"https://console.developers.google.com/project\">Google Developers Console</a> でプロジェクトを作成</li>\n  <li>Google Sheets APIを有効化</li>\n  <li>認証情報(サービスアカウント キー)を作成</li>\n  <li>保存された認証情報の秘密鍵をダウンロード<br />\n  このファイルはセキュリティ上 <strong>超重要</strong> なので、まちがって公開しないように!!!!<br />\n  ・・・・公開して後悔…なんちゃって(^^ゞ</li>\n</ul>\n\n<h3 id=\"記録用スプレッドシートの作成\">記録用スプレッドシートの作成</h3>\n\n<ul>\n  <li><a href=\"https://drive.google.com/drive/u/0/my-drive\">Google Drive</a>から記録するスプレッドシートを作成する(マイドライブからgoogleスプレッドシートを選択すると新規ファイルが作成される)</li>\n  <li>作成されたスプレッドシートに共有ユーザ(サービスアカウントキーのメールアドレス)を追加。権限を編集者、通知のチェックははずしてOKする</li>\n  <li>必要ならシートの追加や名前の変更を行っておく(以下ではシート名が「BME280」になっているものとして説明)</li>\n  <li>1行目に項目名を入れておく。ここではA列から「epoch」「日付」「温度」「湿度」「気圧」としている</li>\n  <li>B列(「日付」の列)を選択し、メニューから「表示形式」→「数値」→「日時」を選択(これをやらないと時刻が見えない))</li>\n  <li>作成されたスプレッドシートのID(URLの docs.google.com/spreadsheets/d/<span style=\"color: red; \">この部分</span>/edit~)をメモしておく</li>\n</ul>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"bme280ノード\">BME280ノード</h3>\n\n<ul>\n  <li><strong>その2</strong>の<strong>BME280を使用するフローを作成する</strong>と同様の手順でBME280ノードを作成する</li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>出力側にFunctionノードを接続\n  コードは以下。<br />\n  あとで時刻を使用しやすいようにエポック時刻で記録するようにしている。<br />\n  また、エポック時刻のままだとスプレッドシーで見たときに日時が分かり難いので、エポック時刻から日時に変更する計算式を入れておく。(ここで直接文字列にすることもできるが)<br />\n  また、Google Sheetsノードの入力はArrayである必要があるようで、Ayyayでラップしておく。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">var</span> <span class=\"nx\">date</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">epoch</span> <span class=\"o\">=</span> <span class=\"nx\">date</span><span class=\"p\">.</span><span class=\"nx\">getTime</span><span class=\"p\">();</span>\n<span class=\"c1\">// msg.payload.date  = date.toString();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">date</span>  <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">=indirect(\"R[0]C[-1]\", false) / (1000*60*60*24) + (9/24) + DATE(1970, 1, 1)</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">];</span>\n\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に上でメモっておいたスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:z」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>set dataのときは使用されないようだ</li>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n        </ul>\n      </li>\n      <li>「Action」に「Set Data」を選択し、その右は「Append」を選択</li>\n      <li>「input」は「msg」を選択し、「payload」を入力</li>\n      <li>「Fields」で「Select」を選択</li>\n      <li>その下に「key」と入力欄が表示されるので、「epoch」と入力し、「追加」をクリック</li>\n      <li>「date」と入力し、「追加」をクリック</li>\n      <li>「temperature_C」と入力し、「追加」をクリック</li>\n      <li>「humidity」と入力し、「追加」をクリック</li>\n      <li>「pressure_hPa」と入力\n        <ul>\n          <li>このデータの並びが入力のプロパティ名とスプレッドシートのセルの並びに対応する</li>\n        </ul>\n      </li>\n      <li>outputもよー分からんけど、とりあえず「msg」を選択し、「_output」にしておく\n        <ul>\n          <li>set dataのときは処理結果が入るようだ</li>\n          <li>get dataのときはリード結果が入るようだ</li>\n        </ul>\n      </li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>このノードの入力にファンクションノードの出力を接続</li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、温度等を測定、スプレッドシートに送信される。<br />\nスプレッドシートを確認すれば、そのデータが記録されているハズである。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1a4f21c6.53e09e\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+spreadsheet\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"b4e73f33.99aec8\",\n        \"type\": \"Bme280\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 220,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"a54ed898.2a114\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"b74c37d3.63a48\",\n        \"type\": \"inject\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 90,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"b4e73f33.99aec8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a54ed898.2a114\",\n        \"type\": \"function\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"データ整形\",\n        \"func\": \"var date = new Date();\\nmsg.payload.epoch = date.getTime();\\n// msg.payload.date  = date.toString();\\n// msg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\",false)/1000/60/60/24 + 9/24 + DATE(1970,1,1)';\\nmsg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\", false) / (1000*60*60*24) + (9 / 24) + DATE(1970, 1, 1)';\\n\\nmsg.payload = [msg.payload];\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 390,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"6a4f8cc4.882e54\",\n                \"adad9a.88697a68\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6a4f8cc4.882e54\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:z\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"set\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": false,\n        \"fields\": \"select\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"epoch\",\n            \"date\",\n            \"temperature_C\",\n            \"humidity\",\n            \"pressure_hPa\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"payload\",\n        \"output\": \"__output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 620,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"93209cb1.cd86\"\n            ],\n            [\n                \"9a8717a8.88bae8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"93209cb1.cd86\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9a8717a8.88bae8\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 220,\n        \"wires\": []\n    },\n    {\n        \"id\": \"adad9a.88697a68\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 850,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node.jsでGoogle spreadsheet にデータを書き込む</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node.jsでGoogle spreadsheet にデータを書き込む</h1>\n      <p>Node.jsでGoogle spreadsheet にデータを書き込む</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Node.jsでGoogle spreadsheet にデータを書き込む方法。<br />\nサンプルプログラムを<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>に置きました。</p>\n\n<p>Google Drive API を サービスアカウントで操作する方法を取りました。</p>\n\n<p>OAuth認証を使う方法は事前準備がめんどっちいので、パス。<br />\nAPIキー認証はリードはできたけど、ライトが出来んかった。あと、シートを公開しないといけないが、やな感じだった。</p>\n\n<h1 id=\"詳細\">詳細</h1>\n\n<p>詳細は\n<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>\nのREADME おひび ソースコードを参照してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その7)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その7)</h1>\n      <p>Node-REDのメモ 応用編 GPIO+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIOの入出力データをWebsocketで飛ばして、Dashboardから操作/Dashboardで表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"gpio入出力データをwebsocketで送受信raspberrypi\">GPIO入出力データをWebsocketで送受信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>RaspberryPiでGPIO出力</strong>、<strong>RaspberryPiでGPIO入力</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>、<strong>Websocketでデータを受信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、GPIO入力データをそのまま送信すると、受け取り側で「0はON?それともOFF?」となってしまうので、GPIO入力の0/1をON/OFFの文字列に変換するファンクションノードを追加している。\n  また、GPIO出力側も同様に、送信側から送られてきたON/OFFの文字列をGPIO出力データの1/0の数値に変換するファンクションノードを挿入している。<br />\n  ターゲットボードの正論理/負論理が変更になった場合はこれらのファンクションノードで調整すれば良い。</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"6e229d5a.774af4\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"109b9bce.e015e4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 730,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4834db5b.5c24d4\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": true,\n        \"x\": 190,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"3ff59514.52c732\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7d90bda.d7b4b8\",\n        \"type\": \"websocket in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"47e24d88.c603e4\",\n        \"x\": 280,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"a38bd8a1.0a5bd8\",\n                \"5e99ea44.cfdac4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9bc37a7.e1e9808\",\n        \"type\": \"websocket out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"c4985621.1edb48\",\n        \"x\": 830,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"a38bd8a1.0a5bd8\",\n        \"type\": \"debug\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 730,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3ff59514.52c732\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"1/0→OFF/ON\",\n        \"func\": \"if (msg.payload) {\\n    msg.payload = 'OFF';\\n}\\nelse {\\n    msg.payload = 'ON';\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"9bc37a7.e1e9808\",\n                \"a38bd8a1.0a5bd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5e99ea44.cfdac4\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"OFF/ON→0/1\",\n        \"func\": \"if (msg.payload == 'OFF') {\\n    msg.payload = 0;\\n}\\nelse {\\n    msg.payload = 1;\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"109b9bce.e015e4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47e24d88.c603e4\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/led0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"c4985621.1edb48\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/sw0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからgpio入出力データを送受信サーバ\">WebsocketからGPIO入出力データを送受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータ送信(サーバ)</strong>、<strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノードに<strong>その4</strong> の <strong>Dashboard のUIを作成する(ボタン)</strong>、<strong>Dashboardでテキストを表示する</strong>で作成したノードを接続すれば良い。</li>\n</ul>\n\n<p>この状態でRaspberryPi側でスイッチをON/OFFすると、Dashboardの「SW」の文字列のON/OFFが切り替わる。\nまた、DashboardのLLED_ON/LED_OFFのボタンをクリックすると、LEDが点灯/消灯する</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"ca6a740f.4d43b8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_GPIO\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"ac19aeee.9f8f5\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 260,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"2098e31e.e6832c\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 270,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8db70b6.86a1178\",\n        \"type\": \"ui_text\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 610,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f45af19.269e\",\n        \"type\": \"websocket in\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"fad64a63.6141a\",\n        \"client\": \"\",\n        \"x\": 270,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"8db70b6.86a1178\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"299e8287.226e6e\",\n        \"type\": \"websocket out\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"d7b33218.4a1f28\",\n        \"client\": \"\",\n        \"x\": 630,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"95b08556.d2cce\",\n        \"type\": \"debug\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 610,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"b7e42e0e.52bdb\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"1b4acf7b.a194c9\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"fad64a63.6141a\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/sw0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"d7b33218.4a1f28\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/led0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"1b4acf7b.a194c9\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ3\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian SDカードイメージファイルの縮小</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian SDカードイメージファイルの縮小</h1>\n      <p>Raspbian SDカードイメージファイルの縮小</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2020/10/25/Jetson_nano_backup.html\">Jetson nano のSDカードをバックアップする</a> \nに改訂版を公開しました。そちらを参照してください。</p>\n\n<h1 id=\"イメージファイルの縮小\">イメージファイルの縮小</h1>\n\n<h3>『イメージファイルの縮小』はUbuntuで実行することを前提に書いてあります。</h3>\n\n<p>SDカードに作成した、RaspberryPiのオリジナルのカスタムブートディスク\n(<a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\">Raspbian Busterのインストール</a>、\n<a href=\"/memoBlog/2019/09/13/raspbian_buster_2.html\">Raspbian Buster Lite版のインストール</a>参照)\nは、イメージファイルにバックアップしておくと、\n再度カスタマイズ作業を行わなくても同じ環境を作成できる。</p>\n\n<p>ただ、このイメージファイルはSDカードを丸ごとファイル化するので、元のSDカードより小さなSDカードにコピーできない。<br />\n(スペック上同じ容量のSDカードでも微妙にサイズが違ったりするので入らないことがある)</p>\n\n<p>そこで、イメージファイルを縮小しておけば、小さなSDカードにもコピーできる(コピー時間も短縮できて一石二鳥)。<br />\nこのとき、ディスクイメージ内部のパーティション情報/ファイルシステム情報をきちんと縮小処理しておかないと\nファイルシステムエラーになってしまうので、注意が必要。</p>\n\n<p>今回はSDカードから作成したイメージファイルを<strong>Ubuntuで</strong>縮小処理するスクリプトを書いてみた。<br />\nとりあえず、手元の環境では動いているが、詳細評価したわけではないので、\n実行する場合は自己責任で。</p>\n\n<p>また、途中<strong>エラーチェックは行っていない</strong>ので、エラーが発生していないか、実行結果を注意深く確認すること。</p>\n\n<h2 id=\"virtualbox-共有フォルダのマウント\">Virtualbox 共有フォルダのマウント</h2>\n\n<p>SDカードのイメージファイルは大きいので、共有フォルダを使ってWindows側のフォルダをアクセスできるようにしておけばディスク領域を圧迫しなくて済む。<br />\nVirtualbox側で共有フォルダ「Share」を作成済みで、/Shareディレクトリにマウントする場合は以下のコマンドで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> vboxsf Share /Share/\n</code></pre></div></div>\n\n<h2 id=\"ツールのインストール\">ツールのインストール</h2>\n\n<p>イメージファイル内のパーティションをそれぞれloopデバイスに割り当てるツールを使用する。<br />\n以下のコマンドでインストールできる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>kpartx\n</code></pre></div></div>\n\n<h2 id=\"スクリプト\">スクリプト</h2>\n\n<p>以下のスクリプトを適当な名前(例えば<code class=\"language-plaintext highlighter-rouge\">shrink_img.sh</code>)で保存し、実行する(<code class=\"language-plaintext highlighter-rouge\">bash shrink_img.sh</code>)。<br />\n実行する前に使用するファイル名を設定すること。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: left\">変数</th>\n      <th style=\"text-align: left\">内容</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: left\">WORK_IMG_FILE</td>\n      <td style=\"text-align: left\">作業用イメージファイルのファイル名</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: left\">NEW_IMG_FILE</td>\n      <td style=\"text-align: left\">小さくしたイメージファイルのファイル名</td>\n    </tr>\n  </tbody>\n</table>\n\n<p>WORK_IMG_FILE で指定したファイルは書き変えられるので、オリジナルのイメージファイルは 別途残しておくこと。</p>\n\n<p>内部で<code class=\"language-plaintext highlighter-rouge\">sudo</code>を実行しているので、パスワードを聞かれたら入力する。</p>\n\n<p>途中、『警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?』と聞かれたら「y」を入力する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># イメージファイル</span>\n<span class=\"nv\">WORK_IMG_FILE</span><span class=\"o\">=</span>/Share/tmp.img            <span class=\"c\"># 作業ファイル</span>\n<span class=\"nv\">NEW_IMG_FILE</span><span class=\"o\">=</span>/Share/shrink.img          <span class=\"c\"># 縮小した(作成する)ファイル</span>\n\n<span class=\"c\"># イメージファイルをマッピング(マッピング済みでも問題ない) </span>\n<span class=\"c\"># 前回の操作が終わるのを待つため-sを付けておく</span>\n<span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-asv</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span>\n\n<span class=\"c\"># loopデバイス名を取得</span>\n<span class=\"c\"># 前回の操作が終わるのを待つため-sを付けておく</span>\n<span class=\"nv\">tmp_var</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-ls</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">LOOP_DEV</span><span class=\"o\">=</span>/dev/mapper/<span class=\"k\">${</span><span class=\"nv\">tmp_var</span><span class=\"p\">[6]</span><span class=\"k\">}</span>          <span class=\"c\"># 結果の位置は決め打ちで(姑息だけど)</span>\n\n<span class=\"c\"># 要求するブロックサイズの取得</span>\n<span class=\"nv\">tmp_var</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>resize2fs <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">req_fs_block</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">tmp_var</span><span class=\"p\">[-1]</span><span class=\"k\">}</span>                 <span class=\"c\"># サイズは結果の最後に入っている</span>\n\n<span class=\"c\"># パーティション情報の取得</span>\n<span class=\"nv\">part_info</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>parted <span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> unit B print<span class=\"sb\">`</span>\n<span class=\"c\"># 1行毎に分割</span>\n<span class=\"nv\">line</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">part_info</span><span class=\"p\">//;/ </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># ext4のパーティション番号を探す</span>\n<span class=\"nv\">part_number</span><span class=\"o\">=</span>0\n<span class=\"nv\">part_start</span><span class=\"o\">=</span>0\n<span class=\"nv\">target_type</span><span class=\"o\">=</span><span class=\"s2\">\"ext4\"</span>\n<span class=\"k\">for </span>l <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span> <span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各要素に分割</span>\n    <span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">l</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n    <span class=\"nv\">elm_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[0]</span><span class=\"k\">}</span>             <span class=\"c\"># パーティション番号</span>\n    <span class=\"nv\">elm_start</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[1]//B/</span><span class=\"k\">}</span>          <span class=\"c\"># ついでに最後のBを取り除いておく</span>\n    <span class=\"nv\">elm_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>               <span class=\"c\"># ファイルシステムタイプ</span>\n    <span class=\"c\"># echo $elm_number $elm_start $elm_type</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n        if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n            <span class=\"c\"># 対象のパーティションが見つかった</span>\n            <span class=\"nv\">part_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_number</span><span class=\"k\">}</span>\n            <span class=\"nv\">part_start</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_start</span><span class=\"k\">}</span>\n            <span class=\"nb\">break\n        </span><span class=\"k\">fi\n    fi\ndone\nif</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"o\">=</span> 0 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"s2\">\"のパーティションが見つかりませんでした\"</span>\n<span class=\"k\">else</span>\n    <span class=\"c\"># 新しいパーティション終了位置を計算</span>\n    <span class=\"nv\">new_fs_block</span><span class=\"o\">=</span><span class=\"k\">$((</span>req_fs_block <span class=\"o\">+</span> <span class=\"m\">100000</span><span class=\"k\">))</span>             <span class=\"c\"># 少し余裕(100000block=390MB)を持たせる</span>\n    <span class=\"nv\">new_fs_byte</span><span class=\"o\">=</span><span class=\"k\">$((</span>new_fs_block <span class=\"o\">*</span> <span class=\"m\">4096</span><span class=\"k\">))</span>                <span class=\"c\"># byteに換算</span>\n    <span class=\"nv\">part_end</span><span class=\"o\">=</span><span class=\"k\">$((</span>part_start <span class=\"o\">+</span> new_fs_byte <span class=\"o\">+</span> <span class=\"m\">2048</span><span class=\"k\">))</span>       <span class=\"c\"># さらに少し余裕を持たせる</span>\n    <span class=\"nv\">img_size_mb</span><span class=\"o\">=</span><span class=\"k\">$((</span><span class=\"o\">(</span>part_end <span class=\"o\">/</span> <span class=\"o\">(</span><span class=\"m\">1024</span> <span class=\"o\">*</span> <span class=\"m\">1024</span><span class=\"k\">))</span> + 10<span class=\"o\">))</span>    <span class=\"c\"># MBに換算 ついでにしつこいくらいに余裕を持たせる </span>\n\n    <span class=\"nb\">set</span> <span class=\"nt\">-x</span>          <span class=\"c\">#--------------------------------------</span>\n\n    <span class=\"c\"># ファイルシステムとパーティションの縮小</span>\n    <span class=\"nb\">sudo </span>e2fsck <span class=\"nt\">-f</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span> \n    <span class=\"nb\">sudo </span>resize2fs <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">new_fs_block</span><span class=\"k\">}</span>\n    parted <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> unit B resizepart <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">part_end</span><span class=\"k\">}</span>\n\n    <span class=\"c\"># 縮小コピー</span>\n    <span class=\"nb\">dd </span><span class=\"k\">if</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> <span class=\"nv\">of</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">NEW_IMG_FILE</span><span class=\"k\">}</span> <span class=\"nv\">count</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">img_size_mb</span><span class=\"k\">}</span> <span class=\"nv\">bs</span><span class=\"o\">=</span>1M\n\n    <span class=\"nb\">set</span> +x          <span class=\"c\">#--------------------------------------</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># マッピング解除</span>\n<span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-d</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span>\n \n</code></pre></div></div>\n\n<h1 id=\"新しいイメージファイルでブートsdを作る\">新しいイメージファイルでブートSDを作る</h1>\n\n<p>縮小したイメージファイルから作成したSDカードはSDカードの容量をすべて使用できるようになっていない。<br />\nそこで、コピーしたSDカードでブートした後、パーティションを拡張する必要がある。</p>\n\n<h2 id=\"sdカードへの書き込みは通常通り\">SDカードへの書き込みは通常通り</h2>\n\n<h2 id=\"書き込んだsdカードでブートする\">書き込んだSDカードでブートする</h2>\n\n<h2 id=\"sdカードのパーティション拡張\">SDカードのパーティション拡張</h2>\n\n<p>色々手順がめんどっちいので、スクリプト作成してみた。<br />\nとりあえず、手元の環境では動いているが、詳細評価したわけではないので、\n実行する場合は自己責任で。</p>\n\n<p>以下のスクリプトを適当な名前(例えば<code class=\"language-plaintext highlighter-rouge\">expand_partition.sh</code>)で保存し、実行する(<code class=\"language-plaintext highlighter-rouge\">bash expand_partition.sh</code>)<br />\n成功したらリブートすること。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># ターゲットのデバイス</span>\n<span class=\"nv\">target_device</span><span class=\"o\">=</span>/dev/mmcblk0\n\n<span class=\"c\"># パーティション情報の取得</span>\n<span class=\"nv\">part_info</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>parted <span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span> unit s print free<span class=\"sb\">`</span>\n\n<span class=\"c\"># 1行毎に分割</span>\n<span class=\"nv\">line</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">part_info</span><span class=\"p\">//;/ </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 最終行</span>\n<span class=\"c\"># declare -i last_index=${#line[@]}-1</span>\n<span class=\"c\"># last_line=${line[$last_index]}</span>\n<span class=\"nv\">last_line</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[</span><span class=\"k\">$((${#</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span><span class=\"o\">-</span><span class=\"m\">1</span><span class=\"k\">))</span><span class=\"p\">]</span><span class=\"k\">}</span>\n\n<span class=\"c\"># :で区切られた各要素に分割</span>\n<span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">last_line</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 変数名付け替え</span>\n<span class=\"c\"># last_number=${elm[0]}</span>\n<span class=\"c\"># last_start=${elm[1]}</span>\n<span class=\"nv\">last_end</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[2]</span><span class=\"k\">}</span>\n<span class=\"c\"># last_size=${elm[3]}</span>\n<span class=\"nv\">last_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>\n\n<span class=\"c\"># 確認</span>\n<span class=\"c\"># echo last_number=  $last_number</span>\n<span class=\"c\"># echo last_start=   $last_start</span>\n<span class=\"c\"># echo last_end=     $last_end</span>\n<span class=\"c\"># echo last_size=    $last_size</span>\n<span class=\"c\"># echo last_type=    $last_type</span>\n\n<span class=\"c\"># 最後のパーティションがfreeか確認</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">last_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> free <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># ext4のパーティション番号を探す</span>\n    <span class=\"nv\">part_number</span><span class=\"o\">=</span>0\n    <span class=\"nv\">target_type</span><span class=\"o\">=</span><span class=\"s2\">\"ext4\"</span>\n    <span class=\"k\">for </span>l <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span> <span class=\"p\">;</span> <span class=\"k\">do</span>\n        <span class=\"c\"># 各要素に分割</span>\n        <span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">l</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n        <span class=\"nv\">elm_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[0]</span><span class=\"k\">}</span>\n        <span class=\"nv\">elm_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n            <span class=\"c\"># echo $elm_number $elm_type</span>\n            <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n                </span><span class=\"nv\">part_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_number</span><span class=\"k\">}</span>\n                <span class=\"nb\">break\n            </span><span class=\"k\">fi\n        fi\n    done\n    if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"o\">=</span> 0 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"ext4のパーティションが見つかりませんでした\"</span>\n    <span class=\"k\">else</span>\n        <span class=\"c\"># リサイズの実行</span>\n        <span class=\"nb\">set</span> <span class=\"nt\">-x</span>\n        <span class=\"nb\">sudo </span>parted <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span> resizepart <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">last_end</span><span class=\"k\">}</span>\n        <span class=\"nb\">sudo </span>resize2fs <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span>p2\n        <span class=\"nb\">set</span> +x\n        <span class=\"nb\">echo</span> <span class=\"s2\">\"リブートしてください\"</span>\n    <span class=\"k\">fi\nelse\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"最終パーティションがfreeではありません\"</span>\n<span class=\"k\">fi</span>\n \n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian Buster Lite版のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian Buster Lite版のインストール</h1>\n      <p>Raspbian Buster with desktopのインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspbian Buster Lite」 の 「DownloadZIP」でダウンロードする。<br />\n以下の手順は、RaspberryPi Zero W、「Version: July 2019」 で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>は表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nframebuffer_width=1280\nframebuffer_height=720\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"ロケールやらタイムゾーンやらの設定\">ロケールやらタイムゾーンやらの設定</h1>\n\n<p>日本語表示や時刻を日本時間に設定するための設定を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    4 Localisation Options\n        I1 Change Locale\n            [ ] ja_JP.UTF-8 UTF-8     でスペースを押して[*] にする\n            TABを押して<Ok>を選んでリターン\n                Default locale for~ と聞かれるので、\n                ja_JP.UTF-8          を選択\n                TABを押して<Ok>を選んでリターン\n    4 Localisation Options\n        I2 Change Timezon\n            Asia\n                Tokyo\n    <Finish>\n</code></pre></div></div>\n\n<p>設定変更を有効にするにはrebootが必要。</p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"c\"># export PYENV_ROOT=/proj/.pyenv</span>\n<span class=\"c\"># export PATH=$PYENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(pyenv init -)\"</span>\n<span class=\"c\"># eval \"$(pyenv virtualenv-init -)\"</span>\n\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"c\"># export NODENV_ROOT=/proj/.nodenv</span>\n<span class=\"c\"># export PATH=$NODENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(nodenv init -)\"</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nSSHなら関係ないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"hdmiコンソール用日本語入力表示環境構築\">HDMIコンソール用日本語入力&表示環境構築</h1>\n\n<p>デフォルトのままだと、HDMIコンソールは日本語の入力はおろか、表示もできない。<br />\nそこで、日本語入力&表示環境を整備する。<br />\nHDMIコンソールで日本語を使わないなら本章は設定不要。</p>\n\n<h2 id=\"フォントのインストール\">フォントのインストール</h2>\n\n<p>フォントをインストールしないと表示できないのでまずはフォントのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk \n</code></pre></div></div>\n\n<h2 id=\"ターミナルエミュレータのインストール\">ターミナルエミュレータのインストール</h2>\n\n<p>デフォルトのターミナルは日本語を表示できないので、日本語対応のターミナルエミュレータを使う。<br />\nネット上にはjfbtermを使用する記事が多いが、jfbtermはイマイチらしいのでfbtermを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fbterm\n</code></pre></div></div>\n\n<h2 id=\"日本語変換システムのインストール\">日本語変換システムのインストール</h2>\n\n<p>日本語入力のためのプログラム。Windowsで言うところのMS-IMEやATOKに相当するもの。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>uim-fep uim-anthy\n</code></pre></div></div>\n\n<h2 id=\"fbtermの設定\">fbtermの設定</h2>\n\n<p>fbtermの設定は、 ~/.fbtermrc で行う。<br />\n<strong>HDMIコンソールから</strong> fbtermを一度起動すると ~/.fbtermrc ができるので、設定変更するときはこれを書き換える。<br />\n例えばこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>font-size<span class=\"o\">=</span>18\n</code></pre></div></div>\n\n<p>fbtermを起動したときに<code class=\"language-plaintext highlighter-rouge\">[input] can’t change kernel keymap table ~</code>と表示されるときは以下を実行すると良い。(表示されるだけで実害はないらしい)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>setcap <span class=\"s1\">'cap_sys_tty_config+ep'</span> /usr/bin/fbterm\n</code></pre></div></div>\n\n<p>または、以下でも良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chmod </span>u+s /usr/bin/fbterm\n</code></pre></div></div>\n\n<p>参考: <a href=\"https://qiita.com/mtomoaki_96kg/items/e5a946fd38f7318d3758?fbclid=IwAR2d8ekXNiD9cqvpqycdfinDZMHZ0OcTmaETTsci1UA9T-aDtc3LvfOiaa0\">https://qiita.com/mtomoaki_96kg/items/e5a946fd38f7318d3758?fbclid=IwAR2d8ekXNiD9cqvpqycdfinDZMHZ0OcTmaETTsci1UA9T-aDtc3LvfOiaa0</a></p>\n\n<h2 id=\"uim日本語変換システムの設定\">uim(日本語変換システム)の設定</h2>\n\n<p>uimでCTRL+SPACEでFEPの切り替えの設定。\n~/.uim に以下の内容を記述(なければ新規作成)。<br />\n参考: <a href=\"https://qiita.com/tukiyo3/items/376e3a2895a71ff9bfc7\">https://qiita.com/tukiyo3/items/376e3a2895a71ff9bfc7</a></p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>(define default-im-name 'anthy)\n(define-key generic-on-key? '(\"<Control> \" \"`\"))\n(define-key generic-off-key? '(\"<Control> \" \"`\"))\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n各行のシングルクォーテーションは1個だけ。文字列として区切っている訳ではない。<br />\n余計なシングルクォーテーションを入れると動かなくなるので注意!!</p>\n</blockquote>\n\n<h2 id=\"起動時にfbtermを起動する\">起動時にfbtermを起動する</h2>\n\n<p>起動時にfbtermを起動するには以下を ~/.profile 、 ~/.bashrc に追加</p>\n\n<h3 id=\"profile\">~/.profile</h3>\n\n<p>最後に以下の内容を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"o\">=</span> <span class=\"s2\">\"linux\"</span> <span class=\"o\">]</span>\n<span class=\"k\">then</span>\n<span class=\"c\">#   FBTERM=1 exec fbterm -- uim-fep</span>\n   <span class=\"nv\">FBTERM</span><span class=\"o\">=</span>1 fbterm <span class=\"nt\">--</span> uim-fep\n   <span class=\"nb\">exit\n</span><span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<p>本当はコメントアウトされてる方の exec を使うようにしないといけないが、現状うまく動かないらしい。<br />\n(Strechでは動いていたと思う)<br />\n仕方ないので、fbtermをbashの子プロセスとして実行するようにしてある。<br />\nこれだとうまく動いている(当然、メモリ消費量は増えるけど)。</p>\n\n<p>また、ログアウトの際にCTRL+Dを2回入力しないといけなくなる(fbtermからのexitとbashからのexit)のを回避するため、 fbterm終了時にexitコマンドを実行している。</p>\n\n<h3 id=\"bashrc\">~/.bashrc</h3>\n\n<p>最後に(でなくてもいいけど)、以下を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>linux<span class=\"p\">)</span>\n        <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$FBTERM</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"nb\">export </span><span class=\"nv\">TERM</span><span class=\"o\">=</span>fbterm\n        <span class=\"p\">;;</span>\n    fbterm<span class=\"p\">)</span>\n        <span class=\"c\"># 何もしない</span>\n        <span class=\"p\">;;</span>\n    <span class=\"k\">*</span><span class=\"p\">)</span>\n        <span class=\"c\"># 何もしない</span>\n        <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n</code></pre></div></div>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その6)</h1>\n      <p>Node-REDのメモ MQTT編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでMQTT通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"mqttでデータを送受信\">MQTTでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにmosquitto broker および mosquitto client toolsを使うこととします。<br />\nこれらは以下のコマンドでインストールできます。</p>\n\n<p>Ubuntuで動作確認。RaspberryPiでも大丈夫なはず。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mosquitto mosquitto-clients\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータ送信publish\">MQTTでデータ送信(Publish)</h2>\n\n<p>MQTTでデータを送信してみます</p>\n\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要なら「名前」を設定\n            <ul>\n              <li>省略するとサーバアドレスとポート番号が表示される</li>\n            </ul>\n          </li>\n          <li>「サーバ」 でブローカのアドレス(またはホスト名)を設定(例: PiDev25.local)</li>\n          <li>「ポート」 でポート番号を設定(一般的な設定なら1883のままで大丈夫)</li>\n          <li>SSL/TLS接続を使用する場合は「SSL/TLS接続を使用」のチェックを入れる</li>\n          <li>クライアントIDを指定したい場合は「クライアント」に設定。通常は空欄で大丈夫</li>\n          <li>キープアライブ時間を「キープアライブ時間」に設定</li>\n          <li>「セッションの初期化」?とりあえず初期設定のままで</li>\n          <li>「旧MQTT 3.1のサポート」?とりあえず初期設定のままで</li>\n          <li>「セキュリティ」タブ、「メッセージ」タブの内容は必要なら設定する。設定しなくても大丈夫</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に送信するトピックを設定\n        <ul>\n          <li>省略すると、トリガノードの出力に設定されているtopicが使用される</li>\n        </ul>\n      </li>\n      <li>「QoS」を「0」/「1」/「2」から選択</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される\n            <ul>\n              <li>トピックも省略されている場合はmqttと表示される</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のようにsubscriberコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> 《トピック》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカからすべてのトピック(“#”)を取得するよう指定しています。<br />\n-v 指定により、対象メッセージのトピックも表示されます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> Pidev25.local <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> <span class=\"s2\">\"#\"</span>\n</code></pre></div></div>\n<p>Node-RED側で mqttの送信をトリガするとmosquitto_subの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>test_data 0\ntest_data 1\ntest_data true\ntest_data false\ntest_data 文字列\ntest_data {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"f580f01a.f771f\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_publish\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"33450bad.82764c\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ea6d9236.74e038\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d7baa4c.08385\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"82148e63.4b97e\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d0b1ac7f.0ac0b\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7e6180b5.f29098\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"test_data\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6f26fe46.a01f58\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"バッファ\",\n        \"topic\": \"test_data\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 140,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d5a5b2db.83462\",\n        \"type\": \"debug\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 500,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"e6218cda.844308\",\n        \"type\": \"mqtt out\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"\",\n        \"qos\": \"\",\n        \"retain\": \"\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 570,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータを受信subscribe\">MQTTでデータを受信(subscribe)</h2>\n\n<p>MQTTでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に受信するトピックを設定\n        <ul>\n          <li>すべてのトピックを受信するには#を設定</li>\n          <li>省略することはできない</li>\n        </ul>\n      </li>\n      <li>「QoS」を設定</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>デプロイ後、ターミナル or コンソールで以下のようにpublisherコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-t</span> 《トピック》 <span class=\"nt\">-m</span> 《メッセージ》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカへ、トピック test_data で、メッセージ test を送信しています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> PiDev25.local <span class=\"nt\">-t</span> <span class=\"s2\">\"test_data\"</span> <span class=\"nt\">-m</span> <span class=\"s2\">\"test\"</span>\n</code></pre></div></div>\n\n<p>コマンドを実行するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"13f22fdd.2e009\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_subscribe\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1760f49a.fd2d3b\",\n        \"type\": \"debug\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 420,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"30229cea.13aba4\",\n        \"type\": \"mqtt in\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"#\",\n        \"qos\": \"2\",\n        \"datatype\": \"auto\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 150,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"1760f49a.fd2d3b\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>モバイル ホットスポットでRaspberryPiをネットに接続</title>\n  </head>\n  <body>\n    <header>\n      <h1>モバイル ホットスポットでRaspberryPiをネットに接続</h1>\n      <p>Windows10のモバイル ホットスポットでRaspberryPiをネットに接続する手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>お出かけ先でも RaspberryPi を、常に同じWi-Fi AP で接続できるような方法を考える。</p>\n\n<p>一つの案として、Windows10のモバイル ホットスポットを経由して RaspberryPi をネットワークにつなげる。\nこの場合、PCと RaspberryPi はセットで持ち歩くものと考えれば、 \nRaspberryPi は常にPCのモバイル ホットスポットのAPに接続すれば良いことになる。</p>\n\n<p>一つのWi-Fiアダプタを通常接続用とモバイル ホットスポット用でシェアすることはできないので、<br />\nUSBドングルを追加して使用する。</p>\n\n<ul>\n  <li>内蔵Wi-Fi → 通常接続用</li>\n  <li>USBドングル → モバイル ホットスポット用</li>\n</ul>\n\n<p>USBドングルは BUFFALO WLI-UC-GNM2S で確認\nWindowsはWindows10 ver.1903 で確認</p>\n\n<h1 id=\"windows側の事前準備\">Windows側の事前準備</h1>\n\n<p>内蔵Wi-Fi は 通常通り ルータに接続しておく。<br />\nこのとき、どのルータに繋いでいるかは考慮しなくて良いはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPCのルータ接続ダウン時、モバイル ホットスポットは使えない</p>\n</blockquote>\n\n<p>USBドングル BUFFALO WLI-UC-GNM2S はあらかじめドライバをインストールしてWindowsに認識させておく。<br />\n接続先は設定しなくて大丈夫。</p>\n\n<ul>\n  <li>Windowsで「設定」→「ネットワークとインターネット」→「モバイル ホットスポット」を開く\n    <ul>\n      <li>「インターネット接続を共有する」で、ルータに接続しているアダプタを選択</li>\n      <li>「Wi-Fi」を選択</li>\n      <li>「ネットワーク名」と「ネットワーク パスワード」をメモっておく</li>\n      <li>この状態で一番上のスイッチを「オン」にする\n        <ul>\n          <li>スイッチがアクティブカラーになったら準備完了</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"raspberrypi側の事前準備\">RaspberryPi側の事前準備</h1>\n\n<h2 id=\"etcwpa_supplicantwpa_supplicantconf-の修正\">/etc/wpa_supplicant/wpa_supplicant.conf の修正</h2>\n\n<p>モバイル ホットスポットか通常のルータか、どちらか生きてる方に接続にいくように設定する。<br />\n(いつもの環境ならモバイル ホットスポット使わなくて良いように)</p>\n\n<p>以下の「モバイルホットスポットのSSID名」「パスワード」は<br />\n上記でメモった「ネットワーク名」と「ネットワーク パスワード」を記入する。<br />\nダブルクォーテーションで囲むのを忘れないこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">ctrl_interface</span><span class=\"o\">=</span><span class=\"nv\">DIR</span><span class=\"o\">=</span>/var/run/wpa_supplicant <span class=\"nv\">GROUP</span><span class=\"o\">=</span>netdev\n<span class=\"nv\">update_config</span><span class=\"o\">=</span>1\n<span class=\"nv\">country</span><span class=\"o\">=</span>JP\n\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"デフォルトのSSID名\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span><span class=\"s2\">\"パスワード\"</span>\n        <span class=\"nv\">priority</span><span class=\"o\">=</span>3\n<span class=\"o\">}</span>\n\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"モバイルホットスポットのSSID名\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span><span class=\"s2\">\"パスワード\"</span>\n        <span class=\"nv\">priority</span><span class=\"o\">=</span>5\n<span class=\"o\">}</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npriority設定値は大きい方が優先される。<br />\n上記の場合、モバイルホットスポットが生きていればそちらが優先される</p>\n</blockquote>\n\n<h2 id=\"ap再接続用スクリプト\">AP再接続用スクリプト</h2>\n\n<p>モバイル ホットスポット の Enable/Disable を切り替えたとき、<br />\n(RaspberryPiを起動してからモバイルホットスポットを有効にするのを忘れていたことに気がついたなど)\nRaspberryPiのネットワーク設定は自動的に新しい環境に切り替わらない。<br />\nコマンドをチマチマ入力するのも面倒なので、コマンド イッパツで再接続処理するようにしておく。</p>\n\n<p>まず、 ~/wifi_reconnect.sh を以下の内容で作成する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo </span>wlan0 down..\n<span class=\"nb\">sudo </span>ifconfig wlan0 down\n<span class=\"nb\">sleep </span>1\n\n<span class=\"nb\">echo </span>wlan0 up..\n<span class=\"nb\">sudo </span>ifconfig wlan0 up\n<span class=\"nb\">sleep </span>3\n\n<span class=\"nb\">echo </span>re-get IP address...\n<span class=\"nb\">sudo </span>dhcpcd <span class=\"nt\">-k</span>\n<span class=\"nb\">sleep </span>3\n<span class=\"nb\">sudo </span>dhcpcd <span class=\"nt\">-n</span>\n<span class=\"nb\">sleep </span>15\n\n<span class=\"nb\">echo </span>DONE!!\n</code></pre></div></div>\n\n<p>スクリプトファイルに実行属性をつける。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod</span> +x ~/wifi_reconnect.sh\n</code></pre></div></div>\n\n<p>再接続したいタイミングで <code class=\"language-plaintext highlighter-rouge\">~/wifi_reconnect.sh</code>を実行する。<br />\nDHCPのアドレス確定時間分を待っているので、コマンド実行には20秒強かかる。</p>\n\n<h1 id=\"raspberrypiの起動\">RaspberryPiの起動</h1>\n\n<p>上記の準備が整ったら、RaspberryPiを起動する。<br />\n起動後、<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>(他のコマンドでも良いけど)でIPアドレスを確認する。</p>\n\n<ul>\n  <li>192.168.137.XXX になっていればOK</li>\n</ul>\n\n<p>また、PC側で「設定」→「ネットワークとインターネット」→「モバイル ホットスポット」の<br />\n「接続されているデバイス」にRaspberryPiが表示されているハズ。</p>\n\n<h1 id=\"問題点\">問題点</h1>\n\n<h2 id=\"windows10-pcがルータにつながっていないと使えない\">Windows10 PCがルータにつながっていないと使えない</h2>\n\n<p>ルータにつながっていないと、そもそもモバイル ホットスポット がオンできない。<br />\nこれは、ネットワーク環境がまったくない場合(つまりPCとRaspberryPiだけで箱庭環境だけ作りたいとき)は使えない。<br />\n回避策としては、スマホのテザリングでネットワークにつなぐ?\n間違って外部にアクセスしちゃったら、パケ死しそう。。。</p>\n\n<h2 id=\"pcの外側ルータのサブネット内からraspberrypiにアクセスできない\">PCの外側(ルータのサブネット内)からRaspberryPiにアクセスできない</h2>\n\n<p>モバイル ホットスポットのサブネットとルータのサブネットは別なので、<br />\nモバイル ホットスポットのサブネットの外側から内側へのアクセスはできない。<br />\nもちろん、ルータの外側からもアクセスできない。<br />\nRaspberryPiにアクセスできるのはモバイル ホットスポットを提供しているPCのみ。</p>\n\n<h2 id=\"mdnsが使えない\">mDNSが使えない</h2>\n\n<p>モバイル ホットスポットのサブネットとルータのサブネットは別なので、\nルータを超えられないmDNSは名前を取得できない。<br />\n回避策としては、/etc/hosts を名前エラーが出るたびに名前追加するか?</p>\n\n<p>なお、WindowsPCからRaspberryPiへのmDNS参照はできるが、RaspberryPiからWindowsPCへのmDNS参照はできない。</p>\n\n<h1 id=\"結論\">結論</h1>\n\n<p>とりあえず、RaspberryPiにアクセスするのはWindowsPC 1台のみで、<br />\nRaspberryPiからアクセスするはルータの外側のみ、という条件なら使えそう。</p>\n\n<p>う~ん、良いところまで行くんだけど、微妙に不満の残る結果に。。。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その5)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをWebsocketで飛ばして、Dashboardでグラフ表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"bme280データをwebsocketで送信raspberrypi\">BME280データをWebsocketで送信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>BME280を使用するフローを作成する</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、送信されるデータはmsg.payloadなので、文字列ではなく、object。<br />\n  (WebsocketのパケットにはobjectをJSON文字列化したものが入る)</p>\n  </li>\n  <li>BME280のデータを送信するためのトリガとなるノードをBME280ノードの入力に接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"411d9021.cb1948\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"72021e21.cce078\",\n        \"type\": \"Bme280\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"571951b6.480168\",\n        \"type\": \"websocket out\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"f24a6df3.ed0608\",\n        \"x\": 660,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4ce01eb0.f1d438\",\n        \"type\": \"debug\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 570,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"480f869f.968e18\",\n        \"type\": \"function\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"DummyData\",\n        \"func\": \"msg.payload = {\\n\\t\\t\\\"temperature_C\\\": Math.floor((Math.random() * (  40 - (-30)) * 100) / 100) + (-30),\\n\\t\\t\\\"humidity\\\":      Math.floor((Math.random() * ( 100 -    0 ) * 100) / 100) +    0,\\n\\t\\t\\\"pressure_hPa\\\":  Math.floor((Math.random() * (1100 -  800 ) * 100) / 100) +  800,\\n\\t\\t\\\"model\\\":\\\"DUMMY\\\"\\n}\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 310,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"c6ba67a3.1c69c\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"72021e21.cce078\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ab623444.9c5148\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"480f869f.968e18\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f24a6df3.ed0608\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/bme280\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからbme280データを受信サーバ\">WebsocketからBME280データを受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノード</li>\n</ul>\n\n<p>これだけでWebsocketからデータは受信できる。<br />\nこのとき、Websocketの受信ノードのmag.payloadはJSON文字列なので、objectに変換してやらないと後段で使用できない。<br />\nそのため、Websocketのノードの出力をjsonノードで変換してやる必要がある。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「json」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「json」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「動作」で「常にJavascriptオブジェクトに変換」を選択</li>\n      <li>プロパティは「msg.payload」を設定(デフォルトのまま)</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとjsonが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力側にWebsocketのノードを接続</li>\n  <li>\n    <p>出力側に受信データを処理するノードを接続</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>この状態でRaspberryPi側でBME280のデータ送信をトリガすれば、受信したデータで処理ノードが実行される</p>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その1サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その1)(サーバ)</h1>\n\n<p>上記、<strong>WebsocketからBME280データを受信(サーバ)</strong>の処理ノードとして</p>\n<ul>\n  <li><strong>その4</strong> の <strong>Dashboardでゲージグラフを表示する</strong>の手順で作成したノードを接続すれば良い。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nこれで理屈的には大丈夫なハズなんだけど、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.pressure_hPa}}</code>を指定すると、値は正常に表示されるけど、グラフが正常に表示されないことがある。。。<br />\nどうやら、この形で指定すると、値が1000を超えるとグラフ表示がおかしくなるようだ。バグか?<br />\n下の(その2)の方法で回避可能。</p>\n</blockquote>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"61238c01.1e1fdc\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"2163c454.8e4654\",\n        \"type\": \"json\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"8a687382.d3a38\",\n                \"54ecaf20.30611\",\n                \"1e9e6439.3de04c\",\n                \"54f5a1ee.e4fb5\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"de53f105.be0bb\",\n        \"type\": \"websocket in\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"2163c454.8e4654\",\n                \"8a687382.d3a38\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8a687382.d3a38\",\n        \"type\": \"debug\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 530,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54ecaf20.30611\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{msg.payload.temperature_C | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 510,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1e9e6439.3de04c\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度\",\n        \"label\": \"%\",\n        \"format\": \"{{msg.payload.humidity| number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 510,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54f5a1ee.e4fb5\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧\",\n        \"label\": \"hPa\",\n        \"format\": \"{{msg.payload.pressure_hPa| number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 510,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"9912b800.6921d8\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その2サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その2)(サーバ)</h1>\n\n<p><strong>(その1)</strong>での不具合を回避するため、msg.payloadのオブジェクト内のそれぞれの変数をバラすfunctionノードを追加する</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「function」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら名前にノード名を設定</li>\n      <li>コードを設定(下記参照)</li>\n      <li>出力数に「3」を設定</li>\n      <li>右上の「完了」をクリック。</li>\n    </ul>\n  </li>\n  <li>これでfunctionノードの出力端子が3個になり、上から温度、湿度、気圧データが出力される。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>// make deep copy\nvar msg_temp  <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_hum   <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_press <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\n\nmsg_temp.topic    <span class=\"o\">=</span> <span class=\"s2\">\"temperature_C\"</span><span class=\"p\">;</span>\nmsg_temp.payload  <span class=\"o\">=</span> msg.payload.temperature_C<span class=\"p\">;</span>\nmsg_hum.topic     <span class=\"o\">=</span> <span class=\"s2\">\"humidity\"</span><span class=\"p\">;</span>\nmsg_hum.payload   <span class=\"o\">=</span> msg.payload.humidity<span class=\"p\">;</span>\nmsg_press.topic   <span class=\"o\">=</span> <span class=\"s2\">\"pressure_hPa\"</span><span class=\"p\">;</span>\nmsg_press.payload <span class=\"o\">=</span> msg.payload.pressure_hPa<span class=\"p\">;</span>\n\n<span class=\"k\">return</span> <span class=\"o\">[</span>msg_temp, msg_hum, msg_press]<span class=\"p\">;</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">var msg_temp  = msg;</code>などとしてはいけない。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">msg_temp</code>は<code class=\"language-plaintext highlighter-rouge\">msg</code>の浅いコピーとなってしまうため、その下で<code class=\"language-plaintext highlighter-rouge\">msg_temp.payload</code>を変更すると、<code class=\"language-plaintext highlighter-rouge\">msg.payload</code>も変更されてしまうことになる。<br />\nこれを防ぐため、深いコピーを作成している。これには<code class=\"language-plaintext highlighter-rouge\">msg</code>をJSON文字列化して、再度パースすることで対応している。</p>\n</blockquote>\n\n<p>フローエディタ上で、どの端子がどの信号か分からなくなるのを防ぐため、端子に名前を付けることができる。<br />\n(付けなくても動作上は問題ない)</p>\n\n<ul>\n  <li>「function」ノードをダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>右上の「完了」ボタンの下にある「外観」ボタン(ウィンドウ表示のアイコン)をクリック</li>\n      <li>ポートラベルの下の出力の下、1、2、3に対して、それぞれ分かりやすい名前を付ける</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>functionノードの入力にjsonノードの出力を接続</li>\n  <li>functionノードのそれぞれの出力にそれぞれを表示するゲージグラフノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"9c09bf08.8c36a8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280_2\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1e53a14c.4133a7\",\n        \"type\": \"json\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"855491ee.723a88\",\n                \"3cee4c1c.c6861c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ada05d07.d2d8b\",\n        \"type\": \"websocket in\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"1e53a14c.4133a7\",\n                \"855491ee.723a88\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"855491ee.723a88\",\n        \"type\": \"debug\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 690,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"51b57ef4.80809\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度2\",\n        \"label\": \"℃\",\n        \"format\": \"{{value | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 670,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"be7cac56.7bcc4\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度2\",\n        \"label\": \"%\",\n        \"format\": \"{{value | number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 670,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"f36e338d.e77e6\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧2\",\n        \"label\": \"hPa\",\n        \"format\": \"{{value | number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 670,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3cee4c1c.c6861c\",\n        \"type\": \"function\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"BME280\",\n        \"func\": \"// make deep copy\\nvar msg_temp  = JSON.parse(JSON.stringify(msg));\\nvar msg_hum   = JSON.parse(JSON.stringify(msg));\\nvar msg_press = JSON.parse(JSON.stringify(msg));\\n\\nmsg_temp.topic    = \\\"temperature_C\\\";\\nmsg_temp.payload  = msg.payload.temperature_C;\\nmsg_hum.topic     = \\\"humidity\\\";\\nmsg_hum.payload   = msg.payload.humidity;\\nmsg_press.topic   = \\\"pressure_hPa\\\";\\nmsg_press.payload = msg.payload.pressure_hPa;\\n\\nreturn [msg_temp, msg_hum, msg_press];\",\n        \"outputs\": 3,\n        \"noerr\": 0,\n        \"x\": 460,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"51b57ef4.80809\"\n            ],\n            [\n                \"be7cac56.7bcc4\"\n            ],\n            [\n                \"f36e338d.e77e6\"\n            ]\n        ],\n        \"inputLabels\": [\n            \"BME280データ\"\n        ],\n        \"outputLabels\": [\n            \"温度\",\n            \"湿度\",\n            \"気圧\"\n        ]\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"34e8ddba.6c67fa\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ2\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その4)</h1>\n      <p>Node-REDのメモ Dashboard編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでDashboardでUIを作成するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"dashboardをインストールする\">Dashboardをインストールする</h1>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-dashboard」と入力</li>\n  <li>下に検索結果が出るので。「node-red-dashboard」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するボタン\">Dashboard のUIを作成する(ボタン)</h1>\n\n<ul>\n  <li>パレット(左側のペイン)の「dashboard」の下の「button」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「button」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「名前」は適当に設定</li>\n          <li>「タブ」 で「新規に ui_tab を追加…」を選択してその右の編集ボタンをクリック\n            <ul>\n              <li>適当に値を設定する</li>\n              <li>右上の「追加」をクリック</li>\n            </ul>\n          </li>\n          <li>または、既存のタブを選択</li>\n          <li>右上の「追加」をクリック</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Icon」「Tooltip」「Colour」「Background」はオプションなので空欄のままで可</li>\n      <li>「Payload」 に クリックされたときに送信するデータを設定</li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"ブラウザでdashboardのuiに接続する\">ブラウザでDashboardのUIに接続する</h1>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/ui に接続\n    <ul>\n      <li>Dashboardが表示されるハズ\n        <ul>\n          <li>複数のタブがある場合、左上の3本線メニュー(≡)から切り替えられる</li>\n        </ul>\n      </li>\n      <li>ボタンをクリックしたらフローが動作する。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するスライダ\">Dashboard のUIを作成する(スライダ)</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「slider」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「slider」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Tooltip」はオプションなので空欄のままで可</li>\n      <li>「Range」に値の最小値、最大値、刻みを設定</li>\n      <li>「Output」を設定\n        <ul>\n          <li>「continuously while sliding」:操作中、一定時間ごとにメッセージを出力</li>\n          <li>「only on release」:スライダを離したとき(値を確定したとき)にメッセージを出力</li>\n        </ul>\n      </li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"dashboardでゲージグラフを表示する\">Dashboardでゲージグラフを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「guage」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「guage」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>デフォルトの<code class=\"language-plaintext highlighter-rouge\">{{value}}</code>では受信したデータのpayload(<code class=\"language-plaintext highlighter-rouge\">msg.payload</code> )が使用される</li>\n          <li>payloadがobjectの場合、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.XXX}}</code>のように指定すると特定の変数が表示できる</li>\n          <li>このとき、<code class=\"language-plaintext highlighter-rouge\">{{</code> と <code class=\"language-plaintext highlighter-rouge\">}}</code> は波括弧を2つ重ねたもの。波括弧1つだと正常に処理されないので、注意</li>\n          <li>表示する数値の有効桁数を設定したい場合は以下のようにフィルタを設定\n            <ul>\n              <li>小数点以下1桁まで表示:<code class=\"language-plaintext highlighter-rouge\">{{value | number:1 }}</code></li>\n              <li>整数部のみ表示:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:0 }}</code></li>\n              <li>10の位へ丸める:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:-1 }}</code></li>\n            </ul>\n          </li>\n          <li>単位を表示するなど、決まった文字列を追加したい場合は「<code class=\"language-plaintext highlighter-rouge\">{{・・・}}℃</code>」のように波括弧の外側に追加</li>\n        </ul>\n      </li>\n      <li>「units」 で単位を設定する。温度なら「℃」など。これは数値表示には表示されず、グラフ内部の単位情報として表示される</li>\n      <li>「Range」 でグラフの値の範囲を指定する。「-20」~「40」など。\n        <ul>\n          <li>入力値が範囲外になった場合はグラフが上下限に張り付くだけで、エラーなどにはならない。また値そのものは数値表示される</li>\n        </ul>\n      </li>\n      <li>「Colour gradient」 でグラフの色を指定する。3つの色は下で設定するSectors の範囲に対応する</li>\n      <li>「Sectors」 で 上で指定した色を表示する範囲を設定する\n        <ul>\n          <li>これはオプションなので設定しなくても良い。指定しなかった場合は上の「Range」で指定した値の範囲を3等分して使用される</li>\n        </ul>\n      </li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nValue formatのフィルタの詳細は<a href=\"https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters\">https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters</a>を見ろと書かれていましたが、残念ながら私にはよく分かりませんでした…</p>\n</blockquote>\n\n<h1 id=\"dashboardでテキストを表示する\">Dashboardでテキストを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「text」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「text」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>上記参照</li>\n        </ul>\n      </li>\n      <li>「Layout」でレイアウトを選択。お好みで</li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a226513f.c36b1\",\n        \"type\": \"tab\",\n        \"label\": \"Dashboard_1\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"160486fa.dc7159\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e89b8821.ec65e8\",\n        \"type\": \"debug\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 580,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d4346336.cf1228\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e403fdac.aa3748\",\n        \"type\": \"ui_slider\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"label\": \"温度\",\n        \"tooltip\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 4,\n        \"width\": 0,\n        \"height\": 0,\n        \"passthru\": true,\n        \"outs\": \"all\",\n        \"topic\": \"\",\n        \"min\": \"-30\",\n        \"max\": \"50\",\n        \"step\": 1,\n        \"x\": 140,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"78c10ecb.1eb67\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"78c10ecb.1eb67\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 6,\n        \"width\": 4,\n        \"height\": 4,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{value}}℃\",\n        \"min\": \"-20\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 570,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"84bd2adf.3b5df8\",\n        \"type\": \"ui_text\",\n        \"z\": \"a226513f.c36b1\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 560,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1127e563.00001b\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"6547952b.517b34\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"6547952b.517b34\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ1\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"dashboard-のレイアウトを修正する\">Dashboard のレイアウトを修正する</h1>\n\n<p>ボタンのサイズを小さくしたり、複数のボタンを横に並べたい場合はレイアウトの修正を行う。</p>\n\n<ul>\n  <li>サイドバー(右側のペイン)の「dashboard」ボタン(グラフのアイコン)をクリック</li>\n  <li>配置タブをクリック</li>\n  <li>タブの部分(「ホーム」など)をマウスでポイントし、「レイアウト」をクリック\n    <ul>\n      <li>表示領域の幅を変更するには、右上の「幅」の設定値を変更する。(単位はグリッド数)</li>\n      <li>各要素をドラッグすると、表示位置を入れ替えられる。</li>\n      <li>各要素のサイズを変更するには、\n        <ul>\n          <li>右上の鍵アイコンをクリックして閉じた状態にする(鍵が開いた状態では表示領域幅に一致するように自動変更される)</li>\n          <li>右下に矢印アイコンが表示されるので、これをつまんでサイズを変更</li>\n        </ul>\n      </li>\n      <li>各要素を横並びにしたい場合は、各要素をドラッグして移動する(表示幅に収まらない場合は移動できない)</li>\n      <li>各要素のサイズ/位置はグリッド単位でのみ可能</li>\n      <li>右上の完了をクリック\nー デプロイする</li>\n    </ul>\n  </li>\n</ul>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その3)</h1>\n      <p>Node-REDのメモ TCP通信編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでTCP通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"udpで送信\">UDPで送信</h1>\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「送信」で出力するメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト)/「ブロードキャストメッセージ」/「マルチキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で送信先ポート番号を設定\n        <ul>\n          <li>受信プログラムが待ち受けしているポート番号を指定</li>\n        </ul>\n      </li>\n      <li>「アドレス」に送信先アドレス(名前 or IPアドレス)を指定</li>\n      <li>さらにその右で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>特定のポートから送信したいときは「ローカルポートを使用」を選択し、その右に送信元ポート番号を指定する\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n          <li>通常は「ローカルポートをランダムに使用」で大丈夫</li>\n        </ul>\n      </li>\n      <li>入力データがBase64エンコードされたBufferオブジェクトの場合は「Base64形式のペイロードを複合」にチェックを入れる\n        <ul>\n          <li>入力データがBase64文字列かをチェックするだけで、ここでデータを変換するわけではない(?)</li>\n          <li>通常はチェックしないでOK</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると送信先アドレスとポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>送信データを作成するノードを接続\n    <ul>\n      <li>UDPノードはmsg.payloadを送信する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"udpで受信\">UDPで受信</h1>\n<ul>\n  <li>パレットの「入力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「待ち受け」で受信待ちするするメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト or マルチキャスト)/「ブロードキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で受信待ちポート番号を設定\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n        </ul>\n      </li>\n      <li>「種類」で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>「出力」で受信したデータをどのような形式で次段のノードに出力するかを選択する\n        <ul>\n          <li>「バイナリバッファ」を選択すると受信したデータをそのままbufferオブジェクトとして出力</li>\n          <li>「文字列」を選択すると受信したデータをStringオブジェクトにデコードする</li>\n          <li>「Base64文字列」を選択すると受信したデータをBase64 Stringオブジェクトにデコードする</li>\n          <li>「Base64文字列」と「文字列」は内部でtoStringのencodingに’base64’を指定するか’utf8’を指定するかの違い(?)</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると受信待ちポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>受信データを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"2506be7d.1b5332\",\n        \"type\": \"tab\",\n        \"label\": \"UDP\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"44364ec0.0b59b8\",\n        \"type\": \"udp out\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"addr\": \"localhost\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"outport\": \"\",\n        \"base64\": false,\n        \"multicast\": \"false\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"20cee006.2fee4\",\n        \"type\": \"inject\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"\",\n        \"payloadType\": \"date\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 150,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"44364ec0.0b59b8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"eb875fd8.7aa5f8\",\n        \"type\": \"udp in\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"multicast\": \"false\",\n        \"group\": \"\",\n        \"datatype\": \"utf8\",\n        \"x\": 160,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"a6b72636.514e2\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a6b72636.514e2\",\n        \"type\": \"debug\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 140,\n        \"wires\": []\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"httpでrest-api\">HTTPでREST API</h1>\n\n<h2 id=\"http入力ノードの作成\">HTTP入力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「入力」の下の「http」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「メソッド」でメソッド種別を選択\n        <ul>\n          <li>ここでは「GET」で設定を進める(他のメソッドは他所で調べてね)</li>\n        </ul>\n      </li>\n      <li>「URL」でエンドポイント(要はパス)を設定</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとメソッドとURLが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>レスポンスを作成するノード(下記)を接続</li>\n</ul>\n\n<h2 id=\"レスポンス生成ノードの作成\">レスポンス生成ノードの作成</h2>\n\n<p>ここでは、簡単にfunctionノードで固定文字列を返すものを作っています。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると空欄になるので、なるべく識別できる名前を付けましょう</li>\n        </ul>\n      </li>\n      <li>「コード」に処理するプログラムを記述\n        <ul>\n          <li>msg.payloadに表示するページの本文を設定する</li>\n          <li>例えば以下</li>\n        </ul>\n      </li>\n      <li>「名前」の横のアイコンをクリックすると作成したノードの保存/読み込みが出来る\n        <ul>\n          <li>コードは <code class=\"language-plaintext highlighter-rouge\">~/.node-red/lib/functions/</code> に指定したフォルダとファイル名で保存される</li>\n          <li>保存したコードは別のノードで読み込むことができる</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"dl\">\"</span><span class=\"s2\"><h1> ぼ~っと生きてんじゃね~よ! </H1></span><span class=\"dl\">\"</span><span class=\"p\">;</span>\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h2 id=\"http出力ノードの作成\">HTTP出力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「出力」の下の「http response」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「http」と表示される</li>\n        </ul>\n      </li>\n      <li>必要なら「状態コード」を設定</li>\n      <li>必要なら「ヘッダ」を設定</li>\n      <li>シンプルな処理の場合、何も設定しなくてもOK</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"入力レスポンス生成出力を接続\">入力、レスポンス生成、出力を接続</h2>\n\n<ul>\n  <li>上記で作成したノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"ブラウザでアクセス接続\">ブラウザでアクセス接続</h2>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/《HTTP入力ノードに設定したURL》 に接続\n    <ul>\n      <li>ブラウザにレスポンス生成ノードで作成したメッセージが表示される</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"7508e635.c8bf48\",\n        \"type\": \"tab\",\n        \"label\": \"HTTP_REST\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c7938d8a.3ae9d\",\n        \"type\": \"http in\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"url\": \"/rest_api_1\",\n        \"method\": \"get\",\n        \"upload\": false,\n        \"swaggerDoc\": \"\",\n        \"x\": 160,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"fb01d5fd.b76918\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fb01d5fd.b76918\",\n        \"type\": \"function\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"ぼ~っと生きてんじゃね~よ!\",\n        \"func\": \"msg.payload = \\\"<h1> ぼ~っと生きてんじゃね~よ! </H1>\\\";\\nreturn msg;\\n\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 430,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"8d3518af.f9da7\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d3518af.f9da7\",\n        \"type\": \"http response\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"statusCode\": \"\",\n        \"headers\": {},\n        \"x\": 690,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"86c0f820.b0a56\",\n        \"type\": \"debug\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 700,\n        \"y\": 120,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"websocketでデータを送受信\">Websocketでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにwscatを使うこととします。<br />\nwscat は 以下のコマンドでインストールできます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> wscat\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信クライアント\">Websocketでデータ送信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「種類」 で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「URL」 でサーバのURLを設定(例: ws://PiDev25.local:5000/ws/data01)</li>\n          <li>「送信/受信」でペイロードのみ送受信するか、メッセージ全体を送受信するかを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5000で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5000\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5000 (press CTRL+C to quit)\nclient connected\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"75e44664.73e018\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"49b725b6.0e0934\",\n        \"type\": \"websocket out\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"99ad88ce.8bcf7\",\n        \"x\": 600,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"762ccf62.73a48\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fe2498d8.71c17\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47ef3c99.d6eefc\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f97b4d60.afc278\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6d15d519.6289ec\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"87c94e6f.db3458\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"175e465.15aaa3a\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e7c2219c.07acf8\",\n        \"type\": \"debug\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"99ad88ce.8bcf7\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5000/ws/data01\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信サーバ\">Websocketでデータ送信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata1 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest1で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wstest1\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-3\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"22d6d63b.99a952\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"d64e2a6a.27ead8\",\n        \"type\": \"websocket out\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"server\": \"d7536de3.b48578\",\n        \"client\": \"\",\n        \"x\": 520,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"79358fcc.5a5a68\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"cd6acb87.0a77\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7991d417.429124\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ee88046b.37b298\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7eac2c2e.6fa39c\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"650517e9.5e34a8\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d197151e.8b01e\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5871022e.6bbb1c\",\n        \"type\": \"debug\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d7536de3.b48578\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wstest1\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信クライアント\">Websocketでデータを受信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>URL でサーバのURLを設定(例: ws://PiDev25.local:5002/ws/wsdata2)</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-2\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5002で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5002\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5002 (press CTRL+C to quit)\nclient connected\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-4\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a45bd125.622fb8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"24a93730.cf2a7\",\n        \"type\": \"websocket in\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"server\": \"45ba6028.84fc88\",\n        \"client\": \"\",\n        \"x\": 220,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"15576052.1536\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"15576052.1536\",\n        \"type\": \"debug\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"45ba6028.84fc88\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5002/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信サーバ\">Websocketでデータを受信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata2 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-3\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest2で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wsdata2\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-5\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"15604b9.9721eb4\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"80f59585.469758\",\n        \"type\": \"websocket in\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"server\": \"11528a5d.783b0e\",\n        \"client\": \"\",\n        \"x\": 140,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"f37c8fe9.6307c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f37c8fe9.6307c\",\n        \"type\": \"debug\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"11528a5d.783b0e\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その2)</h1>\n      <p>Node-REDのメモ GPIO & I2C編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIO操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDはRaspberryPiで起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"raspberrypiでgpio出力\">RaspberryPiでGPIO出力</h1>\n<ul>\n  <li>パレット(左側のペイン)の「Raspberry Pi」の下の「rpi gpio」(出力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で出力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「出力形式」で「デジタル出力」を選択</li>\n      <li>デプロイしたときに端子状態を初期化したい場合は「端子の状態を初期化」をチェック\n        <ul>\n          <li>「端子の初期状態レベル」を選択</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「LED_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>トリガノードはGPIOから出力する値(0 または 1)を出力する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"51e0a206.805964\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_OUT\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"597df548.0311f4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"89834ee2.89e27\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b020b32.e26818\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"21621e60.e300ba\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_1\",\n        \"pin\": \"22\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"87abb89b.307418\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7ae7810.959a88\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 220,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでgpio入力\">RaspberryPiでGPIO入力</h1>\n\n<ul>\n  <li>パレットの「Raspberry Pi」の下の「rpi gpio」(入力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で入力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「抵抗」で端子に接続するプルアップ/ダウン種別を選択\n        <ul>\n          <li>端子の初期化時に内部のプルアップ/ダウン抵抗のどちらを有効にするかを選択</li>\n          <li>ボード上で処理してれば「なし」を選ぶ</li>\n        </ul>\n      </li>\n      <li>デバウンスにチャタリング除去時間を設定</li>\n      <li>デプロイしたときに端子状態を読み込みたい場合は「~初期状態を読み込む」をチェック</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「SWITCH_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力信号を処理するノードを接続\n    <ul>\n      <li>処理ノードへはGPIOから入力された値(0 または 1)が入力される</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1385085c.ab8648\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_IN\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"e9177a48.70b74\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"932b0e92.05cdd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"932b0e92.05cdd8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f31f20e.4b6d28\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW1\",\n        \"pin\": \"16\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d27c860d.7de3a8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d27c860d.7de3a8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 160,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでi2cを使用する\">RaspberryPiでI2Cを使用する</h1>\n\n<h2 id=\"事前準備\">事前準備</h2>\n\n<p>以下はターミナルやコンソールでの作業</p>\n\n<ul>\n  <li>I2Cを有効化する\n    <ul>\n      <li>リブートは不要らしい</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config\n    5 Interfacing Options\n        P5 I2C\n            Would you like the ARM I2C interface to be enabled?\n            に対して<はい>を選択\n            The ARM I2C interface is enabled\n            と表示されるので<了解>\n    <Finish>\n</code></pre></div></div>\n<ul>\n  <li>I2Cデバイスアクセス用ツールをインストールする</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>i2c-tools\n</code></pre></div></div>\n\n<ul>\n  <li>i2cバスをスキャンしてみる(RasbberryPi2/3のI2Cバスはバス1が出てる。古いのだと0のもあるらしい)</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#   ↓結果(例)</span>\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00:          <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n10: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n20: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n30: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n40: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n50: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n60: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n70: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> 76 <span class=\"nt\">--</span>\n<span class=\"c\"># 76がBME280(Bosch温湿度センサ)</span>\n</code></pre></div></div>\n\n<ul>\n  <li>I2Cデバイスのレジスタをリードしてみる</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cget <span class=\"nt\">-y</span> 1 0x76 0xd0\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ↓ 結果</span>\n0x60\n<span class=\"c\"># レジスタ 0xd0(CHIP ID)をリードするとデバイスのID 0x60が読める</span>\n</code></pre></div></div>\n\n<h2 id=\"bme280用ノードをインストールする\">BME280用ノードをインストールする</h2>\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「bme280」と入力</li>\n  <li>下に検索結果が出るので。「node-red-contrib-bme280」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\n2019/09/13現在、何やらインストール時にエラーになるが、<br />\nモジュールのコンパイル時にwarning/noteが出ているだけのようなので、インストール自体はできているようだ。<br />\nとりあえず下記サンプルは動いているので、大丈夫でしょう。</p>\n</blockquote>\n\n<h2 id=\"bme280を使用するフローを作成する\">BME280を使用するフローを作成する</h2>\n<ul>\n  <li>パレットの「入力」の下の「Bme280」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Bme280」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略するとBme280が表示される</li>\n        </ul>\n      </li>\n      <li>Bus# にバス番号(1)を設定</li>\n      <li>I2C Address にI2Cアドレス(0x76)を設定</li>\n      <li>Topicが必要なら設定(デフォルトはbme280)</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>信号を処理するノードを出力側に接続\n    <ul>\n      <li>Bme280ノードの出力メッセージの内容は以下の通り</li>\n    </ul>\n  </li>\n</ul>\n\n<table>\n  <thead>\n    <tr>\n      <th>変数名</th>\n      <th>値の例</th>\n      <th>項目</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>msg.topic</td>\n      <td>“bme280”</td>\n      <td>ノードの設定で設定したTopic</td>\n    </tr>\n    <tr>\n      <td>msg.payload.temperature_C</td>\n      <td>34.23</td>\n      <td>温度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.humidity</td>\n      <td>54.402349427117336</td>\n      <td>湿度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.pressure_hPa</td>\n      <td>1013.9016246356634</td>\n      <td>気圧</td>\n    </tr>\n    <tr>\n      <td>msg.payload.model</td>\n      <td>“BME280”</td>\n      <td>センサ名</td>\n    </tr>\n  </tbody>\n</table>\n\n<ul>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n    {\n        \"id\": \"e4065603.3c6dc\",\n        \"type\": \"tab\",\n        \"label\": \"BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c0602bca.110b8\",\n        \"type\": \"Bme280\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"8b845ce5.ec2fd\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b845ce5.ec2fd\",\n        \"type\": \"debug\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 630,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"cdbf55ce.3aa94\",\n        \"type\": \"inject\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"c0602bca.110b8\"\n            ]\n        ]\n    }\n]\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その1)</h1>\n      <p>Node-REDのインストール他のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDをインストールや、フローを作成する際の手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"ubuntu-に-node-red-をインストールする\">ubuntu に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejsとnpmのインストール\">Node.jsとnpmのインストール</h2>\n\n<p>自動起動とかやらないなら、Node.js は nodenv とか使っても良い気がするが、\n念のためシステムに直接インストールしておく。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">apt install</code> だと古いバージョンになってしまうので、<br />\nnコマンド をインストールし、<br />\nnコマンドで安定版をインストールする。<br />\nその後、<code class=\"language-plaintext highlighter-rouge\">apt</code> でインストールしたNode.jsは削除。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n\n<span class=\"c\"># nコマンドのインストール</span>\n<span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> n\n\n<span class=\"c\"># 安定版のインストール</span>\n<span class=\"nb\">sudo </span>n stable\n\n<span class=\"c\"># aptでインストールしたnode.jsをアンインストール</span>\n<span class=\"nb\">sudo </span>apt purge <span class=\"nt\">-y</span> nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h2 id=\"node-redのインストール\">Node-REDのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> <span class=\"nt\">--unsafe-perm</span> node-red node-red-admin\n</code></pre></div></div>\n\n<p>どうも、ノードの追加とかすると、npmのキャッシュをアクセスするときにpermission deniedと言われてしまうみたいなので、\n以下のコマンドで .npm ディレクトリ以下の所有権を自分にしておく。<br />\n(キャッシュだから削除しても良い気がするが)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> ~/.npm\n</code></pre></div></div>\n\n<h2 id=\"起動\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"停止\">停止</h2>\n\n<p>CTRL-Cで停止する。</p>\n\n<h2 id=\"参考\">参考</h2>\n\n<p><a href=\"https://qiita.com/seibe/items/36cef7df85fe2cefa3ea\">https://qiita.com/seibe/items/36cef7df85fe2cefa3ea</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"windows10-に-node-red-をインストールする\">Windows10 に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npmの-インストール\">Node.js と npmの インストール</h2>\n\n<ul>\n  <li><a href=\"https://nodejs.org/ja/\">Node.jsのサイト</a>からWindows版をダウンロードします。\n  推奨版(2019/09/16現在、10.16.3 LTS)をダウンロードしてください。<br />\n  (もし、別のプラットフォームのものが必要なら上部のメニューの「ダウンロード」からダウンロードします)</li>\n  <li>ダウンロードしたnode-vXX.XX.XX-YY.msiを実行してインストーラを起動し、インストールします。\n  特に迷うところはないと思います。大体、そのまま「次へ」で大丈夫。</li>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell を起動します。\n  念のため、<code class=\"language-plaintext highlighter-rouge\">node -v</code> を実行して、<code class=\"language-plaintext highlighter-rouge\">v10.16.3</code>と表示されることを確認します。\n  次にnpmのアップデートを行います。以下のコマンドを実行してください。( 2019/09/16現在、6.11.3 でした)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g npm\n</code></pre></div></div>\n<h2 id=\"node-redのインストール-1\">Node-REDのインストール</h2>\n\n<ul>\n  <li>コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してインストールします。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g --unsafe-perm node-red\n</code></pre></div></div>\n\n<ul>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してNode-REDを起動します。<br />\n実行したウィンドウは閉じないでください。閉じるとNode-REDが終了してしまいます。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>なお、初めてNode-REDを起動したとき、\n『このアプリの機能のいくつかがWindows Defender ファイアウォールでブロックされています』\nと警告が表示されることがある。</p>\n\n<p>この場合、\n「通信を許可するネットワーク」を選択して「アクセスを許可する」をクリック\nすれば良い。</p>\n\n<h2 id=\"ちょっとヒトコトメモ\">ちょっとヒトコトメモ</h2>\n\n<p>(ぜんぜんヒトコトじゃないけど。。。)</p>\n\n<p>Node-REDを起動したPCからのアクセス(ブラウザ接続など)は成功するのに、\n外部PCやRaspberryPi(もちろん、同一サブネット上の)からのアクセス(ブラウザやWebsocket接続)が失敗する場合がある。</p>\n\n<p>考えられる原因は色々あるが、最も多そうな原因のひとつにファイアウォールでのブロックが考えられる。<br />\n上の警告ダイアログでアクセス許可した際に、プライベートネットワークのみに通信を許可していて、\nかつ、現在接続されているネットワークがパブリックネットワークである場合である。</p>\n\n<p>ファイアウォールでのブロックされているかは<strong>Node-REDを起動した状態</strong>で以下のコマンドで確認できる。</p>\n\n<ul>\n  <li>RaspberryPiの場合</li>\n</ul>\n\n<p>以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 《IPアドレス》 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 192.168.1.2 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、コマンドが終了しないので、CTRL+Cで終了する。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">Connection to 《IPアドレス》 《ポート番号》port [tcp/*] succeeded!</code>と表示される。</p>\n\n<ul>\n  <li>Windowsの場合</li>\n</ul>\n\n<p>Windows Poewrshellで(コマンドプロンプトでは不可)以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 《IPアドレス》  <span class=\"nt\">-port</span> 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 192.168.1.2 <span class=\"nt\">-port</span> 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : False</code>と表示される。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : True</code>と表示される。</p>\n\n<p>これを解決するには、Node-REDを実行しているWindows PCで<br />\n「コントロールパネル」→「Windows Defender ファイアウォール」を開き、<br />\n左側のリストから「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック<br />\n「設定の変更」をクリック\n下のリストから「Node.js: Server-side JavaScript」の右側 パブリックのチェックボックスにチェックを入れる<br />\n「OK」をクリック</p>\n\n<p>この状態で再度RaspberryPi または PCからファイアウォールでのブロックの確認を実行し、ブロックされていないことを確認してください。</p>\n\n<h1 id=\"raspbian-に-node-red-をインストールする\">Raspbian に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npm-と-node-red-のインストール\">Node.js と npm と Node-RED のインストール</h2>\n\n<p>インストールスクリプトを実行すればイッパツで解決。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストールスクリプトの取得</span>\nwget  https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered\n\n<span class=\"c\"># 必要なら中身確認してね</span>\n\n<span class=\"c\"># インストールスクリプトの実行</span>\nbash update-nodejs-and-nodered \n</code></pre></div></div>\n\n<h2 id=\"起動-1\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-start \n</code></pre></div></div>\n<p>CTRL-Cでログ表示のみ止まる(Node-RED自体は動作したまま)</p>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"ログ表示\">ログ表示</h2>\n\n<p>Node-RED で console.log などを実行したときは、ログに表示される。<br />\n<code class=\"language-plaintext highlighter-rouge\">node-red-start</code>したままなら表示されるが、CTRL-Cでログ表示を止めていた場合は\n以下のコマンドでログ表示を再開できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-log\n</code></pre></div></div>\n\n<h2 id=\"停止-1\">停止</h2>\n\n<p>Node-RED自体を停止する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-stop\n</code></pre></div></div>\n\n<h2 id=\"参考-1\">参考</h2>\n\n<p><a href=\"https://qiita.com/utaani/items/7155c62d6c5e96822afb\">https://qiita.com/utaani/items/7155c62d6c5e96822afb</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"フローの操作\">フローの操作</h1>\n\n<h2 id=\"フローを保存するエクスポート\">フローを保存する(エクスポート)</h2>\n\n<p>作成したフローは保存することができます。<br />\nしばらく使わないフローを削除したり、別の環境にコピーする場合に保存しておくと良いでしょう。</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「書き出し」→「クリップボード」をクリック →書き出しダイアログが表示される\n    <ul>\n      <li>書き出す範囲を「現在のタブ」「すべてのタブ」から選択。(フローの一部を選択していた場合は「選択したフロー」も選択可能)</li>\n      <li>その下にはその時のJSONファイルの内容が表示されていますので、ここから</li>\n      <li>さらにその下で出力形式を「インデントのないJSONフォーマット」「インデント付きのJSONフォーマット」から選択。多少ファイルサイズが増減しますが、どちらを選んでも特に問題になるようなことはないでしょう。「インデント付き」の方が目視で確認しやすいと思います。</li>\n      <li>「ダウンロード」をクリックすると、ブラウザのファイル保存(ダウンロード)ダイアログが開くので、保存処理を行う(このときのファイル名はflows.json固定なので、必要に応じて保存後リネームしてください)</li>\n      <li>または、「書き出し」をクリックすると、クリップボードへコピーされるので、直接 別の環境の読み込みダイアログやエディタへペーストすることも可能</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"フローを読み込むインポート\">フローを読み込む(インポート)</h2>\n\n<p>保存したフローは読み込んで使用することができます(当然か)</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「読み込み」→「クリップボード」をクリック →読み込みダイアログが表示される\n    <ul>\n      <li>「読み込むファイルを選択してください」をクリックして読み込むファイルを選択 → ファイルの内容がその下のエディットボックスに表示される</li>\n      <li>または、その下のエディットボックスにJSONデータをペースト</li>\n      <li>読み込み先を「現在のタブ」「新規のタブ」から選択(「選択したフロー」で保存してないとどっちでも同じ気がする)</li>\n      <li>「読み込み」をクリック</li>\n    </ul>\n  </li>\n  <li>読み込まれるので、内容を確認。必要なら修正。</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"フローを削除する\">フローを削除する</h2>\n\n<p>使用しなくなったフローをいつまでも残しておくとトラブルの元ですから、削除しましょう。<br />\n(念のため保存しておくのを忘れずに)</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、削除したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>左上の「削除」をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(次回デプロイするまで処理は残っているので注意)</li>\n</ul>\n\n<h2 id=\"フローを一時的に停止する\">フローを一時的に停止する</h2>\n\n<p>後で使うから削除したくはないけど、今デバッグしてる作業の邪魔になる、というような場合、\n作成したフローを削除せずに一時的に停止することができます。</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、停止したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>状態を「無効」にする</li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(デプロイしないといつまで経っても停止しないので注意)</li>\n</ul>\n\n<p>再開する場合は上記手順と同じで、状態を「有効」にする。</p>\n\n<h2 id=\"フローを全削除する\">フローを全削除する</h2>\n\n<p>色々フローを作成したけど、一回チャラにしてやりなおしたいときは、\n一旦Node-REDを停止(ブラウザ切断だけじゃなく、サーバプログラムを停止)して\n以下の2つのファイルを削除する</p>\n\n<ul>\n  <li>~/.node-red/flows_《ホスト名》.json</li>\n  <li>~/.node-red/.flows_《ホスト名》.json.backup</li>\n</ul>\n\n<p>もちろん、念のためバックアップ取っておくのが好ましい。<br />\nバックアップから復元すれば元通りになるはず。</p>\n\n<p>その後、Node-Redを起動すると、フローが綺麗さっぱり消えているハズ。</p>\n\n<h2 id=\"その2以降のフローの例について\">その2以降の「フローの例」について</h2>\n\n<p>「フローの例」に書かれたJSONコードはテスト用に作成したフローをエクスポート(書き出し)したものです。<br />\nこのコードの表示部分にマウスを乗せると、右上に「Copy」ボタンが表示されますので、このボタンをクリックしてください。JSONコードがクリップボードにコピーされます(マウスをドラッグしての選択は不要)。</p>\n\n<p>この状態で、上記<strong>フローを読み込む(インポート)</strong>に示した方法でフローをインポートするとフローがコピーされます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n複数のフローをインポートした場合、既に存在するノードと同名のノードは別のノードとして生成されます。このとき、名前に「(_1)」などの別ノードを識別できるような記号は付きません。<br />\n特に、WebsocketのノードやDashboardのタブ/グループはシステムの動作や見た目に影響しますので、注意してください。<br />\n自動でよしなにする方法はありませんので、手動でチマチマと修正してください。<br />\nサイドバー(右側のペイン)の「▼」ボタンをクリックし、ノードの設定を表示でノードの設定を表示し、<br />\n各ノードの右側の数字をクリックすると、そのノードを参照しているノードの一覧が表示されます。<br />\nさらにそのノード一覧の各ノードをダブルクリックすると、そのノードが点滅表示されるので、そのノードのプロパティで参照先を変更すれば良いでしょう。</p>\n\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WebIOPiをRaspbian Busterで動かす</title>\n  </head>\n  <body>\n    <header>\n      <h1>WebIOPiをRaspbian Busterで動かす</h1>\n      <p>WebIOPiをRaspbian Busterで動かす</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"背景\">背景</h1>\n\n<p>知人がWebIOPiをRaspbian Busterで動かそうとして、Raspbian Stretch では動いたが、Raspbian Busterだと動かないと言っていたので、\n興味本位でデバッグしてみた。</p>\n\n<p>私はこれを使おうと思ってないので、「鳴かぬなら鳴かせてみせようホトトギス」なだけなので、詳しい使い方とかは調べてません。</p>\n\n<h1 id=\"参照\">参照</h1>\n\n<p>そもそものインストール手順は、<br />\n<a href=\"https://www.hiramine.com/physicalcomputing/raspberrypi3/webiopi_install.html\">WebIOPi のインストール</a><br />\n<a href=\"https://www.fabshop.jp/%E9%96%8B%E7%99%BA%E3%81%8C%E7%B5%82%E4%BA%86%E3%81%97%E3%81%9Fwebiopi%E3%82%92%E6%9C%80%E6%96%B0%E3%81%AEraspbian%E3%81%A7%E5%8B%95%E4%BD%9C%E3%81%95%E3%81%9B%E3%82%88%E3%81%86%E3%80%82/?fbclid=IwAR1u1Hq0wSqnDhPnKDeoyf1b2AmrdpO99TLSevUTZ237D5Ny97pliLjlOwU\">開発が終了したWebIOPiを最新のRaspbianで動作させよう。</a><br />\nあたりを参考にしてちょ。</p>\n\n<h1 id=\"いきなり結論\">いきなり結論</h1>\n\n<p>で、まぁ結論から言うと、根本原因は、BusterのPython3がPython3.7にバージョンアップされたこと。<br />\nちなみに、StretchのPython3はPython3.5 。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">python/webiopi/utils/thread.py</code> 内の 関数 <code class=\"language-plaintext highlighter-rouge\">runLoop()</code>の中で<code class=\"language-plaintext highlighter-rouge\">async</code>を変数に使っていたため、SyntaxErrorが発生していた模様。<br />\nPythom3.7では(正確にはPython3.6から)<code class=\"language-plaintext highlighter-rouge\">async</code>は予約語になっているため、エラーとなっていた。</p>\n\n<p>で、変数名を<code class=\"language-plaintext highlighter-rouge\">async</code>からそれ以外(例えば<code class=\"language-plaintext highlighter-rouge\">async_Flag</code>)に変更すれば良い。</p>\n\n<h1 id=\"でpatchファイル\">で、patchファイル</h1>\n\n<p>修正内容のpatchファイルがこちら。<br />\nついでにCプログラムのコンパイルの際に出るワーニングも消すようにちょこっと修正しときました。(こっちの修正は、かなりヤッツケ…)</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/cpuinfo.c WebIOPi-0.7.1/python/native/cpuinfo.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/cpuinfo.c\t2019-09-03 00:04:59.959369913 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/cpuinfo.c\t2019-09-02 23:55:16.207501342 +0900\n</span><span class=\"p\">@@ -35,7 +35,8 @@</span> char *get_cpuinfo_revision(char *revisio\n       return 0;\n \n    while(!feof(fp)) {\n<span class=\"gd\">-      fgets(buffer, sizeof(buffer) , fp);\n</span><span class=\"gi\">+      char* aaa = fgets(buffer, sizeof(buffer) , fp);\n+      aaa = aaa;\n</span>       sscanf(buffer, \"Hardware\t: %s\", hardware);\n       if (strcmp(hardware, \"BCM2708\") == 0)\n          rpi_found = 1;\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/gpio.c WebIOPi-0.7.1/python/native/gpio.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/gpio.c\t2019-09-03 00:04:59.969368480 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/gpio.c\t2019-09-02 23:58:58.757767098 +0900\n</span><span class=\"p\">@@ -23,6 +23,7 @@</span> SOFTWARE.\n #include <stdio.h>\n #include <stdint.h>\n #include <stdlib.h>\n<span class=\"gi\">+#include <unistd.h>\n</span> #include <string.h>\n #include <fcntl.h>\n #include <sys/mman.h>\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/webiopi/utils/thread.py WebIOPi-0.7.1/python/webiopi/utils/thread.py\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/webiopi/utils/thread.py\t2019-09-03 00:04:44.520586361 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/webiopi/utils/thread.py\t2019-09-02 23:54:10.087479478 +0900\n</span><span class=\"p\">@@ -33,14 +33,14 @@</span> def stop(signum=0, frame=None):\n             task.stop()\n                 \n \n<span class=\"gd\">-def runLoop(func=None, async=False):\n</span><span class=\"gi\">+def runLoop(func=None, async_Flag=False):\n</span>     global RUNNING\n     RUNNING = True\n     signal.signal(signal.SIGINT, stop)\n     signal.signal(signal.SIGTERM, stop)\n \n     if func != None:\n<span class=\"gd\">-        if async:\n</span><span class=\"gi\">+        if async_Flag:\n</span>             TASKS.append(Task(func, True))\n         else:\n             while RUNNING:\n</code></pre></div></div>\n\n<p>これを<code class=\"language-plaintext highlighter-rouge\">webiopi-buster.patch</code>として保存し、以下のコマンドを実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch <span class=\"nt\">-p1</span> <span class=\"nt\">-i</span> webiopi-buster.patch\n</code></pre></div></div>\n\n<p>で後は<code class=\"language-plaintext highlighter-rouge\">settup.sh</code>を実行して、その後は参照ページの通り進めれば良い。</p>\n\n<h1 id=\"めでたしめでたし\">めでたしめでたし</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick2用動作環境の構築</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick2用動作環境の構築</h1>\n      <p>Intel NCStick2用動作環境の構築</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Dセンセの悪魔の囁きに踊らされ、Intel NCStick2をポチってしまった。<br />\nで、動作環境を構築したときのメモを残しておく。</p>\n\n<p>ホストマシンは、RaspberryPi3 model B+ で Raspbian Buster を使用。</p>\n\n<p>Raspbian Busterのインストールは、\n<a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\">Raspbian Busterのインストール</a>\nの手順で行った。</p>\n\n<p><a href=\"http://jellyware.jp/openvino/\">JellyWare:ゼロから学ぶディープラーニング推論</a> \n → <a href=\"http://jellyware.jp/kurage/openvino/c03_setting.html\">ゼロから始めるインストール</a> をマネしただけだが、\nダウンロード先の<strong>URLが微妙に変更</strong>されてたり、\nこのページの説明が<strong>細かすぎてちょっとイラっとした</strong>ので、\n以下に手順の要約を書いておく。</p>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2\n<span class=\"nb\">cd</span> /work/NCS2/\n</code></pre></div></div>\n\n<h2 id=\"openvino-の取得とインストール\">openVINO の取得とインストール</h2>\n\n<p>アーカイブファイル落としてきて、展開するだけ。<br />\nR3がリリースされているようなので、これを使う。(2019/10/01現在)\nちょくちょくリリースされるみたいなので、<a href=\"https://download.01.org/opencv/2019/openvinotoolkit/\">https://download.01.org/opencv/2019/openvinotoolkit/</a>をチェックしてね。<br />\n2020年になったら、~download.01.org/opencv/2020/~ なのかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R3/l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz\n\n<span class=\"c\"># インストール先ディレクトリの作成 & オーナー変更(あとあとめんどくさいので)</span>\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span>  <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n\n<span class=\"c\"># 展開</span>\n<span class=\"nb\">tar </span>xzvf l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span> <span class=\"nt\">--strip-components</span><span class=\"o\">=</span>1\n<span class=\"nb\">sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以下以前の情報</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R2/l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz\n\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo tar</span> <span class=\"nt\">-xf</span> l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz <span class=\"nt\">--strip</span> 1 <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h2 id=\"cmakeのインストール\">cmakeのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n</code></pre></div></div>\n\n<p>他にもmakeとかbuild-essentialとか要るけど、<a href=\"/memoBlog/2019/06/27/pyenv.html\">ここ</a>\nでインストールしたやつがあれば大丈夫っぽい。</p>\n\n<h2 id=\"初期化スクリプトの変更\">初期化スクリプトの変更</h2>\n\n<p>~/.bashrc の最後に以下を追加。<br />\nここでは<code class=\"language-plaintext highlighter-rouge\">${VINO_DIR_TMP}</code>使っちゃダメよ~。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOの設定</span>\n<span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<h2 id=\"初期化スクリプトの変更を反映\">初期化スクリプトの変更を反映</h2>\n\n<p>シリアルコンソールやSSHでlog inしてる場合は、ここで一旦log offして再log in。<br />\nX使ってるならターミナル開きなおす。<br />\nもちろん、<code class=\"language-plaintext highlighter-rouge\">source</code>するだけでも良いけど。<br />\nいちお、.bashrcにちゃんと書けてるか確認の意味で一旦log off or ターミナル開きなおしするのがいいかな。  <br />\n(.bashrcの変更だけなので、再起動までは必要ない) <br />\nlog in時 or 新しいターミナルを開いた時に <code class=\"language-plaintext highlighter-rouge\">[setupvars.sh] OpenVINO environment initialized</code> と表示されることを確認。</p>\n\n<h2 id=\"グループの追加\">グループの追加</h2>\n\n<p>ユーザがグループusersを持っているか確認。(デフォルトなら持ってるハズ) 持ってなかったら追加。<br />\n次のコマンドで追加してくれるっぽいけど。。。</p>\n\n<h2 id=\"udevルールの追加\">udevルールの追加</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sh <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n\n<h2 id=\"いよいよncstick2の登場だ\">いよいよNCStick2の登場だ~~~</h2>\n\n<p>NCStick2をUSBポートにぶっ挿す。<br />\nデカくて他のポートに干渉するので、必要なら延長ケーブルを使ってちょ。</p>\n\n<p>で、認識されたか確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n<span class=\"c\"># こんな感じで表示されるハズ。XXX部分は ぶっ挿したUSBポートで変わる。</span>\n・・・\nBus XXX Device XXX: ID 03e7:2485 Intel Movidius MyriadX\n・・・\n</code></pre></div></div>\n\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n\n<p>とりあえず、ワークディレクトリは<code class=\"language-plaintext highlighter-rouge\">/work/NCS2/</code>を使ってる。<br />\nhome に色々ぶち込むの嫌いなので。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">/work</code>は作成済みで<code class=\"language-plaintext highlighter-rouge\">chown</code>済みとする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ワークディレクトリの作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/sample\n<span class=\"nb\">cd</span> /work/NCS2/sample\n\n<span class=\"c\"># cmakeの実行</span>\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a\"</span> <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/deployment_tools/inference_engine/samples\n\n<span class=\"c\"># makeの実行</span>\nmake <span class=\"nt\">-j2</span> object_detection_sample_ssd\n\n<span class=\"c\"># ネットワークデータの取得</span>\n<span class=\"c\"># shell変数の設定時はスペース入れちゃダメだよ~</span>\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R2/20190716_170000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n\n<span class=\"c\"># 入力ファイルをどっかから持ってきて、<<入力ファイル>>.jpgとしてカレントディレクトリに保存しておく</span>\n<span class=\"c\"># 顔検出のデモなので、人物が何人か写ってる画像を用意してね。</span>\n\n<span class=\"c\"># サンプル実行</span>\n./armv7l/Release/object_detection_sample_ssd  <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> <<入力ファイル>>.jpg\n\n<span class=\"c\"># out_0.bmpができる</span>\n</code></pre></div></div>\n\n<h2 id=\"結果の確認\">結果の確認</h2>\n\n<p>out_0.bmpをテキトーに表示。<br />\n人物の顔が四角で囲まれていることを確認。</p>\n\n<h2 id=\"インストールと動作確認完了\">インストールと動作確認完了</h2>\n\n<p>めでたしめでたし。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian Busterのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian Busterのインストール</h1>\n      <p>Raspbian Buster with desktopのインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspbian Buster with desktop」 の 「DownloadZIP」でダウンロードしてSDカードに書き込んでブート。<br />\n(「・・・ and recommended software」 の方ではない)<br />\n以下の手順は、RaspberryPi3 model B+、「Version: July 2019」 で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>は表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nframebuffer_width=1920\nframebuffer_height=1080\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B1 Desktop / CLI\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B3 Splash Screen\n            Would you like to show the splash screen at boot? \n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    5 Interfacing Options        \n        P3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>    \n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n<p>Windows側のクライアントは、<br />\n<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a> \nから VNC Viewerをダウンロード。<br />\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。<br />\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。<br />\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。<br />\n日本語化の手順はこちらを参考に。 <a href=\"http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"c\"># export PYENV_ROOT=/proj/.pyenv</span>\n<span class=\"c\"># export PATH=$PYENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(pyenv init -)\"</span>\n<span class=\"c\"># eval \"$(pyenv virtualenv-init -)\"</span>\n\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"c\"># export NODENV_ROOT=/proj/.nodenv</span>\n<span class=\"c\"># export PATH=$NODENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(nodenv init -)\"</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マウスフォーカスの変更\">マウスフォーカスの変更</h1>\n\n<p>ウィンドウをクリックしないとフォーカスが移動しないのはイライラするので x-mouse相当の設定をする。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/xdg/openbox/lxde-pi-rc.xml</code>の以下の部分をnoからyesに変更。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><followMouse>yes</followMouse>\n</code></pre></div></div>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Intel NCStick用TinyYOLOの<a href=\"https://github.com/movidius/ncappzoo/blob/ncsdk2/caffe/TinyYolo/run.py\">ソース</a>のコピー</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#! /usr/bin/env python3\n</span>\n<span class=\"c1\"># Copyright(c) 2017 Intel Corporation. \n# License: MIT See LICENSE file in root directory.\n</span>\n<span class=\"kn\">from</span> <span class=\"nn\">mvnc</span> <span class=\"kn\">import</span> <span class=\"n\">mvncapi</span> <span class=\"k\">as</span> <span class=\"n\">mvnc</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n\n\n<span class=\"c1\"># Assume running in examples/caffe/TinyYolo and graph file is in current directory.\n</span><span class=\"n\">input_image_file</span><span class=\"o\">=</span> <span class=\"s\">'../../data/images/nps_chair.png'</span>\n<span class=\"n\">tiny_yolo_graph_file</span><span class=\"o\">=</span> <span class=\"s\">'./graph'</span>\n\n<span class=\"c1\"># Tiny Yolo assumes input images are these dimensions.\n</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n<span class=\"n\">NETWORK_IMAGE_HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n\n\n<span class=\"c1\"># Interpret the output from a single inference of TinyYolo (GetResult)\n# and filter out objects/boxes with low probabilities.\n# output is the array of floats returned from the API GetResult but converted\n# to float32 format.\n# input_image_width is the width of the input image\n# input_image_height is the height of the input image\n# Returns a list of lists. each of the inner lists represent one found object and contain\n# the following 6 values:\n#    string that is network classification ie 'cat', or 'chair' etc\n#    float value for box center X pixel location within source image\n#    float value for box center Y pixel location within source image\n#    float value for box width in pixels within source image\n#    float value for box height in pixels within source image\n#    float value that is the probability for the network classification.\n</span><span class=\"k\">def</span> <span class=\"nf\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># the raw number of floats returned from the inference (GetResult())\n</span>    <span class=\"n\">num_inference_results</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># the 20 classes this network was trained on\n</span>    <span class=\"n\">network_classifications</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">\"aeroplane\"</span><span class=\"p\">,</span> <span class=\"s\">\"bicycle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bird\"</span><span class=\"p\">,</span> <span class=\"s\">\"boat\"</span><span class=\"p\">,</span> <span class=\"s\">\"bottle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bus\"</span><span class=\"p\">,</span> <span class=\"s\">\"car\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"cat\"</span><span class=\"p\">,</span> <span class=\"s\">\"chair\"</span><span class=\"p\">,</span> <span class=\"s\">\"cow\"</span><span class=\"p\">,</span> <span class=\"s\">\"diningtable\"</span><span class=\"p\">,</span> <span class=\"s\">\"dog\"</span><span class=\"p\">,</span> <span class=\"s\">\"horse\"</span><span class=\"p\">,</span> <span class=\"s\">\"motorbike\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"person\"</span><span class=\"p\">,</span> <span class=\"s\">\"pottedplant\"</span><span class=\"p\">,</span> <span class=\"s\">\"sheep\"</span><span class=\"p\">,</span> <span class=\"s\">\"sofa\"</span><span class=\"p\">,</span> <span class=\"s\">\"train\"</span><span class=\"p\">,</span><span class=\"s\">\"tvmonitor\"</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># only keep boxes with probabilities greater than this\n</span>    <span class=\"n\">probability_threshold</span> <span class=\"o\">=</span> <span class=\"mf\">0.07</span>\n\n    <span class=\"n\">num_classifications</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">network_classifications</span><span class=\"p\">)</span> <span class=\"c1\"># should be 20\n</span>    <span class=\"n\">grid_size</span> <span class=\"o\">=</span> <span class=\"mi\">7</span> <span class=\"c1\"># the image is a 7x7 grid.  Each box in the grid is 64x64 pixels\n</span>    <span class=\"n\">boxes_per_grid_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span> <span class=\"c1\"># the number of boxes returned for each grid cell\n</span>\n    <span class=\"c1\"># grid_size is 7 (grid is 7x7)\n</span>    <span class=\"c1\"># num classifications is 20\n</span>    <span class=\"c1\"># boxes per grid cell is 2\n</span>    <span class=\"n\">all_probabilities</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># classification_probabilities  contains a probability for each classification for\n</span>    <span class=\"c1\"># each 64x64 pixel square of the grid.  The source image contains\n</span>    <span class=\"c1\"># 7x7 of these 64x64 pixel squares and there are 20 possible classifications\n</span>    <span class=\"n\">classification_probabilities</span> <span class=\"o\">=</span> \\\n        <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">980</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n    <span class=\"n\">num_of_class_probs</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># The probability scale factor for each box\n</span>    <span class=\"n\">box_prob_scale_factor</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">980</span><span class=\"p\">:</span><span class=\"mi\">1078</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># get the boxes from the results and adjust to be pixel units\n</span>    <span class=\"n\">all_boxes</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">1078</span><span class=\"p\">:],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n    <span class=\"n\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">all_boxes</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># adjust the probabilities with the scaling factor\n</span>    <span class=\"k\">for</span> <span class=\"n\">box_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">):</span> <span class=\"c1\"># loop over boxes\n</span>        <span class=\"k\">for</span> <span class=\"n\">class_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">):</span> <span class=\"c1\"># loop over classifications\n</span>            <span class=\"n\">all_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">,</span><span class=\"n\">class_index</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">class_index</span><span class=\"p\">],</span><span class=\"n\">box_prob_scale_factor</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">])</span>\n\n\n    <span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"o\">>=</span><span class=\"n\">probability_threshold</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">nonzero</span><span class=\"p\">(</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">)</span>\n    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># sort the boxes from highest probability to lowest and then\n</span>    <span class=\"c1\"># sort the probabilities and classifications to match\n</span>    <span class=\"n\">argsort</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argsort</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">))[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n\n\n    <span class=\"c1\"># get mask for boxes that seem to be the same object\n</span>    <span class=\"n\">duplicate_box_mask</span> <span class=\"o\">=</span> <span class=\"n\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># update the boxes, probabilities and classifications removing duplicates.\n</span>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n\n    <span class=\"n\">classes_boxes_and_probs</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)):</span>\n        <span class=\"n\">classes_boxes_and_probs</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">([</span><span class=\"n\">network_classifications</span><span class=\"p\">[</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]])</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">classes_boxes_and_probs</span>\n\n<span class=\"c1\"># creates a mask to remove duplicate objects (boxes) and their related probabilities and classifications\n# that should be considered the same object.  This is determined by how similar the boxes are\n# based on the intersection-over-union metric.\n# box_list is as list of boxes (4 floats for centerX, centerY and Length and Width)\n</span><span class=\"k\">def</span> <span class=\"nf\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">):</span>\n    <span class=\"c1\"># The intersection-over-union threshold to use when determining duplicates.\n</span>    <span class=\"c1\"># objects/boxes found that are over this threshold will be\n</span>    <span class=\"c1\"># considered the same object\n</span>    <span class=\"n\">max_iou</span> <span class=\"o\">=</span> <span class=\"mf\">0.35</span>\n\n    <span class=\"n\">box_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">ones</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">))</span>\n\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">max_iou</span><span class=\"p\">:</span>\n                <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span>\n\n    <span class=\"n\">filter_iou_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">box_mask</span> <span class=\"o\">></span> <span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">filter_iou_mask</span>\n\n<span class=\"c1\"># Converts the boxes in box list to pixel units\n# assumes box_list is the output from the box output from\n# the tiny yolo network and is [grid_size x grid_size x 2 x 4].\n</span><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># number of boxes per grid cell\n</span>    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n\n    <span class=\"c1\"># setup some offset values to map boxes to pixels\n</span>    <span class=\"c1\"># box_offset will be [[ [0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6]] ...repeated for 7 ]\n</span>    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">)),(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)),(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># adjust the box center\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">box_offset</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">box_offset</span><span class=\"p\">,(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># adjust the lengths and widths\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n\n    <span class=\"c1\">#scale the boxes to the image size in pixels\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n\n\n<span class=\"c1\"># Evaluate the intersection-over-union for two boxes\n# The intersection-over-union metric determines how close\n# two boxes are to being the same box.  The closer the boxes\n# are to being the same, the closer the metric will be to 1.0\n# box_1 and box_2 are arrays of 4 numbers which are the (x, y)\n# points that define the center of the box and the length and width of\n# the box.\n# Returns the intersection-over-union (between 0.0 and 1.0)\n# for the two boxes specified.\n</span><span class=\"k\">def</span> <span class=\"nf\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># one diminsion of the intersecting box\n</span>    <span class=\"n\">intersection_dim_1</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># the other dimension of the intersecting box\n</span>    <span class=\"n\">intersection_dim_2</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">intersection_dim_1</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">intersection_dim_2</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># no intersection area\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># intersection area is product of intersection dimensions\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span>  <span class=\"n\">intersection_dim_1</span><span class=\"o\">*</span><span class=\"n\">intersection_dim_2</span>\n\n    <span class=\"c1\"># calculate the union area which is the area of each box added\n</span>    <span class=\"c1\"># and then we need to subtract out the intersection area since\n</span>    <span class=\"c1\"># it is counted twice (by definition it is in each box)\n</span>    <span class=\"n\">union_area</span> <span class=\"o\">=</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">intersection_area</span><span class=\"p\">;</span>\n\n    <span class=\"c1\"># now we can return the intersection over union\n</span>    <span class=\"n\">iou</span> <span class=\"o\">=</span> <span class=\"n\">intersection_area</span> <span class=\"o\">/</span> <span class=\"n\">union_area</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">iou</span>\n\n<span class=\"c1\"># Displays a gui window with an image that contains\n# boxes and lables for found objects.  will not return until\n# user presses a key.\n# source_image is the original image for the inference before it was resized or otherwise changed.\n# filtered_objects is a list of lists (as returned from filter_objects()\n# each of the inner lists represent one found object and contain\n# the following 6 values:\n#    string that is network classification ie 'cat', or 'chair' etc\n#    float value for box center X pixel location within source image\n#    float value for box center Y pixel location within source image\n#    float value for box width in pixels within source image\n#    float value for box height in pixels within source image\n#    float value that is the probability for the network classification.\n</span><span class=\"k\">def</span> <span class=\"nf\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">source_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objects</span><span class=\"p\">):</span>\n    <span class=\"c1\"># copy image so we can draw on it. Could just draw directly on source image if not concerned about that.\n</span>    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n    <span class=\"n\">source_image_width</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">source_image_height</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"n\">x_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_width</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_WIDTH</span>\n    <span class=\"n\">y_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_height</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span>\n\n    <span class=\"c1\"># loop through each box and draw it on the image along with a classification label\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Found this many objects in the image: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)))</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)):</span>\n        <span class=\"n\">center_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span> \n        <span class=\"n\">center_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span>\n        <span class=\"n\">half_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n        <span class=\"n\">half_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n\n        <span class=\"c1\"># calculate box (left, top) and (right, bottom) coordinates\n</span>        <span class=\"n\">box_left</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">-</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_top</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">-</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_right</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">+</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"n\">source_image_width</span><span class=\"p\">)</span>\n        <span class=\"n\">box_bottom</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">+</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"n\">source_image_height</span><span class=\"p\">)</span>\n\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'box at index '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj_index</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">' is... left: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', top: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_top</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', right: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_right</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', bottom: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_bottom</span><span class=\"p\">))</span>  \n\n        <span class=\"c1\">#draw the rectangle on the image.  This is hopefully around the object\n</span>        <span class=\"n\">box_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>  <span class=\"c1\"># green box\n</span>        <span class=\"n\">box_thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span> <span class=\"n\">box_bottom</span><span class=\"p\">),</span> <span class=\"n\">box_color</span><span class=\"p\">,</span> <span class=\"n\">box_thickness</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># draw the classification label string just above and to the left of the rectangle\n</span>        <span class=\"n\">label_background_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">70</span><span class=\"p\">,</span> <span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">70</span><span class=\"p\">)</span> <span class=\"c1\"># greyish green background for text\n</span>        <span class=\"n\">label_text_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>   <span class=\"c1\"># white text\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">20</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"p\">),</span> <span class=\"n\">label_background_color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">' : %.2f'</span> <span class=\"o\">%</span> <span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">5</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"o\">+</span><span class=\"mi\">5</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"n\">label_text_color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n    <span class=\"n\">window_name</span> <span class=\"o\">=</span> <span class=\"s\">'TinyYolo (hit key to exit)'</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">display_image</span><span class=\"p\">)</span>\n\n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"n\">raw_key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># check if the window is visible, this means the user hasn't closed\n</span>        <span class=\"c1\"># the window via the X button (may only work with opencv 3.x\n</span>        <span class=\"n\">prop_val</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">getWindowProperty</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">WND_PROP_ASPECT_RATIO</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">raw_key</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"n\">prop_val</span> <span class=\"o\"><</span> <span class=\"mf\">0.0</span><span class=\"p\">)):</span>\n            <span class=\"c1\"># the user hit a key or closed the window (in that order)\n</span>            <span class=\"k\">break</span>\n\n\n<span class=\"c1\"># This function is called from the entry point to do\n# all the work.\n</span><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Running NCS Caffe TinyYolo example'</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Set logging level to only log errors\n</span>    <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">global_set_option</span><span class=\"p\">(</span><span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">GlobalOption</span><span class=\"p\">.</span><span class=\"n\">RW_LOG_LEVEL</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"n\">devices</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">enumerate_devices</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'No devices found'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"mi\">1</span>\n    <span class=\"n\">device</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Device</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"nb\">open</span><span class=\"p\">()</span>\n\n    <span class=\"c1\">#Load graph from disk and allocate graph via API\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tiny_yolo_graph_file</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'rb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">graph_from_disk</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Graph</span><span class=\"p\">(</span><span class=\"s\">\"Tiny Yolo Graph\"</span><span class=\"p\">)</span>\n    <span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span> <span class=\"o\">=</span> <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">allocate_with_fifos</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"n\">graph_from_disk</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Read image from file, resize it to network width and height\n</span>    <span class=\"c1\"># save a copy in display_image for display, then convert to float32, normalize (divide by 255),\n</span>    <span class=\"c1\"># and finally convert to convert to float16 to pass to LoadTensor as input for an inference\n</span>    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">input_image_file</span><span class=\"p\">)</span>\n    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span><span class=\"p\">,</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">INTER_LINEAR</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">divide</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"mf\">255.0</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>  <span class=\"c1\"># convert to RGB\n</span>\n    <span class=\"c1\"># Load tensor and get result.  This executes the inference on the NCS\n</span>    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">queue_inference_with_fifo_elem</span><span class=\"p\">(</span><span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span><span class=\"p\">,</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">output</span><span class=\"p\">,</span> <span class=\"n\">userobj</span> <span class=\"o\">=</span> <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">read_elem</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># filter out all the objects/boxes that don't meet thresholds\n</span>    <span class=\"n\">filtered_objs</span> <span class=\"o\">=</span> <span class=\"n\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">output</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Displaying image with objects detected in GUI'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Click in the GUI window and hit any key to exit'</span><span class=\"p\">)</span>\n    <span class=\"c1\">#display the filtered objects/boxes in a GUI window\n</span>    <span class=\"n\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objs</span><span class=\"p\">)</span>\n\n    <span class=\"n\">fifo_in</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Finished'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># main entry point for program. we'll call main() to do what needs to be done.\n</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その5)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その5)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"認識結果の表示ルーチンdisplay_objects_in_gui\">認識結果の表示ルーチン(display_objects_in_gui)</h1>\n\n<p>203行目<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">source_image</code>:入力画像(表示画像)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects</code>:整理された認識結果</li>\n</ul>\n\n<p><code class=\"language-plaintext highlighter-rouge\">filtered_objects</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">source_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objects</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>205行目<br />\n入力画像を表示用に<code class=\"language-plaintext highlighter-rouge\">display_image</code>にコピーする。(もともと入力された<code class=\"language-plaintext highlighter-rouge\">source_image</code>は汚さない。)<br />\n<code class=\"language-plaintext highlighter-rouge\">source_image_width</code>、<code class=\"language-plaintext highlighter-rouge\">source_image_height</code>は入力画像の幅と高さ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n    <span class=\"n\">source_image_width</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">source_image_height</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>209行目<br />\n<code class=\"language-plaintext highlighter-rouge\">NETWORK_IMAGE_WIDTH</code>と<code class=\"language-plaintext highlighter-rouge\">NETWORK_IMAGE_HEIGHT</code> は ニューラルネットに入力した画像サイズ(グローバル変数)。<br />\nどうせなら関数パラメータで渡した方がスマートだと思うが…<br />\n<code class=\"language-plaintext highlighter-rouge\">filtered_objects</code>の各データはこのサイズで定義されているので、表示用に変換するための比率を<code class=\"language-plaintext highlighter-rouge\">x_ratio</code>、<code class=\"language-plaintext highlighter-rouge\">y_ratio</code>として得る。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">x_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_width</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_WIDTH</span>\n    <span class=\"n\">y_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_height</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span>\n</code></pre></div></div>\n\n<p>213行目<br />\nそれぞれのバウンティングボックスに対してのループ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Found this many objects in the image: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)))</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)):</span>\n</code></pre></div></div>\n\n<p>215行目<br />\n認識結果のX座標(中心)、Y座標(中心)、幅、高さを表示用画像のサイズに変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">center_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span> \n        <span class=\"n\">center_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span>\n        <span class=\"n\">half_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n        <span class=\"n\">half_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n</code></pre></div></div>\n\n<p>221行目<br />\nX座標(中心)、Y座標(中心)、幅、高さからX座標(左端)、Y座標(上端)、X座標(右端)、Y座標(右端)に変換。<br />\n表示画像の範囲からはみ出ないように制限処理を付けてある。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">box_left</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">-</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_top</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">-</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_right</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">+</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"n\">source_image_width</span><span class=\"p\">)</span>\n        <span class=\"n\">box_bottom</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">+</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"n\">source_image_height</span><span class=\"p\">)</span>\n\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'box at index '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj_index</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">' is... left: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', top: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_top</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', right: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_right</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', bottom: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_bottom</span><span class=\"p\">))</span>  \n</code></pre></div></div>\n\n<p>229行目<br />\n表示画像にバウンティングボックスの四角を描く。<br />\n色は緑、線幅は2。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">box_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>  <span class=\"c1\"># green box\n</span>        <span class=\"n\">box_thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span> <span class=\"n\">box_bottom</span><span class=\"p\">),</span> <span class=\"n\">box_color</span><span class=\"p\">,</span> <span class=\"n\">box_thickness</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>234行目<br />\n表示画像に認識結果の名称とスコアを書く。<br />\n背景は暗い緑。文字色は白。<br />\n表示位置はバウンティングボックスの上20ピクセルの場所。<br />\nサイズは縦20ピクセル、横バウンティングボックスと同サイズ。<br />\n(バウンティングボックスの上端が20未満の時大丈夫なんだろか?表示が切れるだけ?)<br />\n(バウンティングボックスの右端より認識結果文字列が長いときも?)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">label_background_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">70</span><span class=\"p\">,</span> <span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">70</span><span class=\"p\">)</span> <span class=\"c1\"># greyish green background for text\n</span>        <span class=\"n\">label_text_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>   <span class=\"c1\"># white text\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">20</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"p\">),</span> <span class=\"n\">label_background_color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">' : %.2f'</span> <span class=\"o\">%</span> <span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">5</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"o\">+</span><span class=\"mi\">5</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"n\">label_text_color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>ループはここまで。</p>\n\n<p>239行目<br />\n画像の表示</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">window_name</span> <span class=\"o\">=</span> <span class=\"s\">'TinyYolo (hit key to exit)'</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">display_image</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>242行目<br />\nキー入力待ち。待ち時間は1msec。<br />\n待ち時間内にキーが押されなければ-1が返ってくる。<br />\nキー入力はGUIで表示されたウィンドウにフォーカスが当たっているときのみ有効で、コンソール(ターミナルなど)で入力してもダメ。<br />\n64bitマシンでは、キーコードを使用する場合は値を<code class=\"language-plaintext highlighter-rouge\">& 0xff</code>する必要があるが、入力なしを検出するだけなのでそのままでOK。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"n\">raw_key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>247行目<br />\nウィンドウパラメータの取得。<br />\nウィンドウが閉じられていれば-1.0が返る。表示状態ならウィンドウのアクセプト比が返る。<br />\n×ボタンでウィンドウを閉じたときの対策。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">prop_val</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">getWindowProperty</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">WND_PROP_ASPECT_RATIO</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>247行目<br />\nキー入力があった、または、×ボタンでウィンドウが閉じられたら終了。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">raw_key</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"n\">prop_val</span> <span class=\"o\"><</span> <span class=\"mf\">0.0</span><span class=\"p\">)):</span>\n            <span class=\"c1\"># the user hit a key or closed the window (in that order)\n</span>            <span class=\"k\">break</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その4)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その4)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"バウンティングボックス情報の単位変換boxes_to_pixel_units\">バウンティングボックス情報の単位変換(boxes_to_pixel_units)</h1>\n\n<p>129行目<br />\n各バウンティングボックスの座標/サイズ情報配列内のデータは各グリッド内の相対位置/相対サイズなので、画像内の座標に変換する。</p>\n\n<p>パラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_list   </code> : 各バウンティングボックスの座標/サイズ情報配列、</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">image_width</code> : 入力画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">image_height</code> : 入力画像高(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">grid_size  </code> : グリッドサイズ(7)<br />\n<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n [\n   [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n   [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n ]\n ・・・\n 同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>変換後の<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>132行目<br />\n定義されたバウンティングボックスの数。<br />\nGraphファイルに紐づいた値と考えられるので、トップレベルで定義しておいた方が分かりやすいと思うのだが。。。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n</code></pre></div></div>\n\n<p>136行目<br />\nグリッド内オフセットから画像内オフセットに変換するための作業用配列を作成。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">)),(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)),(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>う~ん、まとめて書いてあって分かり難いので、分解してみる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">aa</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span>\n    <span class=\"n\">bb</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">aa</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n    <span class=\"n\">cc</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">bb</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">))</span>\n    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">cc</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>としたとき、</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>aa = [\n       [0, 1, 2, 3, 4, 5, 6]\n     ]\nbb = [\n       [0, 1, 2, 3, 4, 5, 6],\n       ・・・\n       同じものがあと13組(合計14組)\n     ]\ncc = [\n       [\n         [0, 1, 2, 3, 4, 5, 6],\n         ・・・\n         同じものがあと6組(合計7組)\n       ],\n       ・・・\n       同じものがあと1組(合計2組)\n     ]\nbox_offset = [\n               [\n                 [0, 0],\n                 [1, 1],\n                 [2, 2],\n                 [3, 3],\n                 [4, 4],\n                 [5, 5],\n                 [6, 6]\n               ],\n               ・・・\n               同じものがあと6組(合計7組)\n             ]\n</code></pre></div></div>\n<p>となる。</p>\n\n<p>139行目<br />\n各グリッドのX座標データにグリッド番号を加算する(画像内絶対位置になる。単位:グリッド)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">box_offset</span>\n</code></pre></div></div>\n\n<p>140行目<br />\n各グリッドのY座標データにグリッド番号を加算する(画像内絶対位置になる。単位:グリッド)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">box_offset</span><span class=\"p\">,(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>141行目<br />\n各グリッドのX座標とY座標データをグリッド数で割る(画像内相対位置になる)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># adjust the lengths and widths\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n</code></pre></div></div>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\">#scale the boxes to the image size in pixels\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n</code></pre></div></div>\n\n<h2 id=\"処理を書き換えてみる\">処理を書き換えてみる</h2>\n<p>なにやら小難しいことをやっているので、実行速度を考えずに分かりやすく書き換えると以下のようになる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units_alt</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>                               <span class=\"c1\"># 定義されたバウンティングボックス数  \n</span>    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>                     <span class=\"c1\"># グリッド縦方向ループ\n</span>        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>                 <span class=\"c1\"># グリッド横方向ループ\n</span>            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>        <span class=\"c1\"># バウンティングボックスループ\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">gx</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span>        <span class=\"c1\"># box_x\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">gy</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span>       <span class=\"c1\"># box_y\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">**</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span>                             <span class=\"c1\"># box_widtn\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">**</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span>                            <span class=\"c1\"># box_height\n</span></code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その3)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その3)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"重なったボックス情報を削除するためのマスク情報配列を取得get_duplicate_box_mask\">重なったボックス情報を削除するためのマスク情報配列を取得(get_duplicate_box_mask)</h1>\n\n<p>109行目<br />\n重なったボックス情報を削除するためのマスク情報配列を取得する。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_list</code> : バウンティングボックスの座標/サイズ情報のセットの配列<br />\n<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [X座標, Y座標, 幅, 高さ],\n  [X座標, Y座標, 幅, 高さ],\n  ・・・\n]\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>出力は<br />\n重なったボックス情報を削除するためのマスク情報配列。<br />\n閾値を超えたスコアの数 の dtype.bool型の1次元配列。<br />\n出力の配列の構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ True, True, False, False, True, ・・・]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>113行目<br />\n重なっていると判断する重なり比率の閾値</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">max_iou</span> <span class=\"o\">=</span> <span class=\"mf\">0.35</span>\n</code></pre></div></div>\n\n<p>115行目<br />\n重なり判断済みフラグを1で初期化<br />\ndtype=’bool’ で良い気がするが…そうすれば最後のboolへの変換処理が不要になるのに…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">ones</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>117行目<br />\n総当たりチェックを行うためのループ処理<br />\n重なり判断済みフラグが0なら既に重なりBOXとして削除済みなのでスキップ</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n</code></pre></div></div>\n\n<p>120行目<br />\n2つのBOXの重なり比率を計算し、<code class=\"language-plaintext highlighter-rouge\">max_iou</code>より大きければ重なっていると判断する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"k\">if</span> <span class=\"n\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">max_iou</span><span class=\"p\">:</span>\n                <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span>\n</code></pre></div></div>\n<p>123行目<br />\n重なり判断済みフラグをbool型に変換したものを返す</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">filter_iou_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">box_mask</span> <span class=\"o\">></span> <span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">filter_iou_mask</span>\n</code></pre></div></div>\n\n<h1 id=\"2つのboxの重なり比率を計算get_intersection_over_union\">2つのBOXの重なり比率を計算(get_intersection_over_union)</h1>\n\n<p>163行目<br />\nパラメータで与えられる2つのBOXの重なり比率を計算する</p>\n\n<p>パラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_1</code> : ボックス1の座標/サイズ情報</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_2</code> : ボックス2の座標/サイズ情報</li>\n</ul>\n\n<p>各パラメータの配列構成は</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[0]</code> : ボックスのX座標(中心, pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[1]</code> : ボックスのY座標(中心, pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[2]</code> : ボックスの幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[3]</code> : ボックスの高さ(pixel単位)</li>\n</ul>\n\n<p>なお、座標系は  X座標は左端が原点、Y座標は上端が原点</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>166行目<br />\nbox_1 の右端座標 と box_2 の 右端座標 の小さい方 の座標 から<br />\nbox_1 の左端座標 と box_2 の 左端座標 の大きい方 の座標を引く<br />\n    ⇒ 重なっている部分の幅</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">intersection_dim_1</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n</code></pre></div></div>\n\n<p>170行目<br />\nbox_1 の下端座標 と box_2 の下端座標 の小さい方 の座標 から<br />\nbox_1 の上端座標 と box_2 の上端座標 の大きい方 の座標を引く<br />\n    ⇒ 重なっている部分の高さ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">intersection_dim_2</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>173行目<br />\n重なっている部分の幅と高さのどちらかが負数<br />\n    ⇒ 重なっている部分はないので、その面積は0</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">if</span> <span class=\"n\">intersection_dim_1</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">intersection_dim_2</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># no intersection area\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n</code></pre></div></div>\n\n<p>176行目<br />\n重なっている部分の幅と高さのどちらかが正数<br />\n    ⇒ 重なっている部分の面積を計算</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># intersection area is product of intersection dimensions\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span>  <span class=\"n\">intersection_dim_1</span><span class=\"o\">*</span><span class=\"n\">intersection_dim_2</span>\n</code></pre></div></div>\n\n<p>183行目<br />\nbox_1とbox_2の合計面積を計算(box_1の面積 + box_2の面積 - 重なっている部分の面積)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">union_area</span> <span class=\"o\">=</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">intersection_area</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<p>186行目<br />\nbox_1とbox_2の合計面積のうち、重なっている部分の比率を返す。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">iou</span> <span class=\"o\">=</span> <span class=\"n\">intersection_area</span> <span class=\"o\">/</span> <span class=\"n\">union_area</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">iou</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その2)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ncstickの出力を整理する処理ルーチンfilter_objects\">NCStickの出力を整理する処理ルーチン(filter_objects)</h1>\n\n<p>35行目<br />\nNCStickの生の出力を整理して、各Gridが何と認識したのか整理して出力する。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">inference_result  </code> : NCStickの出力をfloat32にキャストした配列(1次元×要素数1470)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image_width </code> : 画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image_height</code> : 画像高(448)</li>\n</ul>\n\n<p>出力は</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs</code> : 整理された認識結果</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<h2 id=\"各パラメータのサイズ\">各パラメータのサイズ</h2>\n\n<p>37行目<br />\nこのサイズはニューラルネット構築の際に決定された値。<br />\nGraphファイルに紐づいた値と考えられる。<br />\nなので、グローバル変数で定義しておいてパラメータで渡す方が良さそうだが。。。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">num_inference_results </code> :  NCStickの出力のサイズ(1470 : 未使用)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">network_classifications</code> : 各クラスのラベル(認識結果の名称)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">num_classifications  </code> :  その個数(20)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">grid_size             </code> :  画像のGrid分割数(7)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_per_grid_cell   </code> :  各グリッドに割り当てられたバウンティングボックス数(2)</li>\n</ul>\n\n<p>以下は認識結果を整理するためのパラメータ。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">probability_threshold </code> :  認識結果の確率の閾値。これ以下の確率は無視する。</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># the raw number of floats returned from the inference (GetResult())\n</span>    <span class=\"n\">num_inference_results</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># the 20 classes this network was trained on\n</span>    <span class=\"n\">network_classifications</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">\"aeroplane\"</span><span class=\"p\">,</span> <span class=\"s\">\"bicycle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bird\"</span><span class=\"p\">,</span> <span class=\"s\">\"boat\"</span><span class=\"p\">,</span> <span class=\"s\">\"bottle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bus\"</span><span class=\"p\">,</span> <span class=\"s\">\"car\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"cat\"</span><span class=\"p\">,</span> <span class=\"s\">\"chair\"</span><span class=\"p\">,</span> <span class=\"s\">\"cow\"</span><span class=\"p\">,</span> <span class=\"s\">\"diningtable\"</span><span class=\"p\">,</span> <span class=\"s\">\"dog\"</span><span class=\"p\">,</span> <span class=\"s\">\"horse\"</span><span class=\"p\">,</span> <span class=\"s\">\"motorbike\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"person\"</span><span class=\"p\">,</span> <span class=\"s\">\"pottedplant\"</span><span class=\"p\">,</span> <span class=\"s\">\"sheep\"</span><span class=\"p\">,</span> <span class=\"s\">\"sofa\"</span><span class=\"p\">,</span> <span class=\"s\">\"train\"</span><span class=\"p\">,</span><span class=\"s\">\"tvmonitor\"</span><span class=\"p\">]</span>\n\n    <span class=\"n\">probability_threshold</span> <span class=\"o\">=</span> <span class=\"mf\">0.07</span>\n\n    <span class=\"n\">num_classifications</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">network_classifications</span><span class=\"p\">)</span> <span class=\"c1\"># should be 20\n</span>\n    <span class=\"n\">grid_size</span> <span class=\"o\">=</span> <span class=\"mi\">7</span> <span class=\"c1\"># the image is a 7x7 grid.  Each box in the grid is 64x64 pixels\n</span>    <span class=\"n\">boxes_per_grid_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span> <span class=\"c1\"># the number of boxes returned for each grid cell\n</span></code></pre></div></div>\n\n<h2 id=\"すべての確率配列\">すべての確率配列</h2>\n\n<p>55行目<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)×クラス数(20) で、一旦0クリアしておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">all_probabilities</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<h2 id=\"各クラスの確率配列\">各クラスの確率配列</h2>\n\n<p>60行目<br />\n<code class=\"language-plaintext highlighter-rouge\">classification_probabilities</code> : NCStickの出力から各クラスの確率配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×クラス数(20)<br />\n入力側は1次元配列なので、要素 0 ~ 979 (980個 = 7×7×20)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classification_probabilities</span> <span class=\"o\">=</span> \\\n        <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">980</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n    <span class=\"n\">num_of_class_probs</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"各バウンティングボックスの確率配列\">各バウンティングボックスの確率配列</h2>\n\n<p>65行目<br />\n<code class=\"language-plaintext highlighter-rouge\">box_prob_scale_factor</code> : NCStickの出力から各バウンティングボックスの確率配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)<br />\n入力側は1次元配列なので、要素 980 ~ 1077 (98個 = 7×7×2)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_prob_scale_factor</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">980</span><span class=\"p\">:</span><span class=\"mi\">1078</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<h2 id=\"各バウンティングボックスの座標サイズ情報配列\">各バウンティングボックスの座標/サイズ情報配列</h2>\n\n<p>68行目<br />\nNCStickの出力から各バウンティングボックスの座標/サイズ情報配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)×XY幅高さ(4)<br />\n入力側は1次元配列なので、要素 1078 ~ 1469 (392個 = 7×7×2×4)<br />\n<code class=\"language-plaintext highlighter-rouge\">all_boxes</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n      [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n<p>幅と高さがイメージサイズに対する比率の平方根な理由は謎。。。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># get the boxes from the results and adjust to be pixel units\n</span>    <span class=\"n\">all_boxes</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">1078</span><span class=\"p\">:],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>69行目<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_to_pixel_units</code>(129行目)で<br />\n各バウンティングボックスの座標/サイズ情報配列を、入力画像幅(448)、入力画像高(448)、グリッドサイズ(7)からピクセル単位に変換</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">all_boxes</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">boxes_to_pixel_units</code> 実行後の <code class=\"language-plaintext highlighter-rouge\">all_boxes</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n\n<p>これらの配列の再配列のイメージはこんな感じ。<br />\n<img src=\"/memoBlog/misc/TinyYOLO_2_1.png\" alt=\"結果の再配列のイメージ\" /></p>\n\n<p>72行目<br />\n各グリッドに対する各クラスの確率と各バウンティングボックスの確率を乗じてすべての確率配列を生成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities</code> は Grid_Y × Grid_X × BBox × NumClass の4次元配列。<br />\nデータはバウンティングボックスごとの各クラスのスコアを示している。<br />\n(バウンティングボックスの確率 × クラスの確率)<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [     0.5488,     0.7152,     0.6028,     0.5449,     0.4237,     0.6459, ]\n      [     0.4376,     0.8918,     0.9637,     0.3834,     0.7917,     0.5289, ]\n    ]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">for</span> <span class=\"n\">box_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">):</span> <span class=\"c1\"># loop over boxes\n</span>        <span class=\"k\">for</span> <span class=\"n\">class_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">):</span> <span class=\"c1\"># loop over classifications\n</span>            <span class=\"n\">all_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">,</span><span class=\"n\">class_index</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">class_index</span><span class=\"p\">],</span><span class=\"n\">box_prob_scale_factor</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>77行目<br />\nすべての確率のマスク配列<code class=\"language-plaintext highlighter-rouge\">probability_threshold_mask</code>を生成する。<br />\nデータはall_probabilitiesの要素の値がprobability_threshold以上であればTrue、未満ならFalseが入っている。<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [ True, True, True, True, False, True, ]\n      [ False, True, True, False, True, True, ]\n    ]\n    ・・・・\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"o\">>=</span><span class=\"n\">probability_threshold</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">),</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">probability_threshold</span>\n</code></pre></div></div>\n\n<p>78行目<br />\n<code class=\"language-plaintext highlighter-rouge\">box_threshold_mask</code> は 4 × 閾値を超えたスコアの数 の 2次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_boxes</code>、<code class=\"language-plaintext highlighter-rouge\">all_probabilities</code>から有効なデータを取り出すためのマスクデータ。<br />\n<code class=\"language-plaintext highlighter-rouge\">probability_threshold_mask</code>で要素が<code class=\"language-plaintext highlighter-rouge\">true</code>のもの(=ゼロでないもの)のインデックス一覧をに格納する。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[0][n]</code> : n番目の閾値を超えたスコアを持つY方向のグリッド番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[1][n]</code> : n番目の閾値を超えたスコアを持つX方向のグリッド番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[2][n]</code> : n番目の閾値を超えたスコアを持つバウンティングボックス番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[3][n]</code> : n番目の閾値を超えたスコアを持つクラス番号</li>\n</ul>\n\n<p>つまり、<br />\n    <code class=\"language-plaintext highlighter-rouge\">all_boxes[box_threshold_mask[0][n]][box_threshold_mask[1][n]][box_threshold_mask[2][n]]</code><br />\n    <code class=\"language-plaintext highlighter-rouge\">all_probabilities[box_threshold_mask[0][n]][box_threshold_mask[1][n]][box_threshold_mask[2][n]][0または1]</code><br />\nがそれぞれn番目の閾値を超えたスコアを持つバウンティングボックスの座標/大きさ情報とスコア(バウンティングボックスごとのペア)を持つ</p>\n\n<p>データ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [ 0, 0, 0, 0, 0, 0, ・・・・\n  [ 0, 0, 0, 0, 0, 0, ・・・・]\n  [ 0, 0, 0, 0, 0, 1, ・・・・]\n  [ 0, 1, 2, 3, 5, 1, ・・・・]\n]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">nonzero</span><span class=\"p\">(</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">gx_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">gy_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">bb_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">cls_list</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n                        <span class=\"n\">gy_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">gy_list</span><span class=\"p\">,</span>  <span class=\"n\">gy</span><span class=\"p\">)</span>\n                        <span class=\"n\">gx_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">gx_list</span><span class=\"p\">,</span>  <span class=\"n\">gx</span><span class=\"p\">)</span>\n                        <span class=\"n\">bb_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">bb_list</span><span class=\"p\">,</span>  <span class=\"n\">bb</span><span class=\"p\">)</span>\n                        <span class=\"n\">cls_list</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">cls_list</span><span class=\"p\">,</span> <span class=\"n\">cls</span><span class=\"p\">)</span>\n    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">gy_list</span><span class=\"p\">,</span> <span class=\"n\">gx_list</span><span class=\"p\">,</span> <span class=\"n\">bb_list</span><span class=\"p\">,</span> <span class=\"n\">cls_list</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>79行目<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 閾値を超えたスコアの数 × 4 の 2次元配列</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n]</code>    : n番目の閾値を超えたスコアを持つバウンティングボックスの座標/サイズ情報のセット\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][0]</code> : X座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][1]</code> : Y座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][2]</code> : 幅(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][3]</code> : 高さ(pixel単位)</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">((</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">),</span> <span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i0</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span> <span class=\"p\">:</span>\n        <span class=\"n\">box_info</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]]</span>\n        <span class=\"n\">box_info</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">box_info</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n        <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">,</span> <span class=\"n\">box_info</span><span class=\"p\">,</span> <span class=\"n\">axis</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>80行目<br />\n・・・  う~ん ・・・</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p>なんか複雑な式なのでちょっと分割してみる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tmp_data</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">tmp_data</code> は Grid_Y × Grid_X × BBox の3次元配列<br />\nデータは各グリッドにBBoxずつ定義されたバウンティングボックスの各クラスに対するスコアの中から最大値を持つ要素のインデックス(=クラス番号)</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">np.argmax()</code>は配列要素の最大値を取るメソッド。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities[GY][GX][BB][CLS]</code>の4次元配列に対してaxis=3を指定して実行していて、<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities[gy][gx][bb][0~NumCls]</code>の最大値を持つ要素のインデックスを <code class=\"language-plaintext highlighter-rouge\">tmp_data[gy][gx][bb]</code>に格納する</p>\n\n<p>データ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [ 1, 2, ]\n    [ 1, 2, ]\n    [ 3, 1, ]\n    [ 2, 0, ]\n    [ 4, 2, ]\n    [ 2, 4, ]\n    [ 0, 5, ]\n  ]\n  ・・・\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code> は 閾値を超えたスコアの数 の 1次元配列<br />\nデータは各グリッドのスコアが最大のクラス番号を格納した1次元配列\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ 1, 1, 1, 1, ・・・\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tmp_data</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_cell</span><span class=\"p\">),</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">].</span><span class=\"n\">tolist</span><span class=\"p\">()</span>\n                <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">a</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">))</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span>  <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i0</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span> <span class=\"p\">:</span>\n        <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">,</span> <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]])</span>\n</code></pre></div></div>\n\n<p>81行目<br />\n<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code> は 閾値を超えたスコアの数 の 1次元配列。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold[n]</code>    : n番目の閾値を超えたスコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probabilities_above_threshold</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'float'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n                        <span class=\"n\">probabilities_above_threshold</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">,</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>この時点でスコアが閾値を超えたグリッドの情報が</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code></li>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code></li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code></li>\n</ul>\n\n<p>に格納される。これらは 一対一対一 の関係になっている。<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 2次元配列だが、X, Y, WIDTH, HEIGHT のペアの配列と考えればわかりやすい。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above[n]</code>  : n番目の閾値を超えたスコアを持つクラス番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold[n]</code>    : n番目の閾値を超えたスコア</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n]</code>            : n番目の閾値を超えたスコアを持つバウンティングボックスの座標/サイズ情報のセット\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][0]</code>       : X座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][1]</code>       : Y座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][2]</code>       : 幅(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][3]</code>       : 高さ(pixel単位)</li>\n    </ul>\n  </li>\n</ul>\n\n<p>85行目<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort</code> は <code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code> の各要素を降順に並べた際のインデックス番号を取り出した1次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort(~)</code> は 指定された配列 の各要素を昇順に並べた際のインデックス番号を取り出した配列を得るメソッド。<br />\n<code class=\"language-plaintext highlighter-rouge\">[::-1]</code>を付けてあるので降順になる。<br />\nそのままだと<code class=\"language-plaintext highlighter-rouge\">list</code>型になってしまうので、<code class=\"language-plaintext highlighter-rouge\">np.array()</code>で<code class=\"language-plaintext highlighter-rouge\">np.ndarray</code>型に変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">argsort</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argsort</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">))[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>86行目<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort</code>  を使って\n<code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code>、<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code>、<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> から <code class=\"language-plaintext highlighter-rouge\">argsort</code>で示されたインデックスで示された順に取り出す。<br />\n⇒ スコアの降順にそれぞれを並べ変える。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>書き換えるほどでもないので、ま、いっか。</p>\n\n<p>92行目<br />\n<code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code> は <code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> を検索して重なったボックス情報を削除するためのマスク情報配列。<br />\n閾値を超えたスコアの数 の dtype.bool型の1次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">get_duplicate_box_mask()</code> は <a href=\"TinyYOLO_3\">別ページ</a>参照。<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ True, True, False, False, True, ・・・]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 既にスコアの高い順に並べ替えられているので、先頭から検索していって最初の出てきたボックスを優先すれば良い。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">duplicate_box_mask</span> <span class=\"o\">=</span> <span class=\"n\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>95行目<br />\n<code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code>  を使ってそれぞれの配列からダブったデータを削除する。<br />\n<code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code>、<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code>、<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> から <code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code>でTrueの要素だけ取り出す。<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code>は ダブっていない結果の数(最終認識結果の数) × 4 の 2次元配列<br />\nそれ以外は ダブっていない結果の数(最終認識結果の数)の 1次元配列</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>99行目<br />\n最終認識結果をlistにまとめなおしてリターンする。<br />\n<code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classes_boxes_and_probs</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)):</span>\n        <span class=\"n\">classes_boxes_and_probs</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">([</span><span class=\"n\">network_classifications</span><span class=\"p\">[</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]])</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">classes_boxes_and_probs</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その1)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その1)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Intel NCStick用TinyYOLOの<a href=\"http://jellyware.jp/kurage/movidius/c13_tinyyolo_run.html\">解説記事</a>を見かけた。<br />\n<a href=\"https://github.com/movidius/ncappzoo/blob/ncsdk2/caffe/TinyYolo/run.py\">ソース</a>を読んでみたが、\n結構難解で(特にnumpy回り)、自分の鶏頭でも思い出せるように調べた結果をメモしてみた。<br />\nNCStick持ってないから実際に動かしてないけど。。。</p>\n\n<p>リポジトリは <a href=\"https://github.com/movidius/ncappzoo\">https://github.com/movidius/ncappzoo</a> だが、このソースはmasterブランチには存在しない。必ずncsdk2ブランチを選択すること。<br />\n<code class=\"language-plaintext highlighter-rouge\">git clone</code> する場合は要注意。</p>\n\n<p>どっか行っちゃうといけないので、ソースのコピーを<a href=\"TinyYOLO_src\">ここ</a>にも置いておく。</p>\n\n<h1 id=\"モジュールのインポート\">モジュールのインポート</h1>\n\n<p>特に難しいことはしてない。mvncがNCStickのドライバ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">mvnc</span> <span class=\"kn\">import</span> <span class=\"n\">mvncapi</span> <span class=\"k\">as</span> <span class=\"n\">mvnc</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n</code></pre></div></div>\n\n<h1 id=\"ファイル名定義\">ファイル名定義</h1>\n\n<p>13行目<br />\n<code class=\"language-plaintext highlighter-rouge\">input_image_file</code> : ここに書かれたファイルを読み込んで認識する。<br />\n<code class=\"language-plaintext highlighter-rouge\">tiny_yolo_graph_file</code> : ニューラルネットのネットリスト(?)  ニューロンの接続情報と重みが入っていると思われる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">input_image_file</span><span class=\"o\">=</span> <span class=\"s\">'../../data/images/nps_chair.png'</span>\n<span class=\"n\">tiny_yolo_graph_file</span><span class=\"o\">=</span> <span class=\"s\">'./graph'</span>\n</code></pre></div></div>\n\n<h1 id=\"認識用の画像サイズ定義\">認識用の画像サイズ定義</h1>\n\n<p>17行目<br />\nニューラルネットに入力する画像サイズ。任意のサイズの画像をこのサイズにリサイズしてから入力する。<br />\nこのサイズはニューラルネット構築の際に決定された値。Graphファイルに紐づいた値と考えられる。</p>\n\n<p>Grid分割数が7×7で、1Grid当たりの画像サイズが64pixelなので、7×64 = 448 でおのずと決まる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">NETWORK_IMAGE_WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n<span class=\"n\">NETWORK_IMAGE_HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n</code></pre></div></div>\n\n<h1 id=\"ncstickの出力を整理する処理ルーチンfilter_objects\">NCStickの出力を整理する処理ルーチン(filter_objects)</h1>\n\n<p>35行目<br />\n<a href=\"TinyYOLO_2\">別ページ</a></p>\n\n<h1 id=\"重なったボックス情報を削除するためのマスク情報配列を取得get_duplicate_box_mask\">重なったボックス情報を削除するためのマスク情報配列を取得(get_duplicate_box_mask)</h1>\n\n<p>109行目<br />\n<a href=\"TinyYOLO_3\">別ページ</a></p>\n\n<h1 id=\"バウンティングボックス情報の単位変換boxes_to_pixel_units\">バウンティングボックス情報の単位変換(boxes_to_pixel_units)</h1>\n\n<p>129行目<br />\n<a href=\"TinyYOLO_4\">別ページ</a></p>\n\n<h1 id=\"2つのboxの重なり比率を計算get_intersection_over_union\">2つのBOXの重なり比率を計算(get_intersection_over_union)</h1>\n\n<p>163行目<br />\n<a href=\"TinyYOLO_3\">別ページ</a></p>\n\n<h1 id=\"認識結果の表示ルーチンdisplay_objects_in_gui\">認識結果の表示ルーチン(display_objects_in_gui)</h1>\n\n<p>203行目<br />\n<a href=\"TinyYOLO_5\">別ページ</a></p>\n\n<h1 id=\"mainルーチン\">mainルーチン</h1>\n\n<h3 id=\"関数の先頭とオープニングメッセージ\">関数の先頭とオープニングメッセージ</h3>\n\n<p>255行目</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Running NCS Caffe TinyYolo example'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickドライバのオプション設定\">NCStickドライバのオプション設定</h3>\n<p>258行目</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Set logging level to only log errors\n</span>    <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">global_set_option</span><span class=\"p\">(</span><span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">GlobalOption</span><span class=\"p\">.</span><span class=\"n\">RW_LOG_LEVEL</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickの検出とオープン\">NCStickの検出とオープン</h3>\n\n<p>260行目<br />\nなかったらエラー終了。<br />\n複数見つかった場合は最初のものをオープンする。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">devices</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">enumerate_devices</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'No devices found'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"mi\">1</span>\n    <span class=\"n\">device</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Device</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"nb\">open</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h3 id=\"graphファイルの読み込み\">Graphファイルの読み込み</h3>\n\n<p>267行目<br />\n14行目で設定したGraphファイルを読み込んで、NCStickドライバに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\">#Load graph from disk and allocate graph via API\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tiny_yolo_graph_file</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'rb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">graph_from_disk</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Graph</span><span class=\"p\">(</span><span class=\"s\">\"Tiny Yolo Graph\"</span><span class=\"p\">)</span>\n    <span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span> <span class=\"o\">=</span> <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">allocate_with_fifos</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"n\">graph_from_disk</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"入力画像の読み込みと前処理\">入力画像の読み込みと前処理</h3>\n\n<p>276行目</p>\n<ul>\n  <li>13行目で設定した画像ファイルを読み込んむ(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>結果表示用にオリジナルサイズのままコピーを取っておく(<code class=\"language-plaintext highlighter-rouge\">display_image</code>)</li>\n  <li>NCStickに入力する画像サイズにリサイズ(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>各画素の値をfloat32型に変換(<code class=\"language-plaintext highlighter-rouge\">input_image</code>  元データは<code class=\"language-plaintext highlighter-rouge\">int</code>)</li>\n  <li>さらに各画素の値を0.0~1.0に正規化(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>色並びをBGRからRGBに再配列(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">input_image_file</span><span class=\"p\">)</span>\n    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span><span class=\"p\">,</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">INTER_LINEAR</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">divide</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"mf\">255.0</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>  <span class=\"c1\"># convert to RGB\n</span></code></pre></div></div>\n\n<h3 id=\"ncstick-による処理\">NCStick による処理</h3>\n\n<p>284行目<br />\nNCStickに前処理した画像を入力し、計算結果を得る。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">input_image</code>の各要素はfloat32型に変換して入力する。(既に変換済みな気もするが…)<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">input_image</code>そのものの型は <code class=\"language-plaintext highlighter-rouge\">numpy.ndarray</code>。<br />\nニューラルネットの処理本体の処理は実質この2行だけ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Load tensor and get result.  This executes the inference on the NCS\n</span>    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">queue_inference_with_fifo_elem</span><span class=\"p\">(</span><span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span><span class=\"p\">,</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">output</span><span class=\"p\">,</span> <span class=\"n\">userobj</span> <span class=\"o\">=</span> <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">read_elem</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickの出力を整理する\">NCStickの出力を整理する</h3>\n\n<p>288行目<br />\n<code class=\"language-plaintext highlighter-rouge\">filter_objects</code>(35行目)で  NCStickの出力を整理する。<br />\n<a href=\"TinyYOLO_2\">別ページ</a>を参照。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">output.astype(np.float32)</code> : NCStickの出力をfloat32にキャストした配列(1次元)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image.shape[1]     </code> : 画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image.shape[0]     </code> : 画像高(448)</li>\n</ul>\n\n<p>得られるデータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> : 整理された認識結果</li>\n</ul>\n\n<p><code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">filtered_objs</span> <span class=\"o\">=</span> <span class=\"n\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">output</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<h3 id=\"認識結果の表示\">認識結果の表示</h3>\n\n<p>290行目<br />\n<code class=\"language-plaintext highlighter-rouge\">display_objects_in_gui</code> (203行目)で 表示用イメージと整理された認識結果を表示。<br />\n<a href=\"TinyYOLO_5\">別ページ</a>を参照。<br />\nパラメータは<br />\n<code class=\"language-plaintext highlighter-rouge\">display_image</code> : 表示用画像\n<code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> : 整理された認識結果</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Displaying image with objects detected in GUI'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Click in the GUI window and hit any key to exit'</span><span class=\"p\">)</span>\n    <span class=\"c1\">#display the filtered objects/boxes in a GUI window\n</span>    <span class=\"n\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"後片付け\">後片付け</h3>\n\n<p>295行目<br />\n各クローズ処理。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">fifo_in</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Finished'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"mainルーチン呼び出し\">mainルーチン呼び出し</h1>\n\n<p>お約束の処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(Windows編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(Windows編)</h1>\n      <p>過去のブログ(Windows編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"リモートデバッグ\">リモートデバッグ</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4784a559cb0e78d060fe01d69a3c829d\">windowsのVisualStudioCodeでRasPiのNode.jsをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/aed3ddde84d76cca5c5be62df1120f81\">windowsのVisualStudioCodeでRasPiのPythonをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/46e92ee968b99174c1e1fa3199465877\">VisualStudioCodeのリモート開発が使えるようになったらしいので試してみる</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/c9bf43575d8fce47233bf191b21fbaad\">NW.jsによるWebアプリのデスクトップアプリ化</a></li>\n</ol>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(RaspberryPi編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(RaspberryPi編)</h1>\n      <p>過去のブログ(RaspberryPi編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"センサ接続gpio\">センサ接続/GPIO</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4f2290b79f3005f839afe798c424fadd\">BOSCH 9軸センサ bmx055 ドライバ(Node.js用) </a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/310580fc726f8b2315d2a81486cbe551\">RaspberryPi向けBOSCH 温度/湿度/気圧センサ(BME280)、9軸センサ(加速度/ジャイロ/地磁気)(BMX055)動作確認プログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/dc6f4c0987e462ca94f003b8d20ea456\">RaspberryPi向けGPIO操作テストプログラム</a></li>\n</ol>\n\n<h1 id=\"webサーバ\">WEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/e37a1d11ac25cf7e421f4d6c32d9a03c\">RaspberryPi向けWEBサーバ&センサテストプログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/18ee6da1c77671949e881eb45dda6edf\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/b23849cf9b82b83fe0c2df22836b6c27\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ/ついでに3D姿勢計算もブラウザでやるっちゃ</a></li>\n</ol>\n\n<h1 id=\"もう一つのwebサーバ\">もう一つのWEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/bcaa47ce1b04bd6b8285e553d6fb9f4f\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/11cc216ffde610e26a5b8cd4ee5b599b\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js/webサーバにExpressを使ってサッパリと</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/8179edb10867faf98e233a52965a9e53\">Raspbianのシリアルコンソールでloginするとイケてないのを改善する</a></li>\n</ol>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのWindows環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのWindows環境での実行</h1>\n      <p>github pagesをWindows環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行できるようにした(<a href=\"/memoBlog/2019/07/17/githubpages.html\">参照</a>)が、\nわざわざUbuntu立ち上げるのが面倒になってきたので、Windows上で実行できるようにしてみた。</p>\n\n<h1 id=\"何はともあれrubyのインストール\">何はともあれRubyのインストール</h1>\n<p>Windows版Rubyをインストールしないとはじまらないので、\n<a href=\"https://www.ruby-lang.org/ja/\">Rubyの総本山</a> から(RubyInstaller のダウンロード](https://rubyinstaller.org/downloads/)\nへ行ってダウンロード。<br />\nWITH DEVKIT を選んでおく方が良いらしい。<br />\nバージョンは最新で良いでしょう(私は Ruby+Devkit 2.6.3-1 (x64) を選びました)。</p>\n\n<p>ダウンロードしたらなんとなーくインストーラ実行して案内にしたがってなんとな~く進んでちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\ngccも要るのかな?Rubyインストール時にMSYS64環境がインストールされるみたいなので、大丈夫かな?<br />\nちなみに、うちの環境はmingw-w64が入ってる。</p>\n</blockquote>\n\n<p>とりあえずbundlerはグローバルに入れとく。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem install bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。<br />\n一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをローカルにインストールする。<br />\nUbuntuみたいにrdenv環境じゃないので、グローバル環境はなるべく汚染したくないので、<code class=\"language-plaintext highlighter-rouge\">--path</code>指定してローカルにインストールする。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div></div>\n\n<p>あるいは、<code class=\"language-plaintext highlighter-rouge\">install.cmd</code>に登録してあるので、そっちを実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRubyのバージョンを変更したり、ディレクトリを移動した場合はgemsディレクトリを削除してから</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div>  </div>\n  <p>を実行する</p>\n</blockquote>\n\n<p>windows対応にあたって、リポジトリの _config.yml と .gitignore は対処済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>サーバ起動</p>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\\server.cmd\n</code></pre></div></div>\n\n<p>もちろん、エクスプローラなどから <code class=\"language-plaintext highlighter-rouge\">server.cmd</code> をダブルクリックして実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこのときのキモ、jekyll実行前に以下を実行してRubyのエンコードをUTF-8に設定している。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>set RUBYOPT=--encoding=UTF-8`  \n</code></pre></div>  </div>\n  <p>これがないとエンコードエラーが発生する。<br />\n環境変数で設定しておけば逐一設定しなくても良いが、どうせcmdファイル書いてあるので、ついでに設定している。</p>\n</blockquote>\n\n<p>firewallが警告を表示するので、許可してちょ。<br />\nまごまごしてるとjekyllがエラー終了しちゃうけど、その後でも許可してしまえば次回からは大丈夫。</p>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>以降は<a href=\"/memoBlog/2019/07/17/githubpages.html\">こっち</a>を見てちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git + samba環境</title>\n  </head>\n  <body>\n    <header>\n      <h1>git + samba環境</h1>\n      <p>gitのローカルリポジトリをsamba環境で使用する際の注意事項</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>gitのローカルリポジトリをsamba経由で見ると、ファイルのAttributeの実行属性が変更されたと誤検出してしまうことがある。\nそんなときは、以下のコマンドでファイルのAttributeを無視するように設定すれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--unset</span> core.filemode\ngit config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>サーバ側は以下を一回だけ実行しておけばサーバ側でのAttributeの管理は有効になる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<p>意図的に実行属性を設定したい場合などは、サーバ側で<code class=\"language-plaintext highlighter-rouge\">git add</code>する。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのローカル環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのローカル環境での実行</h1>\n      <p>github pagesをローカル環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行することができる。</p>\n\n<p>以下の手順はUbuntu 16.04で動作確認した。他のバージョンでは、特にインストールの準備に微妙な違いがあるかもしれない。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<p>apt または rbenvでrubyをインストールしておく。</p>\n\n<p>aptの場合は以下(nativeなライブラリを使うので-devパッケージをインストール) 。<br />\nrbenvの場合は<a href=\"/memoBlog/2019/07/07/rbenv.html\">rbenvのインストール</a>参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ruby-dev\n</code></pre></div></div>\n\n<p>bundlerをインストールする。bundlerはNode.jsでいうところのnpmのうち、package.jsonでローカルインストールしたモジュールを管理する部分に相当するもの(かな?)。<br />\naptでrubyをインストールした場合はrootでインストール必要があるので、<code class=\"language-plaintext highlighter-rouge\">sudo</code>を付けて実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem <span class=\"nb\">install </span>bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span>\n</code></pre></div></div>\n\n<p>モジュールをローカルにインストールすることもできる。<br />\nその場合は以下で。<br />\n–pathオプションのパラメータはお好みで変更してちょ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span> <span class=\"nt\">--path</span> gems\n</code></pre></div></div>\n\n<p>このとき、<code class=\"language-plaintext highlighter-rouge\">_config.yml</code>の以下の部分にモジュールのインストール先(上の例では<code class=\"language-plaintext highlighter-rouge\">gems</code>)を追加しておく(追加しないとjekyll実行時にエラーになる)。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<div style=\"text-align: center;\">↓</div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [gems, server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n\n<h2 id=\"サーバ起動\">サーバ起動</h2>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./server.sh\n</code></pre></div></div>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>ブラウザ(firefoxとchromeで動作確認した。IEでは動かない。Edgeはよーわからん)を起動し、サーバを起動しているマシンのport 4000に接続。このとき、ブラウザはサーバと同じマシンである必要はない。</p>\n\n<h2 id=\"サーバの停止\">サーバの停止</h2>\n\n<p>CTRL+cで停止。</p>\n\n<h2 id=\"サーバの-listen-port-の変更\">サーバの listen port の変更</h2>\n\n<p>必要ならサーバの listen port を変更できる。<br />\nserver.sh 内のコマンドの <code class=\"language-plaintext highlighter-rouge\">--port</code> オプションを変更すればOK.</p>\n\n<h1 id=\"ディレクトリ構成\">ディレクトリ構成</h1>\n\n<p>ディレクトリ構成は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── _config.yml                             jekyllの設定ファイル\n├── Gemfile                                 bundlerの管理ファイル\n├── _layouts                                ページレイアウト用HTMLファイル置き場\n│   ├── default.html                           デフォルト使用\n│   ├── toppage.html                           トップページ用\n│   └── debug.html                             デバッグページ用\n│                                                 どのレイアウトを使うかは各MarkdownファイルのFront-matterで指定する\n├── _includes                               共通で使用するレイアウトはここに置いておく\n│   └── footer.html\n├── _posts                                   投稿記事置き場\n│   ├── 2019-06-22-asyncawait.md\n│   ├── ・・・・\n│   └── YYYY-MM-DD-title.md                     ブログの投稿記事  ファイル名は年-月-日-タイトル とする。\n├── _sass                                    sassのインクルードファイルを置いておく\n│   └── _my_theme.scss                          大本のテーマ設定用sassファイル\n├── assets\n│   ├── css\n│   │   ├── jquery.floatingscroll.css      jQuery の floatingscroll プラグインのCSSファイル\n│   │   └── style.scss                     このページのメインのcssになるsassファイル\n│   └── js\n│       ├── jquery.floatingscroll.min.js    jQuery の floatingscroll プラグインのスクリプトファイル\n│       └── main.js                         各ページで実行するjavascriptファイル\n├── index.md                                 トップページ\n├── misc                                     以下にその他のページデータを置く\n│   ├── debug.md\n│   └── sample.md\n├── favicon.ico                              favicon画像\n├── compile.sh                               サイト構築のみ行うスクリプト\n├── server.sh                                サーバ起動用スクリプト(サイト構築も同時に行う)\n└── _site                                    以下にサイト構築データが生成される\n</code></pre></div></div>\n\n<h1 id=\"投稿記事のファイル名\">投稿記事のファイル名</h1>\n\n<p>投稿記事のファイル名は<code class=\"language-plaintext highlighter-rouge\">YYYY-MM-DD-title.拡張子</code>とする。<br />\nそれ以外のファイル名を付けると無視される。</p>\n\n<p>日付、タイトルは後述のFrontMatterに設定があればそちらが優先される。</p>\n\n<h1 id=\"front-matterの構成\">Front Matterの構成</h1>\n\n<p>Front Matterの主な項目は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>---\ntitle: XXXX                タイトル  指定無ければファイル名のタイトル部分が使用される\ndate: 2019-07-07           日付 指定無ければファイル名の日付部分が使用される\ntags: [\"YYY\",\"ZZZ\"]        タグを指定  このタグでトップページでカテゴリを選択できる 大文字/小文字は区別される\nlayout: toppage            使用するレイアウト 指定無ければdefaultが使用される\nexcerpt: xxxxxx            抜粋  トップページのタイトルの下に表示される\n---\n</code></pre></div></div>\n\n<h1 id=\"あとはお好きに変更してちょ\">あとはお好きに変更してちょ</h1>\n\n<p>自分のリポジトリにpushして、そのリポジトリの設定でgithub pagesを有効にすればいっちょ上がり。</p>\n\n<p>ちなみに、ファイルが一つもないリポジトリではgithub pagesを有効にできないので、ダミーでもいいからファイルをpushしてから設定すること。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>rbenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>rbenvのインストール</h1>\n      <p>rbenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonに対するpyenvのようにrubyのバージョンを変更したり、個別にモジュールを管理したりできるrbenvを導入する。<br />\nあと、モジュールをインストールする <code class=\"language-plaintext highlighter-rouge\">gem install</code> に <code class=\"language-plaintext highlighter-rouge\">sudo</code> を付けなくても良いのも地味に便利。<br />\ngemset(pyenvの仮想環境のようなもの)を作って個別にモジュール管理すれば、色々インストールして訳わからん状態になったときでも、一旦チャラにして観光構築をやりなおせる。</p>\n\n<p>なお、rbenvはrubyをバイナリインストールできなくて、ソースからコンパイルするので、インストールにはそれなりに時間がかかる。</p>\n\n<p>以下の手順はUbuntu 16.04で動作確認した。他のバージョンでは、特にインストールの準備に微妙な違いがあるかもしれない。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>インストールに必要なモジュールをインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>git autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev\n</code></pre></div></div>\n\n<h2 id=\"rbenv本体とプラグインのインストール\">rbenv本体とプラグインのインストール</h2>\n\n<p>rbenv本体とプラグインをインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">RBENV_ROOT</span><span class=\"o\">=</span>/proj/.rbenv    <span class=\"c\"># 環境に合わせて修正してね</span>\ngit clone https://github.com/sstephenson/rbenv.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/sstephenson/ruby-build.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/ruby-build\ngit clone git://github.com/jf/rbenv-gemset.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-gemset\ngit clone https://github.com/sstephenson/rbenv-gem-rehash.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-gem-rehash\ngit clone https://github.com/rkh/rbenv-update.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-update\n</code></pre></div></div>\n<p>rbenv-gemset をインストールすることで、個別のモジュール環境を構築できる。pyenvのvirtualenvみたいな感じ。<br />\nrbenv-gem-rehashをインストールすることで、バージョン切り替えやgemのインストールの度にrbenv rehash を実行しなくてもよくなる。<br />\nrbenv-updateをインストールすることで、<code class=\"language-plaintext highlighter-rouge\">rbenv uppppdate</code> でrbenvと各プラグインのアップデートができる。</p>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>rbenvの設定のため、~/.bashrc に以下を追加。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">RBENV_ROOT</span><span class=\"o\">=</span>/proj/.rbenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$RBENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>rbenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h1 id=\"設定と使い方\">設定と使い方</h1>\n\n<h3 id=\"rbenvでインストールできるバージョンの一覧を表示\">rbenvでインストールできるバージョンの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span>\n</code></pre></div></div>\n\n<h3 id=\"rubyのインストール\">rubyのインストール</h3>\n\n<p>インストールしたいバージョンを指定して実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">install </span>2.6.3\n</code></pre></div></div>\n\n<p>・・・ 気長に待つ。 ・・・</p>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<p>デフォルトで使用したいバージョンを指定して実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv global 2.6.3\n</code></pre></div></div>\n\n<p>念のため指定したバージョンが実行されることを確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ruby <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h3 id=\"gemsetの作成\">gemsetの作成</h3>\n\n<p>色々試したあとに、インストールしたモジュールをチャラにしたいときを考えて、gemset(仮想環境みたいなもん)を構築しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset create 《ベースバージョン》 《gemset名》\n</code></pre></div></div>\n\n<p>例えば、ruby 2.6.3 に test1 という名前のgemsetを作成する場合。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset create 2.6.3 test1\n</code></pre></div></div>\n\n<p>gemsetはインストールされた各バージョンに紐づいて作成される。</p>\n\n<h3 id=\"gemsetの設定\">gemsetの設定</h3>\n\n<p>gemsetはディレクトリ毎に指定する。<br />\nカレントディレクトリに設定されたgemset(なければその親、さらに親と探す)と\nカレントのRubyバージョンが使用される。<br />\nカレントのRubyのバージョンに指定されたgemsetが存在しなければ新しくgemsetを作成するが、中身は空。<br />\nなので、gemsetを指定したときは、同時に <code class=\"language-plaintext highlighter-rouge\">rbenv local</code> でローカルバージョンも指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> 《設定したいディレクトリ》\nrbenv <span class=\"nb\">local</span> 《バージョン》\nrbenv gemset init 《gemset名》\n</code></pre></div></div>\n<p>gemset名を省略するとカレントディレクトリ名と同じ名前でgemsetが作成され、そのgemsetに設定される</p>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\nrbenv gemset init test1\n</code></pre></div></div>\n\n<h3 id=\"作成されたgemsetの一覧表示\">作成されたgemsetの一覧表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset list\n</code></pre></div></div>\n<p>こんな感じで表示される。Rubyのバージョンが異なれば同名のgemsetも作成できる。<br />\nただし、中身は別物。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>rbenv gemset list\n2.3.8:\n  test1\n2.6.3:\n  test1\n</code></pre></div></div>\n\n<h3 id=\"カレントディレクトリで有効なgemsetの確認\">カレントディレクトリで有効なgemsetの確認</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset active\n</code></pre></div></div>\n\n<p>ついでにRubyのバージョンも確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv version\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>rbenv gemset active\nenv1 global\n<span class=\"nv\">$ </span>rbenv version\n2.6.3 <span class=\"o\">(</span><span class=\"nb\">set </span>by /*******/.ruby-version<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"gemsetの指定を無効にするにはrbenv-gemsets-ファイルを削除する\">gemsetの指定を無効にするには.rbenv-gemsets ファイルを削除する</h3>\n\n<p>コマンドで指定を無効にできないので、指定ファイルを手動で削除する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> .rbenv-gemsets\n</code></pre></div></div>\n<p>使用するgemsetを変更したい場合、すでにgemset設定済みのディレクトリでは再設定できない。<br />\n一旦gemsetの指定を無効にしてから、再度 <code class=\"language-plaintext highlighter-rouge\">rbenv gemset init ~</code> する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n\n<h3 id=\"gem関連の設定を確認\">gem関連の設定を確認</h3>\n\n<p>gem関連の設定(GEM_PATHSなど)を確認したいときは以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem <span class=\"nb\">env</span>\n</code></pre></div></div>\n<h3 id=\"helpの表示\">helpの表示</h3>\n\n<p>rbenv 全体のヘルプ(コマンドの確認など)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">help</span>\n</code></pre></div></div>\n\n<p>各コマンドのヘルプ(パラメータやオプションの確認など)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">help</span> 《コマンド》\n</code></pre></div></div>\n\n<h1 id=\"メモ\">メモ</h1>\n\n<h3 id=\"rehashについて\">rehashについて</h3>\n\n<p>設定を変えたりした場合は以下を実行する必要があるが、rbenv-gem-rehashをインストールしてあれば必要なタイミングで自動で行われるので不要。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv rehash \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 16.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 16.04のインストール</h1>\n      <p>Ubuntu 16.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 16.04 のインストール手順のメモです。<br />\nVirtualBox へのインストール前提で書いてます。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-1604-インストール媒体の入手\">Ubuntu 16.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら</p>\n\n<p><a href=\"http://old-releases.ubuntu.com/releases/16.04.5/\">http://old-releases.ubuntu.com/releases/16.04.5/</a></p>\n\n<p>ファイル一覧の下の方の<br />\n<a href=\"http://old-releases.ubuntu.com/releases/16.04.5/ubuntu-16.04.5-desktop-amd64.iso\">「ubuntu-16.04.5-desktop-amd64.iso」</a><br />\nを選択する</p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを1024MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動し、画面の明るさとロックを選択<br />\n「次の時間アイドル状態が続けば画面をオフにする」を「しない」に設定。<br />\n「ロックする」を「オフ」に設定。</p>\n</blockquote>\n\n<h3 id=\"ap-getよりaptが使いやすい\">ap-getよりaptが使いやすい</h3>\n\n<p>最初から入ってたっけ??<br />\n入ってなかったら以下で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>apt\n</code></pre></div></div>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"nb\">sudo </span>apt dist-upgrade <span class=\"o\">(</span>必要なら<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p>終わったらリブート</p>\n\n<h3 id=\"gccとかmakeとかは最初からインストールされているはず\">gccとかmakeとかは最初からインストールされているはず</h3>\n\n<p>入っていない場合は以下でインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<h4 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h2 id=\"使わないパッケージをアンインストール\">使わないパッケージをアンインストール</h2>\n\n<p>使わないパッケージはディスクの肥やしになるだけでなく、余計なアップデートで時間を食うので、以下の感じでアンインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove <package name>\n</code></pre></div></div>\n<p>インストール済みのパッケージは以下で確認できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--manual-installed</span>\n</code></pre></div></div>\n\n<p>依存関係によってインストールされたパッケージも含めて確認するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span>\n</code></pre></div></div>\n\n<h4 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-panel\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n一旦ログアウトして<br />\nサインインボタン横のUbuntuアイコンで「GNOME Flashback (Compiz)」を選択してログインする<br />\n選択した内容は次回起動時も覚えている。</p>\n</blockquote>\n\n<h4 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h4>\n<blockquote>\n  <p>[!TIP]\n端末を起動し、メニューの「編集」→「設定」を選択<br />\n「プロファイル」タブを選択<br />\n使用中のプロファイル(最初のは「default」)を選択し、「編集」をクリック<br />\n「全般」タブの「フォントを指定する」 にチェックを入れ、その右側でフォントを選ぶ<br />\n        Takao ゴシック Regular あたりがおススメ<br />\nついでに「起動時の端末サイズ」も修正しておくとよい</p>\n</blockquote>\n\n<h4 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj\n<span class=\"nb\">sudo mkdir</span> /work1\n<span class=\"nb\">sudo mkdir</span> /work2\n<span class=\"nb\">sudo mkdir</span> /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h4 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h4>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h4 id=\"bashの設定変更\">bashの設定変更</h4>\n<p>~/.bashrcに以下を追記</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n</code></pre></div></div>\n\n<h4 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>compizconfig-settings-manager \n</code></pre></div></div>\n<p>アプリケーション→システムツール→Preference→CompizeConfigSettingsManager でプログラム起動<br />\nウィンドウ・マネジメントのGridのチェックをはずす</p>\n\n<h4 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferenceを選択<br />\n    auto-rise             false<br />\n    focus-mode            sloppy or mouse<br />\n    rise-on-click         true</p>\n</blockquote>\n\n<h4 id=\"ウィンドウのボタンの位置を右側にする\">ウィンドウのボタンの位置を右側にする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferenceを選択<br />\n    「button-layout」に 「menu:minimize,maximize,close」を設定</p>\n</blockquote>\n\n<h4 id=\"日本語入力\">日本語入力</h4>\n<ul>\n  <li>アプリケーション→システムツール→システム設定→言語サポートを選択</li>\n  <li>「言語サポートが完全にはインストールされていません」と出るので<br />\n「インストール」をクリック</li>\n  <li>一旦ログアウトして再ログイン</li>\n  <li>アプリケーション→システムツール→システム設定→テキスト入力設定を選択</li>\n  <li>入力ソースタブを選択</li>\n  <li>左下の+ボタンを押してMozc(Fcitx)を選択して追加ボタンを押す</li>\n</ul>\n\n<h4 id=\"sambaのインストール\">sambaのインストール</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h4 id=\"nfsのインストール\">NFSのインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認(IPアドレスは環境に合わせて変更してね)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h4 id=\"apache-のインストール\">apache のインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>apache2\n<span class=\"nb\">mkdir</span> /proj/wwwroot\n</code></pre></div></div>\n\n<p>/etc/apache2/apache2.conf に以下を追加<br />\n<Directory ~と書いてあるところがあるので、その並びに追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><Directory /proj/wwwroot/>\n    Options Indexes FollowSymLinks\n    AllowOverride None\n    Require all granted\n</Directory>\n</code></pre></div></div>\n\n<p>/etc/apache2/sites-available/000-default.conf の以下を修正</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>DocumentRoot /proj/wwwroot\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/apache2 restart\n</code></pre></div></div>\n\n<h3 id=\"以上でインストールは終了\">以上でインストールは終了</h3>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"nmcliが入ってなかったら以下でインストール\">nmcliが入ってなかったら以下でインストール</h3>\n\n<p>入ってたか、入れたか、何かの依存関係で入ったか覚えてない…</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>network-manager\n</code></pre></div></div>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hostnameを直接エディタで書き換えても可。</p>\n</blockquote>\n\n<h3 id=\"etchosts-の変更\">/etc/hosts の変更</h3>\n<p>旧ホスト名を「old_hostname」、新しいホスト名を「new_hostname」とした場合、以下のコマンドで書き換えられる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/old_hostname/new_hostname/'</span> /etc/hosts\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nエディタで書き換えても可。/etc/hostsを開いて旧ホスト名を新しいものに書き換える。</p>\n</blockquote>\n\n<h3 id=\"ipアドレスの変更固定アドレスにしたい場合\">IPアドレスの変更(固定アドレスにしたい場合)</h3>\n<blockquote>\n  <p>[!TIP]\nシステム設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん。<br />\nなんかこんな感じ。</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"各接続の設定値の表示\">各接続の設定値の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show  <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n<p>「”有線接続 2”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n<p>「”有線接続 2”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n<p>「”有線接続 3”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h1 id=\"共有フォルダの設定とマウント\">共有フォルダの設定とマウント</h1>\n\n<h2 id=\"virtualboxでの共有フォルダの設定\">VirtualBoxでの共有フォルダの設定</h2>\n\n<ul>\n  <li>仮想マシン→設定で設定ダイアログを表示\n    <ul>\n      <li>「共有フォルダ」で「共有フォルダの追加」ボタンをクリック\n        <ul>\n          <li>「フォルダーのパス」に共有するフォルダを指定</li>\n          <li>「フォルダ名」に名前を付ける(例:Share))</li>\n          <li>その他は空欄のまま</li>\n          <li>「OK」をクリック</li>\n        </ul>\n      </li>\n      <li>「OK」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"マウントポイントの作成\">マウントポイントの作成</h2>\n\n<p>マウントポイントを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /Share\n</code></pre></div></div>\n\n<h2 id=\"手動でマウント\">手動でマウント</h2>\n\n<p>以下のコマンドでマウントできる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> vboxsf Share /Share/\n</code></pre></div></div>\n\n<p>アンマウントするときはこちら。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount /Share/\n</code></pre></div></div>\n\n<h2 id=\"自動でマウント\">自動でマウント</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/fstab</code> に以下の内容を追加。\nこれで、起動時に自動でマウントされる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Share /Share vboxsf defaults 0 0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>nodenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>nodenvのインストール</h1>\n      <p>nodenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonのpyenvと同様にNode.jsのバージョン管理システムのnodenvを使用する。<br />\n(両方インストールするくらいならanyenvを使えという説もあるが…)</p>\n\n<p>他にもnvmやnodebrewなんてのもあるらしい。nodenvはディレクトリごとにローカルバージョンを設定できてとても便利なのでおススメ。<br />\nnodeenv(eが2つ)という超マイナーなのもあるけど、間違わないように。</p>\n\n<p>Node.jsはリポジトリにバイナリパッケージが用意されているバージョンはバイナリインストールできる。用意されていないバージョンはソースからコンパイルされるが、必要なライブラリ類のインストールなど必要。ここでは手順は割愛。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>インストールに必要なモジュールをインストールする。インストール済みならスキップして可。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>git\n</code></pre></div></div>\n\n<h2 id=\"nodenv本体のインストール\">nodenv本体のインストール</h2>\n\n<p>nodenv本体をインストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\ngit clone git://github.com/nodenv/nodenv.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/nodenv/node-build.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>nodenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"nodenvでインストールできるバージョンの一覧を表示\">nodenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install</span> <span class=\"nt\">-l</span>\n</code></pre></div></div>\n<p>バイナリインストールできるか確認したい場合は以下。<br />\nバイナリがなければソースからコンパイルされるが、時間がかかるのが嫌な場合に(大抵のバージョンはバイナリが用意されているようだ)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"nt\">-r</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/share/\n<span class=\"c\"># ただし、uname -m が x86_64 | amd64 | i686-64 のときはx64に置き換える</span>\n</code></pre></div></div>\n\n<h3 id=\"nodejsのインストール\">Node.jsのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install </span>10.15.3 \n</code></pre></div></div>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv global 10.15.3\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境について\">仮想環境について</h3>\n\n<p>pyenvと異なり、nodenvは仮想環境をサポートしていない。<br />\nNode.jsはローカルモジュールのインストールが簡単なので、仮想環境を構築しなくても個々のディレクトリでローカルモジュールをインストールすることで仮想環境相当のことが実現できる。</p>\n\n<h3 id=\"npmのバージョンアップ\">npmのバージョンアップ</h3>\n\n<p>「npmが古い~」と言われる前にバージョンアップ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> npm\n</code></pre></div></div>\n\n<h3 id=\"ローカルで使用するバージョンの設定\">ローカルで使用するバージョンの設定</h3>\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは9.11.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">local</span> <バージョン名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv shell <バージョン名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"nodenvのバージョンアップ\">nodenvのバージョンアップ</h1>\n\n<p>Node.jsの新しいバージョンがリリースされ、それをインストールしたい場合など、nodenvのバージョンアップが必要。<br />\n<strong>下記その2の方がおススメ。こっちの手順は参考までに。</strong></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/\ngit pull\n</code></pre></div></div>\n<p>実行後、ターミナルを開きなおす</p>\n\n<h1 id=\"nodenvのバージョンアップ-その2\">nodenvのバージョンアップ その2</h1>\n<p>nodenv-updateをインストールしておけば、<code class=\"language-plaintext highlighter-rouge\">nodenv update</code>を実行するだけですべてのプラグインを含めてバージョンアップしてくれるので、おススメ。インストール方法は下記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/nodenv/nodenv-update.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/nodenv-update\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのnodejsを使いたい場合\">システムのNode.jsを使いたい場合</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv version\n</code></pre></div></div>\n\n<h3 id=\"nodenvでインストールされているnodejsのバージョンを確認\">nodenvでインストールされているNode.jsのバージョンを確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"nodenv自体のバージョン確認\">nodenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"nodenvで使用できるコマンドの確認\">nodenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv commands\n</code></pre></div></div>\n\n<h3 id=\"nodenvのヘルプの表示\">nodenvのヘルプの表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">help</span>\n\n<span class=\"c\"># 各コマンドのヘルプを表示するには以下</span>\nnodenv <span class=\"nb\">help</span> <<span class=\"nb\">command</span><span class=\"o\">></span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのインストール</h1>\n      <p>pyenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>システムのpythonのバージョンを変更したり、モジュールの変更をしたりするとシステム上のスクリプトの動作に影響が出る場合があるので、pyenvで個別のpython環境を構築するのがベター。<br />\nさらに、virtualenvプラグインを使うと、同じpythonのバージョンでもそれぞれに別のモジュールをインストールできる、仮想環境を構築できる。</p>\n\n<p>なお、pyenvはpythonをバイナリインストールできなくて、ソースからコンパイルするので、インストールにはそれなりに時間がかかる(RasPi2で1~2時間くらい?)。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<h3 id=\"必要なモジュールをインストール\">必要なモジュールをインストール</h3>\n<p>インストールに必要なモジュールをインストールする。</p>\n<ul>\n  <li>Bullseye以降ではこちら<br />\n(<code class=\"language-plaintext highlighter-rouge\">python-openssl</code> →  <code class=\"language-plaintext highlighter-rouge\">python3-openssl</code>)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>Buster以前ではこちら\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"bluetoothを使用する場合\">bluetoothを使用する場合</h3>\n<p>bluetoothを使用する場合は以下も必要</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以前、 ubuntuの場合は以下と書いていたが、<code class=\"language-plaintext highlighter-rouge\">libbluetooth3-dev</code>は<code class=\"language-plaintext highlighter-rouge\">libbluetooth-dev</code>の別名定義だったので上のコマンドでOKのはず。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth3-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"pyenv本体とvirtualenvプラグインのインストール\">pyenv本体とvirtualenvプラグインのインストール</h2>\n\n<p>pyenv本体とvirtualenvプラグインをインストール。<br />\nついでにupdateプラグインも入れとく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>pyenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n<span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>Raspbianでは以下も追加<br />\nnumpyをimportしたとき、undefined symbol: PyFPE_jbuf でエラーになる対策。<br />\n参考: <a href=\"https://research.itplants.com/?p=2437\">https://research.itplants.com/?p=2437</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"--enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-fpectl\"</span>\n</code></pre></div></div>\n\n<p>Ubuntuでは以下を追加しておく(デフォルトだとShared Library のimportでエラーになる)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h2 id=\"sudoでpyenv環境を実行するように設定する\">sudoでpyenv環境を実行するように設定する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo</code>でpythonを実行すると、pyenvの設定に関係なくsystemのpythonが実行されてしまいます。<br />\nこれを防ぐためには、<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers</code>の<code class=\"language-plaintext highlighter-rouge\">Defaults secure_path</code>に以下のpathを追加します。</p>\n\n<ul>\n  <li>«pyenvインストール先»/plugins/pyenv-virtualenv/shims:</li>\n  <li>«pyenvインストール先»shims:</li>\n  <li>«pyenvインストール先»/bin:</li>\n</ul>\n\n<p>具体的には以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 変更前\nDefaults  secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n    ↓\n# 変更後\nDefaults  secure_path=\"/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n</code></pre></div></div>\n<ul>\n  <li></li>\n</ul>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"pyenvでインストールできるバージョンの一覧を表示\">pyenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span> \n</code></pre></div></div>\n\n<h3 id=\"pythonのインストール\">pythonのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.4\n</code></pre></div></div>\n\n<p>・・・ 気長に待つ。 ・・・</p>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global 3.6.4\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-V</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境の構築\">仮想環境の構築</h3>\n\n<p>色々試したあとに、インストールしたモジュールをチャラにしたいときを考えて、仮想環境を構築しておく。<br />\nここでは、python 3.6.4を使用して 仮想環境名 mypython を作成。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.6.4 mypython\n</code></pre></div></div>\n\n<p>デフォルトをmypythonに変更する場合は以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global mypython\n</code></pre></div></div>\n\n<h3 id=\"pipのバージョンアップ\">pipのバージョンアップ</h3>\n\n<p>「pipが古い~」と言われる前にバージョンアップ。ついでにsetuptoolsとwheelも。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n<blockquote>\n  <p>[!IMPORTANT]\nベース環境をバージョンアップしても、仮想環境に引き継がれないので、仮想環境毎に実行が必要。</p>\n</blockquote>\n\n<h3 id=\"ローカルバージョンの設定\">ローカルバージョンの設定</h3>\n\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは3.4.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">local</span> <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"i2cを使用する場合raspi\">I2Cを使用する場合(RasPi)</h1>\n\n<p>RaspberryPi環境で、I2Cを使うためのsmbusモジュールは、通常 <code class=\"language-plaintext highlighter-rouge\">sudo apt install python3-smbus</code> でインストールするが、これだとpyenv環境にインストールできない。<br />\nこれはsmbus2をインストールして使用することで回避できる。\nインストールは以下のように実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>smbus2\n</code></pre></div></div>\n<p>ちなみに、pyenv 環境へのモジュールのインストールには <code class=\"language-plaintext highlighter-rouge\">sudo</code> は不要。/usr 下へのインストールではないので。</p>\n\n<p>で、プログラムソース側はsmbusのインストール部分を以下のように修正。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus</span>\n<span class=\"k\">except</span> <span class=\"nb\">ImportError</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus2</span> <span class=\"k\">as</span> <span class=\"n\">smbus</span>\n</code></pre></div></div>\n\n<p>smbus2 だけにしても良いけど、smbus でも動作できるようにしておくのがベターかな。</p>\n\n<h1 id=\"pyenvのバージョンアップ\">pyenvのバージョンアップ</h1>\n<p>pythonの新しいバージョンがリリースされ、それをインストールしたい場合など、pyenvのバージョンアップが必要。<br />\npyenv-updateをインストールしておけば(上記手順でインストール済み)、以下のコマンドですべてのプラグインを含めてバージョンアップしてくれる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv update\n</code></pre></div></div>\n\n<h2 id=\"古い方法\">古い方法</h2>\n<p>pyenv-updateをインストールしていない場合は以下の手順でそれぞれのリポジトリをpullする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit pull\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのpythonを使いたい場合は以下のように実行\">システムのpythonを使いたい場合は以下のように実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv version\n</code></pre></div></div>\n\n<h3 id=\"pyenvでインストールされているpythonのバージョン仮想環境を確認\">pyenvでインストールされているpythonのバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"pyenv自体のバージョン確認\">pyenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"pyenvで使用できるコマンドの確認\">pyenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv commands\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 18.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 18.04のインストール</h1>\n      <p>Ubuntu 18.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Facebook noteに書いておいたら、消されちゃったみたいなので、メモから再度作成<br />\nメモから書き起こしているので、細かいところが違うかも。<br />\n最新版では変更されている箇所があるかも。</p>\n\n<p>VirtualBox へのインストール前提で書いてます。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-1804-インストール媒体の入手\">Ubuntu 18.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら</p>\n\n<p><a href=\"https://www.ubuntulinux.jp/download)\">https://www.ubuntulinux.jp/download)</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを2048MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシーを選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"nb\">sudo </span>apt dist-upgrade <span class=\"o\">(</span>必要なら<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが</p>\n\n<h4 id=\"amazonなんちゃらのやつ\">amazonなんちゃらのやつ</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove ubuntu-web-launchers\n</code></pre></div></div>\n\n<h4 id=\"ツール類\">ツール類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n</code></pre></div></div>\n\n<h4 id=\"ゲーム類\">ゲーム類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h4 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-panel\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n一旦再起動して<br />\nサインインボタン横の歯車ボタンで「GNOME Flashback (Metacity)」を選択してログインする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!IMPORTANT]\n「GNOME Flashback(Compiz)」だとうまく動かない。<br />\n以前はログアウトだけで良かったはずなんだけど、<br />\n再起動しないとダメみたい</p>\n</blockquote>\n\n<h4 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h4>\n<blockquote>\n  <p>[!TIP]\n端末を起動し、メニューの「編集」→「Preferences」を選択<br />\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\nCustom font にチェックを入れ、その右側でフォントを選ぶ<br />\n    Ubuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n</blockquote>\n\n<h4 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj\n<span class=\"nb\">sudo mkdir</span> /work1\n<span class=\"nb\">sudo mkdir</span> /work2\n<span class=\"nb\">sudo mkdir</span> /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h4 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h4>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h4 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h4 id=\"bashの設定変更\">bashの設定変更</h4>\n<p>~/.bashrcに以下を追記</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n</code></pre></div></div>\n\n<h4 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/metacity/edge-tiling                false<br />\n       /org/gnome/mutter/edge-tiling                  false<br />\n       /org/gnome/shell/overrides/edge-tiling         false</p>\n</blockquote>\n\n<h4 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferences/auto-rise             false<br />\n       /org/gnome/descktop/wm/preferences/focus-mode            sloppy or mouse<br />\n       /org/gnome/descktop/wm/preferences/rise-on-click         true</p>\n</blockquote>\n\n<h4 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/nautilus/desktop/trash-icon-visible         false<br />\n       /org/gnome/nautilus/desktop/home-icon-visible          false</p>\n</blockquote>\n\n<h4 id=\"日本語入力\">日本語入力</h4>\n<ul>\n  <li>右上のJaまたはMoと書かれたアイコンをクリック→テキスト入力設定を選択</li>\n  <li>インストールされている言語の管理をクリック</li>\n  <li>「言語サポートが完全にはインストールされていません」と出るので<br />\n「インストール」をクリック</li>\n  <li>一旦log offして再log in</li>\n  <li>右上のJaまたはMoと書かれたアイコンをクリック\n    <ul>\n      <li>Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)</li>\n    </ul>\n  </li>\n  <li>キーボードの全角/半角キーで切り替えられるようになる</li>\n</ul>\n\n<h4 id=\"sambaのインストール\">sambaのインストール</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h4 id=\"nfsのインストール\">NFSのインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h4 id=\"apache-のインストール\">apache のインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>apache2\n<span class=\"nb\">mkdir</span> /proj/wwwroot\n</code></pre></div></div>\n\n<p>/etc/apache2/apache2.conf に以下を追加<br />\n<Directory ~と書いてあるところがあるので、その並びに追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><Directory /proj/wwwroot/>\n    Options Indexes FollowSymLinks\n    AllowOverride None\n    Require all granted\n</Directory>\n</code></pre></div></div>\n\n<p>/etc/apache2/sites-available/000-default.conf の以下を修正</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>DocumentRoot /proj/wwwroot\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/apache2 restart\n</code></pre></div></div>\n\n<h3 id=\"以上でインストールは終了\">以上でインストールは終了</h3>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hosts は書き換えられないので、手動で書き換える</p>\n</blockquote>\n\n<p>IPアドレスの変更(固定アドレスにしたい場合)</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>python の async/await</title>\n  </head>\n  <body>\n    <header>\n      <h1>python の async/await</h1>\n      <p>python の async/awaitってどう動くんだっけ?</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h2 id=\"python-の-asyncawaitってどう動くんだっけ\">python の async/awaitってどう動くんだっけ?</h2>\n\n<p>と思ったので、ちょっとテストプログラムを書いて試してみた。</p>\n\n<p>asyncioはnon-preemptiveなので、最近のpreemptiveに慣れ切った脳ミソにはややこしい。</p>\n\n<p>preemptiveなプログラムを書きたければ、threadingを使えば良い。適材適所というやつだ。</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">asyncio</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n\n<span class=\"n\">argvs</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span>  <span class=\"c1\"># コマンドライン引数を格納したリストの取得\n</span><span class=\"n\">argc</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">)</span> <span class=\"c1\"># 引数の個数\n</span>\n<span class=\"k\">if</span> <span class=\"n\">argc</span> <span class=\"o\">></span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"mi\">5</span>        <span class=\"c1\"># テストケース\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"testCase = \"</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">testCase</span><span class=\"p\">))</span>\n\n<span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>           <span class=\"c1\"># 念のため宣言だけしておく\n</span>\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">sub</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub start        \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub wakeup       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"mi\">42</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"n\">task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">sub</span><span class=\"p\">())</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"k\">await</span> <span class=\"n\">task</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">task</span>\n    \n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main wakeup      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main2</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 start      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 wakeup     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n\n<span class=\"c1\"># =============================================================================\n</span><span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>     <span class=\"c1\"># 開始時刻を記憶\n</span><span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">or</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">4</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">wait</span><span class=\"p\">([</span><span class=\"n\">main</span><span class=\"p\">(),</span> <span class=\"n\">main2</span><span class=\"p\">()]))</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">5</span> <span class=\"p\">:</span>\n    <span class=\"n\">loop</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">get_event_loop</span><span class=\"p\">()</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"unknown test case!!\"</span><span class=\"p\">)</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n\n<p>以下のようにコマンドラインからテストケース番号を指定して実行する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python test.py <testCase>\n</code></pre></div></div>\n\n<h2 id=\"実行結果\">実行結果</h2>\n<h3 id=\"testcase1\">testCase=1</h3>\n\n<p>基本的なパターン、というか、全然非同期実行になってないけど。。。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code>→ <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p>awaitが付いていると、その場でタスクに実行権を渡し、そのタスクが終了するまで待つ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 1\ntestCase <span class=\"o\">=</span>  1\nbefor create     0.00026416778564453125\nafter create     0.00034689903259277344\nbefor call       0.00040340423583984375\nsub start        0.00047469139099121094\nsub wakeup       2.0033931732177734\nafter call       2.0035252571105957\nmain wakeup      3.004753351211548\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase2\">testCase=2</h3>\n\n<p>基本的なパターン、こっちが非同期実行として本命。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code>を実行するときに<code class=\"language-plaintext highlighter-rouge\">await</code>を付けない。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">await</code>が付いていないと、その場でタスクに実行権を渡さず、自分の実行を中断する部分か終了するまでそのまま実行する。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> 呼び出し箇所では即時実行されず、sleep(2)で <code class=\"language-plaintext highlighter-rouge\">main</code> の実行が中断されたところで <code class=\"language-plaintext highlighter-rouge\">sub</code> へ切り替わる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> で <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> が実行されると実行されるタスクがなくなるので、イベントループは実行可能タスク待ちになる。</p>\n\n<p>1秒後、<code class=\"language-plaintext highlighter-rouge\">main</code> が起床するので、そのままmainが終了される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> で イベントループは <code class=\"language-plaintext highlighter-rouge\">main</code> の終了を待っているので、<code class=\"language-plaintext highlighter-rouge\">sub</code> が実行中でも無関係にイベントループを終了してしまい、\n <code class=\"language-plaintext highlighter-rouge\">sub</code> の残りは実行されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 2\ntestCase <span class=\"o\">=</span>  2\nbefor create     0.0002646446228027344\nafter create     0.00034308433532714844\nbefor call       0.00039768218994140625\nafter call       0.0004489421844482422\nsub start        0.0005385875701904297\nmain wakeup      1.0014407634735107\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase3\">testCase=3</h3>\n\n<p>testCase=2 でsubの残りも実行するには?と思って試したパターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で、即座に <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main2())</code> を実行してみた。</p>\n\n<p>見事失敗。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→ <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p>どうやら、 <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で イベントループは一旦 <code class=\"language-plaintext highlighter-rouge\">close</code> されてしまうらしい。</p>\n\n<p>単にtestCase=2の後ろにmain2の実行を付け加えただけになってしまった。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 3\ntestCase <span class=\"o\">=</span>  3\nbefor create     0.00029540061950683594\nafter create     0.0003790855407714844\nbefor call       0.0004353523254394531\nafter call       0.00048828125\nsub start        0.0005817413330078125\nmain wakeup      1.0015552043914795\nmain2 start      1.0021519660949707\nmain2 wakeup     4.0038042068481445\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase4\">testCase=4</h3>\n\n<p>testCase=3 の失敗挽回パターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でmainとmain2をまとめてみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でまとめたタスクがすべて終了するまでイベントループは<code class=\"language-plaintext highlighter-rouge\">close</code> されないので、<code class=\"language-plaintext highlighter-rouge\">sub</code>は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> と <code class=\"language-plaintext highlighter-rouge\">main2</code> のどちらが先に実行されるかは規定されていない様子。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 4\ntestCase <span class=\"o\">=</span>  4\nmain2 start      0.0003325939178466797\nbefor create     0.0004305839538574219\nafter create     0.0005018711090087891\nbefor call       0.0005679130554199219\nafter call       0.0006389617919921875\nsub start        0.0007307529449462891\nmain wakeup      1.002068042755127\nsub wakeup       2.002253293991089\nmain2 wakeup     3.003903388977051\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase5\">testCase=5</h3>\n\n<p>testCase=3 の失敗挽回パターン その2。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.get_event_loop()</code> でイベントループを取得し、<code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> でそれぞれのタスクを実行してみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> → イベントループ終了\nとなっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> ではタスクが終了してもイベントループはcloseされないので、同じイベントループで<code class=\"language-plaintext highlighter-rouge\">main2</code>が実行される。\n結果、<code class=\"language-plaintext highlighter-rouge\">sub</code> は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> が終了するまで <code class=\"language-plaintext highlighter-rouge\">main2</code> は実行(起動)されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 5\ntestCase <span class=\"o\">=</span>  5\nbefor create     0.0002574920654296875\nafter create     0.0003345012664794922\nbefor call       0.00038933753967285156\nafter call       0.0004410743713378906\nsub start        0.0005307197570800781\nmain wakeup      1.0010528564453125\nmain2 start      1.0011804103851318\nsub wakeup       2.002350330352783\nmain2 wakeup     4.002865314483643\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
  ],
  "related_posts": null,
  "time": "2025-06-09 04:55:53 +0000",
  "tags": {
    "Ubuntu": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 24.04のVirtualBoxへのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 24.04のVirtualBoxへのインストール</h1>\n      <p>Ubuntu 24.04のVirtualBoxへのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 24.04のVirtualBoxへのインストール手順をまとめてみた。<br />\n今回は 極力コマンドコピペで実行できるように書いてみた。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2404-インストール媒体の入手\">Ubuntu 24.04 インストール媒体の入手</h2>\n<p>24.04は日本語Remixがリリースされないので(<a href=\"https://www.ubuntulinux.jp/News/ubuntu2404-ja-remix\" target=\"_blank\">ニュース</a>)、\n<a href=\"https://jp.ubuntu.com/download\" target=\"_blank\">本家</a>\nからダウンロードする必要がありますが、海外にあるサーバなのでとっても遅いです。<br />\n国内のミラーサーバの一覧が<a href=\"https://www.ubuntulinux.jp/ubuntu/mirrors#imagemirror\" target=\"_blank\">ここ</a>\nにあるので、お好きなところからダウンロードしてください。<br />\n(私がダウンロードしたときはKDDI研究所が速かった)</p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、CPU数2個以上、メインメモリーを4096MB以上に設定しておくこと</strong></p>\n<blockquote>\n  <p>[!NOTE]\n推奨環境が2 GHzデュアルコアプロセッサ以上、4GBシステムメモリなので。</p>\n</blockquote>\n\n<p>普通にインストール媒体からインストール。<br />\n以下の説明が図付きで分かりやすい:<br />\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a></p>\n\n<blockquote>\n  <p>[!TIP]\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a>では、「仮想マシンの作成」の「ハードウェア」で「EFIを有効化・・・チェックを入れます。」となっているが、\n入れなくて可(入れて試してないので入れて動くのか未確認。図でもチェック入ってないし)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nインストーラにアップデートがある場合は「今すぐアップデート」をクリックしてアップデートし、\n完了したら一旦インストーラを閉じる。<br />\nデスクトップにインストーラアイコンが出来ているので、そこから再度インストーラを起動し、\n最初から設定を行う(これまでの入力は覚えているっぽい)<br />\n参照:<a href=\"https://pc.watch.impress.co.jp/docs/column/ubuntu/1590461.html\" target=\"_blank\">Ubuntu24.04 LTSの新インストーラを徹底解説</a>\nの「インストーラにアップデートがあった場合」</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a>では、「アプリケーション」での「拡張選択」を選択とあるが、\n余計なアプリを入れたくないので「既定の選択」のままにしておく。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n</blockquote>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<blockquote>\n  <p>[!NOTE]\n設定アプリ等のGUIで設定を変更した内容をスクリプト化したいとき、どのパスを変更すれば良いか調べるには、ターミナルで</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf watch /\n</code></pre></div>  </div>\n  <p>と実行しておくと、変更される度にパスと設定値が表示される。<br />\nこれを <code class=\"language-plaintext highlighter-rouge\">dconf write</code> で書き込めばGUIで設定した内容をコマンドラインで再現できる。<br />\n参考:<a href=\"https://qiita.com/liqsuq/items/2c7aa741caa94508050b\" target=\"_blank\">デスクトップで変えた設定をCUIでやりたい!(gnome限定)</a><br />\nその関係で前回まで<code class=\"language-plaintext highlighter-rouge\">gsettings</code>コマンドでの設定手順を載せていたが、今回は<code class=\"language-plaintext highlighter-rouge\">dconf</code>コマンドに変更した。</p>\n\n</blockquote>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<p>まだGuestAdditionをインストールしてないからコピペできないけど、BashのTab補完が効くので、\nちょろっと入力してあとは補完に頼れば大丈夫。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">dconf</code>だと変更済みのパスしか補完対象にならないらしく入力が面倒なので、\nここは補完が効く<code class=\"language-plaintext highlighter-rouge\">gsettings</code>コマンドで。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">dconf</code>だとこんな感じ。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ndconf write /org/gnome/desktop/session/idle-delay 0\n\n<span class=\"c\"># 自動画面ロック OFF</span>\ndconf write /org/gnome/desktop/screensaver/lock-enabled <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\n設定 → Privacy & Security → Screen Lock → 自動画面ロックを off に</p>\n\n  <p>==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\n設定 → Privacy & Security → Screen Lock → Blank Screen Delay を「しない」に</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>裏でソフトウェアの更新が動いていると、ロックファイルがロックされてしばらく適用できないので、<br />\nそうなっちゃったらお茶でも飲んでしばらくお待ちください。<br />\nソフトウェアの更新による自動更新を止める方法は後ほど。</p>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">upgrade</code> や <code class=\"language-plaintext highlighter-rouge\">install</code> 時にオプション <code class=\"language-plaintext highlighter-rouge\">-U</code> (<code class=\"language-plaintext highlighter-rouge\">--update</code>)をつけると\n<code class=\"language-plaintext highlighter-rouge\">update</code>も一緒に実行してくれるので命令ひとつで済む。<br />\n(ubuntu 24.04に搭載された2.7.14以降)</p>\n</blockquote>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools dconf-editor gnome-tweaks \n</code></pre></div></div>\n\n<h3 id=\"一旦リブート\">一旦リブート</h3>\n<p>念のため一旦リブートしておく。</p>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>以前にマウントしたものが残ってたらアンマウントしておくこと(インストール後初めてなのでマウントされてることはないけれど)。<br />\nVirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<blockquote>\n  <p>[!TIPS]\nプログラムが自動で始まらない場合は、CDROMのマウント先(たぶん、<code class=\"language-plaintext highlighter-rouge\">/media/${USER}/VBox_GAs_x.x.xx/</code>)に移動して<code class=\"language-plaintext highlighter-rouge\">sudo ./VBoxLinuxAdditions.run</code>を実行すれば良い。</p>\n</blockquote>\n\n<h3 id=\"再度リブート\">再度リブート</h3>\n<p>GuestAdditionによる更新適用のため、もう一度リブート。<br />\n(再ログインだけでもよさそうな感じではあるが、念のため)</p>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから<br />\n「デバイス」→「クリップボードの共有」→「双方向」 を選択。<br />\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<p>また、デスクトップサイズの変更(仮想マシンのウィンドウのサイズ変更)にも対応できる。</p>\n\n<h3 id=\"使わないアプリのアンインストール\">使わないアプリのアンインストール</h3>\n<p>「アプリケーション」で「既定の選択」を選んでいれば要らないアプリは入っていないハズ。</p>\n\n<h2 id=\"お好みで\">お好みで</h2>\n\n<h3 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h3>\n\n<p>bashでクリップボードからペーストするとペーストした文字が反転表示になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n以前の動作が良い場合は<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>に設定を追加するため、以下を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/inputrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n# disable bracked-paste mode\nset enable-bracketed-paste off\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<blockquote>\n  <p>[!NOTE]\nteraterm使ってるときはteratermが確認ダイアログ出すので邪魔なんだけど、<br />\ngnome-terminalだと誤ペースト防止にそのままが良いかも。</p>\n</blockquote>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>以下のコマンドで~/.bashrcに設定を追加。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.bashrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n# プロンプトの設定\nPS1=\"</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\n\n# キーバインドの設定\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-n\": history-search-forward'\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-p\": history-search-backward'\n\n# ディレクトリスタックの表示改善\nfunction pushd() {\n    command pushd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction popd() {\n    command popd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction dirs() {\n    command dirs -v\n}\n\n# 表示色変更\nexport LS_COLORS='di=01;32:ln=01;36:ex=01;31:'\nexport GREP_COLORS='mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'\n\n# lessのオプション\nexport LESS=\"-iMR\"\n\n# grepのオプション指定(GREP_OPTIONS)は廃止されたのでaliasで設定\n# export GREP_OPTIONS=\"--exclude-dir .git\"\nalias grep='grep --exclude-dir .git'\n\n# for pyenv\nexport PYENV_ROOT=/proj/.pyenv    #環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    # 仮想環境名をプロンプトに表示しない場合は以下を有効化\n    # export VIRTUAL_ENV_DISABLE_PROMPT=1\n    eval \"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"sh\">\"          # pyenv 2.0以降で必要\n    eval \"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"sh\">\"\n    eval \"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"sh\">\"\n    export PYTHON_CONFIGURE_OPTS=\"</span><span class=\"se\">\\</span><span class=\"sh\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"sh\">\n    \"\nfi\n\n# for nodenv\nexport NODENV_ROOT=/proj/.nodenv    # 環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    eval \"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"sh\">\"\nfi\n\n# x11からのログイン以外ならDISPLAYを設定する\n# Ubuntu22.04/24.04だとwaylandになるらしい\nif [ \"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"sh\">\" != \"x11\" ] && [ \"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"sh\">\" != \"wayland\" ]; then\n    export DISPLAY=192.168.78.200:0.0\nfi\necho DISPLAY=\"</span><span class=\"nv\">$DISPLAY</span><span class=\"sh\">\"\n\n# direnv 設定\nif type direnv > /dev/null 2>&1; then\n    export EDITOR=vi\n    eval \"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"sh\">\"\n    \n    # # venvの仮想環境名を表示するための設定\n    # show_virtual_env() {\n    #   if [ -n \"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"sh\">\" ]; then\n    #     echo \"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"sh\">)\"\n    #   fi\n    # }\n    # PS1='</span><span class=\"si\">$(</span>show_virtual_env<span class=\"si\">)</span><span class=\"sh\">'</span><span class=\"nv\">$PS1</span><span class=\"sh\">\nfi\n\n# __pycache__ディレクトリの生成を抑制する\nexport PYTHONDONTWRITEBYTECODE=1\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nヒアドキュメント内での変数展開やコマンド置換を抑止するには、\nヒアドキュメント開始文字列(上記では__EOF__)をシングルクォートで囲む。<br />\n参考:<a href=\"https://qiita.com/take4s5i/items/e207cee4fb04385a9952#%E5%A4%89%E6%95%B0%E5%B1%95%E9%96%8B%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E7%BD%AE%E6%8F%9B\" target=\"_blank\">bashのヒアドキュメントを活用する/変数展開・コマンド置換</a></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npython でimportする度に<code class=\"language-plaintext highlighter-rouge\">__pycache__</code>ディレクトリ<code class=\"language-plaintext highlighter-rouge\">*.pyc</code>ファイルが作成されるのが\n鬱陶しかったので、<code class=\"language-plaintext highlighter-rouge\">PYTHONDONTWRITEBYTECODE</code>に1を設定している。<br />\n2回目以降、若干実行時間が延びるかもしれないが、気にするほどでもないので。<br />\n通常の動作がよければ削除してください。</p>\n</blockquote>\n\n<h3 id=\"ubuntu-japanese-teamのパッケージリポジトリを追加\">Ubuntu Japanese Teamのパッケージリポジトリを追加</h3>\n\n<p>日本語特有のパッケージをインストールするため、Ubuntu Japanese Teamのパッケージリポジトリを追加します。<br />\n参考:<a href=\"https://www.ubuntulinux.jp/News/ubuntu2404-ja-remix\" target=\"_blank\">Ubuntu 24.04 LTSの日本語Remixについて</a>\nの最後の部分</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>wget https://www.ubuntulinux.jp/sources.list.d/noble.sources <span class=\"nt\">-O</span> /etc/apt/sources.list.d/ubuntu-ja.sources <span class=\"o\">&&</span><span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade <span class=\"o\">&&</span><span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ubuntu-defaults-ja\n</code></pre></div></div>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">/usr/share/fonts</code>の下(自分専用なら<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>の下)にコピるだけ。<br />\n下では全部コピってる(移動だけど)けど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp/ <span class=\"o\">&&</span> <span class=\"se\">\\</span>\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.3.1/UDEVGothic_v1.3.1.zip <span class=\"o\">&&</span> <span class=\"se\">\\</span>\nunzip UDEVGothic_v1.3.1.zip <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo mv </span>UDEVGothic_v1.3.1 /usr/share/fonts/truetype/ <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<p>設定を反映するため、開いている端末をすべて閉じで、再度起動します。<br />\n開いたままだと設定が中途半端に反映されてしまいます。<br />\nまた、一つでも端末が残っていると新しく開いた端末にも正常な反映がされません。</p>\n\n<blockquote>\n  <p>[!NOTE]\nCLIで設定するならこちら….なんだけど、UUIDが同じとは限らないので参考まで。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/use-system-font    <span class=\"nb\">false\n</span>dconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/font               <span class=\"s2\">\"'UDEV Gothic JPDOC 12'\"</span>\ndconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/default-size-rows  40\n</code></pre></div>  </div>\n\n  <p>すべてのプロファイルに適用するならこんな感じでもできるかな。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">for </span>prof <span class=\"k\">in</span> <span class=\"si\">$(</span>dconf list /org/gnome/terminal/legacy/profiles:/<span class=\"si\">)</span> <span class=\"p\">;</span> <span class=\"k\">do\n    </span>dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>use-system-font    <span class=\"nb\">false</span>                       <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n    dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>font               <span class=\"s2\">\"'UDEV Gothic JPDOC 12'\"</span>    <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n    dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>default-size-rows  40\n<span class=\"k\">done</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h3>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /NFSROOT <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span> /proj /work /NFSROOT\n</code></pre></div></div>\n\n<h3 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h3>\n\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく<br />\n(CLIでも「どこにインストールする?」と聞かれて「どこだっけ?」となるのでその予防)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<p>設定が正常に行われたか確認するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<p>正常に設定されていれば、以下のような結果が出力される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>0 /dev/sda\n</code></pre></div></div>\n<h3 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h3>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gnome-extensions disable tiling-assistant@ubuntu.com <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/mutter/edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/desktop/wm/preferences/focus-mode        <span class=\"s2\">\"'sloppy'\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/desktop/wm/preferences/auto-raise        <span class=\"nb\">false</span>      <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/desktop/wm/preferences/raise-on-click    <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。<br />\nと書いてあったけど、同じ動き(フォーカスがはずれる)に見える….</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/ding/show-home  <span class=\"nb\">false</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/shell/extensions/ding/show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/desktop/interface/cursor-size 48\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nGUIで設定する場合は「設定」→「アクセシビリティ」→「Seeing」→「Cursor Size」で選択<br />\n(数値ではなく画像で選択)</p>\n</blockquote>\n\n<h3 id=\"ファイルnautilusの設定変更\">ファイル(nautilus)の設定変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<h4 id=\"ロケーションバーをデフォルトにする\">ロケーションバーをデフォルトにする</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/nautilus/preferences/always-use-location-entry <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h4 id=\"詳細表示をデフォルトに\">詳細表示をデフォルトに</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/nautilus/preferences/default-folder-viewer <span class=\"s2\">\"'list-view'\"</span> \n</code></pre></div></div>\n\n<h4 id=\"隠しファイルを表示する\">隠しファイルを表示する</h4>\n<p>隠しファイルの表示はちょっと場所が違う</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gtk/gtk4/settings/file-chooser/show-hidden <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n\n<h4 id=\"ゴミ箱削除\">ゴミ箱削除</h4>\n\n<p>私はゴミ箱使わないので消しときます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n<h4 id=\"dockバーを画面下に表示\">Dockバーを画面下に表示</h4>\n\n<p>Windows7っぽく下に移動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/dock-position <span class=\"s2\">\"'BOTTOM'\"</span>\n</code></pre></div></div>\n\n<h4 id=\"アプリケーションをdockバーの上または左に表示\">アプリケーションをDockバーの上(または左)に表示</h4>\n\n<p>Windows7のスタートボタンっぽく左に移動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/show-apps-at-top <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h4 id=\"アイコンサイズの変更\">アイコンサイズの変更</h4>\n\n<p>最後の数字が大きさなので、お好みの大きさにしてください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/dash-max-icon-size 20\n</code></pre></div></div>\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアとアップデート(software-properties-gtk)を起動\n    <ul>\n      <li>アップデートタブを選択</li>\n      <li>アップデートの自動確認を「なし」に変更</li>\n      <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n      <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n      <li>閉じるをクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a></p>\n\n<p>tewaksを使用する<br />\n<a href=\"https://yassan.hatenablog.jp/entry/2024/05/01/Ubuntu_Bdgie%E3%83%A1%E3%83%A2%EF%BC%9A_Tweeks%E3%81%A7Caps%E3%81%A8Ctrl%E3%81%AESwap\" target=\"_blank\">Ubuntu Bdgieメモ: TweeksでCapsとCtrlのSwap</a><br />\nというのもある。 お好きな方で。</p>\n\n<p>Native環境にインストールしてないので未確認だけど…</p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下のように「quiet splash」を削除。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h2 id=\"ネットワークアダプタの追加\">ネットワークアダプタの追加</h2>\n<p>ホストのWindowsや外部マシンからアクセスできるようにデフォルトのNAT以外にネットワークアダプタを追加します。<br />\n仮想マシンの設定を変更する必要があるので、一旦仮想マシンをシャットダウンしてください。</p>\n\n<h3 id=\"ネットワークアダプタ追加設定\">ネットワークアダプタ追加設定</h3>\n<ul>\n  <li>Virtualboxマネージャ で対象の仮想マシンを選択し、設定ボタンをクリック。</li>\n  <li>開いたウィンドウの左側で「ネットワーク」を選択</li>\n  <li>右側のウィンドウで「アダプタ2」をクリック\n    <ul>\n      <li>「ネットワークアダプタを有効化」にチェックを入れる</li>\n      <li>「割り当て」で「ホストオンリーアダプター」を選択</li>\n    </ul>\n  </li>\n  <li>右側のウィンドウで「アダプタ3」をクリック\n    <ul>\n      <li>「ネットワークアダプタを有効化」にチェックを入れる</li>\n      <li>「割り当て」で「ブリッジアダプター」を選択</li>\n      <li>「名前」で割り当てる物理的なネットワークアダプタを選択</li>\n    </ul>\n  </li>\n  <li>OKをクリック</li>\n</ul>\n\n<p>設定が終わったら仮想マシンを起動します。</p>\n\n<blockquote>\n  <p>[!NOTE]\nNATも削除してブリッジアダプターだけでも大丈夫な気もするが、ネットワーク不調になっても\nホストOS(Windows)からアクセスできるようにホストオンリーアダプターも追加しておく。<br />\nまた、ホストオンリーアダプターも不調になったときでも\nWebアクセスなど最低限のアクセスができるようNATも残しておく。<br />\n要らないと思ったら上記の設定の「ネットワークアダプタを有効化」のチェックをはずせば良い。</p>\n</blockquote>\n\n<h3 id=\"ネットワークのコネクション名の変更\">ネットワークのコネクション名の変更</h3>\n\n<p>ネットワークコントローラを追加したので、ネットワークマネージャのコネクション一覧を見てみます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection \n</code></pre></div></div>\n\n<p>結果はこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>NAME            UUID                                  TYPE      DEVICE \nnetplan-enp0s3  1eef7e45-3b9d-3043-bee3-fc5925c90273  ethernet  enp0s3 \n有線接続 1      eef7ccb4-2a33-336f-bb48-701058d5e6ce  ethernet  enp0s8 \n有線接続 2      eff49436-1aac-36eb-b1f6-2a32cc246b83  ethernet  enp0s9 \nlo              d30bde24-f5dd-458d-86b0-b5c8870f4485  loopback  lo     \n</code></pre></div></div>\n<p>「有線接続 1」と「有線接続 2」がさきほど追加したホストオンリーアダプターとブリッジアダプターなのですが、\nどっちがどっちか判別できません。<br />\nそこで判別できるような名前に変更しておきます。<br />\n(192.168.xx.xxのものだけ変更。NATとloはそのまま)<br />\n変更後のコネクション名はネットワークとの対応が分かりやすくなるよう、\n≪IPアドレスの3桁目≫_LINE としています。<br />\nお好みの名前に変更してください。<br />\n(現在、日本語だと文字化けするバグがあるようです。そのうち直ると思いますが)</p>\n\n<p>手動で設定するのは面倒なので、以下のスクリプトファイルを作成して実行してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># すべてのコネクション名を改行区切りで配列に取得</span>\n<span class=\"nv\">ORG_IFS</span><span class=\"o\">=</span><span class=\"nv\">$IFS</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"s1\">$'</span><span class=\"se\">\\n</span><span class=\"s1\">'</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span>nmcli  <span class=\"nt\">-t</span> <span class=\"nt\">-f</span> NAME connection<span class=\"si\">)</span><span class=\"o\">)</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"nv\">$ORG_IFS</span>        <span class=\"c\"># 元に戻す</span>\n\n<span class=\"k\">for </span>i <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"p\">!connections[@]</span><span class=\"k\">}</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各コネクションについて</span>\n    <span class=\"c\"># 直接取り出すとうまくいかないのでインデックス取り出して内容取得</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[</span><span class=\"nv\">$i</span><span class=\"p\">]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n\n    <span class=\"c\"># 現在設定されているIPv4アドレスを取得</span>\n    <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.ADDRESS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n    <span class=\"c\"># 結果⇒ 「IP4.ADDRESS[1]: 192.168.78.215/24」</span>\n    \n    <span class=\"c\"># IPアドスの各桁とサブネットマスクを空白区切りで取得し、配列に代入</span>\n    <span class=\"c\"># 1個目のsed ⇒ 192.168.78.215/24</span>\n    <span class=\"c\"># 2個目のsed ⇒ 192 168 78 215 24</span>\n    <span class=\"nv\">ipv4octet</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/[</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]/ /g\"</span><span class=\"si\">)</span><span class=\"o\">)</span>\n\n    <span class=\"c\"># echo ${str}</span>\n    <span class=\"c\"># echo ${ipv4octet[0]}  ${ipv4octet[1]}  ${ipv4octet[2]}  ${ipv4octet[3]}  ${ipv4octet[4]}</span>\n    \n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 192 <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 168 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n        <span class=\"c\"># 192.168.XX.XX のコネクション</span>\n        <span class=\"c\"># echo \"**** ${str} ****\"</span>\n\n        <span class=\"c\"># コネクション名を\"≪IPアドレスの3桁目≫_LINE\"変更する</span>\n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> connection.id </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[2]</span><span class=\"k\">}</span><span class=\"s2\">_LINE</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone\n\n</span><span class=\"nb\">echo</span> <span class=\"o\">==</span><span class=\"nv\">RESULT</span><span class=\"o\">==</span>\nnmcli  connection\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)→<br />\n左側のネットワークを選択し、対象のNICの設定ボタン(歯車アイコン)をクリック→<br />\n開いたウィンドウで「identity」タブをクリック→<br />\n「名前」に設定する名前を設定→<br />\n「適用」をクリック</p>\n</blockquote>\n\n<h3 id=\"sambaのインストール\">sambaのインストール</h3>\n\n<h4 id=\"ツール本体のインストール\">ツール本体のインストール</h4>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<h4 id=\"etcsambasmbconf-の設定を変更\">/etc/samba/smb.conf の設定を変更</h4>\n\n<p>以下のコマンドを実行します。<br />\n変更内容は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code>をバックアップ</li>\n  <li>[homes]セクションを有効化</li>\n  <li>[homes]セクションの「read only」を「no」に設定</li>\n  <li>[global]セクションに「map archive = no」を追加</li>\n  <li>ファイル末尾に[proj][work][NFSROOT]セクションを追加<br />\n他にも追加したいセクション(ディレクトリの設定)があったら追加してください。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /etc/samba/smb.conf /etc/samba/smb.conf.org     <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'/\\[homes\\]/s/;//g'</span> /etc/samba/smb.conf     <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'/\\[homes\\]/,/\\[/ {s/^;[^\\[]//g}'</span> /etc/samba/smb.conf   <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"/</span><span class=\"se\">\\[</span><span class=\"s2\">homes</span><span class=\"se\">\\]</span><span class=\"s2\">/,/^</span><span class=\"se\">\\[\\|</span><span class=\"s2\">^;</span><span class=\"se\">\\s</span><span class=\"s2\">*</span><span class=\"se\">\\[</span><span class=\"s2\">/ s/read only = .*/read only = no/1\"</span> /etc/samba/smb.conf <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'s/\\(^\\[global\\].*\\)/\\1\\n\\n    map archive = no/'</span> /etc/samba/smb.conf   <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/samba/smb.conf <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n</span><span class=\"no\">\n__EOF__\n</span></code></pre></div></div>\n\n<h4 id=\"ユーザの追加\">ユーザの追加</h4>\n\n<p>sambaのためのユーザを追加します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>pdbedit <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n</code></pre></div></div>\n\n<p>新しいパスワードを聞かれるので入力</p>\n\n<blockquote>\n  <p>[!NOTE]\n以前は<code class=\"language-plaintext highlighter-rouge\">sudo smbpasswd -a $USER</code> だったけど、最近は上のコマンドが正式らしい。<br />\n(まだ <code class=\"language-plaintext highlighter-rouge\">smbpasswd</code>も使えるけど)</p>\n</blockquote>\n\n<h4 id=\"sambaの再起動\">sambaの再起動</h4>\n\n<p>設定を反映するため、sambaを再起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl reload  smbd.service <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>systemctl restart smbd.service\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">Warning: The unit file, source configuration file or drop-ins of smbd.service changed on disk. Run 'systemctl daemon-reload' to reload units.</code>\nと言われたときは、<code class=\"language-plaintext highlighter-rouge\">sudo systemctl daemon-reload</code>を実行</p>\n</blockquote>\n\n<h3 id=\"nfsのインストール\">NFSのインストール</h3>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<h4 id=\"インストール-1\">インストール</h4>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<h4 id=\"設定ファイルの変更\">設定ファイルの変更</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">/NFSROOT</code>をエクスポートするため、<code class=\"language-plaintext highlighter-rouge\">/etc/exports</code>を修正。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/exports <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<h4 id=\"再起動\">再起動</h4>\n\n<p>変更した設定を反映するため、NFSを再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl restart nfs-server.service \n</code></pre></div></div>\n\n<h4 id=\"確認\">確認</h4>\n\n<h5 id=\"exportできているか確認\">exportできているか確認</h5>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>こんな感じで表示されればOK</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT      \t192.168.0.0/255.255.0.0\n</code></pre></div></div>\n\n<h5 id=\"別のマシンからマウントしてみる\">別のマシンからマウントしてみる</h5>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n\n<p>別のマシンから以下のコマンドを実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">abc</code>の下に今インストールしているPCの<code class=\"language-plaintext highlighter-rouge\">/NFSROOT</code>ディレクトリのファイルが見えたらOK</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<p>マスタイメージを残しておいて、色々な環境をお試しするには仮想マシンをクローンして使うのがおススメ。</p>\n<ul>\n  <li>VirtualBoxのメインウィンドウでマスタイメージの仮想マシンを右クリック→クローンを選択。</li>\n  <li>名前とパスを設定し、MACアドレスのポリシーは「すべてのネットワークアダプタでMACアドレスを生成」を選択。</li>\n  <li>「次へ」をクリック</li>\n  <li>すべてをクローンにチェックが入っていることを確認し、「完了」をクリック\nクローンが終了するまで待つ。</li>\n</ul>\n\n<p>クローンした仮想マシンを起動し、必要な変更を加える。</p>\n\n<h2 id=\"ネットワーク設定の変更\">ネットワーク設定の変更</h2>\n\n<p>マシン名とか同じ名前だと色々不都合があるので、変更しておく。<br />\n他のクローン仮想環境と同時に使わないならそのままでも良いけど。<br />\nIPアドレスも固定で割り振っておくと名前が引けない時にさくっと分かってなにかと便利…\nなんだけど、最近はWindowsもUbuntuもRaspberryPiもmDNSがサポートされてるから自動割り当てのままでもそんなに不便はないかも。</p>\n\n<p>ポリシー</p>\n<ul>\n  <li>IPアドレスの最終桁を決める(numberとする)。</li>\n  <li>ホスト名をskull≪number≫とする</li>\n  <li>ホストオンリーアダプタ/ブリッジアダプタの設定変更\n    <ul>\n      <li>IPv4アドレスを手動設定にする</li>\n      <li>IPv4アドレスの1桁目~3桁目、サブネットマスクを現在のIPアドレスと同じにする</li>\n      <li>IPv4アドレスの最終桁をnumberにする</li>\n      <li>GW、DNSが設定されていれば同じアドレスを設定する</li>\n    </ul>\n  </li>\n</ul>\n\n<p>以下の内容でスクリプトファイルを作成し、実行する。<br />\nホスト名などは適宜変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/usr/bin/env bash</span>\n\n<span class=\"c\"># 設定する数値の入力</span>\n<span class=\"nb\">read</span> <span class=\"nt\">-p</span> <span class=\"s2\">\"数値を入力してください: \"</span> number \n\n<span class=\"c\"># echo ${number}</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[[</span> <span class=\"o\">!</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">=</span>~ ^[0-9]+<span class=\"nv\">$ </span><span class=\"o\">]]</span><span class=\"p\">;</span> <span class=\"k\">then\n  </span><span class=\"nb\">echo</span> <span class=\"s1\">'数値ではありません'</span>\n  <span class=\"nb\">exit </span>1\n<span class=\"k\">fi\n\nif</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"nt\">-lt</span> 2 <span class=\"o\">]</span> <span class=\"o\">||</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"nt\">-gt</span> 254 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n  </span><span class=\"nb\">echo</span> <span class=\"s1\">'数値は2~254でなければなりません'</span>\n  <span class=\"nb\">exit </span>1\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># ホスト名の変更</span>\n<span class=\"nv\">old_name</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">hostname</span><span class=\"si\">)</span>\n<span class=\"nv\">new_name</span><span class=\"o\">=</span><span class=\"s2\">\"skull</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo nmcli general hostname </span><span class=\"k\">${</span><span class=\"nv\">new_name</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n<span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo sed -i -e \"</span>s/<span class=\"k\">${</span><span class=\"nv\">old_name</span><span class=\"k\">}</span>/<span class=\"k\">${</span><span class=\"nv\">new_name</span><span class=\"k\">}</span>/<span class=\"s2\">\" /etc/hosts\"</span>\n<span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n<span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n\n<span class=\"c\"># すべてのコネクション名を改行区切りで配列に取得</span>\n<span class=\"nv\">ORG_IFS</span><span class=\"o\">=</span><span class=\"nv\">$IFS</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"s1\">$'</span><span class=\"se\">\\n</span><span class=\"s1\">'</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span>nmcli  <span class=\"nt\">-t</span> <span class=\"nt\">-f</span> NAME connection<span class=\"si\">)</span><span class=\"o\">)</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"nv\">$ORG_IFS</span>        <span class=\"c\"># 元に戻す</span>\n\n<span class=\"k\">for </span>i <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"p\">!connections[@]</span><span class=\"k\">}</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各コネクションについて</span>\n    <span class=\"c\"># 直接取り出すとうまくいかないのでインデックス取り出して内容取得</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[</span><span class=\"nv\">$i</span><span class=\"p\">]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># 現在設定されているIPv4アドレスを取得</span>\n    <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.ADDRESS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n    <span class=\"c\"># 結果⇒ 「IP4.ADDRESS[1]: 192.168.78.215/24」</span>\n    \n    <span class=\"c\"># IPアドスの各桁とサブネットマスクを空白区切りで取得し、配列に代入</span>\n    <span class=\"c\"># 1個目のsed ⇒ 192.168.78.215/24</span>\n    <span class=\"c\"># 2個目のsed ⇒ 192 168 78 215 24</span>\n    <span class=\"nv\">ipv4octet</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/[</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]/ /g\"</span><span class=\"si\">)</span><span class=\"o\">)</span>\n    \n    <span class=\"c\"># echo ${str}</span>\n    <span class=\"c\"># echo ${ipv4octet[0]}  ${ipv4octet[1]}  ${ipv4octet[2]}  ${ipv4octet[3]}  ${ipv4octet[4]}</span>\n    \n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 192 <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 168 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n        <span class=\"c\"># 192.168.XX.XX のコネクション</span>\n        <span class=\"c\"># echo \"**** ${str} ****\"</span>\n        \n        <span class=\"c\"># 現在設定されているIPv4GWアドレスを取得</span>\n        <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.GATEWAY\"</span> <span class=\"si\">)</span>\n        <span class=\"c\"># 結果⇒ 「IP4.GATEWAY: 192.168.78.1」</span>\n        \n        <span class=\"c\"># IPv4GWアドレスを抽出(未定義では--なので-も抽出対象)</span>\n        <span class=\"nv\">gwaddr</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.</span><span class=\"s2\">-]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span><span class=\"si\">)</span>\n        <span class=\"c\"># \"--\" だったら空文字にする</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">=</span> <span class=\"s2\">\"--\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then </span><span class=\"nv\">gwaddr</span><span class=\"o\">=</span><span class=\"s2\">\"\"</span><span class=\"p\">;</span> <span class=\"k\">fi</span>\n        \n        <span class=\"c\"># 現在設定されているIPv4DNSアドレスを取得(未定義ならこのエントリがない)</span>\n        <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.DNS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n        <span class=\"c\"># 結果⇒ 「IP4.DNS[1]: 192.168.78.1」</span>\n        \n        <span class=\"c\"># IPv4DNSアドレスを抽出</span>\n        <span class=\"nv\">dnsaddr</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span><span class=\"si\">)</span>\n        \n        <span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"ipv4.method manual ipv4.addresses </span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[2]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[4]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n            </span><span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\"> ipv4.gateway </span><span class=\"k\">${</span><span class=\"nv\">gwaddr</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">fi\n        if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n            </span><span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\"> ipv4.dns </span><span class=\"k\">${</span><span class=\"nv\">dnsaddr</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">fi</span>\n        \n        <span class=\"c\"># echo ipv4.method manual ${set_str}</span>\n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n        \n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection down   </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n        \n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection up     </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone\n\n</span><span class=\"nb\">echo</span> <span class=\"o\">==</span><span class=\"nv\">DONE</span><span class=\"o\">==</span>\n</code></pre></div></div>\n\n<p>実行後、<br />\n<code class=\"language-plaintext highlighter-rouge\">ip address</code>や<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPアドレスが変更されていること、<br />\n<code class=\"language-plaintext highlighter-rouge\">hostname</code>でホスト名が変更されていること、<br />\n<code class=\"language-plaintext highlighter-rouge\">cat /etc/hosts</code>でhostsが変更されていること、\nをそれぞれ確認する。</p>\n\n<blockquote>\n  <p>[!TIP]\nIPアドレスの変更をGUIで行うには以下。<br />\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nこのスクリプトをマスタイメージのどこか(例えば<code class=\"language-plaintext highlighter-rouge\">~/bin</code>とか)に保存しておけば、\nクローンする度にスクリプトを実行すればIPアドレスとホスト名の変更をイッパツで完了できる。</p>\n</blockquote>\n\n<h2 id=\"あとはお約束\">あとはお約束</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade\n</code></pre></div></div>\n\n<p>VirtalBoxのバージョンが変更されているときは、GuestAdditionのバージョンアップも忘れずに。<br />\nまた、マスタイメージは定期的に<code class=\"language-plaintext highlighter-rouge\">sudo apt -U upgrade</code>しておくと\nクローン時のアップデート時間が短くて済む。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 22.04をNative環境にインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 22.04をNative環境にインストール</h1>\n      <p>Ubuntu 22.04をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuのダウンロード\">Ubuntuのダウンロード</h1>\n<p><a href=\"https://www.ubuntulinux.jp/download\" target=\"_blank\">Ubuntuの入手</a>からダウンロード<br />\nSecure Boot環境で日本語RemixのISOファイルを使うと<code class=\"language-plaintext highlighter-rouge\">Verification failed: (0x1A) Security Violation</code>\nと怒らたので、jp.ubuntu.comのダウンロードページからUbuntu Desktopをダウンロードした。<br />\nブータブルUSBを作るには、Rufus等を使う(ググってちょ)。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<p>以下の参考ページを参照して起動するとこまでやってちょ。</p>\n\n<ul>\n  <li><a href=\"https://ippei8jp.github.io/memoBlog/2021/07/15/install2004_native.html\" target=\"_blank\">UbuntuをNative環境にインストールする(20.04)</a></li>\n  <li><a href=\"https://ippei8jp.github.io/memoBlog/2022/07/24/install2204.html\" target=\"_blank\">Ubuntu 22.04のVirtualBoxへのインストール</a></li>\n  <li>Ubuntu 22.04 デュアルブートのインストール方法は以下を参考\n    <ul>\n      <li><a href=\"https://dailylife.pman-bros.com/ubuntu22_install/\" target=\"_blank\">Ubuntu 22.04 LTS をインストールする -【マルチブート編】</a></li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"お好みで\">お好みで</h1>\n<p>作業中に画面が消えると鬱陶しいのでパワマネ無効化。<br />\nTAB補完使えばコピペするほどでもないので、最初にやっとく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h1 id=\"最新版にupdate\">最新版にupdate</h1>\n\n<p>とりあえず最新版に</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ついでにsshもインストールしておく。<br />\nwebで調べたコマンドをコピペしたいので。<br />\n参考:<a href=\"https://ippei8jp.github.io/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">ubuntuにSSHサーバをセットアップする</a></p>\n\n<ul>\n  <li>パッケージをインストール\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\n</code></pre></div>    </div>\n    <ul>\n      <li>これだけでパスワード認証は繋がるはず。</li>\n    </ul>\n  </li>\n  <li>公開鍵認証を使用する場合は、公開鍵を<code class=\"language-plaintext highlighter-rouge\">~/.ssh/authorized_keys</code>に追記し、attribute変更。<br />\n(コピペで追記したいのでsshで接続したターミナルから作業するのがベター)</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/.ssh\nvi ~/.ssh/authorized_keys\n<span class=\"c\">### 公開鍵を追記 ###</span>\n<span class=\"nb\">chmod </span>600 ~/.ssh/authorized_keys\n</code></pre></div></div>\n\n<p>念のためここでリブート。</p>\n\n<h1 id=\"chromeとリモートデスクトップのインストール\">chromeとリモートデスクトップのインストール</h1>\n<p>参考: <a href=\"https://qiita.com/grgrjnjn/items/a5c4da336031b63f09a6\" target=\"_blank\">UbuntuにChromeをインストールする手順</a><br />\n参考: <a href=\"https://zenn.dev/karaage0703/articles/cfde5e6a4f43c3\" target=\"_blank\">Linux(Ubuntu)のリモートデスクトップ設定(Google Chrome リモートデスクトップ/xrdp)</a></p>\n\n<h2 id=\"おまじない\">おまじない</h2>\n<p>chrome リモートデスクトップをインストールすると、ローカル端末でのログインができなくなるので、\n以下の処理を行う。</p>\n\n<p>新しく使用する<code class=\"language-plaintext highlighter-rouge\">.desktop</code>ファイルを作成(ubuntuをベースに使用)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /usr/share/xsessions/\n<span class=\"nb\">sudo cp </span>ubuntu.desktop ubuntu-local.desktop\n</code></pre></div></div>\n\n<p>以下のパッチをあてる。</p>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">Name</code>の変更と<code class=\"language-plaintext highlighter-rouge\">Exec</code>に<code class=\"language-plaintext highlighter-rouge\">DISPLAY=\":0\"</code>を追加</p>\n</blockquote>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ubuntu.desktop      2022-04-08 04:07:53.000000000 +0900\n</span><span class=\"gi\">+++ ubuntu-local.desktop        2023-11-11 07:25:37.223280734 +0900\n</span><span class=\"p\">@@ -1,7 +1,7 @@</span>\n [Desktop Entry]\n<span class=\"gd\">-Name=Ubuntu\n</span><span class=\"gi\">+Name=Ubuntu on local\n</span> Comment=This session logs you into Ubuntu\n<span class=\"gd\">-Exec=env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu\n</span><span class=\"gi\">+Exec=env DISPLAY=\":0\" GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu\n</span> TryExec=/usr/bin/gnome-shell\n Type=Application\n DesktopNames=ubuntu:GNOME\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nローカル端末でログインするときはユーザ名選択後、画面右下の歯車アイコンをクリックし、\n「Ubuntu on local」を選択(一度選択すれば記憶されるので2度目以降は確認だけでOK)してログインする。\n (作成したセッションを選択可能にするには、リブートが必要)</p>\n</blockquote>\n\n<h2 id=\"chromeとリモートデスクトップのインストール-1\">chromeとリモートデスクトップのインストール</h2>\n\n<p>手間を省くためにコマンドラインで以下を実行(sshからで可)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール時にエラーにならないようおまじない</span>\n<span class=\"nb\">mkdir</span> ~/.config/chrome-remote-desktop\n\n<span class=\"c\"># リブート時に消せるようにダウンロード先に/tmpを使う</span>\n<span class=\"nb\">cd</span> /tmp\n\n<span class=\"c\"># chromeのダウンロード</span>\nwget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb\n<span class=\"c\"># chromeのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> ./google-chrome-stable_current_amd64.deb\n\n<span class=\"c\"># remote desktopのダウンロード</span>\nwget https://dl.google.com/linux/direct/chrome-remote-desktop_current_amd64.deb\n<span class=\"c\"># remote desktopのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> ./chrome-remote-desktop_current_amd64.deb\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nインストール時、以下のように提案/推奨されるが、入れなくても大丈夫。<br />\n提案パッケージ:<br />\n  python-psutil-doc x11-xfs-utils<br />\n推奨パッケージ:<br />\n  xserver-xorg-video-dummy pipewire</p>\n</blockquote>\n\n<h2 id=\"chrome起動して初期設定googleにログイン\">chrome起動して初期設定&Googleにログイン</h2>\n<p>ローカル端末でchrome起動</p>\n<ul>\n  <li>既定のブラウザにするか、障害レポートを送信するかを選んでOK</li>\n  <li>「Chromeを独自にカスタマイズ」で「開始する」をクリック\n    <ul>\n      <li>あとはお好みで設定</li>\n    </ul>\n  </li>\n  <li>「あなたのChromeをいつでもどこでも」で「続行」をクリック\n    <ul>\n      <li>chromeへのログインで使用するGoogleアカウントにログイン</li>\n    </ul>\n  </li>\n  <li>リモートデスクトップを検索し、「Chromeリモートデスクトップ」を開く\n    <ul>\n      <li><a href=\"https://remotedesktop.google.com/?hl=ja&pli=1\" target=\"_blank\">https://remotedesktop.google.com/?hl=ja&pli=1</a></li>\n    </ul>\n  </li>\n  <li>「パソコンにアクセス」をクリック</li>\n  <li>「リモートアクセスの設定」の「ONにする」ボタンをクリック</li>\n  <li>「名前の設定」で名前を設定して「次へ」</li>\n  <li>「PINの入力」で設定するPINを2回入力して「起動」</li>\n  <li>\n    <p>パスワード入力を求められるのでパスワード入力</p>\n  </li>\n  <li>ローカル端末でログアウト\n    <blockquote>\n      <p>[!WARNING]\nローカル端末でログインしたままだとリモートデスクトップがつながっても画面表示されない</p>\n    </blockquote>\n  </li>\n</ul>\n\n<h2 id=\"window-pc側から接続\">Window PC側から接続</h2>\n<p>Windows PCでリモートデスクトップアプリを起動し、Ubuntuマシンに接続する<br />\nセッションの選択ではUbunto on Xorg または Ubuntuを選択(たぶんどっちも同じ)</p>\n\n<h3 id=\"おまじない1\">おまじない1</h3>\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。<br />\nこのダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下の内容で作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n<p>参考: <a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></p>\n\n<h3 id=\"おまじない2\">おまじない2</h3>\n<p>接続時、毎回セッションの選択をするのは面倒なので、自動で選択できるようにしようとしたが、<br />\nこれをやるとローカル端末でログインできなくなるのでやめておく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n参考までに手順を記載しておく<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.chrome-remote-desktop-session</code>を以下の内容で作成する</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>exec /etc/X11/Xsession 'env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu'\n</code></pre></div>  </div>\n  <p>env以下は使用するセッションに合わせて変更すること。<br />\n(<code class=\"language-plaintext highlighter-rouge\">/usr/share/xsessions/≪セッション名≫.desktop</code>の<code class=\"language-plaintext highlighter-rouge\">Exec</code>行の内容)</p>\n</blockquote>\n\n<h1 id=\"使いそうなプログラムのインストールと使わないプログラムのアンインストール\">使いそうなプログラムのインストールと使わないプログラムのアンインストール</h1>\n\n<h2 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h2>\n\n<p>ま、使うでしょ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweaks \n</code></pre></div></div>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>使うツールがあったら残してちょ。</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h2 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"お好みで-1\">お好みで</h2>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>ディレクトリにコピるだけ。<br />\n下では全部コピってるけど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.0.0/UDEVGothic_v1.0.0.zip \nunzip UDEVGothic_v1.0.0.zip \n<span class=\"nb\">mkdir</span> ~/.fonts\n<span class=\"nb\">cp </span>UDEVGothic_v1.0.0/<span class=\"k\">*</span>.ttf ~/.fonts/\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。<br />\nさっきフォントのインストールに使った端末ウィンドウを使うと\nエラーで端末ウィンドウが落ちるかもしれないんで一旦終了して新しいウィンドウで。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<h1 id=\"その他設定\">その他設定</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>~/.bashrcに以下を追記。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"c\"># Ubuntu22.04だとwaylandになるらしい</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"wayland\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vi\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># # venvの仮想環境名を表示するための設定</span>\n    <span class=\"c\"># show_virtual_env() {</span>\n    <span class=\"c\">#   if [ -n \"$VIRTUAL_ENV\" ]; then</span>\n    <span class=\"c\">#     echo \"($(basename $VIRTUAL_ENV))\"</span>\n    <span class=\"c\">#   fi</span>\n    <span class=\"c\"># }</span>\n    <span class=\"c\"># PS1='$(show_virtual_env)'$PS1</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nUbuntu20.04とちょっとキーが変更されてる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-home <span class=\"nb\">false \n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"ファイルnautilusのデフォルト動作変更\">ファイル(nautilus)のデフォルト動作変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アドレスバーをテキスト形式にする</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences always-use-location-entry <span class=\"nb\">true</span> \n\n<span class=\"c\"># 詳細表示をデフォルトに</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences default-folder-viewer <span class=\"s1\">'list-view'</span> \n\n<span class=\"c\"># 隠しファイルを表示する</span>\n<span class=\"c\"># 隠しファイルの表示はちょっと場所が違う</span>\ngsettings <span class=\"nb\">set </span>org.gtk.Settings.FileChooser show-hidden <span class=\"nb\">true</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアの更新(update-manager)を起動\n    <ul>\n      <li>更新のチェックが始まった場合はちょっと待つ</li>\n      <li>設定…をクリック\n        <ul>\n          <li>アップデートタブを選択</li>\n          <li>アップデートの自動確認を「なし」に変更</li>\n          <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n          <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n          <li>閉じるをクリック</li>\n        </ul>\n      </li>\n      <li>OKで終了</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Chromeリモートデスクトップ環境ではWindowsで設定したのが有効になっているので必要ないが、\nローカル端末で使用する場合に備えて入れ替えを設定しておく。<br />\n方法は、<code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code> に <code class=\"language-plaintext highlighter-rouge\">XKBOPTIONS=\"ctrl:nocaps\"</code> を追加。<br />\n設定を有効にするにはリブート必要。</p>\n\n<p>参考:<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a><br />\nリンク先は「Ubuntu 20.04/18.04 LTS」となっているが、Ubuntu22.04でも同じらしい。</p>\n\n<h3 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h3>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h1 id=\"sambaのインストール\">sambaのインストール</h1>\n\n<p>ツール本体のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加<br />\n作らなかったワークディレクトリの部分は削除してね。<br />\n他にも共有したいディレクトリがあったら追加してちょ。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">force group</code>に設定するグループは存在するグループ(またはユーザ)名に変更してください。</p>\n\n<p>ここではちょっと見たいファイルがあったのでoptも共有してます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"nfsのインストール\">NFSのインストール</h1>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/exports</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n<span class=\"c\"># abcの下にリモートのファイルが見えたらOK</span>\n</code></pre></div></div>\n\n<h1 id=\"pyenvのインストール\">pyenvのインストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<h3 id=\"必要なモジュールをインストール\">必要なモジュールをインストール</h3>\n<p>インストールに必要なモジュールをインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div></div>\n\n<h3 id=\"bluetoothを使用する場合\">bluetoothを使用する場合</h3>\n<p>bluetoothを使用する場合は以下も必要</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>pyenvの設定のため、~/.bashrc に以下を追加。 <br />\n(上記手順で記載済み。念のため再掲しておく)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h2 id=\"sudoでpyenv環境を実行するように設定する\">sudoでpyenv環境を実行するように設定する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo</code>でpythonを実行すると、pyenvの設定に関係なくsystemのpythonが実行されてしまいます。<br />\nこれを防ぐためには、<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers</code>の<code class=\"language-plaintext highlighter-rouge\">Defaults secure_path</code>に以下のpathを追加します。</p>\n\n<ul>\n  <li>«pyenvインストール先»/plugins/pyenv-virtualenv/shims:</li>\n  <li>«pyenvインストール先»shims:</li>\n  <li>«pyenvインストール先»/bin:</li>\n</ul>\n\n<p>具体的には以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 変更前\nDefaults  secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n    ↓\n# 変更後\nDefaults  secure_path=\"/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n</code></pre></div></div>\n<ul>\n  <li></li>\n</ul>\n\n<h2 id=\"pythonのインストール-以降\">pythonのインストール 以降</h2>\n\n<p>参考: <a href=\"http://localhost:4000/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINO 2022.1のbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1はRaspberry Pi OS(64bit)向けのバイナリがリリースされていないので、自力でbuildしてみます。</p>\n\n<p>今回もUbuntu上のDockerコンテナを使用しましたが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思います。</p>\n\n<p>前回はPythonを諦めてクロスコンパイルする方法とbuild時間を諦めてセルフコンパイル(エミュレーション)する方法を使いましたが、<br />\n今回はPython以外をクロスコンパイル、Python関連部をセルフコンパイル(エミュレーション)して生成物をマージする方法をとってみます。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_2022.1_pi64 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_2022.1_pi64\n</code></pre></div></div>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>workディレクトリを作成し、openvino と openvino_contrib のリポジトリをcloneします。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 2022.1.1 <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib checkout 1a28b530ab40d2ad79ab29021dfddfbbc7d2db0b\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の2022.1だと一部のノードが未対応とエラーになるため、対応済みのcommitを使用します。<br />\ntagが振られていないので、commit IDを指定してcheckoutします。<br />\nこれ以降のcommitではopenvinoのバージョン2022.2が必要になります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ntagやbranchが設定されていない場合はcloneでcheckoutするバージョンを指定できないため、\n一旦cloneしてからcommit IDを指定してcheckoutします。<br />\nsubmoluleのcheckoutは対象のバージョンをcheckoutしてから行います。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の最新commit(試した時点ではcommit ID <code class=\"language-plaintext highlighter-rouge\">fd2ac364435757d23a9b3e91d67235b5e6555bf9</code>)を使用する場合は\nopenvinoのバージョン2022.2を使用する必要がありますが、試した時点で <code class=\"language-plaintext highlighter-rouge\">2022.2.0.dev20220829</code> がリリースされているので\nこれを使用します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0.dev20220829  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit -C ./work/openvino_contrib checkout fd2ac364435757d23a9b3e91d67235b5e6555bf9\ngit -C ./work/openvino_contrib submodule update --init --recursive --depth 1\n</code></pre></div>  </div>\n  <blockquote>\n    <p>2022.2.0正式リリース後はこんな感じになるのかな?</p>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  -b 2022.2    --recursive --depth 1 https://github.com/openvinotoolkit/openvino_contrib.git\n</code></pre></div>    </div>\n  </blockquote>\n\n  <p>この場合、NVIDIA GPUのpluginのbuildでエラーになるため、以下のcmakeのオプションに以下のオプションを追加します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      -D BUILD_nvidia_plugin=OFF\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h1 id=\"openvinoのbuildクロスコンパイル\">openVINOのBuild(クロスコンパイル)</h1>\n\n<p>クロスコンパイルでpython関連以外の部分をbuildします。</p>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir cross</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">cross/Dockerfile</code>を作成します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cross/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates:arm64 <span class=\"se\">\\\n</span>    libboost-regex-dev:arm64 <span class=\"se\">\\\n</span>    libgtk2.0-dev:arm64 <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev:arm64 <span class=\"se\">\\\n</span>    libcairo2-dev:arm64 <span class=\"se\">\\\n</span>    libpango1.0-dev:arm64 <span class=\"se\">\\\n</span>    libglib2.0-dev:arm64 <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev:arm64 <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗します</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeは新しめのをインストールしておきたいので、3.23.2をbuildして使用しています。<br />\nもしかすると、<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたものをそのまま使っても大丈夫かもしれませんが。</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_cross cross\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\ncacheを使わずimage buildしたい場合は<code class=\"language-plaintext highlighter-rouge\">--no-cache</code>オプションを追加します。<br />\n以前に作ったイメージのキャッシュを使って<code class=\"language-plaintext highlighter-rouge\">apt install</code>がエラーになったことがあったので。<br />\n(デフォルトのリポジトリに変更があったらしい)</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_cross_2 ov_2022.1_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_cross_2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_2022.1_pi64_cross_2 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/cmake/arm64.toolchain.cmake <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_BEH_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLDNN</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_FUNCTIONAL_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">THREADING</span><span class=\"o\">=</span>SEQ <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">CONTRIB_TOP</span><span class=\"k\">}</span>/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span> 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=${WORK_DIR}/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"クロスコンパイル終了\">クロスコンパイル終了</h3>\n<p>クロスコンパイルはここまでなので、コンテナから抜ける。</p>\n\n<h1 id=\"openvinoのbuildセルフコンパイル\">openVINOのBuild(セルフコンパイル)</h1>\n\n<p>セルフコンパイルでpython関連部分をbuildします。<br />\ncythonを使うときにクロスコンパイルする方法が分からないので、セルフコンパイルで。</p>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir emu</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">emu/Dockerfile</code>を作成します。</p>\n\n<p>python部だけなので、こんなにライブラリとか要らない気もしますが、全部セルフコンパイルするときのことも考えて\n全部入りのイメージを作っておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  emu/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates <span class=\"se\">\\\n</span>    libboost-regex-dev <span class=\"se\">\\\n</span>    libgtk2.0-dev <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev <span class=\"se\">\\\n</span>    libcairo2-dev <span class=\"se\">\\\n</span>    libpango1.0-dev <span class=\"se\">\\\n</span>    libglib2.0-dev <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_emu emu\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_emu_2 ov_2022.1_pi64_emu /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_emu_2\n</code></pre></div></div>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成-1\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build_python <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build_python\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">InferenceEngineDeveloperPackage_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/build <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/src/bindings/python 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">CMAKE_INSTALL_PREFIX</code>の設定はクロスコンパイルのときと同じ設定にしてください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npyenvでインストールしたpythonなど、デフォルトでないpythonを使用する場合に指定します。<br />\n(以下の設定値はubuntu 22.04の標準インストールの場合のパスなのであまり参考にならないかも)</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  -D PYTHON_EXECUTABLE=/usr/bin/python3.8 \\\n  -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.8.so \\\n  -D PYTHON_INCLUDE_DIR=/usr/include/python3.8 \\\n  -D PYTHON_MODULE_EXTENSION=\".so\" \\\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"make-1\">make</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。</p>\n\n<h3 id=\"セルフコンパイル終了\">セルフコンパイル終了</h3>\n<p>セルフコンパイルはここまでなので、コンテナから抜けます。</p>\n\n<h1 id=\"インストール媒体の作成\">インストール媒体の作成</h1>\n\n<p>ホスト側の<code class=\"language-plaintext highlighter-rouge\">work</code>ディレクトリ内を見ると、<code class=\"language-plaintext highlighter-rouge\">intel</code>ディレクトリが出来ているので、ここをtarなどで固めておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>work\n<span class=\"nb\">tar </span>czvf ov1.tar.gz intel/\n</code></pre></div></div>\n\n<p>この<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiにコピーして展開します。</p>\n\n<h1 id=\"raspberrypiへのインストール\">RaspberryPiへのインストール</h1>\n\n<h2 id=\"インストール\">インストール</h2>\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiの適当なディレクトリに展開します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/proj</code>ディレクトリに展開しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /proj/\n<span class=\"nb\">tar </span>xzvf ov1.tar.gz \n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<p>これで<code class=\"language-plaintext highlighter-rouge\">/proj/intel/openvino</code>ディレクトリにインストールされました。</p>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n<p>環境変数の設定のため、以下を実行します。<br />\nshell起動の度に実行が必要なので<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>などに書いておくと良いです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/intel/openvino/setupvars.sh \n</code></pre></div></div>\n\n<h2 id=\"udevルールの設定\">udevルールの設定</h2>\n<p>以下のスクリプトを実行すればNCS2を挿せば認識されるようになります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/proj/intel/openvino/install_dependencies/install_NCS_udev_rules.sh \n</code></pre></div></div>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n<p>openCVの必要になるので、インストールしておきます。<br />\n今回はお手軽にpipでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認用のプログラムは<a href=\"https://github.com/ippei8jp/ov_trial_2022.1\" target=\"_blank\">https://github.com/ippei8jp/ov_trial_2022.1</a> とかにあります。<br />\nでもモデルのダウンロード/コンバートはRaspberryPiではできないので、UbuntuやWondowsで実行したものをコピーして使用してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</h1>\n      <p>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使うためのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1ではpypiからモジュールインストールするだけで使えるようになったのだけれど(python使用時)、<br />\nNCS2を使用しようとすると以下のようなエラーが発生します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>RuntimeError: Cannot load library 'libopenvino_intel_myriad_plugin.so: libopenvino_intel_myriad_plugin.so: cannot open shared object file: No such file or directory\n</code></pre></div></div>\n\n<p>どうやらNCS2(myriad)用のshared libraryがないらしい。<br />\nインストールミスか?と思ったけど、pypiのインストールファイル確認してみたけど、やっぱり入っていない。</p>\n<blockquote>\n  <p>[!NOTE]\nwhlファイルの拡張子をzipに変更するとファイルの中身を確認できる</p>\n</blockquote>\n\n<p>そこで、ソースからNCS2用のshared libraryをbuildしてみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p>参考: <a href=\"https://github.com/openvinotoolkit/openvino/wiki/BuildingForLinux\" target=\"_blank\">BuildingForLinux</a></p>\n\n<p>今回はWSL2の仮想マシンでbuildしてみることにする。<br />\nまた、NCS2用のshared libraryだけが目的なので、pythonモジュールとかはbuildしていない。<br />\nたぶん、ちゃんとCMAKEのオプション設定すればbuild時間が短くなるかもしれないけど、そこはお手軽最優先で。</p>\n\n<blockquote>\n  <p>[!NOTE]\n色々とbuildのために``apt install`するので、WSL2上のcloneした仮想マシンで実行した。<br />\nNCS2はWSL2上で使えないけど、buildするだけなら大丈夫みたい。<br />\n仮想マシンはUbuntu22.04を使用。 たぶん、20.04でも同様と思われる。<br />\nまぁ、Docker使えという説もある…</p>\n</blockquote>\n\n<h2 id=\"ソース取得\">ソース取得</h2>\n\n<p>openVINOのリポジトリからソース取得。<br />\n例によって<code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけてディスク容量&通信時間節約。<br />\n今回はcontribは使わない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> /work  clone  <span class=\"nt\">-b</span> 2022.1.0 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> /work/openvino submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n<span class=\"nb\">cd</span> /work/openvino\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこれ書いてる時点で2022.1.1がリリースされているけど、-bオプション変えればOKでしょう。\nたぶん。。。</p>\n</blockquote>\n\n<h2 id=\"必要なモジュールのインストール\">必要なモジュールのインストール</h2>\n\n<p>必要なモジュールはスクリプトファイルにまとめられているので、それを実行するだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash install_build_dependencies.sh \n</code></pre></div></div>\n\n<p>cmakeのバージョン3.17以上が必要なので、cmakeがそれ以下だとcmakeをソースからbuildしてくれる。<br />\nUbuntu22.04のデフォルト状態だとcmakeのバージョンは3.16なのでbuildが実行される。<br />\nちょっと時間がかかるけど、気長にお待ちください。</p>\n\n<h1 id=\"build\">build</h1>\n\n<p>準備ができたので、buildを実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>make.log\n</code></pre></div></div>\n\n<p>あとはひたすら待つ。<br />\n(うちの環境では1時間くらいだったかな)</p>\n\n<h1 id=\"ターゲットマシンにコピー\">ターゲットマシンにコピー</h1>\n\n<p>makeが終わると、以下のファイルが出来ているはず。<br />\nこの2つをNCS2を使用するターゲットマシンにコピーする。</p>\n\n<ul>\n  <li>openvino/bin/intel64/Release/lib/libopenvino_intel_myriad_plugin.so</li>\n  <li>openvino/bin/intel64/Release/lib/usb-ma2x8x.mvcmd</li>\n</ul>\n\n<p>ターゲットマシンのコピー先はopenVINOモジュールのインストール先の<code class=\"language-plaintext highlighter-rouge\">openvino/libs/</code>ディレクトリの下。<br />\n<code class=\"language-plaintext highlighter-rouge\">libopenvino.so</code>など、soファイルが並んでいるはず。</p>\n\n<p>なお、openVINOモジュールのインストール先は以下のようなコマンドで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"^openvino\"</span>\n</code></pre></div></div>\n\n<p>コピーの方法はエクスプローラでもrcpでも何でもよい。 \nエクスプローラなど、Windows経由でコピーすると実行属性が落ちてしまうけど、<br />\nそもそも実行属性必要ないので気にしなくて良いです。</p>\n\n<h1 id=\"テスト\">テスト</h1>\n<p>NCS2を使用してプログラム実行してみて、エラーにならずに実行できればOK。</p>\n\n<h1 id=\"つぶやき\">つぶやき</h1>\n<p>でも、なんでNCS2用のライブラリ入ってないんだろ?<br />\n単なる入れ忘れ? サポート終了目前?</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 22.04のVirtualBoxへのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 22.04のVirtualBoxへのインストール</h1>\n      <p>Ubuntu 22.04のVirtualBoxへのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 22.04のVirtualBoxへのインストール手順をまとめてみた。\n20.04と大差ないけど、微妙に違う点もあるので。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2204-インストール媒体の入手\">Ubuntu 22.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら:\n<a href=\"https://www.ubuntulinux.jp/products/JA-Localized/download\" target=\"_blank\">Ubuntu Desktop 日本語 Remixのダウンロード</a><br />\n日本語環境構築するなら本家よりRemix版を使った方がなにかと便利(な気がする)。<br />\n<a href=\"https://jp.ubuntu.com/download\" target=\"_blank\">本家はこちら</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを4096MB以上に設定しておくこと</strong></p>\n<blockquote>\n  <p>[!NOTE]\n推奨環境が4GB以上なので。<br />\nウィンドウマネージャだけ動いている状態で1GBちょい使用だったので、\n2048MBでも動くと思う。でも、何か動かしたらすぐ足りなくなりそう。 <br />\nそれにしても、どんどん必要メモリが大きくなるな。<br />\n仮想環境で4GBってことは、HostOS環境下には8GB以上は必要ってことだよな。<br />\nプロセッサも2個割り当てておいた方が良いのかな?<br />\nこれは様子見てからどうするか決めよう。</p>\n</blockquote>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<blockquote>\n  <p>[!TIP]\nウィンドウが画面からはみ出して「続ける」ボタンが押せないときは、Alt+F7キーを押したあと、マウスでドラッグすると\nウィンドウを移動できるので、ボタンが見えるようところまで移動してクリックしてちょ。</p>\n</blockquote>\n\n<p>以下の説明が図付きで分かりやすい:\n<a href=\"https://qiita.com/HirMtsd/items/d43fc5215a88cbf414c9\" target=\"_blank\">Windows11上のVirtualBoxにUbuntu22.04LTSをインストール</a><br />\nWindows11って書いてあるけど、Windows10でも同じ。<br />\nここの説明では「不完全な言語サポート」うんぬんの説明があるけど、日本語Remix版でインストールすると、この部分は不要みたい。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<p>まだGuestAdditionをインストールしてないからコピペできないけど、BashのTab補完が効くので、\nちょろっと入力してあとは補完に頼れば大丈夫。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面 を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源管理を選択<br />\n右側で画面のブランクのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>裏でソフトウェアの更新が動いていると、ロックファイルがロックされてしばらく適用できないので、<br />\nそうなっちゃったらお茶でも飲んでしばらくお待ちください。<br />\nソフトウェアの更新による自動更新を止める方法は後ほど。</p>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweaks \n</code></pre></div></div>\n\n<h3 id=\"一旦リブート\">一旦リブート</h3>\n<p>更新適用のため。</p>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>以前にマウントしたものが残ってたらアンマウントしておくこと(インストール後初めてなのでマウントされてることはないけれど)。<br />\nVirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<blockquote>\n  <p>[!TIPS]\nプログラムが自動で始まらない場合は、CDROMのマウント先(たぶん、<code class=\"language-plaintext highlighter-rouge\">/media/<USER>/VBox_GAs_x.x.xx/</code>)に移動して<code class=\"language-plaintext highlighter-rouge\">sudo VBoxLinuxAdditions.run</code>を実行すれば良い。</p>\n</blockquote>\n\n<h3 id=\"再度リブート\">再度リブート</h3>\n<p>GuestAdditionによる更新適用のため。</p>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから「デバイス」→「クリップボードの共有」→「双方向」<br />\nを選択。\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<h3 id=\"使わないのでアンインストール\">使わないのでアンインストール</h3>\n\n<p>使うツールがあったら残してちょ。</p>\n\n<h4 id=\"ツール類\">ツール類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h4 id=\"ゲーム類\">ゲーム類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h4 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"お好みで\">お好みで</h2>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>ディレクトリにコピるだけ。<br />\n下では全部コピってるけど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.0.0/UDEVGothic_v1.0.0.zip \nunzip UDEVGothic_v1.0.0.zip \n<span class=\"nb\">mkdir</span> ~/.fonts\n<span class=\"nb\">cp </span>UDEVGothic_v1.0.0/<span class=\"k\">*</span>.ttf ~/.fonts/\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。<br />\nさっきフォントのインストールに使った端末ウィンドウを使うと\nエラーで端末ウィンドウが落ちるかもしれないんで一旦終了して新しいウィンドウで。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<h3 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h3>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h3 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h3>\n\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h3 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h3>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>~/.bashrcに以下を追記。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"c\"># Ubuntu22.04だとwaylandになるらしい</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"wayland\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vi\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># # venvの仮想環境名を表示するための設定</span>\n    <span class=\"c\"># show_virtual_env() {</span>\n    <span class=\"c\">#   if [ -n \"$VIRTUAL_ENV\" ]; then</span>\n    <span class=\"c\">#     echo \"($(basename $VIRTUAL_ENV))\"</span>\n    <span class=\"c\">#   fi</span>\n    <span class=\"c\"># }</span>\n    <span class=\"c\"># PS1='$(show_virtual_env)'$PS1</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># openVINO の設定はdirenvで</span>\n<span class=\"c\"># for openVINO</span>\n<span class=\"c\"># source /opt/intel/openvino_2021/bin/setupvars.sh</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nUbuntu20.04とちょっとキーが変更されてる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-home <span class=\"nb\">false \n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"sambaのインストール\">sambaのインストール</h3>\n\n<p>ツール本体のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加<br />\n作らなかったワークディレクトリの部分は削除してね。<br />\n他にも共有したいディレクトリがあったら追加してちょ。<br />\nここではOpenVINOのサンプルとか見たかったのでoptを共有してます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n<span class=\"c\"># abcの下にリモートのファイルが見えたらOK</span>\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"ファイルnautilusのデフォルト動作変更\">ファイル(nautilus)のデフォルト動作変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アドレスバーをテキスト形式にする</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences always-use-location-entry <span class=\"nb\">true</span> \n\n<span class=\"c\"># 詳細表示をデフォルトに</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences default-folder-viewer <span class=\"s1\">'list-view'</span> \n\n<span class=\"c\"># 隠しファイルを表示する</span>\n<span class=\"c\"># 隠しファイルの表示はちょっと場所が違う</span>\ngsettings <span class=\"nb\">set </span>org.gtk.Settings.FileChooser show-hidden <span class=\"nb\">true</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアの更新(update-manager)を起動\n    <ul>\n      <li>更新のチェックが始まった場合はちょっと待つ</li>\n      <li>設定…をクリック\n        <ul>\n          <li>アップデートタブを選択</li>\n          <li>アップデートの自動確認を「なし」に変更</li>\n          <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n          <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n          <li>閉じるをクリック</li>\n        </ul>\n      </li>\n      <li>OKで終了</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a><br />\nリンク先は「Ubuntu 20.04/18.04 LTS」となっているが、Ubuntu22.04でも同じらしい。<br />\nNative環境にインストールしてないので未確認だけど…</p>\n\n<p>リブート必要だが、以下のIPv6無効化とまとめてリブートでも可。</p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<p>マスタイメージを残しておいて、色々な環境をお試しするには仮想マシンをクローンして使うのがおススメ。<br />\nVirtualBoxのメインウィンドウでマスタイメージの仮想マシンを右クリック→クローンを選択、名前とパスを設定し、あとはごにょごにょ…</p>\n\n<p>クローンした仮想マシンを起動し、必要な変更を加える。</p>\n\n<h2 id=\"ネットワーク設定の変更\">ネットワーク設定の変更</h2>\n\n<p>マシン名とか同じ名前だと色々不都合があるので、変更しておく。<br />\n他のクローン仮想環境と同時に使わないならそのままでも良いけど。<br />\nIPアドレスも固定で割り振っておくと名前が引けない時にさくっと分かってなにかと便利…なんだけど、最近はWindowsもUbuntuもRaspberryPiもmDNSがサポートされてるから自動割り当てのままでもそんなに不便はないかも。</p>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<p>このコマンドで<code class=\"language-plaintext highlighter-rouge\">/etc/hostname</code>が書き換えられる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<p>もちろん、vimとかで書き換えても可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<p>下のコマンドを実行するための接続名を確認しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<p>IPアドレスを手動割り当てに変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> \n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<p>IPアドレスを手動割り当てに変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> gw4 <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nIPアドレスの変更をGUIで行うには以下。<br />\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>まとめて実行するならこちら。<br />\nホスト名、接続名、IPアドレスなどは適宜変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># マシン番号の設定とホスト名の設定</span>\n<span class=\"nv\">number</span><span class=\"o\">=</span>30\n<span class=\"nv\">new_hostname</span><span class=\"o\">=</span>skull<span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span>\n\n<span class=\"c\"># HOSTNAMEの変更</span>\n<span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/ubuntu-22.*</span><span class=\"nv\">$/</span><span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span><span class=\"s2\">/\"</span> /etc/hosts\n\n<span class=\"c\"># HOST ONLY ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.56.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n\n<span class=\"c\"># BRIDGE ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.78.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> gw4 <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<h2 id=\"あとはお約束\">あとはお約束</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>VirtalBoxのバージョンが変更されているときは、GuestAdditionのバージョンアップも忘れずに。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Pythonのasyncioでnon-blockingなコンソール入力</title>\n  </head>\n  <body>\n    <header>\n      <h1>Pythonのasyncioでnon-blockingなコンソール入力</h1>\n      <p>Pythonのasyncioでnon-blockingなコンソール入力を行うためのクラス</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでasyncioを使ったときにnon-blockingなコンソール入力(キーボード入力)ができなくて困ったので、実現するためのクラスを作ってみた。</p>\n\n<p>もともと Linux用に作ったら、Windowsだとうまく動かない。<br />\nちょっと汚い方法だけど、とりあえず動くようにしてお茶を濁しておく。<br />\n(あんまりテストしてないから動かなかったらごめん)</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/5033eec9b9b774ede4f87604a51fb162.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>お試しならこのソースをそのまま実行すると実行できます。<br />\n<code class=\"language-plaintext highlighter-rouge\">char_mode = False</code> の部分を変更すると、1行入力モードと1文字入力モードを切り替えられます。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout_mode = True</code> の部分を変更すると、タイムアウトなしとタイムアウトありを切り替えられます。</p>\n\n<p>実際に使用するには、このソースをimportして使ってください。</p>\n\n<h1 id=\"注意\">注意</h1>\n\n<p>Linuxで1文字入力モードを使っている場合は、終了時(例外で死んだ場合も含めて)<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行しないと悲しいことになります。<br />\n(ターミナルの入力モードが変更されてしまうので、うまく入力できなくなる)<br />\nそのために、<code class=\"language-plaintext highlighter-rouge\">atexit.retister()</code>で終了処理ルーチンを登録し、その中で<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行するようにしています。</p>\n\n<h1 id=\"ひとりごと\">ひとりごと</h1>\n\n<p>asyncioのサンプルって、タスク1個で動かしてることが多いからあんまり ありがたみが分からんのかな…<br />\nあと、タスクとコルーチンが同じように語られていて分かり難いのもあると思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINOのクロスコンパイル</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINOのクロスコンパイル</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild(クロスコンパイル環境)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi OS(64bit)向けにopenVINOをクロスコンパイルする方法についてまとめた。<br />\nセルフコンパイル(Docker使用)については『<a href=\"/memoBlog/2022/03/07/openVINO_build_2.html\" target=\"_blank\">openVINO(Raspberry Pi OS(64bit)向け)のbuild</a>』を参照。<br />\nただ、クロスコンパイルだとセルフコンパイルの10倍くらい速い(環境によるけど)ので、クロスコンパイルがおススメ。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_cross <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_cross\n</code></pre></div></div>\n\n<h2 id=\"ソースの取得\">ソースの取得</h2>\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h3>\n<p>以下の1つのpatchファイルを作成する。<br />\nサンプル(テスト?)プログラムのBuildを抑制してコンパイル時間の短縮を計っている。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"opencv-の-gitリポジトリを-clone\">openCV の gitリポジトリを clone</h3>\n<p>opencv のリポジトリをcloneする(opencvのBuildを行わない場合は不要)。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libgtk-3-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_cross <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_cross_1 ov_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_cross_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_cross_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n<p>ここからコンテナ内</p>\n\n<h2 id=\"buildディレクトリの作成\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openvino/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/openvino/build\n</code></pre></div></div>\n\n<h2 id=\"cmake実行\">cmake実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm64.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_SAMPLES</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLANG_FORMAT</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_OPENCV</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n    .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>サンプルはBuildしないので、ENABLE_SAMPLES=OFF を設定</li>\n    <li>ソースをいじるわけではないので、ENABLE_CLANG_FORMAT=OFF を設定</li>\n    <li>openCVインストールされていないので、ENABLE_OPENCV=OFF を設定<br />\n(サンプルのBuildしないのでopenCVなくても大丈夫)</li>\n  </ul>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nログには いくつかWarningがあるが、とくに問題はなさそう</p>\n</blockquote>\n\n<h2 id=\"make\">make</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h2 id=\"その他細々したところ\">その他細々したところ</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"c\"># クロスコンパイルを反映したファイル名になっていないので修正</span>\n<span class=\"nb\">mv</span> /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-x86_64-linux-gnu.so /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-aarch64-linux-gnu.so\n\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>CPU Extentionは<code class=\"language-plaintext highlighter-rouge\">make install</code>でコピーされないので手動でインストールする。</li>\n    <li>バイナリリリースに<code class=\"language-plaintext highlighter-rouge\">inference_engine</code>のシンボリックリンクがあるので同様に作成しておく。</li>\n    <li>ngraphのライブラリファイルのファイル名がx86_64(ホスト環境の名前)になっているので、aarch64に修正。<br />\nバイナリ自体はaarch64になっているので、ファイル名のリネームだけでOK。<br />\n本来はファイル名決めてるところで対処するのが良いのだろうけど、とりあえず力技で。</li>\n  </ul>\n</blockquote>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<p>openCVのBuild方法についてもメモっておく。<br />\npythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。<br />\nその場合は、ここはスキップしても大丈夫。<br />\nopenVINOをBuildしたDockerコンテナで引き続き作業を行う</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk-3-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libjpeg-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libpng-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev:arm64\n</code></pre></div></div>\n<h2 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n</code></pre></div></div>\n<h2 id=\"cmakeの実行\">cmakeの実行</h2>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PKG_CONFIG_LIBDIR</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_ENABLE_PKG_CONFIG</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_FIND_ROOT_PATH</span><span class=\"o\">=</span>/ <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span>/work/opencv/platforms/linux/aarch64-gnu.toolchain.cmake <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_NUMPY_INCLUDE_DIRS</span><span class=\"o\">=</span>/usr/lib/python3/dist-packages/numpy/core/include <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n       .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあらかじめ環境変数<code class=\"language-plaintext highlighter-rouge\">PKG_CONFIG_LIBDIR</code>を設定して<code class=\"language-plaintext highlighter-rouge\">pkg-config</code>でaarch64のライブラリとNativeのツール類を参照するように設定しておく。<br />\nこれをやらないと、libjpegとかをインストールしてあることを検出できない</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeのオプションに <code class=\"language-plaintext highlighter-rouge\">-D CMAKE_FIND_DEBUG_MODE=1</code>を追加すると\ncmake中の<code class=\"language-plaintext highlighter-rouge\">find_xxx</code>の動作のログが出力されるので、パッケージのサーチなどの検索パスの確認などが容易になる。</p>\n</blockquote>\n\n<h2 id=\"make-1\">make</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install-1\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino/opencv</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/opencv</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-D CMAKE_INSTALL_PREFIX=/work/opt/intel/openvino/opencv</code>の部分を変更すれば良いけど、ここはopenVINOのインストール先と合わせておかないとうまく動かない。</p>\n\n<h1 id=\"実機へのインストール\">実機へのインストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">opt</code>ディレクトリ以下を丸ごとアーカイブする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<p>作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>をRaspberryPiの適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"コンテナから出る\">コンテナから出る</h1>\n<p>Dockerコンテナは作業終了したら終了しておく。<br />\nCTRL-D でshell終了</p>\n\n<h1 id=\"補足\">補足</h1>\n<p>コンテナにインストールされているパッケージは以下の通り。<br />\nバージョン違いで動かなくなることもあるかもしれんので、念のため。</p>\n\n<p>こんな感じで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span> | <span class=\"nb\">grep</span> <span class=\"nt\">-v</span> automatic\n</code></pre></div></div>\n\n<p>で、こんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>build-essential/stable,now 12.9 amd64 [installed]\ncmake/stable,now 3.18.4-2+deb11u1 amd64 [installed]\ncrossbuild-essential-arm64/stable,stable,now 12.9 all [installed]\ncython3/stable,now 0.29.21-3+b1 amd64 [installed]\ngit/stable,now 1:2.30.2-1 amd64 [installed]\nlibavcodec-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibavformat-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibgstreamer-plugins-base1.0-dev/stable,now 1.18.4-2 arm64 [installed]\nlibgstreamer1.0-dev/stable,now 1.18.4-2.1 arm64 [installed]\nlibgtk-3-dev/stable,now 3.24.24-4 arm64 [installed]\nlibjpeg-dev/stable,now 1:2.0.6-4 arm64 [installed]\nlibpng-dev/stable,now 1.6.37-3 arm64 [installed]\nlibprotobuf-dev/stable,now 3.12.4-1 arm64 [installed]\nlibprotoc-dev/stable,now 3.12.4-1 arm64 [installed]\nlibpython3-dev/stable,now 3.9.2-3 arm64 [installed]\nlibswscale-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibtiff-dev/stable,now 4.2.0-1 arm64 [installed]\nlibusb-1.0-0-dev/stable,now 2:1.0.24-3 arm64 [installed]\nlibwebp-dev/stable,now 0.6.1-2.1 arm64 [installed]\nprotobuf-compiler/stable,now 3.12.4-1 amd64 [installed]\npython3-minimal/stable,now 3.9.2-3 amd64 [installed]\npython3-numpy/stable,now 1:1.19.5-1 amd64 [installed]\npython3-pip/stable,stable,now 20.3.4-4 all [installed]\nscons/stable,stable,now 4.0.1+dfsg-2 all [installed]\nwget/stable,now 1.21-1+deb11u1 amd64 [installed]\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>aspberry Pi OS(64bit)がリリースされたが、openVINOのBuild済みモジュールはまだこれに対応していない。<br />\nそのうち対応されると思うけど、とりあえず自前でBuildする方法を調べてみた。<br />\nついでにCPU Extensionも作成しておく。<br />\nなお、Raspberry Pi OS(32bit Buster)向けのBuild手順については、\n『<a href=\"/memoBlog/2021/10/28/openVINO_build.html\" target=\"_blank\">openVINO(Raspberry Pi向け)のbuild</a>』を参照。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<p>今回もARM版Dockerコンテナを使用してセルフコンパイルする方法で行う。<br />\n手順そのものは特殊なことはないので、Raspberry Pi上のNative環境でもBuildできそうだけど、\nディスク容量とかスワップ領域とか気にしないといけないかもしれないので試してない。<br />\n(今回はクロスコンパイル環境はなし。cythonの出力モジュールも使いたかったので)</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_emu\n</code></pre></div></div>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h2 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h2>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n32bit版との差分はこんな感じ。<br />\nあれ?32bit版の<code class=\"language-plaintext highlighter-rouge\">python-minimal</code>って間違ってる?<br />\n<code class=\"language-plaintext highlighter-rouge\">python3-numpy</code>で依存モジュールとしてインストールされて事なきを得たのか?<br />\n実質、ベースイメージを変更してるだけだな。</p>\n\n  <div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- Dockerfile.old\t2022-03-01 07:26:28.774187231 +0900\n</span><span class=\"gi\">+++ Dockerfile\t2022-03-01 07:19:45.668393598 +0900\n</span><span class=\"p\">@@ -1,4 +1,4 @@</span>\n<span class=\"gd\">-FROM arm32v7/debian:buster\n</span><span class=\"gi\">+FROM arm64v8/debian:bullseye\n</span> \n USER root\n \n<span class=\"p\">@@ -18,7 +18,7 @@</span>\n     libprotobuf-dev libprotoc-dev protobuf-compiler \\\n     cmake \\\n     python3-pip \\\n<span class=\"gd\">-    python-minimal \\\n</span><span class=\"gi\">+    python3-minimal \\\n</span>     python3-numpy cython3 scons\n \n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_emu_1 ov_pi64_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<p>数時間レベルでかかるので、のんびり待ちましょう。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"その他細々したところ\">その他細々したところ</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コメント\">コメント</h3>\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール\">実機へのインストール</h2>\n\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>を適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>ついでにopenCVのBuild方法についてもメモっておく。</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>openCVのリポジトリをcloneしておく。<br />\n指定するタグは適宜変更してください。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n<p>新しいDockerコンテナ作っても良いけど、別にその必要もないので上記のコンテナをそのまま使用する。</p>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n  <h2 id=\"本番-1\">本番</h2>\n</blockquote>\n\n<h3 id=\"準備-2\">準備</h3>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk2.0-dev  libjpeg-dev libpng-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev\n</code></pre></div></div>\n\n<h3 id=\"build\">Build</h3>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n\n<span class=\"c\"># インストール</span>\nmake <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf opencv.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コンテナから出る-1\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール-1\">実機へのインストール</h2>\n<p>openVINOをBuildしたコンテナで続けてBuildした場合は<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>にopenVINO、openCVがインストールされている。<br />\nこれを適当なディレクトリに展開して環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば良い。</p>\n\n<p>別のコンテナを使用したり、openVINOのBuild結果を削除していた場合は、<br />\n最終的に作成した<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>をopenVINOをインストールしたディレクトリに展開する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi向け)のbuild</h1>\n      <p>Raspberry Pi向けopenVINOのbuild(特にCPU extension)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi用 openVINO は デフォルト状態ではCPUで実行できない(NCS2必須)。<br />\nそこで、オープンソース版openVINOを使用してCPU extensionを作成してみる。<br />\nとはいえ、CPU extension だけサクっと作成できなくて、openVINO全体を作成するハメに…</p>\n\n<p>Raspberry Pi 実機でbuildすると、ディスク容量がバカにならないし、<br />\nあまり実環境を弄りたくなかったので、<br />\nUbuntuマシン上のDockerコンテナで実行する方法を試してみる(Docker Desktop for Windowsでもできると思う)</p>\n\n<h1 id=\"arm版dockerコンテナを使用したセルフコンパイル\">ARM版Dockerコンテナを使用したセルフコンパイル</h1>\n\n<p>Dockerコンテナ全体をQEMU上でARMエミュレーションしてくれるので、特に難しいことを考えずに<br />\nネイティブ環境と変わりなくあつかえる。<br />\nでも、かなり遅い(実機よりちょっと速い?同じくらい?)。<br />\n試した環境では、x86_64な環境でクロスコンパイルした場合の15倍くらいかかった。  <br />\n(M1 Mac上でACVMを使うとかなり早いという噂も…M1 Mac持ってない😢  <a href=\"https://qiita.com/kose3/items/af9edc9c40c9ae8fc5c3\" target=\"_blank\">参考</a>  )</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h3 id=\"qemuのインストール\">qemuのインストール</h3>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_emu\n</code></pre></div></div>\n\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm32v7/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成\">patchファイルを作成</h3>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_emu_1 ov_pi_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n以下のオプションを追加すると少しは速くなるかと思ったが、あまり変わらない。</p>\n  <ul>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_OPENCV=OFF</code></li>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_SAMPLES=OFF</code></li>\n  </ul>\n</blockquote>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。</p>\n\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./inference_engine</code> がない\n    <ul>\n      <li>実体は <code class=\"language-plaintext highlighter-rouge\">deployment_tools/inference_engine</code> なので、シンボリックリンクを作れば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/opencv/</code>からコピーすれば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>opencvのpythonモジュールがない\n        <ul>\n          <li>どこから持ってくれば良いんだろう?</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h3 id=\"実機へのインストール\">実機へのインストール</h3>\n<p>CPU extensionだけなら<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l/</code><br />\nへコピーするだけで良い。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれはmake install してもこれはコピーされないらしい。</p>\n</blockquote>\n\n<p>openVINO全体のインストールなら<code class=\"language-plaintext highlighter-rouge\">work/opt/intel/openvino</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/</code>にコピーすれば良いのだけど、opencvのpythonインタフェースがないので注意。<br />\nということで、実際に試していない…</p>\n\n<blockquote>\n  <p>[!NOTE]\n※※※※ メモ ※※※※ <br />\nopenCVはここでbuildするのではなく、<br />\n<a href=\"https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/\" target=\"_blank\">https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/</a> \nからbuild済みモジュールをダウンロードして<br />\n<code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/</code><br />\nに展開している。</p>\n</blockquote>\n\n<h1 id=\"i386版32bit-x86dockerコンテナを使用したクロスコンパイル\">i386版(32bit x86)Dockerコンテナを使用したクロスコンパイル</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>セルフコンパイルは時間がかかりすぎるので、クロスコンパイルで試してみた。<br />\nかなり早くなったが、一部使えないモジュールが…<br />\n当初の目的のCPU extensionは使えるので、掲載しとく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n当初、64bit版debianをベースに作業しようとしたが、\npybind11のbuildで以下のように怒られる。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Make Error at build/_deps/pybind11-src/tools/FindPythonLibsNew.cmake:127 (message):\n  Python config failure: Python is 64-bit, chosen compiler is 32-bit\nCall Stack (most recent call first):\n  build/_deps/pybind11-src/tools/pybind11Tools.cmake:16 (find_package)\n  build/_deps/pybind11-src/CMakeLists.txt:33 (include)\n</code></pre></div>  </div>\n  <p>以下のような対策が考えられる。</p>\n  <ul>\n    <li>FindPythonLibsNew.cmakeにbit数チェックをしないようにパッチを当てる\n      <ul>\n        <li>やり方がよう分からん…</li>\n      </ul>\n    </li>\n    <li>amd64なdebianに32bitのpythonをインストールする\n      <ul>\n        <li>イマイチうまくインストールできなかった</li>\n      </ul>\n    </li>\n  </ul>\n\n  <p>しかたないので、32bit版debianで作ることにした</p>\n</blockquote>\n\n<h2 id=\"準備-1\">準備</h2>\n\n<h3 id=\"作業用ディレクトリの準備-1\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_buster_32 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_buster_32\n</code></pre></div></div>\n<h3 id=\"openvino-の-gitリポジトリを-clone-1\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> i386/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> armhf <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-armhf <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:armhf <span class=\"se\">\\\n</span>    libgtk-3-dev:armhf <span class=\"se\">\\\n</span>    libavcodec-dev:armhf <span class=\"se\">\\\n</span>    libavformat-dev:armhf <span class=\"se\">\\\n</span>    libswscale-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:armhf <span class=\"se\">\\\n</span>    libpython3-dev:armhf <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python-argparse <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"c\"># aptでインストールするので削除</span>\n<span class=\"c\"># RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.3/cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     tar xzvf cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     (cd cmake-3.21.3 && ./bootstrap --parallel=$(nproc --all) -- -DCMAKE_USE_OPENSSL=OFF && make --jobs=$(nproc --all) && make install) && \\</span>\n<span class=\"c\">#     rm -rf cmake-3.21.3 cmake-3.21.3.tar.gz</span>\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"patchファイルを作成-1\">patchファイルを作成</h3>\n\n<p>以下の2つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch1.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake\nindex 6cb15a0..66a1ef6 100644\n</span><span class=\"gd\">--- a/cmake/dependencies.cmake\n</span><span class=\"gi\">+++ b/cmake/dependencies.cmake\n</span><span class=\"p\">@@ -19,8 +19,9 @@</span> if(CMAKE_CROSSCOMPILING AND CMAKE_HOST_SYSTEM_NAME MATCHES Linux AND CMAKE_HOST_\n     find_program(\n         SYSTEM_PROTOC\n         NAMES protoc\n<span class=\"gd\">-        PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n-        NO_DEFAULT_PATH)\n</span><span class=\"gi\">+        # PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n+        # NO_DEFAULT_PATH)\n+        )\n</span>     if(NOT SYSTEM_PROTOC)\n         message(FATAL_ERROR \"[ONNX IMPORTER] Missing host protoc binary\")\n     endif()\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる-1\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../patch1.patch<span class=\"o\">)</span>\n<span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino apply ../../patch1.patch\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_buster_32 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32_1</code> を使用。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_buster_32_1 ov_pi_buster_32 /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/386) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_buster_32_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_buster_32_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make-1\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n\n<p>コンテナから出て、<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の \n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l</code>/<br />\nへコピーする</p>\n\n<blockquote>\n  <p>[!WARNING]\ncythonの出力がx86のコードを吐くので、pythonモジュールの一部に正常に動作しないものがある。<br />\npythonモジュールを使いたいときはセルフコンパイルするしかないかな?</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerでopenVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerでopenVINO</h1>\n      <p>DockerでopenVINOプログラムの開発</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>DockerコンテナでopenVINOのプログラム開発を行う手順。<br />\n↓ここを参考にUbuntu 20.04/openVINO 2021.3に変更してみる。ついでによく使う機能の準備もやっておく。<br />\n<a href=\"https://kuttsun.blogspot.com/2021/06/openvino-docker.html\">https://kuttsun.blogspot.com/2021/06/openvino-docker.html</a></p>\n\n<h1 id=\"dockerイメージの作成\">Dockerイメージの作成</h1>\n\n<p>上の参照先を参考に公式イメージに必要な処理を加えておく。<br />\nDockerfile は以下。<br />\n参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>ベースをopenVINO/ubuntu20に変更</li>\n  <li>sudoとvimとless入れとく。sudoはパスワードなしで動作するようにしとく。</li>\n  <li>開発マシンなのでbaskhの補完機能を有効にしておく</li>\n  <li>キーバインド変更 ( <code class=\"language-plaintext highlighter-rouge\">^p</code> / <code class=\"language-plaintext highlighter-rouge\">^n</code> )</li>\n  <li>日本語文字化け対策</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code> がキー入力待ちになってbuildエラーになるので<code class=\"language-plaintext highlighter-rouge\">-y</code>オプションを追加</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-docker highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースイメージ</span>\n<span class=\"k\">FROM</span><span class=\"s\"> openvino/ubuntu20_dev:2021.3</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">ENV</span><span class=\"s\"> DEBIAN_FRONTEND=noninteractive</span>\n\n<span class=\"c\"># sudo と vim と less のインストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install sudo </span>vim less <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo </span>openvino <span class=\"nv\">ALL</span><span class=\"o\">=</span><span class=\"se\">\\(</span>root<span class=\"se\">\\)</span> NOPASSWD:ALL <span class=\"o\">></span> /etc/sudoers.d/openvino <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">chmod </span>0440 /etc/sudoers.d/openvino\n\n<span class=\"c\"># bashの補完機能 & キーバインドの設定 & 日本語文字化け対策</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nb\">install </span>bash-completion <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"s2\">\". /usr/share/bash-completion/bash_completion\"</span> <span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-n</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-forward' </span><span class=\"se\">\\n\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-p</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-backward'</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">export LANG=C.UTF-8</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">export LANGUAGE=en_US:</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc\n\n<span class=\"c\"># 依存パッケージのインストール(-yオプションで Yes自動選択)</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies <span class=\"o\">&&</span> ./install_openvino_dependencies.sh <span class=\"nt\">-y</span>\n\n<span class=\"c\"># サンプル、デモアプリのビルド</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/samples/cpp <span class=\"o\">&&</span> ./build_samples.sh\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/demos <span class=\"o\">&&</span> ./build_demos.sh\n<span class=\"c\"># /opt/intel/openvino_2021/deployment_tools/demo にデモアプリがある</span>\n\n<span class=\"c\"># 他に必要なものを適宜インストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>wget git python3-pip\n<span class=\"k\">RUN </span>pip3 <span class=\"nb\">install </span>onnxruntime flask\n\n<span class=\"c\"># aptのクリア</span>\n<span class=\"k\">RUN </span>apt clean <span class=\"o\">&&</span> <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> /var/lib/apt/lists/<span class=\"k\">*</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> openvino</span>\n\n<span class=\"c\"># bash起動</span>\n<span class=\"k\">CMD</span><span class=\"s\"> [ \"/bin/bash\" ]</span>\n</code></pre></div></div>\n\n<h1 id=\"ビルド\">ビルド</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker build <span class=\"nt\">-t</span> myopenvino/ubuntu20_dev:2021.3 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h1 id=\"コンテナの生成\">コンテナの生成</h1>\n<p>参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>カレントディレクトリ下のworkを/workに割り当てるように追加</li>\n  <li>GPU関連の設定を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ./work\ndocker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"se\">\\</span>\n       <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"se\">\\</span>\n       myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nX-Windowの表示先(<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code> 変数) は ここで固定されるので、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を変更したい場合は<br />\nコンテナをスタートした後、コンテナ内で手打ちで設定するか、<br />\n変更後の<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を設定したターミナルから以下を実行。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> openvino_2021.3 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<p>Windows の場合は以下な感じ。<br />\nDISPLAY変数は環境に合わせて変更してちょ。<br />\nNCS周りの設定は削除してある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.204:0.0 <span class=\"nt\">-v</span> %CD%<span class=\"se\">\\w</span>ork:/work myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ndocker をWSL上のコマンドラインから起動しているときは<code class=\"language-plaintext highlighter-rouge\">%CD%</code>でなく<code class=\"language-plaintext highlighter-rouge\">$PWD</code><br />\nPowerShellでコマンドを複数行に分割する場合は、行末記号は<code class=\"language-plaintext highlighter-rouge\">\\</code> ではなく <code class=\"language-plaintext highlighter-rouge\">`</code><br />\nコマンドプロンプトでは<code class=\"language-plaintext highlighter-rouge\">^</code> NYAGOSは分からん😢<br />\nそれぞれ違ってびみょーにストレス…</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> openvino_2021.3\n</code></pre></div></div>\n\n<p>コンテナ内でデモを動かしてみる<br />\n(デモの実行で必要なライブラリ類がインストールされたりするので、実行しましょう)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ~/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/demo1.log\n\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/dem2.log\n</code></pre></div></div>\n\n<p>前に作ったプログラムを試してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\ngit clone https://github.com/ippei8jp/ov_trial.git\n<span class=\"c\"># 入力画像の準備</span>\n<span class=\"nb\">cd </span>ov_trial/images/\nbash download.sh\n<span class=\"c\"># モデルファイルの準備(mobilenet-ssdのダウンロードがエラーになるけど大勢に影響ない) </span>\n<span class=\"nb\">cd</span> ../convert_model_ssd/\nbash convert_model_ssd.sh \n\n<span class=\"c\"># 認識してみる</span>\n<span class=\"nb\">cd</span> ../ssd/\nbash test.sh list\nbash test.sh 6\n</code></pre></div></div>\n\n<h1 id=\"ncs2の使用ubuntuのみ\">NCS2の使用(ubuntuのみ)</h1>\n<p>ubuntuではホストに接続したNCS2を使用することもできる。<br />\nただし、DockerコンテナからNCS2を使用するにはDokerホスト側にドライバをインストールしておく必要がある。<br />\n(udevルールだけ?イマイチ自信ないのでフルパッケージでインストールしておいた)<br />\n以下の部分がNCS2を使用するために必要な設定。(上記コマンド例では設定済み)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</h1>\n      <p>ローカル(Windows)のVSCodeからリモートホスト(ubuntu)上のDockerコンテナ内のプログラムをデバッグする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからUbuntu上のDockerコンテナに接続してデバッグする方法。</p>\n\n<p>UbuntuへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>\nsudo なしで Docker動かせるようにしとく必要あり</p>\n\n<h1 id=\"リモートホストへの接続\">リモートホストへの接続</h1>\n<p>UbuntuへのSSH接続の準備については<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">こちら</a></p>\n\n<h2 id=\"手順\">手順</h2>\n<ul>\n  <li>WindowsマシンでVScode 起動する</li>\n  <li>拡張機能「Remote Development」をインストールしておく。</li>\n  <li>左下にある「><」ボタンをクリック</li>\n  <li>上にメニューが出るので、「Connect to host…」 または「Connect Current Window to Host…」を選択</li>\n  <li>続いて「Select configured SSH host~」で接続するホストを選択。\n    <ul>\n      <li>新規接続の場合は「Add New SSH Host…」を選択</li>\n      <li>「ssh «user»@«IPアドレス or マシン名»」</li>\n      <li>設定を保存するファイルを選択。特に理由がなければ c:\\Users\\«ユーザ».config でいいかな。</li>\n      <li>右下に「Host added!」ウィンドウが出るので「Connect」をクリック</li>\n      <li>初めて接続するホストの場合、上にSelect the platform of remote host “~” と聞かれるのでOS種別を選択</li>\n      <li>「あんた«OS»を選らんだでー。~に保存したから変えたかったら ここ変更しぃや~」みたいなことを言ってるウィンドウが出るので「Don’t Show Again」をクリック</li>\n    </ul>\n  </li>\n  <li>接続された。右下の「><」ボタンが「>< SSH:«マシン名»」に変わっている。</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n一度接続すればリモートエクスプローラ(SSH TARGETS)に表示されるのでそこから接続しても良い。</p>\n</blockquote>\n\n<p>リモートホスト上のプログラムをデバッグしたい場合はここでフォルダを開いてごちょごちょやればよい。</p>\n\n<h1 id=\"dockerコンテナへの接続\">Dockerコンテナへの接続</h1>\n<h2 id=\"準備\">準備</h2>\n<p>WindowsマシンにDocker desktop for windows が必要になるので、インストールしておく。<br />\nWindowsへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\">こちら</a><br />\nCLIだけでよさそうなんだけど、CLIだけってのがどこかにあるのか分からんかったのでとりあえず全部入れた。<br />\nDocker Desktopは動いてなくて良いので、Exitして可。<br />\n普段から使わないならDocker Dashboardの設定のGeneralから「Start Docker Desktop when you log in」のチェックを はずしておけばOK。</p>\n\n<h2 id=\"dockerexeで疎通確認\">docker.exeで疎通確認</h2>\n<p>コマンドプロンプト等で以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">set </span><span class=\"nv\">DOCKER_HOST</span><span class=\"o\">=</span>ssh://«ユーザ名»@«ホスト»\ndocker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<p>リモートホスト上のコンテナの状態が返ってくるか確認。</p>\n\n<h2 id=\"docker-hostの設定\">DOCKER HOSTの設定</h2>\n<p>VScodeの<code class=\"language-plaintext highlighter-rouge\">settings.json</code> に以下の一文を追加する。もちろん上で確認した内容で。</p>\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\">    </span><span class=\"nl\">\"docker.host\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"ssh://«ユーザ名»@«ホスト»\"</span><span class=\"err\">,</span><span class=\"w\">\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルにつなぎたいときはこの行をコメントアウト(<code class=\"language-plaintext highlighter-rouge\">//</code>をつける)すればOK。<br />\n<code class=\"language-plaintext highlighter-rouge\">setting.json</code>はJSONファイルだけど、 <code class=\"language-plaintext highlighter-rouge\">//</code>でコメントアウトできる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nVScode settings.json の開き方</p>\n  <ul>\n    <li>メニュー ファイル→ユーザ設定→ 設定</li>\n    <li>設定画面の右上のボタン「設定(JSON)を開く」をクリック</li>\n  </ul>\n\n  <p>または</p>\n  <ul>\n    <li>メニュー表示→コマンドパレット</li>\n    <li>Preference:  Open Settings(JSON) を選択</li>\n  </ul>\n</blockquote>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その1\">VScodeでリモート エクスプローラからリモートホストに接続(その1)</h2>\n<p>リモートホストに拡張機能 Docker と Docker Explorer をインストールしておき、\nDockerペインを開くとリモートホスト上のコンテナとかが見える</p>\n\n<p>ここでは既にリモートホスト上でコンテナ作成済みとする。<br />\n(イメージからコンテナ作ったりDockerfileからBuildしたりできると思うけど、今はおいとく)</p>\n\n<ul>\n  <li>接続するコンテナが起動していない場合はDockerペインで使用するコンテナを右クリック→Start でコンテナを起動</li>\n  <li>起動したら対象コンテナのアイコンが三角マークになる</li>\n  <li>同じくDockerペインで使用するコンテナを右クリック→Attach Visual Studio Code を選択</li>\n  <li>select the container to attach VS Code と聞かれるのでアタッチするコンテナを選択(コンテナ選択してAttachしたはずだけど、なぜかここで再度選択が必要)</li>\n  <li>初めて接続した場合は「Attaching to a container may execute arbitrary code」<br />\nと言われるので、変なコードが実行されないことが分かっていれば Got it をクリック</li>\n  <li>接続された。右下の「><」ボタンが「>< Conteiner «コンテナ名»」に変わっている。</li>\n</ul>\n\n<p>あとはリモート SSH や ローカルのDockerでのデバッグと同じ。</p>\n\n<h2 id=\"接続の終了\">接続の終了</h2>\n<p>接続を終了する場合は</p>\n<ul>\n  <li>メニュー表示→コマンドパレット</li>\n  <li>Remote:  Close Remote Connection を選択</li>\n</ul>\n\n<p>このとき、コンテナからだけでなく、リモートホストからも切断される。</p>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その2\">VScodeでリモート エクスプローラからリモートホストに接続(その2)</h2>\n<p>リモートエクスプローラ(Containers)で接続するコンテナを右クリックし、「Attach to Container」または「Attach in New Window」を選択<br />\n(コンテナが起動されていなければ起動して)コンテナに接続される。</p>\n\n<p>あんまりごちょごちょしなくて済むのでこっちの方がおススメかな。</p>\n\n<h1 id=\"ネットワークポート\">ネットワークポート</h1>\n<p>通常Cockerコンテナ内のネットワークポートをホストや外部コンピュータからアクセスするには、<br />\nコンテナ作成時に-p (–publish) オプションで接続を受け入れるポート番号を指定する必要があるが、<br />\nVScodeから接続している場合は、Docker内のネットワークポートにVScodeが実行されているマシンからlocalhost:«ポート番号»で接続できる。<br />\n(アクセス遅いけど、ちょっと別のポート開けて試したい なんて時には便利)</p>\n\n<p>ただし、これはDockerが動作しているホストコンピュータや他のコンピュータからはアクセスできない。<br />\nこれらからアクセスするには-pオプションを指定する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n<p><a href=\"https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0\">https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0</a><br />\n↑ここにある、「Remote-Containers: Open Folder in Container…」での手順はリモートホストに接続した状態では実行できないらしい。<br />\nどうしてもこのコンテナでデバッグしたい場合は、<br />\n一旦リモートホスト上でVSCodeを起動してコンテナを作成しておき、<br />\nその後ローカルPCからこのコンテナにアタッチするような手順をふめばデバッグできる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ubuntuにSSHサーバをセットアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ubuntuにSSHサーバをセットアップする</h1>\n      <p>ubuntuにSSHサーバをセットアップするし、公開鍵認証を設定する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuにsshサーバをセットアップする\">UbuntuにSSHサーバをセットアップする</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n\n<p>この状態でWindowsなどから以下のコマンドで接続するとパスワード認証でlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«ユーザ名»@«IPアドレス»<span class=\"s1\">'s password: «パスワードを入力»  \n</span></code></pre></div></div>\n\n<p>リモート接続でshellを使うだけならこれでも良いが、\nVScodeでリモートデバッグをしたりするときなどはパスワード入力を何回も行う必要があったりして面倒。<br />\nそこで、公開鍵認証を設定してパスワード入力を不要にする。</p>\n\n<h1 id=\"秘密鍵と公開鍵の生成と公開鍵ファイルの設置\">秘密鍵と公開鍵の生成と公開鍵ファイルの設置</h1>\n<p>Windowsマシンで以下のコマンドを実行して秘密鍵ファイルと公開鍵ファイルを生成する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh-keygen.exe <span class=\"nt\">-t</span> rsa\n<span class=\"o\">(</span>リターン3回<span class=\"o\">)</span>\n※ 本当はpassphase入れないといけないけど、ローカルお試し環境なので省略\n</code></pre></div></div>\n<p>実行すると以下のファイルが出来る</p>\n<ul>\n  <li>%USERPROFILE%/.ssh/id_rsa</li>\n  <li>%USERPROFILE%/.ssh/id_rsa.pub</li>\n</ul>\n\n<p>このうち、<code class=\"language-plaintext highlighter-rouge\">id_rsa.pub</code>をUbuntuマシンの <code class=\"language-plaintext highlighter-rouge\">~/.ssh</code>へ<code class=\"language-plaintext highlighter-rouge\">authorized_keys</code>というファイル名でコピー(既に存在する場合は追記)する。</p>\n<blockquote>\n  <p>[!NOTE]\nやり方検索すると<code class=\"language-plaintext highlighter-rouge\">scp</code>コマンドでコピーする方法が紹介されているが、\n家の中だけなのでネットワークドライブ経由でのコピーや\nファイル自体はテキストファイルなので、SSH接続したshellからエディタを起動して\nコピペするのでも良い。</p>\n</blockquote>\n\n<p>コピーが完了したらファイルのパーミッションを変更する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod </span>600 ~/.ssh/authorized_keys\n</code></pre></div></div>\n\n<h1 id=\"接続テスト\">接続テスト</h1>\n<p>この状態でWindowsマシンから以下のコマンドで接続するとパスワード認証なしでlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«パスワード入力なしで接続»\n</code></pre></div></div>\n\n<p>Windows側のユーザディレクトリ/.ssh/config の設定もやっておくと便利<br />\n参考: <a href=\"https://qiita.com/passol78/items/2ad123e39efeb1a5286b\">https://qiita.com/passol78/items/2ad123e39efeb1a5286b</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerコンテナからGUIを起動する</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerコンテナからGUIを起動する</h1>\n      <p>Windos/Ubuntu の DockerコンテナからGUIを起動する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuでローカルのデスクトップに表示する場合\">Ubuntuでローカルのデスクトップに表示する場合</h1>\n<p>Docker(ubuntu)のみ。<br />\nコンテナ生成時に以下のように<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数の設定と<code class=\"language-plaintext highlighter-rouge\">/tmp/.X11-unix/</code>のマウントを行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test3 <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n<p>この場合、表示する前にホスト側で以下を実行しておく必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>xhost +local:\n</code></pre></div></div>\n<p>実行していない場合、GUI起動コマンド実行で以下のエラーが出る。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>No protocol specified\nError: Can't open display: XXX\n</code></pre></div></div>\n\n<p>Ubuntuを再起動したときに設定は忘れられてしまうので、起動の度に実行必要。</p>\n\n<blockquote>\n  <p>[!NOTE]\nxhostはセキュリティ上問題があるとのことだが、家の中だけだし、localだけなら許可してもいいかな…\nrc.localあたりに書いとこうかと思ったけど、使用するときだけ実行するのが無難かな。</p>\n</blockquote>\n\n<h1 id=\"windows上のvcxsrvに表示する場合\">Windows上のVcXsrvに表示する場合</h1>\n<p>Docker(windows)だとコレ一択。<br />\nDocker(ubuntu)でも大丈夫。<br />\nなので、Docker(ubuntu)にリモート接続で使用することがある場合はこっちを使っておくのが良いと思う。<br />\nWindowsマシンのIPアドレスが192.168.XXX.XXX(マシン名指定不可)だとして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test4 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XXX.XXX:0.0 <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>VSCodeでDocker内のpythonプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>VSCodeでDocker内のpythonプログラムをデバッグする</h1>\n      <p>VSCodeでDocker内のpythonプログラムをデバッグする(Windos/Ubuntu)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからWindows上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nubuntu上のVSCodeからubuntu上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nどちらもほぼ同じ手順でデバッグできる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>VScodeに拡張機能Python、Docker、Remote Containers をインストールしておく</p>\n\n<h1 id=\"コンテナ起動\">コンテナ起動</h1>\n<p>ターミナルからコンテナ起動する<br />\nソースの編集をしやすいように、ホストのフォルダを<code class=\"language-plaintext highlighter-rouge\">/work</code>に割り当てている。<br />\nいや、VSCodeで編集すれば問題ないんだけどさ…<br />\nいつも編集は別のエディタ使ってたりするとコンテナ内のファイルいじるのが面倒なので…</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Windows\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> /m/work/zzz:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ubuntu\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> <span class=\"sb\">`</span><span class=\"nb\">realpath</span> .<span class=\"sb\">`</span>:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンテナを一度作成してあれば起動していなくても大丈夫らしい。</p>\n</blockquote>\n\n<h1 id=\"コンテナに接続\">コンテナに接続</h1>\n<p>VScodeのリモートエクスプローラにコンテナが見える</p>\n<blockquote>\n  <p>[!NOTE]\nRemote SSHやRemote WSLがインストールされている場合はリモートエクスプローラ上部のドロップダウンリストからContainersを選択</p>\n</blockquote>\n\n<p>対象のコンテナを右クリックして<code class=\"language-plaintext highlighter-rouge\">Attach to Container</code> または<code class=\"language-plaintext highlighter-rouge\">Attach in New Window</code>をクリック<br />\n<code class=\"language-plaintext highlighter-rouge\">Attaching to a container may execute arbitrary code</code><br />\nと言われるたら、変なコードが実行されないことが分かっていれば <code class=\"language-plaintext highlighter-rouge\">Got it</code> をクリック</p>\n<blockquote>\n  <p>[!NOTE]\n一度開いたフォルダはその下にショートカットが表示されているので、そこから開けば手っ取り早い。</p>\n</blockquote>\n\n<p>コンテナが開く</p>\n\n<p>コンテナ内には拡張機能が入ってないので、必要な拡張機能をインストールする</p>\n\n<h1 id=\"デバッグ\">デバッグ</h1>\n<p>エクスプローラでデバッグしたいフォルダを開いてソースを開く(VSCodeの設定によっては前回開いていたフォルダが開かれる)<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Python: Select Interpreter</code> で 使用するpythonを選択する。<br />\nこのとき、必ずしも使用するpythonのpathが表示されているとは限らないので、<br />\n(逆にコンテナ内にないホスト側のものが表示されたりする😢)<br />\n表示されていない場合は<code class=\"language-plaintext highlighter-rouge\">+ Enter Interpreter path...</code>から使用するpythonを選択する。<br />\n上記イメージの場合、<code class=\"language-plaintext highlighter-rouge\">/usr/local/bin/python3</code> なので、これを設定。</p>\n<blockquote>\n  <p>[!NOTE]\nあらかじめコンソールで which python3 して調べておく</p>\n</blockquote>\n\n<p>あとはローカルと同じようにデバッグできる。</p>\n\n<h1 id=\"コンテナとの接続終了\">コンテナとの接続終了</h1>\n\n<p>コンテナとの接続を終了するときは<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Remote: Close Remote Connection</code> で終了する。</p>\n\n<p>接続終了してもコンテナを停止しないので、別途停止処理を行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker stop py_test2\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>こういうのもある。<br />\n(参照しているのはmicrosoft純正のサンプルらしい)<br />\n普通にDocker使うのと異なるファイル<code class=\"language-plaintext highlighter-rouge\">devcontainer.json</code>を使うので、\n便利なんだか不便なんだか…<br />\nDocker拡張機能なくても動かせた気がする。<br />\n<a href=\"https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html\">https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Dockerをインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Dockerをインストールする</h1>\n      <p>Windos/Ubuntu に Dockerをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows10-home-に-dockerをインストールする\">Windows10 Home に Dockerをインストールする</h1>\n<p>HomeだとWSL2必須なので、WSL2はあらかじめインストールして使用できるようにしておく。<br />\n<a href=\"/memoBlog/2021/03/03/WSL_memo.html\" target=\"_blank\">WSL2 メモ</a></p>\n\n<p><a href=\"https://docs.docker.jp/docker-for-windows/install-windows-home.html\" target=\"_blank\">https://docs.docker.jp/docker-for-windows/install-windows-home.html</a> を参考にインストールする。 <br />\nとはいっても、<a href=\"https://hub.docker.com/editions/community/docker-ce-desktop-windows/\" target=\"_blank\">https://hub.docker.com/editions/community/docker-ce-desktop-windows/</a>からダウンロードして実行するだけ。</p>\n\n<p>コンテナを一杯作るとデータ領域がどんどん肥大していくので、Cドライブから変更しておいた方が良いかも。<br />\n<a href=\"https://nosubject.io/windowsdocker-desktop-move-disk-image/\" target=\"_blank\">Docker Desktop の ディスク領域 を Cドライブから別のドライブへ移動する方法</a><br />\nを参考に作業すればOK。<br />\nVHDをエクスポート、元の仮想マシンのレジストリを削除、他の場所へ同名でインポート、とやってる。</p>\n\n<h1 id=\"ubuntu-に-dockerをインストールする\">Ubuntu に Dockerをインストールする</h1>\n<p><a href=\"https://docs.docker.jp/linux/step_one.html\" target=\"_blank\">https://docs.docker.jp/linux/step_one.html</a> を参考にインストールする。 <br />\n実際は以下を実行するだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>curl <span class=\"nt\">-fsSL</span> https://get.docker.com/ | sh\n</code></pre></div></div>\n\n<p>docker実行に逐一<code class=\"language-plaintext highlighter-rouge\">sudo</code>をつけるのは面倒なので、以下の設定をしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> docker\n</code></pre></div></div>\n<p>設定後は念のためリブートしておく(logoutだけで可らしいけど)。</p>\n\n<h1 id=\"インストール後のお試し実行\">インストール後のお試し実行</h1>\n<p>正常に動いていることを確認するためになんか動かしてみる。<br />\n以下はWindows版で書かれているが、基本的にUbuntuでも同じ。<br />\n<a href=\"https://qiita.com/nanaki11/items/97e5685ed84547526be2\" target=\"_blank\">https://qiita.com/nanaki11/items/97e5685ed84547526be2</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">docker pull</code>はしなくても<code class=\"language-plaintext highlighter-rouge\">docker run</code>したときにローカルにimegeがなければ自動でダウンロードしてくれるらしい。</p>\n\n<h1 id=\"コマンド例\">コマンド例</h1>\n<p>ちょろっと試したコマンド群</p>\n<h2 id=\"コンテナの生成\">コンテナの生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの起動\">コンテナの起動</h2>\n<p>終了したコンテナの再開も同じ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> py_test\n</code></pre></div></div>\n\n<h2 id=\"コンテナに新たなコンソール接続\">コンテナに新たなコンソール接続</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> py_test /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの生成と起動を同時に行う\">コンテナの生成と起動を同時に行う</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">create</code>を<code class=\"language-plaintext highlighter-rouge\">run</code>に変えるだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"nwork-を-work-にマウントする場合windows\">n:\\work を /work にマウントする場合(Windows)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /n/work:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"カレントディレクトリを-work-にマウントする場合ubuntu\">カレントディレクトリを /work にマウントする場合(ubuntu)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナ一覧起動中のもののみ\">コンテナ一覧(起動中のもののみ)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<h2 id=\"コンテナ一覧終了したものを含む\">コンテナ一覧(終了したものを含む)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n\n<h2 id=\"pull済みイメージ一覧\">pull済みイメージ一覧</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<h2 id=\"コンテナの情報を確認する\">コンテナの情報を確認する</h2>\n<p>下記コマンドでJSONデータが出力される。<br />\n直近で興味ありそうなのは<code class=\"language-plaintext highlighter-rouge\">HostConfig</code>、<code class=\"language-plaintext highlighter-rouge\">Mounts</code>、<code class=\"language-plaintext highlighter-rouge\">NetworkSettings</code>あたりかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker inspect py_test2\n</code></pre></div></div>\n\n<h1 id=\"どんなイメージがあるのか\">どんなイメージがあるのか?</h1>\n<p><a href=\"https://hub.docker.com/search?type=image\" target=\"_blank\">dockerhub</a>でサーチしてちょ。</p>\n\n<h1 id=\"dockerはwsl2でどんな感じで動いているのか\">DockerはWSL2でどんな感じで動いているのか?</h1>\n<p>あんまり意味ないけど。<br />\n<a href=\"https://www.docker.com/blog/new-docker-desktop-wsl2-backend/\" target=\"_blank\">https://www.docker.com/blog/new-docker-desktop-wsl2-backend/</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>UbuntuをNative環境にインストールする(20.04)</title>\n  </head>\n  <body>\n    <header>\n      <h1>UbuntuをNative環境にインストールする(20.04)</h1>\n      <p>Ubunt(20.04)をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"インストール\">インストール</h1>\n<p>最初の起動まではこちらに詳しく書かれています。<br />\n<a href=\"https://qiita.com/koba-jon/items/019a3b4eac4f60ca89c9\" target=\"_blank\">Ubuntu 20.04 LTS インストール方法(外付けドライブ用)</a></p>\n\n<blockquote>\n  <p>[!WARNING]\nEFIシステムパーティションを作成するのを忘れがち。<br />\n外付けだと作成忘れると内蔵HDDのEFIシステムパーティションに追記されちゃうので注意。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\nユーザ名に英数字以外を含むとChrome remote desktop の インストール&設定でエラーになることがあるので、<br />\n英数字以外を含まないユーザ名を設定することをおススメします。</p>\n</blockquote>\n\n<h1 id=\"その後の設定手順\">その後の設定手順</h1>\n\n<h2 id=\"最新版にアップデート\">最新版にアップデート</h2>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h2 id=\"ipアドレス確認したいとき\">IPアドレス確認したいとき</h2>\n<p>SSHのクライアントからの接続先が分からないと困るので、\nIPアドレスを確認するためにnet-toolsをインストールして\nifconfigで確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\nifconfig\n</code></pre></div></div>\n\n<h2 id=\"sshのインストール\">sshのインストール</h2>\n<p>WindowsPCにあるデータをubuntuPCにキーボードで打ち込むのは効率が悪いので、最も簡単なsshでリモートログインできるようにしてみる。</p>\n\n<p>以下のコマンドでsshサーバをインストールし、サーバを開始する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n\n<p>クライアントからTeraTermなどでsshで対象マシンのポート22に接続する</p>\n\n<h2 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面ロック を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h2 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h2>\n\n<p>とりあえず入れとこう</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\n</code></pre></div></div>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが…</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h3 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>NFSサーバの再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.XX.XX:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"bashの設定変更\">bashの設定変更</h2>\n\n<p>~/.bashrcに以下を追記</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h2 id=\"guiの動作の設定変更をお好みで\">GUIの動作の設定変更をお好みで</h2>\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.mutter auto-maximize\ngsettings get org.gnome.mutter edge-tiling\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.desktop.wm.preferences auto-raise \ngsettings get org.gnome.desktop.wm.preferences focus-mode \ngsettings get org.gnome.desktop.wm.preferences raise-on-click\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.shell.extensions.desktop-icons show-home\ngsettings get org.gnome.shell.extensions.desktop-icons show-trash\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。<br />\ndconf-editorでも良いよ(しつこい…)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 ==================================</span>\n<span class=\"c\"># Dockバー上のゴミ箱表示有無</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock show-trash\n\n<span class=\"c\"># アプリケーションのDockバー上の表示位置</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock show-apps-at-top\n\n<span class=\"c\"># Dockバー表示位置</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock dock-position\n\n<span class=\"c\"># Dockバー上のアイコンサイズ</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock dash-max-icon-size\n\n<span class=\"c\"># 設定 ==================================</span>\n<span class=\"c\"># Dockバー上のゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># Dockバー上のアイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.interface cursor-size\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"capsキーをctrlキーに変更\">CAPSキーをCtrlキーに変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.input-sources xkb-options\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.input-sources xkb-options <span class=\"se\">\\[\\'</span>ctrl:nocaps<span class=\"se\">\\'\\]</span>\n\n<span class=\"c\"># 設定を有効にするにはGUIでのlogout&再loginが必要</span>\n\n</code></pre></div></div>\n\n<h2 id=\"日本語入力\">日本語入力</h2>\n<p>前は設定必要だったけど、なんか大丈夫になったみたい</p>\n<blockquote>\n  <p>[!NOTE]\n以前の設定手順<br />\n右上の「A」または「あ」と書かれたアイコンをクリック→「テキスト入力設定」を選択\n一番下の「インストールされている言語の管理」をクリック\n「言語サポートが完全にはインストールされていません」と出るので「インストール」をクリック\n一旦log offして再log in\n右上のJaまたはMoと書かれたアイコンをクリック\n    Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)\nキーボードの全角/半角キーで切り替えられるようになる</p>\n</blockquote>\n\n<h2 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h2>\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nUbuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>IPv6が動いてるとうまく行かない環境のときは無効化しておく。<br />\n参考:<a href=\"https://www.server-memo.net/ubuntu/ubuntu_disable_ipv6.html#IPv6-4\" target=\"_blank\">UbuntuでIPv6を無効化する方法</a></p>\n\n<p>sysctlで設定するのがお手軽かな?</p>\n\n<h2 id=\"システムバックアップ\">システムバックアップ</h2>\n<p>Nativeならバックアップしといた方がいいかな。<br />\n参考:<a href=\"https://gihyo.jp/admin/serial/01/ubuntu-recipe/0588\">第588回 TimeShiftでUbuntuをホットバックアップする 2019年版</a> <br />\n<code class=\"language-plaintext highlighter-rouge\">add-apt-repository</code> でリポジトリを追加しなくても大丈夫。標準リポジトリにも入ってるから。</p>\n\n<h2 id=\"chrome-remote-desktopインストール\">chrome remote desktopインストール</h2>\n\n<p>remote desktop使いたいので、インストールする。</p>\n\n<h3 id=\"chromeのインストール\">chromeのインストール</h3>\n<p><a href=\"https://www.google.com/chrome/\">Google Chrome - Google の高速で安全なブラウザをダウンロード</a>からダウンロードしてインストール。</p>\n\n<h3 id=\"おまじない\">おまじない</h3>\n<p>remote desktopのインストール時にエラーが発生するので、以下のディレクトリを作成しておく。<br />\n(インストーラのバグらしい)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/.config/chrome-remote-desktop\n</code></pre></div></div>\n\n<h3 id=\"remote-desktopのインストール\">remote desktopのインストール</h3>\n<p>以下参考ページ</p>\n<ul>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>パソコンでリモート アクセスを設定する</li>\n      <li>パソコンにリモート アクセスする</li>\n    </ul>\n  </li>\n</ul>\n\n<p>接続すると、開始するセッションの選択画面になるので、「Ubuntu」を選択。</p>\n\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。<br />\nこのダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></li>\n</ul>\n\n<p>要約すると\n<code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下の内容で作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Keras on tensorflow2 で SSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>Keras on tensorflow2 で SSD</h1>\n      <p>Tensorflow2上のKerasでSSDを実行を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>※ 2021.05.21 kerasをtensorflow.kerasに変更</p>\n\n<h1 id=\"概要\">概要</h1>\n\n<p>Kerasを使ってSSDを実行してみようと思ったら、Tensorflow1.x上の情報ばかり出てきて、Tensorflow2で実行するのに手間取ったのでメモ。<br />\n(最終的にopenVINOに持っていきたいなぁ、と思って試し始めたんだけど、openVINOにサクッと変換できるのはcaffeだった😅)<br />\nということで、やったけど 続きはないかも。実行遅いし…😩💨</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p><a href=\"https://smilerobo.com/papero/tips_keras_tf_ssd/\" target=\"_blank\">【実験】学習済のSSDを使ってPaPeRo i に複数種類の物体を数えさせる</a>\nを参考に、KerasをTensorflow2で動かしてみる。</p>\n\n<p>Pythonは3.8を使用した(念のため明記しておく)。</p>\n\n<p>Anaconda使ってないし、Paperoじゃないので、そのまんまじゃないけど、<br />\nとりあえずSSDを動かしてみよう。</p>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n\n<p>まずは、python仮想環境の準備をする。<br />\npyenv環境前提。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースディレクトリとpython仮想環境の準備</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/keras2/\n<span class=\"nb\">cd</span> /work/keras2/\npyenv virtualenv 3.8.8 keras2\npyenv <span class=\"nb\">local </span>keras2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># pythonモジュールのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n<span class=\"c\"># kerasはtensorflow内を直接参照にしたので不要  </span>\n<span class=\"c\"># pip install keras</span>\npip <span class=\"nb\">install </span>matplotlib\npip <span class=\"nb\">install </span>imageio\n</code></pre></div></div>\n\n<p>インストールされているpythonモジュールは以下の通り</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.2\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.4.0\ngoogle-auth==1.30.0\ngoogle-auth-oauthlib==0.4.4\ngoogle-pasta==0.2.0\ngrpcio==1.34.1\nh5py==3.1.0\nidna==2.10\nimageio==2.9.0\nkeras-nightly==2.5.0.dev2021032900\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.4.2\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.2.52\nopt-einsum==3.3.0\nPillow==8.2.0\nprotobuf==3.17.0\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nsix==1.15.0\ntensorboard==2.5.0\ntensorboard-data-server==0.6.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.5.0\ntensorflow-estimator==2.5.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==2.0.1\nwrapt==1.12.1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nKeras修正以前の状態は以下</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.1\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.3.3\ngoogle-auth==1.28.0\ngoogle-auth-oauthlib==0.4.3\ngoogle-pasta==0.2.0\ngrpcio==1.32.0\nh5py==2.10.0\nidna==2.10\nimageio==2.9.0\nKeras==2.4.3\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.3.4\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.1.48\nopt-einsum==3.3.0\nPillow==8.1.2\nprotobuf==3.15.6\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nPyYAML==5.4.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nscipy==1.6.1\nsix==1.15.0\ntensorboard==2.4.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.4.1\ntensorflow-estimator==2.4.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==1.0.1\nwrapt==1.12.1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"patchファイルの準備\">patchファイルの準備</h2>\n\n<p>参照先には色々手順が書いてあるが、めんどくさいので パッチファイル用意した(足りない修正もあるし)。<br />\n以下の内容を<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code> <code class=\"language-plaintext highlighter-rouge\">ssd_keras_2.patch</code>のファイル名で保存しておく。</p>\n\n<h3 id=\"ssd_keraspatch\">ssd_keras.patch</h3>\n\n<p>参照先の情報によるpatch</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/ssd.py b/ssd.py\nindex c0049d8..656cd83 100644\n</span><span class=\"gd\">--- a/ssd.py\n</span><span class=\"gi\">+++ b/ssd.py\n</span><span class=\"p\">@@ -2,14 +2,15 @@</span>\n \n import keras.backend as K\n from keras.layers import Activation\n<span class=\"gd\">-from keras.layers import AtrousConvolution2D\n</span><span class=\"gi\">+#from keras.layers import AtrousConvolution2D\n</span> from keras.layers import Convolution2D\n from keras.layers import Dense\n from keras.layers import Flatten\n from keras.layers import GlobalAveragePooling2D\n from keras.layers import Input\n from keras.layers import MaxPooling2D\n<span class=\"gd\">-from keras.layers import merge\n</span><span class=\"gi\">+#from keras.layers import merge\n+from keras.layers.merge import concatenate\n</span> from keras.layers import Reshape\n from keras.layers import ZeroPadding2D\n from keras.models import Model\n<span class=\"p\">@@ -34,109 +35,115 @@</span> def SSD300(input_shape, num_classes=21):\n     input_tensor = input_tensor = Input(shape=input_shape)\n     img_size = (input_shape[1], input_shape[0])\n     net['input'] = input_tensor\n<span class=\"gd\">-    net['conv1_1'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    net['conv1_1'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_1')(net['input'])\n<span class=\"gd\">-    net['conv1_2'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    \n+    net['conv1_2'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_2')(net['conv1_1'])\n<span class=\"gd\">-    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+\n+    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool1')(net['conv1_2'])\n     # Block 2\n<span class=\"gd\">-    net['conv2_1'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+    net['conv2_1'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_1')(net['pool1'])\n<span class=\"gd\">-    net['conv2_2'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+\n+    net['conv2_2'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_2')(net['conv2_1'])\n<span class=\"gd\">-    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool2')(net['conv2_2'])\n<span class=\"gi\">+\n</span>     # Block 3\n<span class=\"gd\">-    net['conv3_1'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_1'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_1')(net['pool2'])\n<span class=\"gd\">-    net['conv3_2'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_2'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_2')(net['conv3_1'])\n<span class=\"gd\">-    net['conv3_3'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_3'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_3')(net['conv3_2'])\n<span class=\"gd\">-    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool3')(net['conv3_3'])\n     # Block 4\n<span class=\"gd\">-    net['conv4_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_1')(net['pool3'])\n<span class=\"gd\">-    net['conv4_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_2')(net['conv4_1'])\n<span class=\"gd\">-    net['conv4_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_3')(net['conv4_2'])\n<span class=\"gd\">-    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool4')(net['conv4_3'])\n<span class=\"gd\">-    # Block 5\n-    net['conv5_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+# Block 5\n+    net['conv5_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_1')(net['pool4'])\n<span class=\"gd\">-    net['conv5_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_2')(net['conv5_1'])\n<span class=\"gd\">-    net['conv5_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_3')(net['conv5_2'])\n<span class=\"gd\">-    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), border_mode='same',\n</span><span class=\"gi\">+    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), padding='same',\n</span>                                 name='pool5')(net['conv5_3'])\n     # FC6\n<span class=\"gd\">-    net['fc6'] = AtrousConvolution2D(1024, 3, 3, atrous_rate=(6, 6),\n-                                     activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['fc6'] = Convolution2D(1024, (3, 3), dilation_rate=(6, 6),\n+                                     activation='relu', padding='same',\n</span>                                      name='fc6')(net['pool5'])\n     # x = Dropout(0.5, name='drop6')(x)\n     # FC7\n<span class=\"gd\">-    net['fc7'] = Convolution2D(1024, 1, 1, activation='relu',\n-                               border_mode='same', name='fc7')(net['fc6'])\n</span><span class=\"gi\">+    net['fc7'] = Convolution2D(1024, (1, 1), activation='relu',\n+                               padding='same', name='fc7')(net['fc6'])\n</span>     # x = Dropout(0.5, name='drop7')(x)\n     # Block 6\n<span class=\"gd\">-    net['conv6_1'] = Convolution2D(256, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv6_1'] = Convolution2D(256, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv6_1')(net['fc7'])\n<span class=\"gd\">-    net['conv6_2'] = Convolution2D(512, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+\n+\n+    net['conv6_2'] = Convolution2D(512, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv6_2')(net['conv6_1'])\n<span class=\"gd\">-    # Block 7\n-    net['conv7_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+        # Block 7\n+    net['conv7_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv7_1')(net['conv6_2'])\n     net['conv7_2'] = ZeroPadding2D()(net['conv7_1'])\n<span class=\"gd\">-    net['conv7_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='valid',\n</span><span class=\"gi\">+    net['conv7_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='valid',\n</span>                                    name='conv7_2')(net['conv7_2'])\n     # Block 8\n<span class=\"gd\">-    net['conv8_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv8_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv8_1')(net['conv7_2'])\n<span class=\"gd\">-    net['conv8_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['conv8_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv8_2')(net['conv8_1'])\n     # Last Pool\n     net['pool6'] = GlobalAveragePooling2D(name='pool6')(net['conv8_2'])\n     # Prediction from conv4_3\n     net['conv4_3_norm'] = Normalize(20, name='conv4_3_norm')(net['conv4_3'])\n     num_priors = 3\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv4_3_norm_mbox_loc')(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_loc'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_loc_flat')\n<span class=\"p\">@@ -144,7 +151,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv4_3_norm_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_conf'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_conf_flat')\n<span class=\"p\">@@ -155,16 +162,16 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv4_3_norm_mbox_priorbox'] = priorbox(net['conv4_3_norm'])\n     # Prediction from fc7\n     num_priors = 6\n<span class=\"gd\">-    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, 3, 3,\n-                                        border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, (3, 3),\n+                                        padding='same',\n</span>                                         name='fc7_mbox_loc')(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_loc_flat')\n     net['fc7_mbox_loc_flat'] = flatten(net['fc7_mbox_loc'])\n     name = 'fc7_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, 3, 3,\n-                                         border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, (3, 3),\n+                                         padding='same',\n</span>                                          name=name)(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_conf_flat')\n     net['fc7_mbox_conf_flat'] = flatten(net['fc7_mbox_conf'])\n<span class=\"p\">@@ -174,7 +181,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['fc7_mbox_priorbox'] = priorbox(net['fc7'])\n     # Prediction from conv6_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv6_2_mbox_loc')(net['conv6_2'])\n     net['conv6_2_mbox_loc'] = x\n     flatten = Flatten(name='conv6_2_mbox_loc_flat')\n<span class=\"p\">@@ -182,7 +189,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv6_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv6_2'])\n     net['conv6_2_mbox_conf'] = x\n     flatten = Flatten(name='conv6_2_mbox_conf_flat')\n<span class=\"p\">@@ -193,7 +200,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv6_2_mbox_priorbox'] = priorbox(net['conv6_2'])\n     # Prediction from conv7_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv7_2_mbox_loc')(net['conv7_2'])\n     net['conv7_2_mbox_loc'] = x\n     flatten = Flatten(name='conv7_2_mbox_loc_flat')\n<span class=\"p\">@@ -201,7 +208,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv7_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv7_2'])\n     net['conv7_2_mbox_conf'] = x\n     flatten = Flatten(name='conv7_2_mbox_conf_flat')\n<span class=\"p\">@@ -212,7 +219,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv7_2_mbox_priorbox'] = priorbox(net['conv7_2'])\n     # Prediction from conv8_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv8_2_mbox_loc')(net['conv8_2'])\n     net['conv8_2_mbox_loc'] = x\n     flatten = Flatten(name='conv8_2_mbox_loc_flat')\n<span class=\"p\">@@ -220,7 +227,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv8_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv8_2'])\n     net['conv8_2_mbox_conf'] = x\n     flatten = Flatten(name='conv8_2_mbox_conf_flat')\n<span class=\"p\">@@ -241,7 +248,7 @@</span> def SSD300(input_shape, num_classes=21):\n     priorbox = PriorBox(img_size, 276.0, max_size=330.0, aspect_ratios=[2, 3],\n                         variances=[0.1, 0.1, 0.2, 0.2],\n                         name='pool6_mbox_priorbox')\n<span class=\"gd\">-    if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+    if K.image_data_format() == 'channels_last':\n</span>         target_shape = (1, 1, 256)\n     else:\n         target_shape = (256, 1, 1)\n<span class=\"p\">@@ -249,42 +256,47 @@</span> def SSD300(input_shape, num_classes=21):\n                                     name='pool6_reshaped')(net['pool6'])\n     net['pool6_mbox_priorbox'] = priorbox(net['pool6_reshaped'])\n     # Gather all predictions\n<span class=\"gd\">-    net['mbox_loc'] = merge([net['conv4_3_norm_mbox_loc_flat'],\n</span><span class=\"gi\">+    net['mbox_loc'] = concatenate([net['conv4_3_norm_mbox_loc_flat'],\n</span>                              net['fc7_mbox_loc_flat'],\n                              net['conv6_2_mbox_loc_flat'],\n                              net['conv7_2_mbox_loc_flat'],\n                              net['conv8_2_mbox_loc_flat'],\n                              net['pool6_mbox_loc_flat']],\n<span class=\"gd\">-                            mode='concat', concat_axis=1, name='mbox_loc')\n-    net['mbox_conf'] = merge([net['conv4_3_norm_mbox_conf_flat'],\n</span><span class=\"gi\">+                            axis=1,\n+                                  name='mbox_loc')\n+    net['mbox_conf'] = concatenate([net['conv4_3_norm_mbox_conf_flat'],\n</span>                               net['fc7_mbox_conf_flat'],\n                               net['conv6_2_mbox_conf_flat'],\n                               net['conv7_2_mbox_conf_flat'],\n                               net['conv8_2_mbox_conf_flat'],\n                               net['pool6_mbox_conf_flat']],\n<span class=\"gd\">-                             mode='concat', concat_axis=1, name='mbox_conf')\n-    net['mbox_priorbox'] = merge([net['conv4_3_norm_mbox_priorbox'],\n</span><span class=\"gi\">+                              axis=1,\n+                              name='mbox_conf')\n+    net['mbox_priorbox'] = concatenate([net['conv4_3_norm_mbox_priorbox'],\n</span>                                   net['fc7_mbox_priorbox'],\n                                   net['conv6_2_mbox_priorbox'],\n                                   net['conv7_2_mbox_priorbox'],\n                                   net['conv8_2_mbox_priorbox'],\n                                   net['pool6_mbox_priorbox']],\n<span class=\"gd\">-                                 mode='concat', concat_axis=1,\n</span><span class=\"gi\">+                                 axis=1,\n</span>                                  name='mbox_priorbox')\n     if hasattr(net['mbox_loc'], '_keras_shape'):\n         num_boxes = net['mbox_loc']._keras_shape[-1] // 4\n     elif hasattr(net['mbox_loc'], 'int_shape'):\n<span class=\"gd\">-        num_boxes = K.int_shape(net['mbox_loc'])[-1] // 4\n</span><span class=\"gi\">+        num_boxes = net['mbox_loc'].int_shape()[-1] // 4\n+    elif hasattr(net['mbox_loc'], 'get_shape'):\n+        num_boxes = net['mbox_loc'].get_shape()[-1] // 4\n</span>     net['mbox_loc'] = Reshape((num_boxes, 4),\n                               name='mbox_loc_final')(net['mbox_loc'])\n     net['mbox_conf'] = Reshape((num_boxes, num_classes),\n                                name='mbox_conf_logits')(net['mbox_conf'])\n     net['mbox_conf'] = Activation('softmax',\n                                   name='mbox_conf_final')(net['mbox_conf'])\n<span class=\"gd\">-    net['predictions'] = merge([net['mbox_loc'],\n</span><span class=\"gi\">+    net['predictions'] = concatenate([net['mbox_loc'],\n</span>                                net['mbox_conf'],\n                                net['mbox_priorbox']],\n<span class=\"gd\">-                               mode='concat', concat_axis=2,\n</span><span class=\"gi\">+                               axis=2,\n+                               #axis = 0,\n</span>                                name='predictions')\n     model = Model(net['input'], net['predictions'])\n     return model\n<span class=\"gh\">diff --git a/ssd_layers.py b/ssd_layers.py\nindex 5e10478..41ee510 100644\n</span><span class=\"gd\">--- a/ssd_layers.py\n</span><span class=\"gi\">+++ b/ssd_layers.py\n</span><span class=\"p\">@@ -29,7 +29,8 @@</span> class Normalize(Layer):\n         Add possibility to have one scale for all features.\n     \"\"\"\n     def __init__(self, scale, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n+\n</span>             self.axis = 3\n         else:\n             self.axis = 1\n<span class=\"p\">@@ -41,7 +42,7 @@</span> class Normalize(Layer):\n         shape = (input_shape[self.axis],)\n         init_gamma = self.scale * np.ones(shape)\n         self.gamma = K.variable(init_gamma, name='{}_gamma'.format(self.name))\n<span class=\"gd\">-        self.trainable_weights = [self.gamma]\n</span><span class=\"gi\">+        self._trainable_weights = [self.gamma]\n</span> \n     def call(self, x, mask=None):\n         output = K.l2_normalize(x, self.axis)\n<span class=\"p\">@@ -81,7 +82,7 @@</span> class PriorBox(Layer):\n     \"\"\"\n     def __init__(self, img_size, min_size, max_size=None, aspect_ratios=None,\n                  flip=True, variances=[0.1], clip=True, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n</span>             self.waxis = 2\n             self.haxis = 1\n         else:\n<span class=\"p\">@@ -108,7 +109,7 @@</span> class PriorBox(Layer):\n         self.clip = True\n         super(PriorBox, self).__init__(**kwargs)\n \n<span class=\"gd\">-    def get_output_shape_for(self, input_shape):\n</span><span class=\"gi\">+    def compute_output_shape(self, input_shape):\n</span>         num_priors_ = len(self.aspect_ratios)\n         layer_width = input_shape[self.waxis]\n         layer_height = input_shape[self.haxis]\n<span class=\"gh\">diff --git a/ssd_utils.py b/ssd_utils.py\nindex 0a9ffb1..4fc7a49 100644\n</span><span class=\"gd\">--- a/ssd_utils.py\n</span><span class=\"gi\">+++ b/ssd_utils.py\n</span><span class=\"p\">@@ -1,7 +1,8 @@</span>\n \"\"\"Some utils for SSD.\"\"\"\n \n import numpy as np\n<span class=\"gd\">-import tensorflow as tf\n</span><span class=\"gi\">+import tensorflow.compat.v1 as tf\n+tf.disable_v2_behavior()\n</span> \n \n class BBoxUtility(object):\n<span class=\"gh\">diff --git a/testing_utils/videotest.py b/testing_utils/videotest.py\nindex 0cbae3c..7b2ff4f 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest.py\n</span><span class=\"p\">@@ -3,13 +3,14 @@</span>\n import cv2\n import keras\n from keras.applications.imagenet_utils import preprocess_input\n<span class=\"gd\">-from keras.backend.tensorflow_backend import set_session\n</span><span class=\"gi\">+# from keras.backend.tensorflow_backend import set_session\n</span> from keras.models import Model\n from keras.preprocessing import image \n import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-from scipy.misc import imread, imresize\n</span><span class=\"gi\">+# from scipy.misc import imread, imresize\n+from imageio import imread\n</span> from timeit import default_timer as timer\n \n import sys\n<span class=\"p\">@@ -84,8 +85,8 @@</span> class VideoTest(object):\n             \"trying to open a webcam, make sure you video_path is an integer!\"))\n         \n         # Compute aspect ratio of video     \n<span class=\"gd\">-        vidw = vid.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)\n-        vidh = vid.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)\n</span><span class=\"gi\">+        vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)\n+        vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)\n</span>         vidar = vidw/vidh\n         \n         # Skip frames until reaching start_frame\n<span class=\"gh\">diff --git a/testing_utils/videotest_example.py b/testing_utils/videotest_example.py\nindex fb4d873..27ec148 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest_example.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest_example.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import os\n+# GPU不使用を設定\n+os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n+\n</span> import keras\n import pickle\n from videotest import VideoTest\n<span class=\"p\">@@ -9,16 +13,38 @@</span> from ssd import SSD300 as SSD\n input_shape = (300,300,3)\n \n # Change this if you run with other classes than VOC\n<span class=\"gd\">-class_names = [\"background\", \"aeroplane\", \"bicycle\", \"bird\", \"boat\", \"bottle\", \"bus\", \"car\", \"cat\", \"chair\", \"cow\", \"diningtable\", \"dog\", \"horse\", \"motorbike\", \"person\", \"pottedplant\", \"sheep\", \"sofa\", \"train\", \"tvmonitor\"];\n</span><span class=\"gi\">+class_names = [ \n+                \"background\", \n+                \"aeroplane\", \n+                \"bicycle\", \n+                \"bird\", \n+                \"boat\", \n+                \"bottle\", \n+                \"bus\", \n+                \"car\", \n+                \"cat\", \n+                \"chair\", \n+                \"cow\", \n+                \"diningtable\", \n+                \"dog\", \n+                \"horse\", \n+                \"motorbike\", \n+                \"person\", \n+                \"pottedplant\", \n+                \"sheep\", \n+                \"sofa\", \n+                \"train\", \n+                \"tvmonitor\"\n+            ];\n</span> NUM_CLASSES = len(class_names)\n \n model = SSD(input_shape, num_classes=NUM_CLASSES)\n \n # Change this path if you want to use your own trained weights\n<span class=\"gd\">-model.load_weights('../weights_SSD300.hdf5') \n</span><span class=\"gi\">+model.load_weights('../../weights_SSD300.hdf5') \n</span>         \n vid_test = VideoTest(class_names, model, input_shape)\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('path/to/your/video.mkv')\n</span><span class=\"gi\">+vid_test.run('../../testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h3 id=\"ssd_keras_2patch\">ssd_keras_2.patch</h3>\n\n<p>keras修正対応</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras_2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd.py ssd_keras.tmp/ssd.py\n</span><span class=\"gd\">--- ssd_keras/ssd.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd.py\t2021-05-21 07:06:44.970000000 +0900\n</span><span class=\"p\">@@ -1,19 +1,17 @@</span>\n \"\"\"Keras implementation of SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.layers import Activation\n-#from keras.layers import AtrousConvolution2D\n-from keras.layers import Convolution2D\n-from keras.layers import Dense\n-from keras.layers import Flatten\n-from keras.layers import GlobalAveragePooling2D\n-from keras.layers import Input\n-from keras.layers import MaxPooling2D\n-#from keras.layers import merge\n-from keras.layers.merge import concatenate\n-from keras.layers import Reshape\n-from keras.layers import ZeroPadding2D\n-from keras.models import Model\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.keras.layers import Activation\n+from tensorflow.keras.layers import Convolution2D\n+from tensorflow.keras.layers import Dense\n+from tensorflow.keras.layers import Flatten\n+from tensorflow.keras.layers import GlobalAveragePooling2D\n+from tensorflow.keras.layers import Input\n+from tensorflow.keras.layers import MaxPooling2D\n+from tensorflow.keras.layers import concatenate\n+from tensorflow.keras.layers import Reshape\n+from tensorflow.keras.layers import ZeroPadding2D\n+from tensorflow.keras.models import Model\n</span> \n from ssd_layers import Normalize\n from ssd_layers import PriorBox\n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd_layers.py ssd_keras.tmp/ssd_layers.py\n</span><span class=\"gd\">--- ssd_keras/ssd_layers.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd_layers.py\t2021-05-21 06:31:11.780000000 +0900\n</span><span class=\"p\">@@ -1,8 +1,8 @@</span>\n \"\"\"Some special pupropse layers for SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.engine.topology import InputSpec\n-from keras.engine.topology import Layer\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.python.keras.engine.input_spec import InputSpec\n+from tensorflow.python.keras.engine.base_layer import Layer\n</span> import numpy as np\n import tensorflow as tf\n \n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest.py ssd_keras.tmp/testing_utils/videotest.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest.py\t2021-05-21 07:08:24.680000000 +0900\n</span><span class=\"p\">@@ -1,15 +1,13 @@</span>\n \"\"\" A class for testing a SSD model on a video file or webcam \"\"\"\n \n import cv2\n<span class=\"gd\">-import keras\n-from keras.applications.imagenet_utils import preprocess_input\n-# from keras.backend.tensorflow_backend import set_session\n-from keras.models import Model\n-from keras.preprocessing import image \n</span><span class=\"gi\">+import tensorflow.keras as keras\n+from tensorflow.keras.applications.imagenet_utils import preprocess_input\n+from tensorflow.keras.models import Model\n+from tensorflow.keras.preprocessing import image \n</span> import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-# from scipy.misc import imread, imresize\n</span> from imageio import imread\n from timeit import default_timer as timer\n \n<span class=\"p\">@@ -179,6 +177,7 @@</span>\n             cv2.putText(to_draw, fps, (3,10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0,0,0), 1)\n             \n             cv2.imshow(\"SSD result\", to_draw)\n<span class=\"gd\">-            cv2.waitKey(10)\n-            \n-        \n</span><span class=\"gi\">+            key = cv2.waitKey(1)\n+            if key == 27:\n+                # ESCキー\n+                break\n</span><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest_example.py ssd_keras.tmp/testing_utils/videotest_example.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest_example.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest_example.py\t2021-05-21 07:04:24.320000000 +0900\n</span><span class=\"p\">@@ -2,7 +2,7 @@</span>\n # GPU不使用を設定\n os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n \n<span class=\"gd\">-import keras\n</span><span class=\"gi\">+import tensorflow.keras as keras\n</span> import pickle\n from videotest import VideoTest\n \n<span class=\"p\">@@ -47,4 +47,4 @@</span>\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('../../testvideo3.mp4')\n</span><span class=\"gi\">+vid_test.run('../../images/testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h2 id=\"学習済み重みファイルのダウンロード\">学習済み重みファイルのダウンロード</h2>\n\n<p>参照先の記載にしたがって、重み学習済み重みファイルをダウンロードする。</p>\n\n<p>wgetでは取得できなかったので、ブラウザで↓ここ から weights_SSD300.hdf5 をダウンロード。<br />\n<a href=\"https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA\" target=\"_blank\">https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA</a><br />\nで、ZIPファイルをカレントディレクトリに解凍しておく。</p>\n\n<h2 id=\"ソースのダウンロードパッチをあてる\">ソースのダウンロード&パッチをあてる</h2>\n\n<p>githubからソースをダウンロードする。<br />\nこのままではエラーになるので、先ほど作成したパッチファイル<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code>でパッチをあてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/rykov8/ssd_keras.git\n<span class=\"nb\">cd </span>ssd_keras\npatch <span class=\"nt\">-p1</span> < ../ssd_keras.patch \n<span class=\"c\"># Keras修正対応パッチ</span>\npatch <span class=\"nt\">-p1</span> < ../ssd_keras_2.patch \n</code></pre></div></div>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>testing_utils/\npython videotest_example.py\n</code></pre></div></div>\n\n<p>おー。<br />\nしかし遅い…. <br />\nKerasは遅いみたい。。。orz…</p>\n\n<h1 id=\"こんなんもある\">こんなんもある</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50\" target=\"_blank\">「Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PyPiからopenVINOをインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>PyPiからopenVINOをインストール</h1>\n      <p>PyPiで配布されているopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>openVINOを使いたいが、SDKをインストールするのは面倒というズボラさんのためのTips😅<br />\nNCS2を使うためのドライバをインストールするにはSDK必要だが(WSLだとそもそもNCS2は使えないけど)、CPUだけでさくっと使いたいときなんかは有効かな?<br />\nあと、SDKインストール済みだけど、別のバージョン試したいときとか。</p>\n\n<p>対象はWindwos(試してないけど)、Ubuntu(x86_64 の 18.04、20.04)。(macOSも対象らしいけど使ったことないのでよーわからん😅)<br />\nPython は3.6、3.7、3.8<br />\nRasoberryPiは現在のところ対象外。</p>\n\n<h1 id=\"pypiのページ\">PyPiのページ</h1>\n\n<p>PyPiは以下にページがある。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino/\" target=\"_blank\">openvino · PyPI</a></li>\n</ul>\n\n<p>ただし、現状はUbuntuでPython3.8を使用する場合は以下を使用(Ubuntu Python3.7は両方用意されているらしい)。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino-ubuntu20/\" target=\"_blank\">openvino-ubuntu20 · PyPI</a></li>\n</ul>\n\n<h1 id=\"pythonモジュールのインストール\">pythonモジュールのインストール</h1>\n<p>上記ページに記載された通りだが、大抵openCVも必要になるので、インストールしておく。 <br />\n最近はopenCVも<code class=\"language-plaintext highlighter-rouge\">pip</code>コマンドイッパツでインストールできるのでラクチン😊</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOのインストール</span>\npip <span class=\"nb\">install </span>openvino\n<span class=\"c\"># またはこちら</span>\n<span class=\"c\"># pip install openvino-ubuntu20</span>\n\n<span class=\"c\"># openCVのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<p>インストールすると、現状、以下のモジュールがインストールされる(ubuntuでpython3.7/3.8の場合)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>numpy==1.20.1\nopencv-python==4.5.1.48\nopenvino==2021.2\ntbb==2020.3.254\n</code></pre></div></div>\n\n<h1 id=\"実行前の準備\">実行前の準備</h1>\n\n<p>openVINOモジュールは<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>の設定が必要なので、\nシステムのpythonを使用するときは上記ページに記載された通りに<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>を設定する。<br />\nただし、pyenvを使用している場合は、以下のように設定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"k\">}</span>:<span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/versions/<span class=\"sb\">`</span>pyenv version-name<span class=\"sb\">`</span>/lib\n</code></pre></div></div>\n\n<p>pyenvで環境を切り替えることを考えると、<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>で設定するより、スクリプト実行ラッパで設定した方が無難かも。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu20.04 on WSL2 で openVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu20.04 on WSL2 で openVINO</h1>\n      <p>WSL2上のUbuntu20.04でopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"環境構築\">環境構築</h1>\n\n<p>WSL環境ではNCS2は使えないが、CPU演算での実行は可能。<br />\n以下インストール~デモ実行までのメモ。</p>\n\n<p>基本は以下を参考に。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></li>\n  <li><a href=\"/memoBlog/2020/10/18/openVINO_ubuntu_3.html\">openVINO フルパッケージ(2021.1)をインストール(追加)</a></li>\n</ul>\n\n<p>WSLのインストールメモはこちら:<a href=\"/memoBlog/2021/03/03/WSL_memo.html\">WSL2 メモ</a><br />\nUbuntuは20.04。<br />\n今回はopenVINO 2021.2を使用した。</p>\n\n<h2 id=\"pyenvの仮想環境を作成\">pyenvの仮想環境を作成</h2>\n<p>まずは、pythonの環境を準備。<br />\n以下ではpythonは3.7.10を使用。(3.8を使えばTensorflow2を使えるらしい(?))</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.10 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n\n<p>ubuntuのライブラリ類をインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev \n<span class=\"c\"># 他にもあるかもしれんけど、とりあえずこれだけ。</span>\n</code></pre></div></div>\n\n<p>WSLでは以下も必要(グラフィック系処理が入ってないので)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgtk-3-0\n</code></pre></div></div>\n<h2 id=\"ダウンロードしたopenvinoアーカイブの展開とインストール\">ダウンロードしたopenVINOアーカイブの展開とインストール</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/mnt/f/Download/</code>にダウンロードしたファイルがあるとして。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\n<span class=\"nb\">tar </span>xzvf /mnt/f/Download/l_openvino_toolkit_p_2021.2.185.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2021.2.185/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n<span class=\"c\"># なぜかXwindow設定しててもテキストベースになる...</span>\n<span class=\"c\"># てきとーに答えていく。</span>\n</code></pre></div></div>\n\n<p>スクリプト終了したら、以下に従い進めていく。<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html</a></p>\n\n<h2 id=\"後半のコマンド一覧と注意事項\">後半のコマンド一覧と注意事項</h2>\n\n<ul>\n  <li>環境変数の設定とpythonモジュールのインストール</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># このコマンド、~/.bashrcにも書いておくこと</span>\n<span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n\n<span class=\"c\"># このコマンド実行すると、pyenvでなくsystemのpipでモジュールがインストールされるので実行しない</span>\n<span class=\"c\"># しかも、systemのpip3が壊れる...すごい罠😡</span>\n<span class=\"c\"># cd /opt/intel/openvino_2021/deployment_tools/model_optimizer/install_prerequisites/</span>\n<span class=\"c\"># sudo -E ./install_prerequisites.sh </span>\n\n<span class=\"c\"># 代わりに以下を実行(上記スクリプトは結局これを実行しているだけなので)</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npython 3.7で実行すると、</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version >= \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われるけど、無視して良い。<br />\nこれはPython3.8未満か以上で異なるバージョンのTensorflowがインストールされるように設定されているため。<br />\nちなみに、python 3.8でやると</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version < \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nもし、<code class=\"language-plaintext highlighter-rouge\">install_prerequisites.sh</code>を実行してしまい、pip3が壊れてしまった場合は\n以下で復旧する(一旦アンインストールしてから再インストール)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove python3-pip \n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip \n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"デモ実行\">デモ実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino_2021/deployment_tools/demo\n<span class=\"nb\">sudo cp</span> /work/.python-version <span class=\"nb\">.</span>\n\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/demo1.log\n\n<span class=\"c\"># このデモはグラフィック表示可能環境で実行する必要がある。  </span>\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/dem2.log\n</code></pre></div></div>\n\n<h1 id=\"別の仮想環境を用意する場合\">別の仮想環境を用意する場合</h1>\n\n<p>別の仮想環境を用意するときは以下で新しい仮想環境下にモジュールをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 20.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 20.04のインストール</h1>\n      <p>Ubuntu 20.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>VirtualBox へのインストール前提で書いてます。<br />\nでも、仮想マシンの作成以外は同じかな。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2004-インストール媒体の入手\">Ubuntu 20.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら:\n<a href=\"https://www.ubuntulinux.jp/products/JA-Localized/download\" target=\"_blank\">Ubuntu Desktop 日本語 Remixのダウンロード</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを2048MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<p>以下の説明が図付きで分かりやすい:\n<a href=\"https://qiita.com/HirMtsd/items/225c20b77a7cd5194834\" target=\"_blank\">Windows10上のVirtualBoxにUbuntu20.04をインストール</a></p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面ロック を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから「デバイス」→「クリップボードの共有」→「双方向」<br />\nを選択。\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h3 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h2>\n<blockquote>\n  <p>[!NOTE]\n前のバージョンまでは、WMをGnome Flashbackに変更してたけど、<br />\n日本語入力とかと相性悪いみたいなので、やめといた方が無難<br />\nインストールする場合はここを参考に: <a href=\"https://goto-linux.com/ja/2020/3/13/ubuntu-20.04-gnome-flashback%E3%83%86%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%95%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB/\" target=\"_blank\">Ubuntu 20.04 Gnome Flashbackデスクトップのインストール</a></p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-session-flashback\n</code></pre></div>  </div>\n  <p>「GNOME Flashback(Compiz)」はなくなったらしい</p>\n</blockquote>\n\n<h2 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h2>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nUbuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h2>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"bashの設定変更\">bashの設定変更</h2>\n\n<p>~/.bashrcに以下を追記</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h2 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h2 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h2 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nFlashbackの場合は以下らしい。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.gnome-flashback.desktop.icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.gnome-flashback.desktop.icons show-trash <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h2>\n<p>なんとなく使いにくいので好みのデザインに変更。<br />\ndconf-editorでも良いよ(しつこい…)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h2 id=\"日本語入力\">日本語入力</h2>\n<p>前は設定必要だったけど、なんか大丈夫になったみたい</p>\n<blockquote>\n  <p>[!NOTE]\n以前の設定手順<br />\n右上の「A」または「あ」と書かれたアイコンをクリック→「テキスト入力設定」を選択\n一番下の「インストールされている言語の管理」をクリック\n「言語サポートが完全にはインストールされていません」と出るので「インストール」をクリック\n一旦log offして再log in\n右上のJaまたはMoと書かれたアイコンをクリック\n    Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)\nキーボードの全角/半角キーで切り替えられるようになる</p>\n</blockquote>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h2 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h2>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h2 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h2>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a></p>\n\n<p>リブート必要だが、以下のIPv6無効化とまとめてリブートでも可。</p>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>grubメニューの更新</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hosts は書き換えられないので、手動で書き換える</p>\n</blockquote>\n\n<p>IPアドレスの変更(固定アドレスにしたい場合)</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<p>まとめて実行するならこちら。<br />\n接続名があってるかは確認しておくこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># マシン番号の設定とホスト名の設定</span>\n<span class=\"nv\">number</span><span class=\"o\">=</span>30\n<span class=\"nv\">new_hostname</span><span class=\"o\">=</span>skull<span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span>\n\n<span class=\"c\"># HOSTNAMEの変更</span>\n<span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/ubuntu-20.*</span><span class=\"nv\">$/</span><span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span><span class=\"s2\">/\"</span> /etc/hosts\n\n<span class=\"c\"># HOST ONLY ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n\n<span class=\"c\"># BRIDGE ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージ(2021.1)をインストール(追加)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージ(2021.1)をインストール(追加)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2021.1対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a>で\nubuntuへopenVINO 2020.3のインストールしたが、今回は 2021.1 を追加インストールしたのでメモ。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>前に登録したときに通知されたURLから「Choose Version」でバージョン選んでダウンロードできる。<br />\n新しく登録しなても大丈夫(登録方法は<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>参照)。</p>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>これは前回と同じ。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫だが、<br />\ncmakeは<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたバージョンだと古くてNGといわれてしまうので、<br />\n別途本家からダウンロードしてインストールする(ubuntu 18.04の場合。20.04だとたぶん<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたので大丈夫)。</p>\n\n<ul>\n  <li>既に<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストール済みの場合は、アンインストールする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt purge <span class=\"nt\">--auto-remove</span> cmake\n</code></pre></div>    </div>\n  </li>\n  <li>本家からダウンロードして展開\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/Kitware/CMake/releases/download/v3.18.4/cmake-3.18.4-Linux-x86_64.tar.gz  \n<span class=\"nb\">tar </span>xzvf cmake-3.18.4-Linux-x86_64.tar.gz \n</code></pre></div>    </div>\n  </li>\n  <li>/opt ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv </span>cmake-3.18.4-Linux-x86_64 /opt/\n</code></pre></div>    </div>\n  </li>\n  <li>/usr/bin ディレクトリにシンボリックリンク作成\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /opt/cmake-3.18.4-Linux-x86_64/bin/<span class=\"k\">*</span> /usr/bin/\n</code></pre></div>    </div>\n  </li>\n  <li>バージョン確認\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">--version</span> \n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>インストール手順も<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫。</p>\n\n<p>完了したらこれが表示されるページのURLは以下に変更されている。<br />\n<a href=\"https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<p>2020.3インストール済みだと端折っても大丈夫かと思ったけど、微妙にパッケージ増えてたりするので、再度やった方が良い。<br />\n環境変数の設定のために、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に記述する処理は以下に変更(<code class=\"language-plaintext highlighter-rouge\">openvino</code>→<code class=\"language-plaintext highlighter-rouge\">openvino_2021</code>)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\n<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を実行すると、再度<code class=\"language-plaintext highlighter-rouge\">apt</code>で<code class=\"language-plaintext highlighter-rouge\">cmake</code>がインストールされてしまいます。<br />\nopenVINOのインストール完了後であれば<code class=\"language-plaintext highlighter-rouge\">cmake</code>のバージョンが古くても大丈夫ですが、<br />\n気になるなら、再度アンインストールとシンボリックリンクの作成を行います。<br />\n(実行前に<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を編集してcmake消しておいても良いけど)</p>\n</blockquote>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>これは2020.3インストール済みだと端折ってもOK。<br />\n初めてインストールなら<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>を参照。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順はWiresharkで色々操作しないといけないのがめんどっちいので、スクリプトで自動化してみた。</p>\n\n<p>WiresharkのCUI版である、tsharkを使うと出来るらしいとの情報があったので、試してみたときのメモ。<br />\n今回はRaspberryPiだけ。Windowsは対応してません。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_1.html\">WiresharkでUSBパケットをキャプチャするときの注意事項</a> \nの準備は出来ているものとする。(Wiresharkは入ってなくても大丈夫。もちろん 入ってても良いよ。)</p>\n\n<p>tsharkは以下のコマンドイッパツでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tshark \n</code></pre></div></div>\n\n<p>で、あとは以下のスクリプトを\n<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの<code class=\"language-plaintext highlighter-rouge\">json_read.py</code>と同じディレクトリに作成し、実行するだけ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cap.sh\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/usr/bin/env bash</span>\n\n<span class=\"c\"># 第一引数でキャプチャ期間(sec)</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-z</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n  <span class=\"c\"># 引数なしだと2secに設定</span>\n  <span class=\"nv\">period</span><span class=\"o\">=</span>2\n<span class=\"k\">else</span>\n  <span class=\"c\"># 引数のチェック</span>\n  <span class=\"k\">if </span><span class=\"nb\">expr</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> : <span class=\"s1\">'[0-9]*'</span> <span class=\"o\">></span> /dev/null <span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># 数値</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nv\">$1</span> <span class=\"nt\">-lt</span> 1 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n      <span class=\"c\"># 1未満の数値</span>\n      <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n      <span class=\"nb\">exit\n    </span><span class=\"k\">else</span>\n      <span class=\"c\"># 1以上の数値(OK)</span>\n      <span class=\"nv\">period</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span>\n    <span class=\"k\">fi\n  else</span>\n    <span class=\"c\"># 数値でない</span>\n    <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n    <span class=\"nb\">exit\n  </span><span class=\"k\">fi\nfi</span>\n\n<span class=\"c\"># 現在時刻</span>\n<span class=\"nv\">cur_time</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">date</span> <span class=\"s2\">\"+%y%m%d_%H%M%S\"</span><span class=\"sb\">`</span>\n<span class=\"c\"># ファイル名生成</span>\n<span class=\"nv\">fname_base</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span>_<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># USBパケットキャプチャ</span>\n<span class=\"nb\">echo</span> <span class=\"s2\">\"Capture USB packets for </span><span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span><span class=\"s2\"> second from </span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\ntshark <span class=\"nt\">-i</span> usbmon1 <span class=\"nt\">-w</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-a</span> duration:<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># バス番号、デバイス番号の抽出</span>\n<span class=\"nv\">tmp_str</span><span class=\"o\">=</span><span class=\"sb\">`</span>lsusb | <span class=\"nb\">grep </span>WebCam<span class=\"sb\">`</span>\n<span class=\"nv\">bus_and_dev</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">tmp_str</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/Bus </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">Device </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">: ID.*/</span><span class=\"se\">\\1</span><span class=\"s2\"> </span><span class=\"se\">\\2</span><span class=\"s2\">/g\"</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">bus</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[0]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">dev</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[1]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">endpoint</span><span class=\"o\">=</span>1\n<span class=\"nv\">addr</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">bus</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">dev</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">endpoint</span><span class=\"k\">}</span>\n<span class=\"c\"># echo ${addr}</span>\n\n<span class=\"c\"># JSONファイルをエクスポート</span>\n<span class=\"nb\">echo </span>JSON data save to <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json...\ntshark <span class=\"nt\">-r</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-Y</span> <span class=\"s2\">\"usb.src==</span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">addr</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span> <span class=\"nt\">-T</span> json <span class=\"o\">></span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json\n\n<span class=\"c\"># JSON->CSV 変換</span>\npython json_read.py <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.csv\n\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。キャプチャ時間を秒で設定する。省略時は2秒。<br />\n出力されるファイル名は実行時の時刻で作成された文字列に各拡張子を付加したもの。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash cap.sh <span class=\"o\">[</span>キャプチャ時間<span class=\"o\">(</span>sec<span class=\"o\">)]</span>\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>なんかパラメータチェックが一番長いなぁ…😅</p>\n\n<p>33行目でパケットキャプチャ実行。</p>\n\n<p>35~41行目で対象USB機器のアドレス(バス番号、デバイス番号)を取得している。<br />\n36行目の<code class=\"language-plaintext highlighter-rouge\">grep</code>のパラメータは対象となるUSB機器に合わせて変更してちょ。<br />\nエンドポイント番号は対象機器によって固定なので、調べてね。\n分からなかったら、キャプチャしたデータをWiresharkで読み込んで確認してちょ。</p>\n\n<p>46行目でキャプチャしたファイルをJSONファイルにエクスポート。</p>\n\n<p>49行目でJSON→CSV変換。</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>これで<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順をスクリプトイッパツで完了できる。<br />\nま、特定環境でしか試してないから、どんな環境でも使えるとは限らないけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要--背景\">概要 & 背景</h1>\n\n<p>WiresharkでUSBパケットをキャプチャしたとき、実際に転送されてるデータの中身が見たいというニッチな要求があった。<br />\n(送ったデータがちゃんとUSBバスに出てるよね~、という確認がしたいなどの用途)</p>\n\n<p>Wiresharkのセーブデータ渡して「Wiresharkで見てね~」と言ったら「見方が分からん!」と…<br />\nで、Excelで一覧表にしてあげようと思い、エクスポートできんかな~と探してみるも、適当な機能が見つからず…<br />\nしかたなく、変換スクリプトかましてCSVに出力してExcelで読み込んでみよう、と試した時のメモ。</p>\n\n<p>今回はisochronous転送のデータの中身をダンプしている。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<ol>\n  <li>最初に解析したいパケットをキャプチャしておく(これをやらなきゃ始まらん…)。</li>\n  <li>必要なら表示フィルタで解析したいパケットだけ選び出す。</li>\n  <li>それらのパケットの一部だけ(最初の1秒だけ など)解析したい場合はそのパケット群を選択する。<br />\n   RaspberryPiでのやり方が分からん…Windows版なら他のアプリ同様、先頭で左クリック→最後でshift押しながら左クリックでOK。<br />\n   どうしても出来なかったら、RaspberryPiでキャプチャしたのを保存して、そのファイル(pcapngファイル)をWindowsにコピーして、\n   Windows上のWiresharkで読み込んでくだされ…😅</li>\n  <li>メニューの「ファイル」→「パケット解析をエクスポート」→「JSONとして」を選択</li>\n  <li>ファイル操作ダイアログが表示される\n    <ul>\n      <li>真ん中の「ファイル名」を入力</li>\n      <li>左下の「パケットの範囲」で\n        <ul>\n          <li>「表示されたパケット」を選択</li>\n          <li>「すべてのパケット」または「選択されたパケットのみ」を選択<br />\n (ここで「範囲」を選んで入力すれば選択しなくてもいいのかな?試してないので不明)</li>\n        </ul>\n      </li>\n      <li>「保存」をクリック</li>\n    </ul>\n  </li>\n</ol>\n\n<p>これでJSONファイルが保存される。</p>\n\n<h1 id=\"csvファイルに変換\">CSVファイルに変換</h1>\n\n<p>さぁ、このJSONファイルを読み込んで必要な部分を取り出すスクリプトを書けばOKじゃん?と思ったが、<br />\nそうは問屋がおろしてくれない😢<br />\nじつはWiresharkがエクスポートするJSONファイルはJSONファイルの文法からはずれた部分があるのだ…<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">/_source/layers/usb</code> の配下に複数のキー<code class=\"language-plaintext highlighter-rouge\">usb</code>があって、すべてのUSBデータを読み込めない。<br />\n(JSONの仕様では同一階層に複数の同じキーの存在を許さない。pythonのJSONモジュールでは複数あるデータのうち、一つだけが読み込まれる)<br />\nここが配列になってればOKだと気が付いて、チカラワザで変換する処理を追加してみた。</p>\n\n<p>で、pyshonで書いたスクリプトがこちら。<br />\nWindows/RaspberryPi どっちでも大丈夫と思うけど、Windowsでしか試してない。<br />\npythonは3.6以降が必要。3.7.7で動作確認。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  json_read.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"c1\"># テンポラリファイル名\n</span><span class=\"n\">tmp_file</span> <span class=\"o\">=</span> <span class=\"s\">'tmp.json'</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'==== USAGE ========================='</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'    </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> <JSON file> <CSV file>'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'===================================='</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">json_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">csv_file</span>  <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'Error: JSON file not exist!!'</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># \"usb\" キーが複数あるので、これをリストに変換したJSONファイルを作成する\n# かなり力技...\n</span><span class=\"k\">def</span> <span class=\"nf\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_json</span><span class=\"p\">,</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_tmp</span><span class=\"p\">:</span>\n        <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        \n        <span class=\"k\">while</span> <span class=\"n\">line</span><span class=\"p\">:</span>\n            <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"n\">line_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>           <span class=\"c1\"># 行番号\n</span>            <span class=\"c1\"># line = line.rstrip('\\r\\n')              # CRLFを削除\n</span>            <span class=\"k\">if</span> <span class=\"n\">find_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">'\"usb\": '</span><span class=\"p\">,</span> <span class=\"s\">''</span><span class=\"p\">)</span>      <span class=\"c1\"># key名称 \"usb\"を削除\n</span>                <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'START: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          \"usb_data\": [</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">+</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'{'</span><span class=\"p\">)</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">-</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'}'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">brackets</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'END: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          ]</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb.iso.numdesc\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">f_pos</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">tell</span><span class=\"p\">()</span>\n                    <span class=\"n\">next_line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>        <span class=\"c1\"># 次の行を読み込んで\n</span>                    <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"n\">f_pos</span><span class=\"p\">)</span>                   <span class=\"c1\"># ファイル位置を戻す\n</span>                    <span class=\"k\">if</span> <span class=\"n\">next_line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                    <span class=\"c1\"># 括弧の数\n</span>            <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">line</span><span class=\"p\">)</span>\n            <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># JSONファイルの修正\n</span><span class=\"n\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># パケット解析用変数\n</span><span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n<span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># JSONファイルの読み込み\n</span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n    <span class=\"n\">json_load</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(json_load)\n</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">csv_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_csv</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ヘッダの出力\n</span>    <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">'PacketNo,Date,Relative_time,Delta_time,Packet Size,Video Stream Size,Video Stream offset,Frame No,Stream No,Stream Data</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">json_data</span> <span class=\"ow\">in</span> <span class=\"n\">json_load</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フレームデータ\n</span>        <span class=\"n\">frame_data</span>          <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"frame\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_index</span>         <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.number\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_epoc</span>     <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_epoch\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_delta</span>    <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_delta_displayed\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_relative</span> <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_relative\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_dt</span>       <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">fromtimestamp</span><span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">frame_time_epoc</span><span class=\"p\">))</span>\n        <span class=\"n\">frame_time</span>          <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_time_dt</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_len</span>           <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.len\"</span><span class=\"p\">]</span>\n        <span class=\"c1\"># print(f'{frame_index},\"\\'{frame_time}\",{frame_len},', end='')\n</span>        <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_index</span><span class=\"si\">}</span><span class=\"s\">,\"</span><span class=\"se\">\\'</span><span class=\"si\">{</span><span class=\"n\">frame_time</span><span class=\"si\">}</span><span class=\"s\">\",</span><span class=\"si\">{</span><span class=\"n\">frame_time_relative</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_time_delta</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_len</span><span class=\"si\">}</span><span class=\"s\">,'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># USBデータ\n</span>        <span class=\"n\">usb_datas</span>  <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"usb\"</span><span class=\"p\">][</span><span class=\"s\">\"usb_data\"</span><span class=\"p\">]</span>\n        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"k\">for</span> <span class=\"n\">usb_data</span> <span class=\"ow\">in</span> <span class=\"n\">usb_datas</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f',,,,,', end='')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">',,,,,'</span><span class=\"p\">)</span>\n            <span class=\"n\">iso_len</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_len'</span><span class=\"p\">])</span>\n            <span class=\"n\">iso_off</span>  <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_off'</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">iso_len</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">\"usb.iso.data\"</span><span class=\"p\">]</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"s\">'0x'</span><span class=\"o\">+</span><span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">':'</span><span class=\"p\">,</span> <span class=\"s\">',0x'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">stream_number</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_number</span><span class=\"p\">)</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"s\">''</span>\n                \n                <span class=\"c1\"># print(f'{iso_len},{iso_off},{stream_number},{iso_data}')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_number_str</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">stream_number</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_data</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x02'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x03'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"n\">stream_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f'{iso_len},{iso_off},,')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,,</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># テンポラリファイルの削除\n</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。(RaspberryPiだと<code class=\"language-plaintext highlighter-rouge\">python3</code>にしてちょ)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python json_read.py «入力JSONファイル» «出力CSVファイル»\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>やっつけスクリプトなので、エラーチェックはかなりいい加減…</p>\n\n<p>関数<code class=\"language-plaintext highlighter-rouge\">modify_json()</code> が 前述のJSONファイルの不具合をチカラワザで修正する処理。</p>\n\n<p>テンポラリファイルとしてカレントディレクトリに<code class=\"language-plaintext highlighter-rouge\">tmp.json</code>を作成するので、注意。\nファイル名を変更したければ、8行目の<code class=\"language-plaintext highlighter-rouge\">tmp_file</code>を変更。<br />\nこのファイルはスクリプトの最後で削除している。<br />\n作成したテンポラリファイルを残しておきたければ最後の<code class=\"language-plaintext highlighter-rouge\">os.remove(tmp_file)</code>をコメントアウト。</p>\n\n<p>71~72行目で修正したJSONファイルを読み込み。</p>\n\n<p>75行目で書き出すCSVファイルをオープン。</p>\n\n<p>78行目~のforループで各JSONレコードを読み込みながら処理。</p>\n\n<p>82,85~86行目でframe.time_epochから時刻文字列を作成。<br />\n時刻は<code class=\"language-plaintext highlighter-rouge\">frame.time</code>を使用する手もあるが、ここはプラットフォームによって変化するらしいので同じ表示にするためにエポックタイムから生成している。<br />\nその他時刻関連データでは、<code class=\"language-plaintext highlighter-rouge\">frame.time_delta_displayed</code>で「前のパケットからの相対時間」、\n<code class=\"language-plaintext highlighter-rouge\">frame.time_relative</code>で「最初のパケットからの相対時間」を取得している。</p>\n\n<p>94行目~のforループがデータを取り出す部分。<br />\nisochronous転送のデータではないデータを取り出したい場合は、所望のデータのキーに置き換えて取り出せば良い。<br />\n<code class=\"language-plaintext highlighter-rouge\">frame_number</code>と<code class=\"language-plaintext highlighter-rouge\">stream_number</code>は私の解析用の補助データなので気にしないでネ。</p>\n\n<p>あとは、エクスポートされたJSONファイルとスクリプトを見比べてちゃぶだい。(^^ゞ</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>あとは、csvファイルをExcelで読み込むなり、pandasとかを使った別のスクリプトで加工するなりしてちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットをキャプチャするときの注意事項</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットをキャプチャするときの注意事項</h1>\n      <p>WiresharkでUSBパケットをキャプチャしようとしてちょっとハマったのでメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>WiresharkでUSBパケットをキャプチャするための準備(Linux版)<br />\nWindows版はちょっと異なると思うけど試してないので、ググってね😅。</p>\n\n<h1 id=\"wiresharkのインストール実行\">Wiresharkのインストール&実行</h1>\n\n<p>ふつーに<code class=\"language-plaintext highlighter-rouge\">apt install</code>するだけ。<br />\nWindows版と異なり、USBパケットキャプチャのために別途USBキャプチャプログラムをインストールする必要はない。<br />\nついでに<code class=\"language-plaintext highlighter-rouge\">sudo</code>しなくても実行できるように自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>グループを追加しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>wireshark\n<span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> wireshark \n</code></pre></div></div>\n\n<p>ここで一旦ログアウト&再ログイン or 再起動。</p>\n\n<p>このままだとUSBパケットキャプチャのためのプログラム(<code class=\"language-plaintext highlighter-rouge\">usbmon</code>)が動いてないので、動かす必要がある。<br />\n<strong>起動の度に</strong>ターミナルから以下のコマンドを実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbmon\n</code></pre></div></div>\n\n<p>Wiresharkの実行は、ターミナルから<code class=\"language-plaintext highlighter-rouge\">wireshark</code>を実行するか、メニューの「インターネット」→「Wireshark」を選択します。<br />\n(自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>`グループを追加してあるので、メニューからでも実行できます)</p>\n\n<p>起動の度に<code class=\"language-plaintext highlighter-rouge\">usbmon</code>を起動するのは面倒な場合は、以下の手順で自動化できます。</p>\n\n<ol>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/udev/rules.d/99-usbmon.rules</code>を以下の内容で作成\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>SUBSYSTEM==\"usbmon\", GROUP=\"wireshark\", MODE=\"640\"\n</code></pre></div>    </div>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/modules</code> に以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbmon\n</code></pre></div>    </div>\n  </li>\n  <li>リブート</li>\n</ol>\n\n<h1 id=\"wiresharkの使い方\">Wiresharkの使い方</h1>\n\n<p>あちこちのホームページに詳しく解説されているので、ぐぐってちょ(←なんて他力本願…😅)。<br />\nRaspberryPi4の場合、USBのインタフェースはusbmon1とusbmon2があるが、どっちをキャプチャするかは、接続した機器がUSB2.0かUSB3.0による。<br />\nたぶん、usbmon1がUSB2.0(外側/内側)、usbmon2がUSB3.0(内側のみ)だと思う。<br />\n<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)がusbmonYのYにあたるとだと推測。</p>\n\n<h1 id=\"wiresharkでパケット解析\">Wiresharkでパケット解析</h1>\n\n<p>USBのパケットの表示フィルタの書き方がネット上でもなかなか見つからなかったので、簡単なものだけメモ。</p>\n\n<h2 id=\"特定のusb機器のパケットだけ表示\">特定のUSB機器のパケットだけ表示</h2>\n\n<p>実際にはエンドポイントまで指定しているので、複数のエンドポイントを同時に表示したければ、OR(<code class=\"language-plaintext highlighter-rouge\">||</code>)で条件つなげてください。\n(<code class=\"language-plaintext highlighter-rouge\">1.5.*</code>みたいな書き方が出来るのかは不明 )</p>\n\n<p>この例の<code class=\"language-plaintext highlighter-rouge\">1.5.1</code>の<br />\n左の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)、 <br />\n中央の<code class=\"language-plaintext highlighter-rouge\">5</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のデバイス番号(<code class=\"language-plaintext highlighter-rouge\">Device YYY</code>の部分の数字)(<strong>挿抜の度に変わる</strong>)、 <br />\n右の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb -D /dev/bus/usb/XXX/YYY</code>(XXX、YYYは上記のバス番号、デバイス番号。0は省略不可) で表示される情報の <br />\n<code class=\"language-plaintext highlighter-rouge\">bEndpointAddress</code>で確認できるけど、これは機器内部で固定されてるはず。<br />\nと、難しく調べんでも、一度全部キャプチャしたものを表示して欲しいパケットを探してみてそこのアドレスを見れば分かる。</p>\n\n<p>USBホストの吐合は<code class=\"language-plaintext highlighter-rouge\">\"host\"</code>になる。</p>\n\n<h3 id=\"特定の機器の送信パケットだけ表示\">特定の機器の送信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\"\n</code></pre></div></div>\n<h3 id=\"特定の機器の受信パケットだけ表示\">特定の機器の受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n<h3 id=\"特定の機器の送受信パケットだけ表示\">特定の機器の送受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\" || usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのバグ??</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのバグ??</h1>\n      <p>pyenvのバグ??</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>バグかどうかわからんけど、思った通りの動作をしなかったので、メモ。</p>\n\n<h1 id=\"現象\">現象</h1>\n\n<p>pyenv を使う環境で、</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    python script.py <span class=\"nt\">--option</span> /path/to/file\n</code></pre></div></div>\n\n<p>と実行した場合、カレントディレクトリと<code class=\"language-plaintext highlighter-rouge\">/path/to/file</code>の存在するディレクトリで使用するpythonのバージョンが異なる場合、<br />\n(どちらか片方 or 両方で <code class=\"language-plaintext highlighter-rouge\">pyenv local</code>が指定されている)<br />\nカレントディレクトリではなく、/path/to/fileの存在するディレクトリで使用するpythonのバージョンが指定されてしまうらしい。</p>\n\n<p>問題が発生するシチュエーションは そんなに多くないと思うけど、 双方のバージョンでインストールしてるモジュールが違ったりすると困ったことになる。</p>\n\n<h1 id=\"原因\">原因</h1>\n\n<p>色々試行錯誤してみてわかったことを結論だけ。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> を見ると、<br />\nコマンドラインをサーチして最初に見つかったファイルの属する<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読むらしい。<br />\n(以下の部分)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    ・・・\n    <span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"k\">in</span>\n        <span class=\"nt\">-c</span><span class=\"k\">*</span> <span class=\"p\">|</span> <span class=\"nt\">--</span> <span class=\"p\">)</span> <span class=\"nb\">break</span> <span class=\"p\">;;</span>\n        <span class=\"k\">*</span>/<span class=\"k\">*</span> <span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-f</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n                </span><span class=\"nb\">export </span><span class=\"nv\">PYENV_FILE_ARG</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span>\n                <span class=\"nb\">break\n            </span><span class=\"k\">fi</span>\n            <span class=\"p\">;;</span>\n    <span class=\"k\">esac</span>\n    ・・・\n</code></pre></div></div>\n<p>本来ならスクリプトファイルのあるディレクトリの<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読んでほしいはずなのに…<br />\n<code class=\"language-plaintext highlighter-rouge\">*/* )</code> でなく、<code class=\"language-plaintext highlighter-rouge\">*)</code> じゃないのかな? なんか深い訳があるのかもしれんけど…</p>\n\n<h1 id=\"対処方法\">対処方法</h1>\n\n<p>で、以下のいずれかの方法で対処できる。</p>\n\n<ul>\n  <li>オプションの場合は、オプションとオプションパラメータの間をスペースでなく、<code class=\"language-plaintext highlighter-rouge\">=</code>にする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  python script.py <span class=\"nt\">--option</span><span class=\"o\">=</span>/path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>ただし、パーサが<code class=\"language-plaintext highlighter-rouge\">argparse.ArgumentParser</code>など、オプションとオプションパラメータの区切りに<code class=\"language-plaintext highlighter-rouge\">=</code>が使えるものでなければダメ。</li>\n      <li>しかも、そもそもオプションパラメータでなくコマンドパラメータだったらどうしようもない…orz…</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pyenv shell</code>で使用するバージョンを指定する\n    <ul>\n      <li>メンドクサイ…</li>\n    </ul>\n  </li>\n  <li>スクリプトファイルの前に<code class=\"language-plaintext highlighter-rouge\">--</code>を追加してやる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">--</span> script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> では<code class=\"language-plaintext highlighter-rouge\">-c</code>か<code class=\"language-plaintext highlighter-rouge\">--</code>が見つかったら<code class=\"language-plaintext highlighter-rouge\">PYENV_FILE_ARG</code>を探すループを抜けてくれるので。</li>\n      <li>ちょっとめんどくさい…</li>\n    </ul>\n  </li>\n  <li>スクリプト名の前に./を追加する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ./script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>これが一番シンプルかな?</li>\n      <li>てか、コレしかないっしょ。 常に<code class=\"language-plaintext highlighter-rouge\">./</code>付けるクセ付ければいいし。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"免責のツモリ\">免責(のツモリ)</h1>\n\n<p>あくまで自分のメモなんで、、、  ゴニョゴニョ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その6</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その6</h1>\n      <p>tensorflow lite で色々なSSDモデルを使う手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はソースが大半なので、githubにリポジトリ作った。<br />\n内容は各ディレクトリのREADME.mdを見てチョ。<br />\n<a href=\"https://github.com/ippei8jp/tflite_trial\">https://github.com/ippei8jp/tflite_trial</a></p>\n\n<p>順序は <code class=\"language-plaintext highlighter-rouge\">download_models</code> → <code class=\"language-plaintext highlighter-rouge\">mk_tflite_ssd</code> → <code class=\"language-plaintext highlighter-rouge\">images</code> → <code class=\"language-plaintext highlighter-rouge\">ssd</code> が良いと思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール(改訂版)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2020.3対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a>で\nubuntuへのインストール手順を書いたが、今読み返すと結構分かりにくかったので改訂版を書いとく。<br />\n今回はNCS2をubuntuで使えるようにしたので、その手順も追加。<br />\nついでに、今日(2020/06/16)現在の最新版Ver.2020.3での手順確認したので、反映しておく。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<p>参考 :<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">AIを始めよう!OpenVINOのインストールからデモの実行まで[R4対応]</a></p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>何やら登録しないとダウンロードさせてくれないらしい。</p>\n<ul>\n  <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download.html\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a> <br />\nLinux* (supports Ubuntu, CentOS, and Yocto Project)を選択\n    <ul>\n      <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download/linux.html\">Free Download</a>  <br />\n<span style=\"border: 1px solid;\">Register & Download</span>をクリック\n        <ul>\n          <li><a href=\"https://software.seek.intel.com/openvino-toolkit?os=linux\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a><br />\n必要事項を記入して<span style=\"border: 1px solid;\">Submit</span>をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>openVINO用のpython環境を用意しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work1/\npyenv virtualenv 3.7.7 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p>あとで「入ってない」って言われるので先にインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev\n</code></pre></div></div>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>ダウンロードしたファイルを展開してインストールスクリプトを実行する。<br />\n今回はバージョン 2020.3 で確認した。<br />\n最新版は <a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html</a> を参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf l_openvino_toolkit_p_<version>.tgz\n<span class=\"nb\">cd </span>l_openvino_toolkit_p_<version>/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n<p>GUIで次へを押していく。</p>\n\n<p>完了したらこれが表示されるので、したがって進める。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<h3 id=\"install-external-software-dependencies\">Install External Software Dependencies</h3>\n<p>依存パッケージのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh \n</code></pre></div></div>\n\n<h3 id=\"set-the-environment-variables\">Set the Environment Variables</h3>\n<p>環境変数の設定<br />\n~/.bashrc に以下の一文を追加。これでこの後開くコンソールでは環境変数が設定される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>source /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<p>現在のターミナルでも使えるように以下のコマンドを実行しておく。コンソール開きなおしてもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<h3 id=\"configure-the-model-optimizer\">Configure the Model Optimizer</h3>\n<p>モデルオプティマイザのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh \n</code></pre></div></div>\n\n<p>上記スクリプトではsystemのpython3にpipモジュールがインストールされてしまうので、<br />\npyenv環境にも必要なpipモジュールをインストールしておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell openVINO                       <span class=\"c\"># python環境を固定したいので</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\npyenv shell <span class=\"nt\">--unset</span>                        <span class=\"c\"># python環境を戻しておく</span>\n</code></pre></div></div>\n\n<h3 id=\"run-the-verification-scripts-to-verify-installation\">Run the Verification Scripts to Verify Installation</h3>\n<p>デモ実行<br />\n「Verify Installation」って書いてあるけど、実行必須。</p>\n\n<ul>\n  <li>デモ用ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo/\n</code></pre></div>    </div>\n  </li>\n  <li>sudoでpyenvが使えないので、代わりに <code class=\"language-plaintext highlighter-rouge\">/work1</code>  で作成した <code class=\"language-plaintext highlighter-rouge\">.python-version</code>をコピーしておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /work1/.python-version <span class=\"nb\">.</span>\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境にデモ環境で必要なpipモジュールをインストールしておく 。Systemのpython使うときは↓のスクリプト実行時にインストールされる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その1\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/demo1.log\n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その2\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/dem2.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"steps-for-intel-processor-graphics-gpu\">Steps for Intel® Processor Graphics (GPU)</h3>\n<p>今回はGPUを使わないのでスキップ</p>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>NCS2の準備<br />\n色々書いてあるけど、これ一発でOK。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n中ではこんなことをやってます。<br />\nグループusersに自分を追加<br />\n(ログアウト & 再ログインするまで追加は反映されません)<br />\nudevルールの作成と再ロード</p>\n</blockquote>\n\n<p>NCS2をUSBポートにブッ挿すして認識したか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下があったら認識できてる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ID 03e7:2485\n</code></pre></div></div>\n\n<h3 id=\"steps-for-intel-vision-accelerator-design-with-intel-movidius-vpus\">Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPUs</h3>\n<p>今回はVPUを使わないのでスキップ</p>\n\n<p>デモプログラムの実行で動作確認</p>\n\n<p>で、Run a Sample Application に行く前に、ログアウト&再ログインでいいはずだけど、念のためリブート。</p>\n\n<h3 id=\"run-a-sample-application\">Run a Sample Application</h3>\n<p>リブートして開いてたページが分からなくなるといけないので、念のためURL貼っとく。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample</a></p>\n\n<ul>\n  <li>デモ実行ディレクトリに移動。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~/inference_engine_samples_build/intel64/Release\n</code></pre></div>    </div>\n  </li>\n  <li>CPUでデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> CPU\n</code></pre></div>    </div>\n  </li>\n  <li>NCS2でデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> MYRIAD\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>このページの手順はここでおしまい。</p>\n\n<h1 id=\"他のサンプルも試してみよう\">他のサンプルも試してみよう。</h1>\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n<h3 id=\"前準備\">前準備</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work1/NCS/sample <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work1/NCS/sample/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release /opt/intel/openvino_2020.3.194/deployment_tools/inference_engine/samples/cpp/\n</code></pre></div></div>\n\n<h3 id=\"ssdを試してみよう\">SSDを試してみよう</h3>\n<h4 id=\"build\">build</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">-j2</span> object_detection_sample_ssd\n</code></pre></div></div>\n<h4 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R4/20200117_150000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n</code></pre></div></div>\n\n<h4 id=\"実行\">実行</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./intel64/Release/object_detection_sample_ssd <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> /work/data/data2/z_20141013051441.jpg \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nコマンド実行時の<code class=\"language-plaintext highlighter-rouge\">-i</code>オプションは入力画像ファイル。<br />\n人の顔が写っているjpegファイルを指定しましょう。 \n顔が写ってなければ顔検出できません(^^ゞ</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[ INFO ] Execution successful</code>と表示されたら実行成功だと思う。</p>\n\n<h4 id=\"結果画像を表示してみる\">結果画像を表示してみる。</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>eog out_0.bmp \n</code></pre></div></div>\n\n<h4 id=\"おーーーー\"><strong><em>おーーーー</em></strong></h4>\n\n<h1 id=\"ここまでの作業でインストールしたpipパッケージ一覧\">ここまでの作業でインストールしたpipパッケージ一覧</h1>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.9.0\nastor==0.8.1\ncertifi==2020.4.5.2\nchardet==3.0.4\ndecorator==4.4.2\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.2.0\ngraphviz==0.8.4\ngrpcio==1.29.0\nh5py==2.10.0\nidna==2.9\nimportlib-metadata==1.6.1\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.2\nMarkdown==3.2.2\nmxnet==1.5.1\nnetworkx==2.4\nnumpy==1.18.5\nonnx==1.7.0\nopt-einsum==3.2.1\nprotobuf==3.6.1\nPyYAML==5.3.1\nrequests==2.23.0\nsix==1.15.0\ntensorboard==1.15.0\ntensorflow==1.15.3\ntensorflow-estimator==1.15.1\ntermcolor==1.1.0\ntyping-extensions==3.7.4.2\nurllib3==1.25.9\nWerkzeug==1.0.1\nwrapt==1.12.1\nzipp==3.1.0\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その5</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その5</h1>\n      <p>Tensorflow v1.15のインストールとソースからのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はUbuntuだけ。</p>\n\n<h1 id=\"tensorflow-115-のインストール\">Tensorflow 1.15 のインストール</h1>\n\n<p>Tensorflow1系でないと動かない環境とかサンプルとかあるので、<br />\nTensorflow v1.15をインストールする。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_1.15.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_1.15.0\n<span class=\"nb\">cd</span> /work/tf_1.15.0\npyenv <span class=\"nb\">local </span>tf_1.15.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"tensorflow-115-ライブラリのインストール\">Tensorflow 1.15 ライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>1.15\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nGPU使わないので-cpu付きパッケージを選択する</p>\n</blockquote>\n\n<h1 id=\"tensorflow-115-のbuild\">Tensorflow 1.15 のbuild</h1>\n\n<p>Tensorflowのpythonライブラリは<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできるが、\nソースからbuildしないと使えないツールもあるのでbuild環境を整える。</p>\n\n<p>参考: <a href=\"https://www.tensorflow.org/install/source?hl=ja\">ソースからのビルド | Tensorflow</a></p>\n\n<h2 id=\"bazelのインストール\">Bazelのインストール</h2>\n\n<p>Tensorflow をソースからbuildするには<code class=\"language-plaintext highlighter-rouge\">bazel</code>が必要なので、インストールしておく。</p>\n<blockquote>\n  <p>[!NOTE]\nBazelはVer.0.26.1 以下 を使用しないといけない<br />\nVer. 0.26.1はaptでインストールできない</p>\n</blockquote>\n\n<p>参考: <a href=\"https://docs.bazel.build/versions/0.26.0/install-ubuntu.html\">Installing Bazel on Ubuntu</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/bazelbuild/bazel/releases/download/0.26.1/bazel-0.26.1-installer-linux-x86_64.sh\n<span class=\"nb\">chmod</span> +x bazel-0.26.1-installer-linux-x86_64.sh\n./bazel-0.26.1-installer-linux-x86_64.sh <span class=\"nt\">--user</span>\n</code></pre></div></div>\n\n<p>実行ファイルは、<code class=\"language-plaintext highlighter-rouge\">~/bin/bazel</code> になるので、pathが~/binに通ってない場合は、一旦 ログアウトして 再ログイン\n(pathが通ってない場合、configureでエラーになる)</p>\n\n<h2 id=\"必要なpipパッケージのインストール\">必要なpipパッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>six numpy wheel mock <span class=\"s1\">'future>=0.17.1'</span>\npip <span class=\"nb\">install </span>keras_applications <span class=\"nt\">--no-deps</span>\npip <span class=\"nb\">install </span>keras_preprocessing <span class=\"nt\">--no-deps</span>\n</code></pre></div></div>\n\n<h2 id=\"tennsorflowのソースを取得\">tennsorflowのソースを取得</h2>\n\n<p>githubからcloneして V1.15.3 をチェックアウトしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/\ngit clone https://github.com/tensorflow/tensorflow.git\n<span class=\"nb\">cd </span>tensorflow\ngit checkout <span class=\"nt\">-b</span> v1.15.3 refs/tags/v1.15.3\n</code></pre></div></div>\n\n<h1 id=\"buildの設定\">buildの設定</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\n./configure\n<span class=\"c\"># いくつか質問されるので、すべてデフォルト(リターン)を入力</span>\n</code></pre></div></div>\n\n<h1 id=\"buildの実行\">buildの実行</h1>\n<h2 id=\"実行のひな形\">実行のひな形</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build //《対象ディレクトリ》:《ターゲット》\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n※ 対象ディレクトリはカレントディレクトリからの相対パス<br />\n※ ターゲットは対象ディレクトリのBUILDファイルで確認</p>\n</blockquote>\n\n<h2 id=\"例えばこんな感じ\">例えばこんな感じ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel build //tensorflow/lite/toco:toco\nbazel build //tensorflow/python/tools:freeze_graph\nbazel build //tensorflow/tools/graph_transforms:summarize_graph\nbazel build //tensorflow/tools/graph_transforms:transform_graph\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRAMは4GB以上必要かな?<br />\nオプション<code class=\"language-plaintext highlighter-rouge\">--local_ram_resources=2048</code>を指定すると使用するRAMを2GBに限定できる(指定する数値はMB単位)。<br />\n使用するPCのスペックによってかかる時間はマチマチ。<br />\nNativeなUbuntuで4コア8スレッドでも3~4時間程度かかる。<br />\nVirtualboxで1コア使用だと24時間とかかかることも。</p>\n</blockquote>\n\n<h2 id=\"buildしたファイルの実行\">buildしたファイルの実行</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">bazel run</code> で実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nオプションをbazelではなく実行するコマンドに渡すため、<code class=\"language-plaintext highlighter-rouge\">--</code> を入れる必要がある。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel run //tensorflow/lite/toco:toco <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:summarize_graph <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:transform_graph <span class=\"nt\">--</span> «オプション»\n</code></pre></div></div>\n\n<p>絶対パスで実行するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph «オプション»\n</code></pre></div></div>\n\n<p>パスが長いので、以下を設定しておくと便利。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">alias            </span><span class=\"nv\">toco</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">summarize_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">transform_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph'</span>\n</code></pre></div></div>\n\n<h2 id=\"おまけ\">おまけ</h2>\n\n<p>フツーはこっちがメインだが…(^^ゞ<br />\npipでインストールすれば必要ないが、Tensorflowのpipパッケージを作成するにはこちら。<br />\n(オプション変更したいときとか)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build <span class=\"nt\">--config</span><span class=\"o\">=</span>v1 //tensorflow/tools/pip_package:build_pip_package\n./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg\npip <span class=\"nb\">install</span> /tmp/tensorflow_pkg/tensorflow-1.15.3-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その4</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その4</h1>\n      <p>tensorflowのモデルファイル(*.pbや*.tflite)の可視化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>tensorflowのモデルファイル( <code class=\"language-plaintext highlighter-rouge\">*.pb</code> や <code class=\"language-plaintext highlighter-rouge\">*.tflite</code> )を可視化する方法について。<br />\n<code class=\"language-plaintext highlighter-rouge\">tensorboard</code> を使う方法などもあるが、最もお手軽と思われる <code class=\"language-plaintext highlighter-rouge\">netron</code> を使用する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれやらなくても、<a href=\"https://lutzroeder.github.io/netron/\">https://lutzroeder.github.io/netron/</a> にアクセスすれば使える。</p>\n</blockquote>\n\n<h1 id=\"netron-の-インストール\">netron の インストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code>をインストールする。<br />\n<code class=\"language-plaintext highlighter-rouge\">netron</code> はtensorflowのバージョンに依存しない(そもそもtensorflow自体に依存してない)のでTensorflow1系、Tenorflow2系 どちらの環境にインストールしてもよい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>netron\n</code></pre></div></div>\n\n<h1 id=\"netron-の-実行\">netron の 実行</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code> を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>netron <span class=\"nt\">--host</span> 0.0.0.0 <span class=\"o\">[</span><span class=\"nt\">--port</span> xxxx]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--host</code> オプションを指定しないとlocalhostからしか接続できないので、他のマシンから接続するときは指定する。<br />\n<code class=\"language-plaintext highlighter-rouge\">--port</code> オプションのデフォルトは8080なので、変更したいときは指定する。</p>\n\n<h1 id=\"モデルファイルの表示\">モデルファイルの表示</h1>\n\n<p>ブラウザ(Winマシンからで可)で実行したマシンのポート8008(またはオプションで指定したxxxx)に接続。<br />\n例:<code class=\"language-plaintext highlighter-rouge\">http://ncc-1701u.local:8080/</code></p>\n\n<p>表示された画面でOpen Model…をクリックして表示するモデルファイルを選ぶ。<br />\nしばらく待つと表示される。<br />\nモデルファイルはブラウザからアップロードするので、ブラウザから参照できる場所になければならない(サーバ側にあってもダメ)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">*.pb</code> ファイルが大きいとうまく表示できないみたい。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その3</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その3</h1>\n      <p>Tensorflow 2.2.0をインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Edge-TPUを直接操作するわけではないが、Tensorflowで作成されたモデルファイルをtflite用に変換する準備として<br />\ntensorflowをインストールする。<br />\nここではVersion 2.2.0を使用する。</p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<p>coral環境に追加インストールでも良いが、今回は別の環境を用意する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_2.2.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_2.2.0\n<span class=\"nb\">cd</span> /work/tf_2.2.0\npyenv <span class=\"nb\">local </span>tf_2.2.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"tensorflow-220-のインストール\">tensorflow 2.2.0 のインストール</h1>\n\n<p>インストールするパッケージはGPUを使わないので-cpu付きパッケージを選択する。<br />\nTensorflowはバージョンによって機能差が激しいので、インストールするバージョンを指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>2.2.0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その2</h1>\n      <p>Google Coral USB Accelerator で SSD(Single Shot MultiBox Detector)を実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n一部を除き、基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<h1 id=\"tflite-の-モデルファイルをedgetpu使用モデルに変換する方法\">tflite の モデルファイルをEdgeTPU使用モデルに変換する方法</h1>\n<p>通常のtfliteのモデルファイルはCPUのみ(またはCPU+GPU)を使用するように構成されていて、\nそのまま実行してもEdge-TPUは使用されない。<br />\nそこで、Edge-TPU使用モデルに変換するため、edgetpu_compilerを使用する必要がある。<br />\n(ただし、Ubuntuのみ。RasPi不可。)</p>\n\n<h2 id=\"edgetpu_compiler-のインストール\">edgetpu_compiler のインストール</h2>\n\n<p>CPU使用モデルからEdge-TPU使用モデルに変換するツール<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code>をインストールする。<br />\naptリポジトリの登録はTPUライブラリインストール時に行っているので不要(以下ではコメントアウトしてある)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -</span>\n<span class=\"c\"># echo \"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list</span>\n<span class=\"c\"># sudo apt update</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>edgetpu-compiler\n</code></pre></div></div>\n\n<h2 id=\"使用方法\">使用方法</h2>\n<p>基本的に以下。<br />\ntfliteファイルを喰わせるとファイル名に<code class=\"language-plaintext highlighter-rouge\">_edgetpu</code>を付加したファイルが作成される。<br />\nこれがEdge-TPU使用するモデルファイル。<br />\n詳細は<a href=\"https://coral.ai/docs/edgetpu/compiler/\">Edge TPU Compiler</a> を参照。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>edgetpu_compiler [options] model...\n</code></pre></div></div>\n\n<h1 id=\"事前準備\">事前準備</h1>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n\n<p>openCVをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"ssdを実行してみる\">SSDを実行してみる</h1>\n\n<h2 id=\"作業用ディレクトリの作成移動\">作業用ディレクトリの作成&移動</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral/ssd/\n<span class=\"nb\">cd</span> /work/coral/ssd/\n</code></pre></div></div>\n\n<h2 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h2>\n\n<p>用意されているSSDのモデルをダウンロードし、Edge-TPU使用モデルを作成する。<br />\n実行が終了すると、<code class=\"language-plaintext highlighter-rouge\">models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite</code> ができる。</p>\n\n<ul>\n  <li>ダウンロード元: <a href=\"https://www.tensorflow.org/lite/models/object_detection/overview\">Object detection</a>\nの 「Get Started」の「Download starter model and labels」</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl <span class=\"nt\">-O</span> https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip\nunzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip \n<span class=\"nb\">mv </span>detect.tflite coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># リネームしなくてもいいけど、後でわからなくならないようにリネームしておく</span>\n<span class=\"nb\">mv </span>labelmap.txt coco_ssd_mobilenet_v1_1.0_quant.labels   <span class=\"c\"># 同上</span>\nedgetpu_compiler coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># EdgeTPU使用モデルに変換</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"テスト用画像の準備\">テスト用画像の準備</h2>\n\n<p>適当な画像を<code class=\"language-plaintext highlighter-rouge\">image</code>ディレクトリに用意しておく。<br />\n使用できるファイル形式は<code class=\"language-plaintext highlighter-rouge\">jpg</code>と<code class=\"language-plaintext highlighter-rouge\">mp4</code></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>images\n<span class=\"nb\">cd </span>images/\n<span class=\"c\"># 適当な画像ファイルをダウンロードする</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"ssdのプログラムソース\">SSDのプログラムソース</h2>\n\n<p>以下の内容を<code class=\"language-plaintext highlighter-rouge\">object_detection_demo_ssd.py</code>として保存しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">tflite_runtime.interpreter</span> <span class=\"k\">as</span> <span class=\"n\">tflite</span>\n\n<span class=\"c1\"># shared library\n</span><span class=\"n\">EDGETPU_SHARED_LIB</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n  <span class=\"s\">'Linux'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.so.1'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Darwin'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.1.dylib'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Windows'</span><span class=\"p\">:</span> <span class=\"s\">'edgetpu.dll'</span>\n<span class=\"p\">}[</span><span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">system</span><span class=\"p\">()]</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># interpreter の生成\n</span><span class=\"k\">def</span> <span class=\"nf\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">):</span>\n    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"o\">=</span><span class=\"n\">model_file</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span>\n                <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">model_file</span><span class=\"p\">,</span>\n                <span class=\"n\">experimental_delegates</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n                    <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">load_delegate</span><span class=\"p\">(</span><span class=\"n\">EDGETPU_SHARED_LIB</span><span class=\"p\">)</span>\n                <span class=\"p\">])</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    \n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">output_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_output_details</span><span class=\"p\">()</span>\n    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n\n    <span class=\"n\">tflite_results1</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Locations (Top, Left, Bottom, Right)\n</span>    <span class=\"n\">tflite_results2</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Classes (0=Person)\n</span>    <span class=\"n\">tflite_results3</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Scores\n</span>    <span class=\"n\">tflite_results4</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Number of detections\n</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">tflite_results4</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])):</span>\n        <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        \n        <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>        <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n\n        <span class=\"n\">prob</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results3</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">prob</span> <span class=\"o\">>=</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'Class=</span><span class=\"si\">{</span><span class=\"n\">class_name</span><span class=\"si\">:</span><span class=\"mi\">15</span><span class=\"si\">}</span><span class=\"s\">    Probability=</span><span class=\"si\">{</span><span class=\"n\">prob</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    Location=(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)-(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n            <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span>    <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span>   <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span>  <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 表示色\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 対象物の枠とラベルの描画\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"n\">bottom</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">20</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"o\">+</span><span class=\"mi\">160</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"s\">\"{} ({:.3f})\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">class_name</span><span class=\"p\">,</span> <span class=\"n\">prob</span><span class=\"p\">),</span>\n                        <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># interpreterの構築\n</span>    <span class=\"n\">interpreter</span> <span class=\"o\">=</span> <span class=\"n\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">allocate_tensors</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">input_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()</span>\n    \n    <span class=\"c1\"># 入力データ\n</span>    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">org_frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>                 <span class=\"c1\"># オリジナルのフレームレート\n</span>    <span class=\"n\">org_frame_time</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span> <span class=\"o\">/</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>                <span class=\"c1\"># オリジナルのフレーム時間\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">org_frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルの読み込み\n</span>        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルがない場合\n</span>        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># フレーム数\n</span>    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 実行時間測定用変数の初期化\n</span>    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n    <span class=\"c1\"># フレーム測定用タイマ\n</span>    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># モデルの入力サイズ\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># 画像の前処理 =============================================================================\n</span>        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                          <span class=\"c1\"># 前処理開始時刻\n</span>        \n        <span class=\"c1\"># 画像の読み込み\n</span>        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレームを作成\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># モデル入力用にリサイズ\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>   <span class=\"c1\"># input size of coco ssd mobilenet?\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">]]</span>                          <span class=\"c1\"># BGR -> RGB\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">in_frame</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>                 <span class=\"c1\"># 3D -> 4D\n</span>        \n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>     <span class=\"c1\"># 前処理にかかった時間\n</span>        \n        <span class=\"c1\"># 推論実行 =============================================================================\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"c1\"># 推論本体\n</span>        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">set_tensor</span><span class=\"p\">(</span><span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">],</span> <span class=\"n\">in_frame</span><span class=\"p\">)</span>\n        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">invoke</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>                          <span class=\"c1\"># 推論処理にかかった時間\n</span>        \n        <span class=\"c1\"># 検出結果の解析 =============================================================================\n</span>        <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                               <span class=\"c1\"># 解析処理開始時刻\n</span>        <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n        <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>                    <span class=\"c1\"># 解析処理にかかった時間\n</span>        \n        <span class=\"c1\"># 結果の表示 =============================================================================\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 表示処理開始時刻\n</span>        \n        <span class=\"c1\"># 測定データの表示\n</span>        <span class=\"n\">frame_number_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'frame_number   : </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span>\n        <span class=\"k\">if</span> <span class=\"n\">frame_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span>  <span class=\"s\">'Frame time     : ---'</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Frame time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms    </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> fps'</span>\n        <span class=\"n\">inf_time_message</span>        <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Inference time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">render_time_message</span>     <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Rendering time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">parsing_time_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'parse time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        \n        <span class=\"c1\"># 結果の書き込み\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_number_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>     <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>   <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像の保存\n</span>        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>                 <span class=\"c1\"># 表示処理にかかった時間\n</span>        \n        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"c1\"># フレーム処理終了 =============================================================================\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_key_code</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"make_interpretermodel_file\">make_interpreter(model_file)</h3>\n\n<p>interpreter(認識エンジン)を構築する処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>モデルファイル内に<code class=\"language-plaintext highlighter-rouge\">\"edgetpu-custom-op\"</code>という文字列が含まれていたらTPU使用モデルと判定してTPU使用のための共有ライブラリをダウンロードして初期化する。<br />\nそうでなければCPUのみ使用モデルなので、 共有ライブラリなしで初期化する。</p>\n\n<p>もっと単純にモデルファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>が含まれていたらTPU使用モデルと判定しても良いかもしれない(<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code> は出力ファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>を付加するので)。</p>\n\n<h3 id=\"parse_resultinterpreter-frame-labels_map-args\">parse_result(interpreter, frame, labels_map, args)</h3>\n\n<p>認識結果の解析と結果の表示(検出枠とラベルの描画)</p>\n\n<p>認識結果から検出した座標、クラスID、スコアを取得し、出力画像に描画している。</p>\n\n<p>出力データの構成は<a href=\"https://www.tensorflow.org/lite/models/object_detection/overview#output\">ここ</a>を参照。</p>\n\n<p>どうやらこのモデルは検出個数が10個に設定されているようだ。</p>\n\n<h3 id=\"main\">main()</h3>\n\n<p>メインルーチン</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>タイミング調整部分は、認識処理が速かった場合に結果表示画像の表示時間を実際の入力画像の表示時間に合わせるため、ちょっと小細工を入れてある。</p>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--help</span>\nusage: object_detection_demo_ssd.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT <span class=\"o\">[</span><span class=\"nt\">-l</span> LABELS]\n                                    <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> LABELS, <span class=\"nt\">--labels</span> LABELS\n                        Optional. Labels mapping file\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合edge-tpu使用\">静止画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合edge-tpu使用\">動画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n再生が終了するか、画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n<h2 id=\"静止画の場合cpuのみ\">静止画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合cpuのみ\">動画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その1</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その1</h1>\n      <p>Google Coral USB Acceleratorのインストールメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<p>参考サイト:\n<a href=\"https://qiita.com/rhene/items/7b34f60b73645d430789\">RaspberryPi 4でCoral USB TPU Accelerator(EdgeTPU)をとりあえず使う</a></p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<h2 id=\"edgetpu用ライブラリのインストール\">EdgeTPU用ライブラリのインストール</h2>\n\n<p>下記コマンドを実行して、EdgeTPU用ライブラリ(ドライバ類)をインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/coral-edgetpu.list\ncurl https://packages.cloud.google.com/apt/doc/apt-key.gpg | <span class=\"nb\">sudo </span>apt-key add -\n\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># 通常版をインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libedgetpu1-std\n<span class=\"c\"># または、最大クロック版</span>\n<span class=\"c\"># sudo apt install libedgetpu1-max</span>\n</code></pre></div></div>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 coral\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral\n<span class=\"nb\">cd</span> /work/coral\npyenv <span class=\"nb\">local </span>coral \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<p>numpyのinstallで失敗するので、以下を実行しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n</code></pre></div></div>\n\n<h2 id=\"tfliteモジュールのインストール\">TFLiteモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install  </span>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nどれをインストールするかは<a href=\"https://www.tensorflow.org/lite/guide/python\">Python quickstart</a>で確認<br />\n========= 例えば、ubuntu/raspbianのときはpythonのバージョンに応じて以下のどれかを指定 ==============</p>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (x86-64)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl</td>\n      </tr>\n    </tbody>\n  </table>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (ARM 32)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl</td>\n      </tr>\n    </tbody>\n  </table>\n</blockquote>\n\n<h2 id=\"coral-usb-acceleratorの接続と確認\">Coral USB Acceleratorの接続と確認</h2>\n\n<p>USBポートに Coral USB Accelerator を接続する</p>\n\n<p>認識されたことを確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下の表示があったら正常に認識されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>«省略»\nBus XXX Device YYY: ID 1a6e:089a Global Unichip Corp. \n«省略»\n</code></pre></div></div>\n\n<h1 id=\"動作確認サンプルプログラム\">動作確認(サンプルプログラム)</h1>\n\n<h2 id=\"サンプルソースのインストール\">サンプルソースのインストール</h2>\n\n<p>Githubからソースをダウンロードする</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/\ngit<span class=\"k\">**</span> clone https://github.com/google-coral/tflite.git\n</code></pre></div></div>\n\n<h2 id=\"サンプルプログラムの実行その1-classification\">サンプルプログラムの実行(その1) classification</h2>\n\n<h3 id=\"プログラムディレクトリへの移動\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/classification/\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh \n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py \n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n<p>結果の例は以下。<br />\n結果は「Ara macao(コンゴウインコ)」と表示されている。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference on Edge TPU is slow because it includes loading the model into Edge TPU memory.\n12.4ms\n4.2ms\n4.1ms\n4.2ms\n4.2ms\n-------RESULTS--------\nAra macao (Scarlet Macaw): 0.77734\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n\n<p><a id=\"CPUonlydiff\"> </a></p>\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合もCoral USB Acceleratorを接続しておかないとエラーになる。<br />\n接続しなくても実行できるようにするには以下のパッチを適用し、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">-cpu</code>オプションを指定する。</p>\n\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/python/examples/classification/classify_image.py b/python/examples/classification/\n</span><span class=\"gi\">> classify_image.py\n</span><span class=\"gh\">index 75f1d76..44fb798 100644\n</span><span class=\"gd\">--- a/python/examples/classification/classify_image.py\n</span><span class=\"gi\">+++ b/python/examples/classification/classify_image.py\n</span><span class=\"p\">@@ -12,7 +12,7 @@</span>\n<span class=\"err\">#</span> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n # See the License for the specific language governing permissions and\n # limitations under the License.\n<span class=\"gd\">-r\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span><span class=\"gi\">+\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span>\n    To run this code, you must attach an Edge TPU attached to the host and\n    install the Edge TPU runtime (`libedgetpu.so`) and `tflite_runtime`. For\n<span class=\"p\">@@ -64,9 +64,12 @@</span> def load_labels(path, encoding='utf-8'):\n       return {index: line.strip() for index, line in enumerate(lines)}\n\n\n<span class=\"gd\">-def make_interpreter(model_file):\n</span><span class=\"gi\">+def make_interpreter(model_file, cpu=False):\n</span>   model_file, *device = model_file.split('@')\n<span class=\"gd\">-  return tflite.Interpreter(\n</span><span class=\"gi\">+  if cpu :\n+    return tflite.Interpreter(model_path=model_file)\n+  else :\n+    return tflite.Interpreter(\n</span>       model_path=model_file,\n       experimental_delegates=[\n           tflite.load_delegate(EDGETPU_SHARED_LIB,\n<span class=\"p\">@@ -92,11 +95,19 @@</span> def main():\n   parser.add_argument(\n       '-c', '--count', type=int, default=5,\n       help='Number of times to run inference')\n<span class=\"gi\">+  parser.add_argument(\n+      '--cpu', action='store_true',\n+      help='use cpu only(default:use with TPU)')\n</span>   args = parser.parse_args()\n\n+  if args.cpu :\n<span class=\"gi\">+    print('**** USE CPU ONLY!! ****')\n+  else :\n+    print('**** USE WITH TPU ****')\n+\n</span>   labels = load_labels(args.labels) if args.labels else {}\n\n-  interpreter = make_interpreter(args.model)\n<span class=\"gi\">+  interpreter = make_interpreter(args.model, args.cpu)\n</span>   interpreter.allocate_tensors()\n\n   size = classify.input_size(interpreter)\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"サンプルプログラムの実行その2-detection\">サンプルプログラムの実行(その2) detection</h2>\n\n<h3 id=\"プログラムディレクトリへの移動-1\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/detection\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール-1\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh\n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行-1\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<p>結果の例は以下。<br />\n以下の表示と同時に認識結果の画像が別ウィンドウで表示される。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference is slow because it includes loading the model into Edge TPU memory.\n27.90 ms\n11.59 ms\n11.36 ms\n11.89 ms\n11.10 ms\n-------RESULTS--------\ntie\n  id:     31\n  score:  0.83984375\n  bbox:   BBox(xmin=226, ymin=417, xmax=290, ymax=539)\nperson\n  id:     0\n  score:  0.83984375\n  bbox:   BBox(xmin=2, ymin=5, xmax=507, ymax=590)\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行-1\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションを指定すると、結果画像を保存するとともに、表示を行う。<br />\n指定しなければ認識だけ行う(結果の画像表示もしない)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションによる出力ファイルの形式は指定した拡張子で決定される。jpgやbmpなど。<br />\nrawデータで出力した場合(拡張子rgb)は、以下のコマンドでjpgやbmpに変換できる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.jpg\n</code></pre></div>  </div>\n\n  <p>または</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.bmp\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合でCoral USB Acceleratorを接続していなくてエラーになる場合は<br />\n<a href=\"#CPUonlydiff\">こちら</a>を参照</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>UbuntuをNative環境にインストールする(18.04)</title>\n  </head>\n  <body>\n    <header>\n      <h1>UbuntuをNative環境にインストールする(18.04)</h1>\n      <p>Ubunt(18.04)をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntu-をnative環境virtualboxではなくにインストールする\">Ubuntu をNative環境(Virtualboxではなく)にインストールする</h1>\n\n<p><a href=\"/memoBlog/2019/06/26/install1804.html\">Ubuntu 18.04のインストール</a>ではVirtualbox環境にUbuntuをインストールする手順を書いたが、ここではNative環境にインストールする手順を説明する。</p>\n\n<p>ハードウェア構成としては、Ubuntuを外付けHDDにインストールし、内蔵ディスクのWindowsは消さずにデュアルブート環境にする。<br />\n手順はPCはNECのLavie all-in-oneタイプ(ちょっと古い奴)で確認している。<br />\nBIOS関連など、PC固有の機能に左右される部分は機種によって異なるので注意。</p>\n\n<h2 id=\"前準備\">前準備</h2>\n\n<h3 id=\"hddをgpt化\">HDDをGPT化</h3>\n<p>インストールするHDDのパーティションがMBRだとEFIブートができないので、<br />\n対象ハードディスクのパーテイションテーブルをGPTに変更<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://pc-karuma.net/windows-10-convert-mbr-gpt-disk/\">Windows10 - MBRディスク ⇔ GPTディスクに変換(変更)</a></li>\n</ul>\n\n<h3 id=\"インストールメディアでインストーラ起動\">インストールメディアでインストーラ起動</h3>\n<p>インストールメディアはブータブルUSBメモリを作成すると便利<br />\nブータブルUSBメモリの作成は以下を参照</p>\n<ul>\n  <li><a href=\"https://forest.watch.impress.co.jp/library/software/rufus/?fbclid=IwAR0Ry5oRt3jOegmkkswUQmudtvuleLCkH44-Tx8brnS0VYQJLQLBmGtT5Lw\">窓の杜 Rufus</a></li>\n  <li><a href=\"https://pc-freedom.net/software/how-to-use-rufus/?fbclid=IwAR1bXsLVQviiwpcQSZapci1vgJKF4rFv1nmIh7knZkrdQDJkGh7BLTrcXi4\">RufusでLinuxのインストールメディアを作る</a></li>\n  <li><a href=\"https://rufus.ie/\">本家</a></li>\n</ul>\n\n<p>ダウンロードしたファイルはインストーラではなく、ポータブル版の実行ファイル。<br />\n大体直感的に使えるけど、<strong><em>UEFI モードで起動できるようにするにはパーティション構成でGPTを選択しないといけない</em></strong>らしい。<br />\nGPT にしておけば、UEFI モードでブートするPCのbootデバイスの優先順位をUSBをHDDより高くしておけば対象のHDDからブートできる。</p>\n\n<p>これで逐一CD-Rを焼かなくて済む。<br />\nまた、起動もCD-Rより高速。</p>\n\n<h2 id=\"対象ハードディスクにインストール\">対象ハードディスクにインストール</h2>\n<p>以下を参照。</p>\n<ul>\n  <li><a href=\"https://linuxfan.info/ubuntu-18-04-install-guide\">Ubuntu 18.04 LTSインストールガイド【スクリーンショットつき解説】</a></li>\n</ul>\n\n<h2 id=\"再起動してbiosセットアップメニューを起動\">再起動してBIOSセットアップメニューを起動</h2>\n<p>NEC LAVIEの場合、電源ON時にF2キーを連打し、BIOSセットアップメニューを表示<br />\n「Boot」の「Boot Priority Order」の起動順序で「Ubuntu」を「Windows」の上に持ってくる。<br />\nその後、 saveしてreset。</p>\n\n<h2 id=\"基本的な初期設定\">基本的な初期設定</h2>\n<p>Virtualbox版の手順の<a href=\"/memoBlog/2019/06/26/install1804.html\">Ubuntu 18.04のインストール</a>を参照。<br />\n基本的にこれと同じで大丈夫(GuestAdditionのインストール、grub-pcのインストール先情報の変更を除く)</p>\n\n<h3 id=\"もっと簡単に設定する方法があった\">もっと簡単に設定する方法があった</h3>\n<p>以下の項目はもっと簡単に設定する方法があったのでメモ。</p>\n\n<ul>\n  <li>「ウィンドウが勝手に最大化するのをやめる」</li>\n  <li>「ウィンドウにマウスを乗せるとフォーカスされるようにする」</li>\n  <li>「デスクトップからゴミ箱とホームを消す」</li>\n</ul>\n\n<p>これらの設定はdconf-editorでなく、gnome-tweaksを使うと簡単(dconf-editorでもOK)</p>\n\n<p>gnome-tweaksのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\ngnome-tweaks\n</code></pre></div></div>\n<ul>\n  <li>「ウィンドウにマウスを乗せるとフォーカスされるようにする」\n    <ul>\n      <li>「ウィンドウ」で「ウィンドウフォーカス」を「Sloppy」にする</li>\n    </ul>\n  </li>\n  <li>「デスクトップからゴミ箱とホームを消す」\n    <ul>\n      <li>「デスクトップ」で選択</li>\n    </ul>\n  </li>\n  <li>「CTRLとCapsLockの入れ替えを行う」(Virtualboxではホスト側で入れ替えてたので不要だった)\n    <ul>\n      <li>「キーボードとマウス」で「追加のレイアウトオプション」をクリック\n        <ul>\n          <li>Ctrl position」の「CapsLockをCtrlとして扱う」を選択する。\n            <ul>\n              <li>「CtrlとCapsLockを入れ替える」だとうまく動かないので注意。</li>\n              <li>UnityとGNOME Flashbackでは設定は別らしい。</li>\n              <li>GNOME Flashbackでは「CtrlとCapsLockを入れ替える」でもOK。</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>「ウィンドウが勝手に最大化するのをやめる」\n    <ul>\n      <li>設定項目が見当たらないので、dconf editorで設定する。\n        <ul>\n          <li>dconf editor起動して以下を変更\n            <ul>\n              <li>/org/gnome/metacity/edge-tiling false</li>\n              <li>/org/gnome/mutter/edge-tiling false</li>\n              <li>/org/gnome/shell/overrides/edge-tiling false</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"sshのインストール\">sshのインストール</h1>\n<p>WindowsPCにあるデータをubuntuPCにキーボードで打ち込むのは効率が悪いので、最も簡単なsshでリモートログインできるようにしてみる。</p>\n\n<p>以下のコマンドでsshサーバをインストールし、サーバを開始する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n<p>クライアントからTeraTermなどでsshで対象マシンのポート22に接続する</p>\n\n<h1 id=\"vncで画面共有する\">vncで画面共有する</h1>\n\n<p>sshリモートログインよりもうちょっと使いやすくしたいので、vncで画面共有するようにしてみる。</p>\n\n<p>chrome リモートデスクトップ等とは異なり、コンソールに表示している画面を共有して操作するもの。<br />\n使用したクライアント(VNC-Viewer)がヘボいからなのか、ちょっと反応鈍いけど、<br />\nコンソールで作業していた実行状況を確認したり<br />\n会社でトラブった人のリモートサポートなんかに使えるかも。</p>\n\n<p>やり方自体はとてもシンプル。<br />\n特にインストールとかも必要ない。<br />\n(クライアント側はVNC viewerなどを実行する必要があるけど、こっちもインストールは不要(単体実行))</p>\n\n<p>例によって手順の説明は他力本願(^^ゞ<br />\n参照:</p>\n<ul>\n  <li><a href=\"https://www.yokoweb.net/2019/12/09/ubuntu-18_04-desktop-vnc-remote/\">【Ubuntu 18.04 Desktop】WinやMacパソコンからVNCでリモート接続し画面共有する </a></li>\n</ul>\n\n<p>そのままトレースすればできるけど、ちょっと「ん?」と思ってしまうエラーが。<br />\n同じページの<a href=\"https://www.yokoweb.net/2019/12/09/ubuntu-18_04-desktop-vnc-remote/#toc5\">ココ</a>に解決策がかかれているけど、ちゃんと前もって書いておいてほしいもんだ(笑)。<br />\n解決策の要約は以下の通り。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false</span>\n<span class=\"c\"># 実行後再起動必要</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ndconf editor でも設定可能。<br />\nなので、dconf editorとの設定操作とバッティングしないように注意<br />\ndconf editorで設定する場合は以下<br />\n   /org/gnome/desktop/remote-access/require-encryption</p>\n</blockquote>\n\n<p>あくまで共有なのでコンソール側でGUIログインしてないとつながらない。<br />\n反応鈍いので、普段使いにはちょっとストレスかも。<br />\nchrome リモートデスクトップ使えるならそっち使ったほうがいいかな。</p>\n\n<h1 id=\"chromeリモートデスクトップのインストール\">chromeリモートデスクトップのインストール</h1>\n\n<p>chromeリモートデスクトップ による接続は画面の共有ではなく、新しいセッションによる接続となる(Xclientみたいなもん?)。<br />\nwindowsマシンに接続した場合は表示画面のミラーリングだったが。</p>\n\n<p>chromeのインストール&リモートデスクトップのインストールはWindowsとほぼ同じ。<br />\n以下参考ページ</p>\n<ul>\n  <li><a href=\"https://www.google.com/chrome/\">Google Chrome フェブブラウザ</a></li>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>パソコンでリモート アクセスを設定する</li>\n      <li>パソコンにリモート アクセスする</li>\n    </ul>\n  </li>\n</ul>\n\n<p>接続すると、開始するセッションの選択画面になるので、「Ubuntu」を選択。GNOME Flashbackだとつながらない…なんで??</p>\n\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。このダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></li>\n</ul>\n\n<p>要約すると\n<code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下を入力</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n<h2 id=\"コンソール画面を共有したい場合\">コンソール画面を共有したい場合</h2>\n\n<p>chromeリモートデスクトップでvnc同様のコンソール画面の共有をすることも可能。<br />\n設定方法は以下を参照。</p>\n<ul>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>他のユーザとパソコンを共有する</li>\n    </ul>\n  </li>\n</ul>\n\n<p>この方法だと、アクセスコードの生成(コンソール側)/アクセスコードの入力(リモート側)/アクセス許可(コンソール側)と手続きが少々煩雑(毎回必要)。<br />\n画面共有で操作するにはvncのほうが簡単かな?</p>\n\n<h1 id=\"biosセットアップメニューでのブートマネージャの表示名を変更する\">BIOSセットアップメニューでのブートマネージャの表示名を変更する</h1>\n\n<p>ubuntu をインストールした後、BIOSセットアップメニューでブート優先順位を指定しようとすると<br />\nubuntuのブートマネージャが2つ表示されて、どちらを選べばよいのか見分けがつかない。<br />\n(機種によってはpathが表示されて見分けられるものもあるらしいが、私のPCはそうなってない)</p>\n\n<p>そこで、表示名を変更して見分けがつくようにしてみる。</p>\n\n<p>以下、参考ページ</p>\n<ul>\n  <li><a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1383uefinvnm/uefinvnm.html\">bcdeditでUEFIのブート・エントリの名前を変更する</a></li>\n</ul>\n\n<p>まず、Windowsを起動し、管理者権限でコマンドプロンプト(cmd.exe)を実行する。\nPowerShellではちょっとテクニックが要る(というほど大げさではないが)みたいなので、\nコマンドプロンプトで実行するのが無難。</p>\n\n<p>現在の状態の確認</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /enum firmware\n</code></pre></div></div>\n\n<p>実行結果</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ファームウェアのブート マネージャー\n--------------------------------\nidentifier              {fwbootmgr}\ndisplayorder            {bootmgr}\n                        {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\n                        {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ntimeout                 1\n\nWindows ブート マネージャー\n--------------------------------\n《省略》\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\ubuntu\\shimx64.efi\ndescription             ubuntu\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\Ubuntu\\grubx64.efi\ndescription             ubuntu\n</code></pre></div></div>\n\n<p>表示名を変更する<br />\n指定するuuidは現状の確認で確認したuuidに置き換えること。<br />\ndescriptionが表示名なので、これを好みの名前に変更する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /set {9b7f627e-7edc-11ea-84b2-806e6f6e6963} description  \"ubuntu shimx64\"\nbcdedit /set {9b7f627f-7edc-11ea-84b2-806e6f6e6963} description  \"ubuntu grubx64\"\n</code></pre></div></div>\n\n<p>結果を確認する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /enum firmware\n</code></pre></div></div>\n\n<p>実行結果</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ファームウェアのブート マネージャー\n--------------------------------\nidentifier              {fwbootmgr}\ndisplayorder            {bootmgr}\n                        {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\n                        {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ntimeout                 1\n\nWindows ブート マネージャー\n--------------------------------\n《省略》\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\ubuntu\\shimx64.efi\ndescription             ubuntu shimx64\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\Ubuntu\\grubx64.efi\ndescription             ubuntu grubx64\n</code></pre></div></div>\n\n<p>ちなみに、shimx64.efi と grubx64.efi の違いは、セキュアブートの対応/非対応の違いである。<br />\n通常(セキュアブート有効のハズ)はshimx64.efiで良いと思われる。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://netlog.jpn.org/r271-635/2019/08/uefi_windows10_ubuntu_install.html\">UEFIのWindows 10マシンにUbuntu 18.04を追加インストールしデュアルブート化する</a>\n    <ul>\n      <li>「UbuntuがUEFIのブートメニューに登録されていることを確認」のあたり</li>\n    </ul>\n  </li>\n</ul>\n\n<p>この設定はbuntuを再インストールすると上書きされてしまうので、再度変更する必要がある。</p>\n\n<h1 id=\"grubのboot-menuの表示などの変更方法\">GRUBのboot menuの表示などの変更方法</h1>\n\n<p>デフォルトのubuntuインストール状態では、GRUBのブートメニューが表示されない。<br />\nそこで、ブートメニューを表示するように変更してみる。<br />\nついでに、設定する箇所が同じなので、</p>\n\n<ul>\n  <li>タイムアウトまでの時間の変更(あっ?と思った瞬間にブートされちゃうと悲しいので)</li>\n  <li>スプラッシュスクリーンを表示しなくする(ちゃんとブートしてるか心配なので(笑))</li>\n</ul>\n\n<p>も設定しておく。</p>\n\n<p>まず、ubuntuを起動してターミナル起動</p>\n\n<p>rootでないとできないことなので、rootでbashを実行しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>bash                                     \n</code></pre></div></div>\n\n<p>設定ファイル <code class=\"language-plaintext highlighter-rouge\">/etc/default/grub</code> を以下の内容で変更する</p>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- grub.org\t2020-05-08 06:16:59.908079737 +0900\n</span><span class=\"gi\">+++ grub\t2020-05-08 06:17:13.540255464 +0900\n</span><span class=\"p\">@@ -3,11 +3,11 @@</span>\n # For full documentation of the options in this file, see:\n #   info -f grub -n 'Simple configuration'\n \n<span class=\"gd\">-GRUB_DEFAULT=0\n-GRUB_TIMEOUT_STYLE=hidden\n-GRUB_TIMEOUT=10\n</span><span class=\"gi\">+GRUB_DEFAULT=saved\n+GRUB_TIMEOUT_STYLE=menu\n+GRUB_TIMEOUT=30\n</span> GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`\n<span class=\"gd\">-GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash\"\n</span><span class=\"gi\">+GRUB_CMDLINE_LINUX_DEFAULT=\n</span> GRUB_CMDLINE_LINUX=\"\"\n \n # Uncomment to enable BadRAM filtering, modify to suit your needs\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">GRUB_DEFAULT</code> がデフォルトの選択項目。 <code class=\"language-plaintext highlighter-rouge\">saved</code> は前回選択項目。rebootのときだけ??動きがイマイチわからんかった。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_TIMEOUT_STYLE</code> がメニュー表示形式。<code class=\"language-plaintext highlighter-rouge\">hidden</code> は表示しない、<code class=\"language-plaintext highlighter-rouge\">menu</code> はメニューを表示する。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_TIMEOUT</code> がタイムアウトまでの時間。単位は秒。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_CMDLINE_LINUX_DEFAULT</code> がLinux起動時のコマンドラインオプション。<code class=\"language-plaintext highlighter-rouge\">quiet splash</code> を指定すると起動メッセージを表示せず、スプラッシュスクリーンを表示する。これを削除することで起動メッセージが表示される</p>\n\n<p>変更した設定をcfgファイルに反映する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>grub-mkconfig <span class=\"nt\">-o</span> /boot/grub/grub.cfg            \n</code></pre></div></div>\n\n<p>これで、次回起動時からGRUBのブートメニューが変更される</p>\n\n<p>以下、参考ページ:</p>\n<ul>\n  <li><a href=\"http://www.usupi.org/sysad/202.html\">いますぐ実践! Linux システム管理</a></li>\n</ul>\n\n<p>この項目と直接関係ないけど、起動時にのfsckを実行する方法の参考ページ。</p>\n<ul>\n  <li><a href=\"https://linux.just4fun.biz/?Linux%E7%92%B0%E5%A2%83%E8%A8%AD%E5%AE%9A/%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E9%96%93%E9%9A%94%E3%81%AE%E7%A2%BA%E8%AA%8D\">Linux環境設定/起動時のファイルシステムチェック間隔の確認 </a></li>\n</ul>\n\n<h1 id=\"usb-hdd接続-ubuntuのboot未接続windowsのbootにする方法\">USB-HDD接続→ Ubuntuのboot、未接続→Windowsのbootにする方法</h1>\n\n<p>ubuntuがインストールされたUSB-UDDが接続されていたらubuntuが、接続されていなければ内蔵HDDのWindowsが自動的に起動するようにしてみる。<br />\n(デフォルトのインストール状態だとブート優先順位を変更しないと切り替えられない)<br />\nちょうどFDDブートのような感じ。</p>\n\n<p>BIOSセットアップにより、ブートモードはUEFIブートで、ブート優先順位はubuntuの方を高く設定しておく。</p>\n\n<p>まず、ubuntuを起動する</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/boot/efi/EFI/ubuntu/grub.cfg</code> を以下のように変更する。<br />\nrootでないとアクセスできないので、<code class=\"language-plaintext highlighter-rouge\">sudo bash</code>  して rootでshellを動かして作業するのが良い。</p>\n\n<ul>\n  <li>元のファイル\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>search.fs_uuid 60c491cd-126d-4f4a-a321-84bb2e0d9068 root hd1,gpt1 \nset prefix=($root)'/boot/grub'\nconfigfile $prefix/grub.cfg\n</code></pre></div>    </div>\n  </li>\n  <li>変更後のファイル\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>if search.fs_uuid 60c491cd-126d-4f4a-a321-84bb2e0d9068 root hd1,gpt1 ;then\n set prefix=($root)'/boot/grub'\n configfile $prefix/grub.cfg\nelse\n set timeout_style=menu\n set timeout=0\n menuentry 'Windows Boot Manager (on /dev/sda2)' --class windows --class os $menuentry_id_option 'osprober-efi-2A43-3D28' {\n    insmod part_gpt\n    insmod fat\n    set root='hd0,gpt2'\n    if [ x$feature_platform_search_hint = xy ]; then\n       search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  2A43-3D28\n    else\n       search --no-floppy --fs-uuid --set=root 2A43-3D28\n    fi\n    chainloader /EFI/Microsoft/Boot/bootmgfw.efi\n}\nfi\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>メモ:</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">60c491cd-126d-4f4a-a321-84bb2e0d9068</code>  は ubuntuのインストールされたパーティションのuuidなので、接続したUSB-HDDDのuuidに合わせて変更する。\n    <ul>\n      <li>パーティションのuuidは以下で確認可能。\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"s1\">' \\/boot\\/efi '</span> /etc/mtab         <span class=\"c\"># デバイスファイルを確認する</span>\n<span class=\"nb\">sudo </span>blkid /dev/sda2                   <span class=\"c\"># 確認したデバイスファイルを指定する</span>\n</code></pre></div>        </div>\n      </li>\n      <li>あるいは、元のファイルのuuidをコピるのでもOK。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">2A43-3D28</code>はEFIシステムパーティションのuuidなので、環境に合わせて変更する。\n    <ul>\n      <li>パーティションのuuidは以下で確認可能。\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"s1\">' \\/ '</span> /etc/mtab                  <span class=\"c\"># デバイスファイルを確認する</span>\n<span class=\"nb\">sudo </span>blkid /dev/sdb1                   <span class=\"c\"># 確認したデバイスファイルをしてする</span>\n</code></pre></div>        </div>\n      </li>\n      <li>あるいは、<code class=\"language-plaintext highlighter-rouge\">/boot/grub/grub.cfg</code> の <code class=\"language-plaintext highlighter-rouge\">menuentry 'Windows Boot Manager ~</code>  の部分をパクってきても可。</li>\n    </ul>\n  </li>\n  <li>このファイルはbuntuを再インストールすると上書きされてしまうので、再度編集する必要がある。</li>\n</ul>\n\n<p>処理の解説:<br />\n元のgrub.cfgではUSB-HDDが接続されていなければ <code class=\"language-plaintext highlighter-rouge\">$prefix/grub.cfg</code>  が見つからないので、GRUBメニューが表示されない。<br />\nそこで、<code class=\"language-plaintext highlighter-rouge\">search.fs_uuid</code> の実行結果により、ディスクが見つかったら従来通りの処理、<br />\n見つからなかったらWindows Boot Managerを起動するようにしている。</p>\n\n<h3 id=\"参考情報\">参考情報</h3>\n<p>WindowsからEFIシステムパーティションのファイルを編集するには、このあたりを参考に。</p>\n<ul>\n  <li><a href=\"https://bi.biopapyrus.jp/os/win/dualboot-fix-bootmenu.html\">デュアルブートから Ubuntu を削除する方法</a><br />\nマウントする部分だけね。</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD(その2)</h1>\n      <p>openVINOのSSDのサンプルプログラムのモデルデータを変更してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> でSSDを動かしてみたが、\n検出できるオブジェクトの種類が少なくてちょっと寂しかったので、別のモデルがないか探してみた。</p>\n\n<p>で、調べてみると、openCVのopen_model_zoo以外にもTensorFlowの公式モデルなどをダウンロードして変換するスクリプトが用意されていた。<br />\nで、以下手順。</p>\n\n<h1 id=\"モデルのダウンロードモデルのirへの変換\">モデルのダウンロード&モデルのIRへの変換</h1>\n\n<h4 id=\"テンポラリディレクトリの作成移動\">テンポラリディレクトリの作成&移動</h4>\n\n<p>とりあえず作業用のディレクトリを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/temp\n<span class=\"nb\">cd</span> /work/temp\n</code></pre></div></div>\n\n<h3 id=\"使用できるモデルの一覧を表示\">使用できるモデルの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py  <span class=\"nt\">--print_all</span>\n</code></pre></div></div>\n\n<p>ちなみに、モデル毎の設定は以下にあるので、雰囲気で解読してちょ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>${INTEL_OPENVINO_DIR}/deployment_tools/open_model_zoo/models/public/${modelname}/model.yml\n</code></pre></div></div>\n\n<h3 id=\"このへんのモデルを使ってみる\">このへんのモデルを使ってみる</h3>\n\n<p>なんとなく、mobilenetが小さそうなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssd_mobilenet_v2_coco\n</code></pre></div></div>\n\n<p>または</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssdlite_mobilenet_v2\n</code></pre></div></div>\n\n<p>ssdlightの方がモデルデータが小さい。その分精度は落ちるらしい。<br />\n検出できるオブジェクトの種類は同じ。<br />\n出力は90種類だが、途中欠番があるみたいなので実質80種類くらい。<br />\n変わったところでは「テディベア」なんてのもある。試してみたらちゃんと認識した(あたりまえか…)。<br />\ncocoデータセット<a href=\"http://cocodataset.org/#home\">http://cocodataset.org/#home</a>なので、有名どころですね。<br />\nあ、「80 object categories 91 stuff categories」ってちゃんと書いてある…</p>\n\n<h3 id=\"ダウンロード\">ダウンロード</h3>\n\n<p>まずはダウンロード。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/</code>にモデルがダウンロードされる。</p>\n\n<h3 id=\"モデルデータをirファイルへ変換\">モデルデータをIRファイルへ変換</h3>\n\n<p>もとのモデルデータはTensorFlowで使用するProtocolBuffer形式なので、openVINOで使用できるIR形式に変換する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/converter.py <span class=\"nt\">--precisions</span> FP16 <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/FP16/</code>にIRモデルが出来る。</p>\n\n<h3 id=\"そのままの場所で使用しても良いが他のモデルとまとめておく\">そのままの場所で使用しても良いが、他のモデルとまとめておく</h3>\n\n<p>モデルがあちこちにあると管理しずらくなるので、他のモデルと同じところに置いておく。<br />\n必要なのはxmlとbin。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>public/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>/FP16/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>.<span class=\"o\">{</span>xml,bin<span class=\"o\">}</span> /work/NCS2/openvino_models/FP16/\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">.{xml,bin}</code>のところにスペースなどを入れてしまうとうまく動かないので注意。<br />\n結構「あとで読みやすいように」と入れてしまいがち(特にスクリプト書くとき)なので注意。</p>\n\n<h3 id=\"ラベルファイルの作成\">ラベルファイルの作成</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/work/NCS2/openvino_models/FP16/${modelname}.labels</code>にラベルデータを作成しておく。<br />\nなくても可。<br />\n作り方は後述。</p>\n\n<h3 id=\"実行\">実行</h3>\n\n<p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> の「デモ実行」と同じ手順で\nモデルファイルを差し替えて(<code class=\"language-plaintext highlighter-rouge\">--model</code>オプション)実行すれば良い。</p>\n\n<h1 id=\"ラベルファイルの作成方法\">ラベルファイルの作成方法</h1>\n\n<p>ラベルデータはモデルデータには含まれていないようなので、作成する方法を検討してみた。</p>\n\n<h3 id=\"tensorflowのmodelsモジュールをダウンロード\">tensorflowのmodelsモジュールをダウンロード</h3>\n\n<p>まず、モデルデータの作成情報のあるモジュールをダウンロードしておく。<br />\ngitでなくてもzipをダウンロードして展開しておいても可(ちょっとデカいので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git models_tf\n</code></pre></div></div>\n\n<h3 id=\"作業ディレクトリに移動\">作業ディレクトリに移動</h3>\n\n<p>あとでpythonプログラムを作成するときに色々面倒がないので、作業ディレクトリはココで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models_tf/research\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">object_detection/samples/configs</code>から対応するconfigファイルを探して(なんとなく雰囲気で探せ!)表示<br />\n<code class=\"language-plaintext highlighter-rouge\">label_map_path</code>に記載されたファイルがlabel_mapファイル<br />\nこのとき、PATH_TO_BE_CONFIGURED は <code class=\"language-plaintext highlighter-rouge\">object_detection/data</code> に読み替えること</p>\n\n<p>ssd_mobilenet_v2_cocoの場合は以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/samples/configs/ssd_mobilenet_v2_coco.config\n</code></pre></div></div>\n\n<p>上記ファイルの場合、label_mapは以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/data/mscoco_label_map.pbtxt\"\n</code></pre></div></div>\n\n<p>こにファイルにIDとラベルが定義されているが、そのままラベルファイルとしては認識できない。<br />\nIDには途中抜けがあるので注意(そのままgrepで抜き出してはダメ)</p>\n\n<h2 id=\"ラベルデータ変換プログラムを作成する\">ラベルデータ変換プログラムを作成する</h2>\n\n<p>label_map.pbtxtからラベル一覧を取得するのを手作業で行うのは大変なので、プログラムを作成する。</p>\n\n<h3 id=\"protocのインストール\">protocのインストール</h3>\n\n<p>まずは必要なモジュールのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n</code></pre></div></div>\n\n<h3 id=\"protoファイルからpythonモジュールを作成する\">protoファイルからpythonモジュールを作成する</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>protoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"変換プログラムのソース\">変換プログラムのソース</h3>\n\n<p>label_mapからテーブルを作成するスクリプト(labelmap2labels.py)をカレントディレクトリに作成する。<br />\nやっつけ仕事なので、かなりテキトー(笑)、、、</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">object_detection.utils</span> <span class=\"kn\">import</span> <span class=\"n\">label_map_util</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"==== USAGE ====\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"    python </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> label_map_file\"</span><span class=\"p\">)</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># パラメータが1個でない\n</span>    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_map_file = \"object_detection/data/mscoco_complete_label_map.pbtxt\"\n</span><span class=\"n\">label_map_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># 第一パラメータのファイルが存在しない\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"error: '</span><span class=\"si\">{</span><span class=\"n\">label_map_file</span><span class=\"si\">}</span><span class=\"s\">' not exist</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_mapからカテゴリインデックスを作成\n</span><span class=\"n\">category_index</span> <span class=\"o\">=</span> <span class=\"n\">label_map_util</span><span class=\"p\">.</span><span class=\"n\">create_category_index_from_labelmap</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span>\n\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># print(i)\n</span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">category_index</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">\"name\"</span><span class=\"p\">]</span>\n    <span class=\"k\">except</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'{name}\\t# {i}')\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n    \n<span class=\"c1\"># 個数確認のためにダミーを出力\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スクリプトの実行\">スクリプトの実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.py label_map_file\n</code></pre></div></div>\n\n<p>結果は標準出力へ出力されるので、ファイルにcastして使用する</p>\n\n<p>例:</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.pyobject_detection/data/mscoco_complete_label_map.pbtxt <span class=\"o\">></span> mscoco_complete.labels\n</code></pre></div></div>\n\n<p>出来上がったlabelsファイルを必要なところへコピーして使ってちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO で顔検出(特定人物識別)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO で顔検出(特定人物識別)</h1>\n      <p>openVINOの顔検出(特定人物識別)のサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOで顔検出(特定人物識別)するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"ソースをワークディレクトリにコピー\">ソースをワークディレクトリにコピー</h1>\n\n<p>ファイルのオーナがrootなので、編集しやすいようにワークディレクトリにソースをコピーし、そこで作業する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>face_recognition_demo/\n</code></pre></div></div>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p>いくつかのモデルデータが必要になるので、ダウンロードする。<br />\nワイルドカードでファイル指定したかったので、wgetでなくcurlを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/landmarks-regression-retail-0009/FP16/landmarks-regression-retail-0009.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-reidentification-retail-0095/FP16/face-reidentification-retail-0095.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\n<span class=\"nb\">cd</span> ..\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ncurlは「カレントディレクトリにターゲットと同じファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-O</code> と 「任意のファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-o</code>オプションしかなく、\nwgetの「ターゲットと同じファイル名で保存先ディレクトリを指定して保存」の<code class=\"language-plaintext highlighter-rouge\">-P</code>に相当するオプションがないので、\nカレントディレクトリを保存先に移動してから<code class=\"language-plaintext highlighter-rouge\">-O</code> オプションでコマンドを実行する。</p>\n</blockquote>\n\n<h1 id=\"足りないモジュールのインストール\">足りないモジュールのインストール</h1>\n\n<p>使用するモジュールでこれまでのお試しで未インストールのモジュールがあるのでインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>scipy\n</code></pre></div></div>\n\n<h1 id=\"ソースの修正\">ソースの修正</h1>\n\n<p>ソースはそのままで問題ないが、ちょっと修正しておく。</p>\n\n<p>主な変更内容は以下の通り。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code> オプションの追加と関連処理</li>\n  <li>Unknownと識別できた場合で検出枠の色を変える</li>\n  <li>入力ファイルを絶対パスに変換(不具合対策)</li>\n  <li>出力ファイルのフォーマットのmp4対応を追加(オリジナルはaviのみ対応)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur face_recognition_demo.org/face_recognition_demo.py face_recognition_demo/face_recognition_demo.py\n</span><span class=\"gd\">--- face_recognition_demo.org/face_recognition_demo.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/face_recognition_demo.py\t2019-11-27 06:29:07.507574900 +0900\n</span><span class=\"p\">@@ -62,6 +62,10 @@</span>\n     gallery.add_argument('--run_detector', action='store_true',\n                          help=\"(optional) Use Face Detection model to find faces\" \\\n                          \" on the face images, otherwise use full images.\")\n<span class=\"gi\">+    gallery.add_argument('--run_detector_no_save', action='store_true',\n+                         help=\"(optional) Use Face Detection model to find faces\" \\\n+                         \" on the face images, otherwise use full images.\" \\\n+                         \" not save detected face image.\")\n</span> \n     models = parser.add_argument_group('Models')\n     models.add_argument('-m_fd', metavar=\"PATH\", default=\"\", required=True,\n<span class=\"p\">@@ -142,7 +146,7 @@</span>\n         log.info(\"Building faces database using images from '%s'\" % (args.fg))\n         self.faces_database = FacesDatabase(args.fg, self.face_identifier,\n                                             self.landmarks_detector,\n<span class=\"gd\">-                                            self.face_detector if args.run_detector else None, args.no_show)\n</span><span class=\"gi\">+                                            self.face_detector if args.run_detector or args.run_detector_no_save else None, args.no_show, args.run_detector_no_save)\n</span>         self.face_identifier.set_faces_database(self.faces_database)\n         log.info(\"Database is built, registered %s identities\" % \\\n             (len(self.faces_database)))\n<span class=\"p\">@@ -261,9 +265,8 @@</span>\n             .face_identifier.get_identity_label(identity.id)\n \n         # Draw face ROI border\n<span class=\"gd\">-        cv2.rectangle(frame,\n-                      tuple(roi.position), tuple(roi.position + roi.size),\n-                      (0, 220, 0), 2)\n</span><span class=\"gi\">+        color1 = (0, 220, 0) if identity.id == FaceIdentifier.UNKNOWN_ID else (0, 0, 220)\n+        cv2.rectangle(frame, tuple(roi.position), tuple(roi.position + roi.size), color1, 2)\n</span> \n         # Draw identity label\n         text_scale = 0.5\n<span class=\"p\">@@ -398,19 +401,17 @@</span>\n         try:\n             stream = int(path)\n         except ValueError:\n<span class=\"gd\">-            pass\n</span><span class=\"gi\">+            # 数字でなければ絶対パスに変換\n+            stream = osp.abspath(path)\n</span>         return cv2.VideoCapture(stream)\n \n     @staticmethod\n     def open_output_stream(path, fps, frame_size):\n         output_stream = None\n         if path != \"\":\n<span class=\"gd\">-            if not path.endswith('.avi'):\n-                log.warning(\"Output file extension is not 'avi'. \" \\\n-                        \"Some issues with output can occur, check logs.\")\n</span><span class=\"gi\">+            forcc = cv2.VideoWriter.fourcc(*'mp4v') if path.endswith('.mp4') else cv2.VideoWriter.fourcc(*'MJPG')\n</span>             log.info(\"Writing output to '%s'\" % (path))\n<span class=\"gd\">-            output_stream = cv2.VideoWriter(path,\n-                                            cv2.VideoWriter.fourcc(*'MJPG'), fps, frame_size)\n</span><span class=\"gi\">+            output_stream = cv2.VideoWriter(path, forcc, fps, frame_size)\n</span>         return output_stream\n \n \n<span class=\"gh\">diff -ur face_recognition_demo.org/faces_database.py face_recognition_demo/faces_database.py\n</span><span class=\"gd\">--- face_recognition_demo.org/faces_database.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/faces_database.py\t2019-11-20 06:31:13.481819754 +0900\n</span><span class=\"p\">@@ -36,10 +36,11 @@</span>\n         def cosine_dist(x, y):\n             return cosine(x, y) * 0.5\n \n<span class=\"gd\">-    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False):\n</span><span class=\"gi\">+    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False, no_db_save=False):\n</span>         path = osp.abspath(path)\n         self.fg_path = path\n         self.no_show = no_show\n<span class=\"gi\">+        self.no_db_save = no_db_save\n</span>         paths = []\n         if osp.isdir(path):\n             paths = [osp.join(path, f) for f in os.listdir(path) \\\n<span class=\"p\">@@ -96,7 +97,7 @@</span>\n                     self.add_item(descriptor, label)\n \n     def ask_to_save(self, image):\n<span class=\"gd\">-        if self.no_show:\n</span><span class=\"gi\">+        if self.no_show or self.no_db_save:\n</span>             return None\n         save = False\n         label = None\n<span class=\"p\">@@ -209,12 +210,14 @@</span>\n             match = len(self.database)-1\n         else:\n             filename = \"{}-{}.jpg\".format(label, len(self.database[match].descriptors)-1)\n<span class=\"gd\">-        filename = osp.join(self.fg_path, filename)\n-\n-        log.debug(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n-        if osp.exists(filename):\n-            log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n-        cv2.imwrite(filename, image)\n</span><span class=\"gi\">+        \n+        if name :\n+            filename = osp.join(self.fg_path, filename)\n+            log.info(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n+            if osp.exists(filename):\n+                log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n+            else :\n+                cv2.imwrite(filename, image)\n</span>         return match\n \n     def add_item(self, desc, label):\n</code></pre></div></div>\n\n<h1 id=\"前準備\">前準備</h1>\n\n<p>識別したい顔の画像を適当なディレクトリに保存しておく。ファイル形式はjpgまたはpng。<br />\n一人ずつ1画像で顔部分のみ切り出しておく。<br />\n複数の人の顔を識別したい場合はそれぞれ別々に保存しておく。</p>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"実行用スクリプトの作成\">実行用スクリプトの作成</h2>\n\n<p>実行コマンドが長ったらしくて入力が面倒なので、以下のスクリプト(demo.sh)を作成しておく。<br />\nUbuntuとRaspberrypiを識別して自動でコマンドオプションを変更するようにしてある。 \n作成したら実行属性を付与しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/bin/bash</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"face_recognition_demo.py\"</span>\n\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"       -m_fd models/face-detection-retail-0004.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_lm models/landmarks-regression-retail-0009.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_reid models/face-reidentification-retail-0095.xml\"</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"o\">==</span> <span class=\"s2\">\"armv7l\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Raspberry Pi\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_fd MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_lm MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_reid MYRIAD\"</span>\n<span class=\"k\">else\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Ubuntu\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> --cpu_lib /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so\"</span>\n<span class=\"k\">fi\n\n\nif</span> <span class=\"o\">[</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 0 <span class=\"nt\">-o</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 1 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n\t<span class=\"c\"># パラメータなし/1個はエラー</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\n</span><span class=\"s2\">==== usage ====\"</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"nv\">$0</span><span class=\"s2\"> database_dir input_file [other option(s)]</span><span class=\"se\">\\n\\n\\n</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">exit </span>1\n<span class=\"k\">else\n    </span><span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -fg </span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\"> --input </span><span class=\"k\">${</span><span class=\"nv\">2</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    <span class=\"c\"># 3番目以降すべてのパラメータを追加</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"p\">@</span>:3:<span class=\"p\">(</span><span class=\"nv\">$#-2</span><span class=\"p\">)</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi\n</span><span class=\"nb\">echo</span> <span class=\"s2\">\"python </span><span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\npython <span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n\n<p>第1パラメータに識別子する顔画像を保存したディレクトリ、第2パラメータに入力ビデオファイル名を指定する。<br />\nこれらのパラメータは省略不可。<br />\n追加でオプションを指定したい場合は第3パラメータ以降に指定する。<br />\nたとえば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo.sh data data/video.mp4  <span class=\"nt\">--output</span> result.mp4\n</code></pre></div></div>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python face_recognition_demo.py <span class=\"nt\">-h</span>\nusage: face_recognition_demo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-i</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-o</span> PATH] <span class=\"o\">[</span><span class=\"nt\">--no_show</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-tl</span><span class=\"o\">]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-cw</span> CROP_WIDTH] <span class=\"o\">[</span><span class=\"nt\">-ch</span> CROP_HEIGHT] <span class=\"nt\">-fg</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">--run_detector</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--run_detector_no_save</span><span class=\"o\">]</span>\n                                <span class=\"nt\">-m_fd</span> PATH <span class=\"nt\">-m_lm</span> PATH <span class=\"nt\">-m_reid</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-l</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-c</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]]\n                                <span class=\"o\">[</span><span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]] <span class=\"o\">[</span><span class=\"nt\">-exp_r_fd</span> NUMBER]\n                                <span class=\"o\">[</span><span class=\"nt\">--allow_grow</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit\n\n</span>General:\n  <span class=\"nt\">-i</span> PATH, <span class=\"nt\">--input</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to the input video <span class=\"o\">(</span><span class=\"s1\">'0'</span> <span class=\"k\">for </span>the\n                        camera, default<span class=\"o\">)</span>\n  <span class=\"nt\">-o</span> PATH, <span class=\"nt\">--output</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to save the output video to\n  <span class=\"nt\">--no_show</span>             <span class=\"o\">(</span>optional<span class=\"o\">)</span> Do not display output\n  <span class=\"nt\">-tl</span>, <span class=\"nt\">--timelapse</span>      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Auto-pause after each frame\n  <span class=\"nt\">-cw</span> CROP_WIDTH, <span class=\"nt\">--crop_width</span> CROP_WIDTH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this width\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n  <span class=\"nt\">-ch</span> CROP_HEIGHT, <span class=\"nt\">--crop_height</span> CROP_HEIGHT\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this height\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n\nFaces database:\n  <span class=\"nt\">-fg</span> PATH              Path to the face images directory\n  <span class=\"nt\">--run_detector</span>        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images.\n  <span class=\"nt\">--run_detector_no_save</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images. not save\n                        detected face image.\n\nModels:\n  <span class=\"nt\">-m_fd</span> PATH            Path to the Face Detection model XML file\n  <span class=\"nt\">-m_lm</span> PATH            Path to the Facial Landmarks Regression model XML file\n  <span class=\"nt\">-m_reid</span> PATH          Path to the Face Reidentification model XML file\n\nInference options:\n  <span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Detection model\n                        <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Facial Landmarks\n                        Regression model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Reidentification\n                        model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> PATH, <span class=\"nt\">--cpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For MKLDNN <span class=\"o\">(</span>CPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to a shared library with custom layers\n                        implementations\n  <span class=\"nt\">-c</span> PATH, <span class=\"nt\">--gpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For clDNN <span class=\"o\">(</span>GPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to the XML file with descriptions of the\n                        kernels\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> Be more verbose\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_stats</span>     <span class=\"o\">(</span>optional<span class=\"o\">)</span> Output detailed per-layer performance stats\n  <span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Probability threshold <span class=\"k\">for </span>face\n                        detections<span class=\"o\">(</span>default: 0.6<span class=\"o\">)</span>\n  <span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Cosine distance threshold between two\n                        vectors <span class=\"k\">for </span>face identification <span class=\"o\">(</span>default: 0.3<span class=\"o\">)</span>\n  <span class=\"nt\">-exp_r_fd</span> NUMBER      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Scaling ratio <span class=\"k\">for </span>bboxes passed to face\n                        recognition <span class=\"o\">(</span>default: 1.15<span class=\"o\">)</span>\n  <span class=\"nt\">--allow_grow</span>          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Allow to grow faces gallery and to dump on\n                        disk. Available only <span class=\"k\">if</span> <span class=\"nt\">--no_show</span> option is off.\n</code></pre></div></div>\n\n<p>主なオプションの意味は以下の通り。</p>\n\n<h3 id=\"-m_fd\"><code class=\"language-plaintext highlighter-rouge\">-m_fd</code></h3>\n\n<p>必須。<br />\n顔位置検出モデルファイル</p>\n\n<h3 id=\"ーm_lm\"><code class=\"language-plaintext highlighter-rouge\">ーm_lm</code></h3>\n\n<p>必須。<br />\n顔特徴点検出モデルファイル</p>\n\n<h3 id=\"-m_reid\"><code class=\"language-plaintext highlighter-rouge\">-m_reid</code></h3>\n\n<p>必須。<br />\n顔識別モデルファイル</p>\n\n<h3 id=\"-d_fd\"><code class=\"language-plaintext highlighter-rouge\">-d_fd</code></h3>\n\n<p>顔位置検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_lm\"><code class=\"language-plaintext highlighter-rouge\">-d_lm</code></h3>\n\n<p>顔特徴点検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_reid\"><code class=\"language-plaintext highlighter-rouge\">-d_reid</code></h3>\n\n<p>顔識別に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"--cpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--cpu_lib</code></h3>\n\n<p>CPU用カスタムレイヤライブラリ(?)ファイル</p>\n\n<h3 id=\"--gpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--gpu_lib</code></h3>\n\n<p>GPU用カスタムレイヤライブラリ(?)ファイル(使ったことないからワカラン)</p>\n\n<h3 id=\"-fg\"><code class=\"language-plaintext highlighter-rouge\">-fg</code></h3>\n\n<p>必須。<br />\n識別する顔画像を格納したディレクトリ<br />\nこのディレクトリ内のjpg、pngファイルのみ抽出してくれるので、他のファイルが混在しても大丈夫。</p>\n\n<h3 id=\"--input\"><code class=\"language-plaintext highlighter-rouge\">--input</code></h3>\n\n<p>必須。<br />\n入力ファイル(動画ファイル)を指定する。 <br />\n静止画でもエラーにならないが、一瞬で消えるので、オプション –timelapse でキー入力待ちにするか、\nオプション –outputでファイル出力すると確認できる。<br />\n省略時はカメラが指定される。</p>\n\n<h3 id=\"--output\"><code class=\"language-plaintext highlighter-rouge\">--output</code></h3>\n\n<p>認識結果をファイルに出力する。<br />\n指定しなければファイルは作成されない(表示のみ)。 \n拡張子がmp4のときはMP4(追加した処理)。<br />\nそれ以外はMJPEGで保存(aviにするのが望ましい。それ以外だとffmpegがなんか言うがファイルはできてるっぽい)。</p>\n\n<h3 id=\"--no_show\"><code class=\"language-plaintext highlighter-rouge\">--no_show</code></h3>\n\n<p>画像表示しない。<br />\n通常は–outputと組み合わせて使う。</p>\n\n<h3 id=\"--timelapse\"><code class=\"language-plaintext highlighter-rouge\">--timelapse</code></h3>\n\n<p>1フレーム表示するごとにキー入力待ちになる。</p>\n\n<h3 id=\"--crop_width--crop_height\"><code class=\"language-plaintext highlighter-rouge\">--crop_width</code>、<code class=\"language-plaintext highlighter-rouge\">--crop_height</code></h3>\n\n<p>入力画像を指定したサイズに切り取る。切り取る場所は元画像の中心。<br />\n両方指定しないと無効。</p>\n\n<h3 id=\"--run_detector\"><code class=\"language-plaintext highlighter-rouge\">--run_detector</code></h3>\n\n<p>オプションを指定するとデータベース作成時に顔検出して新たに顔画像を作成してくれる。<br />\nデータベースファイルが全身画像だったり、複数人数が一緒に写っていてもOK。<br />\n1回指定すれば画像が残っているので以降は指定しなくても良い。</p>\n\n<h3 id=\"--run_detector_no_save\"><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code></h3>\n\n<p>追加したオプション<br />\n指定するとデータベース作成時に顔検出するが、顔画像の保存はしない。</p>\n\n<h3 id=\"--verbose\"><code class=\"language-plaintext highlighter-rouge\">--verbose</code></h3>\n\n<p>指定するとloglevelがDEBUGになる</p>\n\n<h3 id=\"--perf_stats\"><code class=\"language-plaintext highlighter-rouge\">--perf_stats</code></h3>\n\n<p>指定するとフレーム毎にパフォーマンスステータスを表示する</p>\n\n<h3 id=\"-t_fd\"><code class=\"language-plaintext highlighter-rouge\">-t_fd</code></h3>\n\n<p>顔位置検出に使用する閾値。省略時は0.6。</p>\n\n<h3 id=\"-t_reid\"><code class=\"language-plaintext highlighter-rouge\">-t_reid</code></h3>\n\n<p>顔識別に使用する閾値。省略時は0.3。</p>\n\n<h3 id=\"-exp_r_fd\"><code class=\"language-plaintext highlighter-rouge\">-exp_r_fd</code></h3>\n\n<p>顔位置検出した枠のサイズを何倍にするか。ギリギリだとうまく行かないから?省略時は1.15</p>\n\n<h3 id=\"--allow_grow\"><code class=\"language-plaintext highlighter-rouge\">--allow_grow</code></h3>\n\n<p>認識画像で知らない顔が出てきたらその都度登録するか確認する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でYOLO(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でYOLO(その2)</h1>\n      <p>openVINOのYOLOのプログラムをちょこっと改変</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> のソースを\n<a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> のソースと形状を合わせたもの。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">math</span> <span class=\"kn\">import</span> <span class=\"n\">exp</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-iout\"</span><span class=\"p\">,</span> <span class=\"s\">\"--iou_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Intersection over union threshold for overlapping \"</span>\n                                                       <span class=\"s\">\"detections filtering\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-ni\"</span><span class=\"p\">,</span> <span class=\"s\">\"--number_iter\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Number of inference iterations\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pc\"</span><span class=\"p\">,</span> <span class=\"s\">\"--perf_counts\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Report performance counters\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span>\n                      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-r\"</span><span class=\"p\">,</span> <span class=\"s\">\"--raw_output_message\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Output inference results raw values showing\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">YoloParams</span><span class=\"p\">:</span>\n    <span class=\"c1\"># ------------------------------------------- Extracting layer parameters ------------------------------------------\n</span>    <span class=\"c1\"># Magic numbers are copied from yolo samples\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">param</span><span class=\"p\">,</span> <span class=\"n\">side</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"mi\">3</span> <span class=\"k\">if</span> <span class=\"s\">'num'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'num'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">=</span> <span class=\"mi\">4</span> <span class=\"k\">if</span> <span class=\"s\">'coords'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'coords'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">classes</span> <span class=\"o\">=</span> <span class=\"mi\">80</span> <span class=\"k\">if</span> <span class=\"s\">'classes'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'classes'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">10.0</span><span class=\"p\">,</span> <span class=\"mf\">13.0</span><span class=\"p\">,</span> <span class=\"mf\">16.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">33.0</span><span class=\"p\">,</span> <span class=\"mf\">23.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">61.0</span><span class=\"p\">,</span> <span class=\"mf\">62.0</span><span class=\"p\">,</span> <span class=\"mf\">45.0</span><span class=\"p\">,</span> <span class=\"mf\">59.0</span><span class=\"p\">,</span> <span class=\"mf\">119.0</span><span class=\"p\">,</span> <span class=\"mf\">116.0</span><span class=\"p\">,</span> <span class=\"mf\">90.0</span><span class=\"p\">,</span> <span class=\"mf\">156.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">198.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">373.0</span><span class=\"p\">,</span> <span class=\"mf\">326.0</span><span class=\"p\">]</span> <span class=\"k\">if</span> <span class=\"s\">'anchors'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"p\">[</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">a</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'anchors'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n\n        <span class=\"k\">if</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">:</span>\n            <span class=\"n\">mask</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">idx</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'mask'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">mask</span><span class=\"p\">)</span>\n\n            <span class=\"n\">maskedAnchors</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n            <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">mask</span><span class=\"p\">:</span>\n                <span class=\"n\">maskedAnchors</span> <span class=\"o\">+=</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"n\">maskedAnchors</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">=</span> <span class=\"n\">side</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"o\">=</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span>  <span class=\"c1\"># Weak way to determine but the only one.\n</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">log_params</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># params_to_print = {'classes': self.classes, 'num': self.num, 'coords': self.coords, 'anchors': self.anchors}\n</span>        <span class=\"c1\"># [log.info(\"         {:8}: {}\".format(param_name, param)) for param_name, param in params_to_print.items()]\n</span>        <span class=\"k\">pass</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">entry_index</span><span class=\"p\">(</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">coord</span><span class=\"p\">,</span> <span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">location</span><span class=\"p\">,</span> <span class=\"n\">entry</span><span class=\"p\">):</span>\n    <span class=\"n\">side_power_2</span> <span class=\"o\">=</span> <span class=\"n\">side</span> <span class=\"o\">**</span> <span class=\"mi\">2</span>\n    <span class=\"n\">n</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">//</span> <span class=\"n\">side_power_2</span>\n    <span class=\"n\">loc</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">%</span> <span class=\"n\">side_power_2</span>\n    <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">side_power_2</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">coord</span> <span class=\"o\">+</span> <span class=\"n\">classes</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">entry</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">loc</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"p\">,</span> <span class=\"n\">h_scale</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"p\">):</span>\n    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">w</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">y</span> <span class=\"o\">-</span> <span class=\"n\">h</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">w</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">+</span> <span class=\"n\">h</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"nb\">dict</span><span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"o\">=</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"o\">=</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"o\">=</span><span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"o\">=</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">blob</span><span class=\"p\">,</span> <span class=\"n\">resized_image_shape</span><span class=\"p\">,</span> <span class=\"n\">original_im_shape</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">threshold</span><span class=\"p\">):</span>\n    <span class=\"c1\"># ------------------------------------------ Validating output parameters ------------------------------------------\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    <span class=\"k\">assert</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">==</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"s\">\"Invalid size of output blob. It sould be in NCHW layout and height should \"</span> \\\n                                     <span class=\"s\">\"be equal to width. Current height = {}, current width = {}\"</span> \\\n                                     <span class=\"s\">\"\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ------------------------------------------ Extracting layer parameters -------------------------------------------\n</span>    <span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">orig_im_w</span> <span class=\"o\">=</span> <span class=\"n\">original_im_shape</span>\n    <span class=\"n\">resized_image_h</span><span class=\"p\">,</span> <span class=\"n\">resized_image_w</span> <span class=\"o\">=</span> <span class=\"n\">resized_image_shape</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">predictions</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">flatten</span><span class=\"p\">()</span>\n    <span class=\"n\">side_square</span> <span class=\"o\">=</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n\n    <span class=\"c1\"># ------------------------------------------- Parsing YOLO Region output -------------------------------------------\n</span>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">side_square</span><span class=\"p\">):</span>\n        <span class=\"n\">row</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">//</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"n\">col</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">%</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"k\">for</span> <span class=\"n\">n</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">num</span><span class=\"p\">):</span>\n            <span class=\"n\">obj_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">)</span>\n            <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">scale</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"n\">box_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n            <span class=\"c1\"># Network produces location predictions in absolute coordinates of feature maps.\n</span>            <span class=\"c1\"># Scale it to relative coordinates.\n</span>            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">col</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">0</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">row</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"c1\"># Value for exp is very big number in some cases so following construction is using here\n</span>            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">w_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n                <span class=\"n\">h_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">3</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n            <span class=\"k\">except</span> <span class=\"nb\">OverflowError</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"c1\"># Depends on topology we need to normalize sizes by feature maps (up to YOLOv3) or by input shape (YOLOv3)\n</span>            <span class=\"n\">w</span> <span class=\"o\">=</span> <span class=\"n\">w_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_w</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"n\">h</span> <span class=\"o\">=</span> <span class=\"n\">h_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_h</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">):</span>\n                <span class=\"n\">class_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span>\n                                          <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">+</span> <span class=\"n\">j</span><span class=\"p\">)</span>\n                <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"n\">scale</span> <span class=\"o\">*</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">class_index</span><span class=\"p\">]</span>\n                <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                    <span class=\"k\">continue</span>\n                <span class=\"n\">objects</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">=</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">=</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"o\">=</span><span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"o\">=</span><span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">j</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">,</span>\n                                          <span class=\"n\">h_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_w</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"n\">objects</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n    <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">height_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span>\n    <span class=\"k\">if</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">height_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">*</span> <span class=\"n\">height_of_overlap_area</span>\n    <span class=\"n\">box_1_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">box_2_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">area_of_union</span> <span class=\"o\">=</span> <span class=\"n\">box_1_area</span> <span class=\"o\">+</span> <span class=\"n\">box_2_area</span> <span class=\"o\">-</span> <span class=\"n\">area_of_overlap</span>\n    <span class=\"k\">if</span> <span class=\"n\">area_of_union</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"mi\">0</span>\n    <span class=\"k\">return</span> <span class=\"n\">area_of_overlap</span> <span class=\"o\">/</span> <span class=\"n\">area_of_union</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>                 <span class=\"c1\"># 冒頭でinputは一つでなければエラーになってるので決め打ちで[0]\n</span>    <span class=\"n\">in_frame_shape</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">:]</span>       <span class=\"c1\"># HWC→BCHWに変更してあるので、height/widthはshape[2:]で取得\n</span>    <span class=\"k\">for</span> <span class=\"n\">layer_name</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">.</span><span class=\"n\">items</span><span class=\"p\">():</span>\n        <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">parents</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]].</span><span class=\"n\">shape</span><span class=\"p\">)</span>\n        <span class=\"n\">layer_params</span> <span class=\"o\">=</span> <span class=\"n\">YoloParams</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n        <span class=\"c1\"># log.info(\"Layer {} parameters: \".format(layer_name))\n</span>        <span class=\"n\">layer_params</span><span class=\"p\">.</span><span class=\"n\">log_params</span><span class=\"p\">()</span>\n        <span class=\"n\">objects</span> <span class=\"o\">+=</span> <span class=\"n\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">out_blob</span><span class=\"p\">,</span> \n                                        <span class=\"n\">in_frame_shape</span><span class=\"p\">,</span>\n                                        <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">],</span> \n                                        <span class=\"n\">layer_params</span><span class=\"p\">,</span>\n                                        <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Filtering overlapping boxes with respect to the --iou_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">sorted</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">,</span> <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"k\">lambda</span> <span class=\"n\">obj</span> <span class=\"p\">:</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">reverse</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">iou_threshold</span><span class=\"p\">:</span>\n                <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># Drawing objects with respect to the --prob_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">obj</span> <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span> <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">Detected boxes for batch {}:\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">))</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\" Class ID | Confidence | XMIN | YMIN | XMAX | YMAX | COLOR \"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">origin_im_size</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Validation bbox of detected object\n</span>        <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"c1\"># color = (int(min(obj['class_id'] * 12.5, 255)),\n</span>        <span class=\"c1\">#          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span>        <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n        <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]]</span> <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"ow\">and</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">>=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]</span> <span class=\"k\">else</span> \\\n            <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">])</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span>\n                <span class=\"s\">\"{:^9} | {:10f} | {:4} | {:4} | {:4} | {:4} | {} \"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">det_label</span><span class=\"p\">,</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">color</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]),</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span>\n                    <span class=\"s\">\"#\"</span> <span class=\"o\">+</span> <span class=\"n\">det_label</span> <span class=\"o\">+</span> <span class=\"s\">' '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"s\">' %'</span><span class=\"p\">,</span>\n                    <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.6</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"c1\"># YOLOのoutputsは1ではない\n</span>    \n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Sample supports only YOLO V3 based single input topologies\"</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>     <span class=\"c1\"># inputは一つだけなので決め打ちで[0]\n</span>    \n    <span class=\"c1\">#  Defaulf batch_size is 1\n</span>    <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n    \n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n        \n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span> <span class=\"o\">=</span>      <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span> <span class=\"o\">=</span>   <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span>  <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_yolov3_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                             <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                             <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                             <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-iout</span> IOU_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-ni</span> NUMBER_ITER] <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-r</span><span class=\"o\">]</span>\n                                             <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG]\n                                             <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n  <span class=\"nt\">-iout</span> IOU_THRESHOLD, <span class=\"nt\">--iou_threshold</span> IOU_THRESHOLD\n                        Optional. Intersection over union threshold <span class=\"k\">for\n                        </span>overlapping detections filtering\n  <span class=\"nt\">-ni</span> NUMBER_ITER, <span class=\"nt\">--number_iter</span> NUMBER_ITER\n                        Optional. Number of inference iterations\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_counts</span>    Optional. Report performance counters\n  <span class=\"nt\">-r</span>, <span class=\"nt\">--raw_output_message</span>\n                        Optional. Output inference results raw values showing\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD</h1>\n      <p>openVINOのSSDのサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>YOLOとは別のアルゴリズムSSDで物体認識するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_ssd_async</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">models.list</code>によると、以下のモデルデータが使用できるらしい。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>face-detection-adas-????\nface-detection-adas-binary-????\nface-detection-retail-????\npedestrian-and-vehicle-detector-adas-????\npedestrian-detection-adas-????\npedestrian-detection-adas-binary-????\nperson-detection-retail-????\nvehicle-detection-adas-????\nvehicle-detection-adas-binary-????\nvehicle-license-plate-detection-barrier-????\n</code></pre></div></div>\n\n<p>ここでは、vehicle-detection-adas-binary-????を使ってみることにする。</p>\n\n<p>以下の手順でモデルデータをダウンロードする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/pedestrian-and-vehicle-detector-adas-0001/FP16/pedestrian-and-vehicle-detector-adas-0001\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>ラベルデータは用意されていないので、ラベルデータを以下の内容で、<code class=\"language-plaintext highlighter-rouge\">${models_diir}/pedestrian-and-vehicle-detector-adas-0001.labels</code>のファイル名で作成する。<br />\nオリジナルでは<code class=\"language-plaintext highlighter-rouge\">--label</code>オプションでラベルデータファイルを指定するようになっているが、\nモデルデータファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものをデフォルトのラベルデータファイルとして認識するように変更しておいた。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>UNKNOWN\nvehicles\npedestrians\nUNKNOWN\n</code></pre></div></div>\n\n<p>どのIDが何を示すか書いてる場所を見つけられなかったんだよなぁ~。<br />\nとりあえず、結果表示から推測するしかないか。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<p>ちょっとのつもりで改造してたら、結構たくさんの変更になったので、ソース全体を掲載しておく。<br />\n(RaspberryPiにはソース入ってないし)<br />\nおもな変更点は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--save</code> <code class=\"language-plaintext highlighter-rouge\">--log</code> <code class=\"language-plaintext highlighter-rouge\">--sync</code> <code class=\"language-plaintext highlighter-rouge\">--no_disp</code> オプションの追加</li>\n  <li>結果解析部分の関数化(後でYOLOと比較しやすいように)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># print(res[out_blob].shape)\n</span>    <span class=\"c1\">#  -> (1, 1, 200, 7)        200:バウンディングボックスの数\n</span>    <span class=\"c1\"># データ構成は\n</span>    <span class=\"c1\"># https://docs.openvinotoolkit.org/2019_R1/_pedestrian_and_vehicle_detector_adas_0001_description_pedestrian_and_vehicle_detector_adas_0001.html\n</span>    <span class=\"c1\"># の「outputs」を参照\n</span>    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"n\">out_blob</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]:</span>     <span class=\"c1\"># このループは200回まわる\n</span>        <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>                       <span class=\"c1\"># confidence for the predicted class(スコア)\n</span>        <span class=\"k\">if</span> <span class=\"n\">conf</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">:</span>      <span class=\"c1\"># 閾値より大きいものだけ処理\n</span>            <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n            <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 表示色\n</span>            <span class=\"c1\"># color = (min(class_id * 12.5, 255), min(class_id * 7, 255), min(class_id * 5, 255))\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>            <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># バウンディングボックスとラベル、スコアを表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">det_label</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">conf</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">%\"</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Demo supports only single output topologies\"</span>\n\n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"c1\"># SSDのinputsは1とは限らないのでスキャンする\n</span>    <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">for</span> <span class=\"n\">blob_name</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">:</span>\n        <span class=\"c1\"># print(f'{blob_name}   {net.inputs[blob_name].shape}')\n</span>        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">4</span><span class=\"p\">:</span>\n            <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">2</span><span class=\"p\">:</span>\n            <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"nb\">RuntimeError</span><span class=\"p\">(</span><span class=\"s\">\"Unsupported {}D input layer '{}'. Only 2D and 4D input layers are supported\"</span>\n                               <span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">),</span> <span class=\"n\">blob_name</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    <span class=\"k\">if</span> <span class=\"n\">img_info_input_blob</span><span class=\"p\">:</span>\n        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">img_info_input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n\n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span>     <span class=\"o\">=</span> <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span>  <span class=\"o\">=</span> <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span> <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_ssd_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                          <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                          <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO(C++版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO(C++版)</h1>\n      <p>tinyYOLOのC++版デモプログラムのbuildと実行</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nのpythonで実行したデモプログラムのC++版をbuild&実行してみる。</p>\n\n<h1 id=\"ubuntu環境での実行\">ubuntu環境での実行</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h2 id=\"デモのソースプログラム\">デモのソースプログラム</h2>\n\n<p>ドライバのインストール先 <code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/deployment_tools/open_model_zoo/demos</code> にあるので、そのまま参照しても良いが、\nソース修正に備えて、ソースをコピっておく(オーナーも変更)と何かと便利。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++/openvino_demo <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos <span class=\"nb\">.</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> demos/\n</code></pre></div></div>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>出力文字列のサイズと位置を調整</li>\n  <li>-saveオプションの追加と認識結果画像ファイルの保存処理の追加</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.hpp.org\t2019-10-31 14:39:14.757039048 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.hpp\t2019-10-31 06:16:49.178945707 +0900\n</span><span class=\"p\">@@ -93,6 +93,7 @@</span>\n /// \\brief Define a flag to disable showing processed video<br>\n /// It is an optional parameter\n DEFINE_bool(no_show, false, no_show_processed_video);\n<span class=\"gi\">+DEFINE_bool(save, false, \"Optional. save image file.\");\n</span> \n /**\n * \\brief This function shows a help message\n<span class=\"p\">@@ -115,4 +116,5 @@</span>\n     std::cout << \"    -iou_t                    \" << iou_thresh_output_message << std::endl;\n     std::cout << \"    -auto_resize              \" << input_resizable_message << std::endl;\n     std::cout << \"    -no_show                  \" << no_show_processed_video << std::endl;\n<span class=\"gi\">+    std::cout << \"    -save                     \" << \"Optional. save image file.\" << std::endl;\n</span> }\n</code></pre></div></div>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.org\t2019-10-31 05:46:38.515000000 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"p\">@@ -197,6 +197,21 @@</span>\n         }\n         // -----------------------------------------------------------------------------------------------------\n \n<span class=\"gi\">+        // =====================================================================================\n+        // 動画ファイルを書き出すためのオブジェクトを宣言する\n+        cv::VideoWriter writer;\n+        // =====================================================================================\n+        // =====================================================================================\n+        if (FLAGS_save) {\n+            double fps    = cap.get(cv::CAP_PROP_FPS);\t\t\t\t// フレームレートを取得\n+            int fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v');\t\t// MP4形式を指定\n+            // * エンコード形式 \"XVID\" = AVI, \"MP4V\" = MPEG4, \"WMV1\" = WMV\n+\n+            // 動画ファイルを書き出すためのファイルをオープンする\n+            writer.open(\"result.mp4\", fourcc, fps, cv::Size(width, height));\n+        }\n+        // =====================================================================================\n+\n</span>         // --------------------------- 1. Load inference engine -------------------------------------\n         slog::info << \"Loading Inference Engine\" << slog::endl;\n         Core ie;\n<span class=\"p\">@@ -356,17 +371,17 @@</span>\n                 std::ostringstream out;\n                 out << \"OpenCV cap/render time: \" << std::fixed << std::setprecision(2)\n                     << (ocv_decode_time + ocv_render_time) << \" ms\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 25), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 255, 0));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 15), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 255, 0));\n</span>                 out.str(\"\");\n                 out << \"Wallclock time \" << (isAsyncMode ? \"(TRUE ASYNC):      \" : \"(SYNC, press Tab): \");\n                 out << std::fixed << std::setprecision(2) << wall.count() << \" ms (\" << 1000.f / wall.count() << \" fps)\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 50), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 0, 255));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 30), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 0, 255));\n</span>                 if (!isAsyncMode) {  // In the true async mode, there is no way to measure detection time directly\n                     out.str(\"\");\n                     out << \"Detection time  : \" << std::fixed << std::setprecision(2) << detection.count()\n                         << \" ms (\"\n                         << 1000.f / detection.count() << \" fps)\";\n<span class=\"gd\">-                    cv::putText(frame, out.str(), cv::Point2f(0, 75), cv::FONT_HERSHEY_TRIPLEX, 0.6,\n</span><span class=\"gi\">+                    cv::putText(frame, out.str(), cv::Point2f(0, 45), cv::FONT_HERSHEY_TRIPLEX, 0.4,\n</span>                                 cv::Scalar(255, 0, 0));\n                 }\n \n<span class=\"p\">@@ -410,7 +425,7 @@</span>\n                         cv::putText(frame,\n                                 (label < static_cast<int>(labels.size()) ?\n                                         labels[label] : std::string(\"label #\") + std::to_string(label)) + conf.str(),\n<span class=\"gd\">-                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 1,\n</span><span class=\"gi\">+                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.4,\n</span>                                     cv::Scalar(0, 0, 255));\n                         cv::rectangle(frame, cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin)),\n                                       cv::Point2f(static_cast<float>(object.xmax), static_cast<float>(object.ymax)), cv::Scalar(0, 0, 255));\n<span class=\"p\">@@ -420,6 +435,11 @@</span>\n             if (!FLAGS_no_show) {\n                 cv::imshow(\"Detection results\", frame);\n             }\n<span class=\"gi\">+            // =====================================================================================\n+            if (FLAGS_save) {\n+                writer << frame;\n+            }\n+            // =====================================================================================\n</span> \n             t1 = std::chrono::high_resolution_clock::now();\n             ocv_render_time = std::chrono::duration_cast<ms>(t1 - t0).count();\n<span class=\"p\">@@ -457,6 +477,11 @@</span>\n         if (FLAGS_pc) {\n             printPerformanceCounts(*async_infer_request_curr, std::cout, getFullDeviceName(ie, FLAGS_d));\n         }\n<span class=\"gi\">+        // =====================================================================================\n+        if (FLAGS_save) {\n+            writer.release();\n+        }\n+        // =====================================================================================\n</span>     }\n     catch (const std::exception& error) {\n         std::cerr << \"[ ERROR ] \" << error.what() << std::endl;\n\n</code></pre></div></div>\n\n<h2 id=\"buildディレクトリの作成とbuild\">buildディレクトリの作成とbuild</h2>\n\n<p>cmakeの実行とbuild</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<p>ちょっと時間がかかる。</p>\n\n<h2 id=\"モデルデータ\">モデルデータ</h2>\n\n<p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nで作成したモデルデータをそのまま使用する。<br />\nラベルデータファイルのファイル名はモデルデータのxmlファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものに固定だが、モデルデータ作成時にコピー済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./intel64/Release/</code>に作成される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./intel64/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-l</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> ../../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>-save オプションを指定すると、認識結果の動画をresult.mp4(ファイル名は固定)に保存する。</p>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>デモプログラムはRasspberryPiでも動作させることができる。<br />\nソースはRaspberryPi側にはないので、ubuntuからコピーする。</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>ubuntuで作成した /work/NCS2/c++/openvino_demo/demos ディレクトリと/work/NCS2/openvino_models ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"buildディレクトリの作成とbuild-1\">buildディレクトリの作成とbuild</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a -Wno-psabi\"</span> ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./armv7l/Release/</code>に作成される。<br />\n入力ファイル(-i オプション)はフルパスで指定すること。相対パスだとファイルが見つからないと怒られる。<br />\n※ 下のパッチを当てると相対パスでも大丈夫になる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./armv7l/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-d</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> /work/NCS2/data/testvideo3.mp4 \n</code></pre></div></div>\n\n<p>なぜか-saveオプションが効かない。。。</p>\n\n<h2 id=\"入力ファイル名に相対パスを使用できるようにするためのパッチ\">入力ファイル名に相対パスを使用できるようにするためのパッチ</h2>\n\n<p>入力ファイル名をrealpath()で絶対パスに変換して使用することで対応。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.1\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-11-01 11:25:29.720856218 +0900\n</span><span class=\"p\">@@ -30,6 +30,9 @@</span>\n #include <ext_list.hpp>\n #endif\n \n<span class=\"gi\">+#include <limits.h>\n+#include <unistd.h>\n+\n</span> using namespace InferenceEngine;\n \n bool ParseAndCheckCommandLine(int argc, char *argv[]) {\n<span class=\"p\">@@ -180,7 +183,23 @@</span>\n \n         slog::info << \"Reading input\" << slog::endl;\n         cv::VideoCapture cap;\n<span class=\"gd\">-        if (!((FLAGS_i == \"cam\") ? cap.open(0) : cap.open(FLAGS_i.c_str()))) {\n</span><span class=\"gi\">+\n+        bool open_status;\n+        if (FLAGS_i == \"cam\") {\n+            open_status = cap.open(0);\n+        }\n+        else {\n+            std::string input_filename;\n+            char input_filename_char[PATH_MAX+1];\n+            if (!realpath(FLAGS_i.c_str(), input_filename_char)) {\n+                throw std::logic_error(\"Cannot get realpath\");\n+            }\n+            input_filename = input_filename_char;\n+            slog::info << \"input filename :\" + input_filename << slog::endl;\n+            open_status = cap.open(input_filename.c_str());\n+\n+        }\n+        if (!open_status) {\n</span>             throw std::logic_error(\"Cannot open input file or camera: \" + FLAGS_i);\n         }\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO</h1>\n      <p>darknetのモデルデータをopenVINOのモデルデータに変換し、tinyYOLOで画像認識を行う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOの2019 R3.1 がリリー(2019.10.29現在、ubuntu用のみ)スされ、YOLOのサンプルプログラムが用意されていたので、tinyYOLOを実行してみた。</p>\n\n<p>参考:<a href=\"https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html\">https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html</a></p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"darknetのモデルデータをopenvinoのモデルデータに変換\">darknetのモデルデータをopenVINOのモデルデータに変換</h1>\n\n<p>上記参考サイトの手順に従って、darknetのtinyYOLOモデルデータをopenVINOのモデルデータに変換する。</p>\n\n<h2 id=\"darknet--tensorflow-変換のためのプログラム取得\">darknet → tensorflow 変換のためのプログラム取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2\ngit clone https://github.com/mystic123/tensorflow-yolo-v3.git\n<span class=\"nb\">cd </span>tensorflow-yolo-v3/\ngit checkout ed60b90\n</code></pre></div></div>\n\n<h2 id=\"darknet-tinyyoloモデルデータ取得\">darknet tinyYOLOモデルデータ取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://raw.githubusercontent.com/pjreddie/darknet/master/data/coco.names\nwget https://pjreddie.com/media/files/yolov3-tiny.weights\n</code></pre></div></div>\n\n<h1 id=\"darknet--tensorflow-モデルデータ変換\">darknet → tensorflow モデルデータ変換</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python convert_weights_pb.py <span class=\"nt\">--class_names</span> coco.names <span class=\"nt\">--data_format</span> NHWC <span class=\"nt\">--weights_file</span> yolov3-tiny.weights <span class=\"nt\">--tiny</span>\n<span class=\"nb\">mv </span>frozen_darknet_yolov3_model.pb yolo_v3_tiny.pb\n</code></pre></div></div>\n\n<h2 id=\"モデルデータを変換\">モデルデータを変換</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP16 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div></div>\n\n<p>/work/NCS2/openvino_models/FP16ディレクトリに yolo_v3_tiny.bin yolo_v3_tiny.mapping yolo_v3_tiny.xml の3つが出来る</p>\n\n<blockquote>\n  <p>[!NOTE]\nFP32で計算する場合はこちら<br />\nNCStick使用時はFP16のみサポートなので、FP16で作っておくと使い回しできて楽。<br />\nそんなに認識精度が変わるわけでもなさそうだし。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP32\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP32 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"ラベルデータもコピー\">ラベルデータもコピー</h2>\n\n<p>pbファイルにはラベルデータが入っているはずだが、この後の変換でラベルデータは欠落するらしい。<br />\n後のプログラムのためにファイル名変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>coco.names <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels\n</code></pre></div></div>\n\n<h2 id=\"デモプログラムをコピー\">デモプログラムをコピー</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ..\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_yolov3_async <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>object_detection_demo_yolov3_async/\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>MP4ファイルのパスが絶対パスでないと正常にオープンできない対策(ubuntuではやらなくても大丈夫)</li>\n  <li>1フレームあたりの処理時間の計測と表示処理を追加</li>\n  <li>認識枠の表示色変更(ちょっと見難かったので)</li>\n  <li>計測データ表示処理の並べ替え(ソースが見難かったので。フレーム時間の追加以外の動作は変更なし)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py.org\t2019-10-29 05:08:34.982999999 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"p\">@@ -210,7 +210,8 @@</span>\n     else:\n         labels_map = None\n \n<span class=\"gd\">-    input_stream = 0 if args.input == \"cam\" else args.input\n</span><span class=\"gi\">+    # input_stream = 0 if args.input == \"cam\" else args.input\n+    input_stream = 0 if args.input == \"cam\" else os.path.abspath(args.input)\n</span> \n     is_async_mode = True\n     cap = cv2.VideoCapture(input_stream)\n<span class=\"p\">@@ -234,6 +235,8 @@</span>\n     next_request_id = 1\n     render_time = 0\n     parsing_time = 0\n<span class=\"gi\">+    frame_time = 0\n+    prev_time = time()\n</span> \n     # ----------------------------------------------- 6. Doing inference -----------------------------------------------\n     log.info(\"Starting inference...\")\n<span class=\"p\">@@ -263,6 +266,8 @@</span>\n \n         # Start inference\n         start_time = time()\n<span class=\"gi\">+        frame_time = start_time - prev_time         # 1フレームの処理時間\n+        prev_time = start_time\n</span>         exec_net.start_async(request_id=request_id, inputs={input_blob: in_frame})\n         det_time = time() - start_time\n \n<span class=\"p\">@@ -303,8 +308,9 @@</span>\n             # Validation bbox of detected object\n             if obj['xmax'] > origin_im_size[1] or obj['ymax'] > origin_im_size[0] or obj['xmin'] < 0 or obj['ymin'] < 0:\n                 continue\n<span class=\"gd\">-            color = (int(min(obj['class_id'] * 12.5, 255)),\n-                     min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span><span class=\"gi\">+            # color = (int(min(obj['class_id'] * 12.5, 255)),\n+            #          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n+            color = (255, 128, 128)\n</span>             det_label = labels_map[obj['class_id']] if labels_map and len(labels_map) >= obj['class_id'] else \\\n                 str(obj['class_id'])\n \n<span class=\"p\">@@ -322,16 +328,17 @@</span>\n         # Draw performance stats over frame\n         inf_time_message = \"Inference time: N\\A for async mode\" if is_async_mode else \\\n             \"Inference time: {:.3f} ms\".format(det_time * 1e3)\n<span class=\"gi\">+        frame_time_message = \"Frame time: {:.3f} ms\".format(frame_time * 1e3)\n</span>         render_time_message = \"OpenCV rendering time: {:.3f} ms\".format(render_time * 1e3)\n         async_mode_message = \"Async mode is on. Processing request {}\".format(cur_request_id) if is_async_mode else \\\n             \"Async mode is off. Processing request {}\".format(cur_request_id)\n         parsing_message = \"YOLO parsing time is {:.3f}\".format(parsing_time * 1e3)\n \n<span class=\"gd\">-        cv2.putText(frame, inf_time_message, (15, 15), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200, 10, 10), 1)\n-        cv2.putText(frame, render_time_message, (15, 45), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n-        cv2.putText(frame, async_mode_message, (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5,\n-                    (10, 10, 200), 1)\n-        cv2.putText(frame, parsing_message, (15, 30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n</span><span class=\"gi\">+        cv2.putText(frame, inf_time_message,    (15, 15),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, parsing_message,     (15, 30),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, render_time_message, (15, 45),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, frame_time_message,  (10, int(origin_im_size[0] - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, async_mode_message,  (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n</span> \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n</code></pre></div></div>\n\n<p>上のパッチ内容をa.patchとして保存したとして、以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch object_detection_demo_yolov3_async.py a.patch \n\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\n入力ファイルをmp4に変えるだけ。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしいが、カメラないので未確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>RaspberryPi用はopenVINO 2019R3のまま(2019.10.29現在、R3.1はリリースされていない)だけど、問題なし。</p>\n\n<p>ubuntuで作成した object_detection_demo_yolov3_async ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"静止画の場合-1\">静止画の場合</h2>\n\n<p>実行コマンドは以下。  ubuntuの実行コマンドと比べて、以下の変更がある。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--device MYRIAD</code>を追加</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">--cpu_extension</code>を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合-1\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\nこちらも入力ファイルをmp4に変えるだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p>openCVではMP4ファイルを保存することができる。<br />\nobject_detection_demo_yolov3_async.py に以下の変更を加えることで、認識結果をMP4ファイルに保存することができる。</p>\n\n<p>以下の修正ファイルは簡易的に保存する処理を追加したため、保存ファイル名は決め打ち。 <br />\n汎用的にするなら、オプションで指定できるようにしてもいいかもね。</p>\n\n<p>ただし、実際に保存するタイミングとMP4ファイルのタイムインデックスが一致するわけではないので、\n処理時の見た目と保存ファイルを再生したときの見た目は異なるので注意が必要。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"gi\">+++ record.py\t2019-10-29 11:35:37.296005608 +0900\n</span><span class=\"p\">@@ -218,6 +218,18 @@</span>\n     number_input_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n     number_input_frames = 1 if number_input_frames != -1 and number_input_frames < 0 else number_input_frames\n \n<span class=\"gi\">+    # =====================================================================================\n+    # 幅と高さを取得\n+    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n+    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n+    size = (width, height)\n+    # フレームレート(1フレームの時間単位はミリ秒)の取得\n+    frame_rate = int(cap.get(cv2.CAP_PROP_FPS))\n+    # フォーマット\n+    fmt = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')\n+    writer = cv2.VideoWriter('./outtest.mp4', fmt, frame_rate, size)\n+    # =====================================================================================\n+\n</span>     wait_key_code = 1\n \n     # Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n<span class=\"p\">@@ -342,6 +354,9 @@</span>\n \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n<span class=\"gi\">+        # =====================================================================================\n+        writer.write(frame)\n+        # =====================================================================================\n</span>         render_time = time() - start_time\n \n         if is_async_mode:\n<span class=\"p\">@@ -359,6 +374,10 @@</span>\n             is_async_mode = not is_async_mode\n             log.info(\"Switched to {} mode\".format(\"async\" if is_async_mode else \"sync\"))\n \n<span class=\"gi\">+    # =====================================================================================\n+    writer.release()\n+    # =====================================================================================\n+\n</span>     cv2.destroyAllWindows()\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>改訂版はこちら→<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></p>\n\n<p>caffeモデルなどをopenVINOへ変換するには、フルパッケージが必要らしい。<br />\nでもって、フルパッケージはRaspberryPiでは使用できなくて、WindowsやLinux、macOSが必要。<br />\nということで、openVINO フルパッケージをubuntu 18.04にインストールする。 <br />\n(16.04でも大丈夫かもしれないけど、今回は18.04を使う。LTSじゃないのはやめといた方が良さそう)</p>\n\n<h1 id=\"ダウンロード--インストール前半\">ダウンロード & インストール前半</h1>\n\n<p>ダウンロードはこの辺を参考に。。。<br />\n<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758</a><br />\nなにやら登録しないといけないらしい。</p>\n\n<p>ダウンロードしたら、てきとーなところに展開して、インストーラを実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\n2910.10 「2019 R3.1」がリリースされた。ファイル名は「l_openvino_toolkit_p_2019.3.376.tgz」</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf /Share/l_openvino_toolkit_p_2019.3.334.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2019.3.334\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n\n<p>nextをクリックしていけば大丈夫(Agreeするとこはあるけど)。<br />\nあとで色々インストールしろと言われるけど、あとでやるので無視して大丈夫<br />\n・・・・しばらく待つ・・・・<br />\nいったんFinishするとブラウザが表示される<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h1 id=\"インストール後半--動作確認\">インストール後半 & 動作確認</h1>\n\n<h2 id=\"install-external-software-dependenciesとな\">「Install External Software Dependencies」とな?</h2>\n\n<p>なんか実行してインストールしろってことらしい。<br />\nroot権限で実行しないとエラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh\n</code></pre></div></div>\n\n<p>なんか色々インストールされるっぽい。<br />\n中身はOSのディストリビューションとバージョンでインストールパッケージを切り替えてインストールしてるらしい。</p>\n\n<h2 id=\"set-the-environment-variablesとな\">「Set the Environment Variables」とな?</h2>\n\n<p>環境変数の設定らしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<p>~/.bashrcに追加しておくと良いとのことなので、そうする。</p>\n\n<h2 id=\"configure-the-model-optimizerとな\">「Configure the Model Optimizer」とな?</h2>\n\n<p>モデルオプティマイザの設定。<br />\nこれが欲しかったのよ。</p>\n\n<p>必要なpipモジュールをインストールするらしい。<br />\n必要なものだけインストールすることもできるけど、一括でインストールしといた方が手間がかからないでしょう。</p>\n\n<p>pyenvを使ってると、<code class=\"language-plaintext highlighter-rouge\">sudo pip3</code>されると、systemのpip3が動いてしまい、pyenv環境にモジュールがインストールされない。<br />\nスクリプトの中で必要なコマンドだけ実行する(随分スッキリしちゃったなぁ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\n</code></pre></div></div>\n\n<p>バージョン不一致とか言われたら、適宜バージョン合わせてアップグレードorダウングレードしてちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nsetuptoolsは<code class=\"language-plaintext highlighter-rouge\">pip install -U setuptools</code>でOKなはず。<br />\nnumpyは<code class=\"language-plaintext highlighter-rouge\">mxnet 1.3.1 has requirement numpy<1.15.0,>=1.8.2, but you'll have numpy 1.17.3 which is incompatible.</code>と言われるのだけど、tensorflow 1.15.0だとnumpy 1.16.0以上を要求する。<br />\nとりあえず、tenssorflowを1.13.1にしてnumpyを1.14.6にしてみて様子見。<br />\n現状のバージョン一覧は以下。これを<code class=\"language-plaintext highlighter-rouge\">requirements.txt</code>として保存し、<code class=\"language-plaintext highlighter-rouge\">pip install -r requirements.txt</code>するとこのバージョンでそろえてくれるはず。</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.8.1\nastor==0.8.0\ncertifi==2019.9.11\nchardet==3.0.4\ndecorator==4.4.0\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.1.7\ngraphviz==0.8.4\ngrpcio==1.24.3\nh5py==2.10.0\nidna==2.8\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.0\nMarkdown==3.1.1\nmock==3.0.5\nmxnet==1.3.1\nnetworkx==2.3\nnumpy==1.14.6\nonnx==1.6.0\nopt-einsum==3.1.0\npipdeptree==0.13.2\nprotobuf==3.6.1\nrequests==2.22.0\nsix==1.12.0\ntensorboard==1.13.1\ntensorflow==1.13.1\ntensorflow-estimator==1.13.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4\nurllib3==1.25.6\nWerkzeug==0.16.0\nwrapt==1.11.2\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nオリジナルの方法はこちら</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"run-the-verification-scripts-to-verify-installationとな\">「Run the Verification Scripts to Verify Installation」とな?</h2>\n\n<p>なになに、実行必須?たしかにapt installが実行される。<br />\nなら、タイトルに “to Verify Installation” とか書くなよ!</p>\n\n<p>build前に<code class=\"language-plaintext highlighter-rouge\">apt install</code> と <code class=\"language-plaintext highlighter-rouge\">pip install</code>が走る。</p>\n\n<p>こっちもpyenv使ってるとpipで悲しいことになるので、先にpipだけ実行しておく。<br />\nスクリプト側でもpipが走ってsystemのモジュールが追加されるが、悪影響はないと思うので、そのままにしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div></div>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n./demo_squeezenet_download_convert_run.sh\n</code></pre></div></div>\n\n<p>・・・・こんなことをやってるらしい・・・・</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">target_precision</code> は FP16 になっている</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">apt install</code> で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pip install</code>で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/open_model_zoo/tools/downloaderdownloader.py</code>でモデルのダウンロードを行う\n    <ul>\n      <li>ダウンロード済みならスキップ»</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/model_optimizer/mo.py</code>でモデル変換を行う\n    <ul>\n      <li>変換済みならスキップ»</li>\n    </ul>\n  </li>\n  <li>サンプルプログラムのbuild</li>\n  <li>サンプルプログラム(classification_sample_async)の実行<br />\n  実行結果はこんな感じ</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./classification_sample_async -d CPU -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/openvino_models/ir/FP16//public/squeezenet1.1/squeezenet1.1.xml \n\n[ INFO ] InferenceEngine: \n\tAPI version ............ 2.1\n\tBuild .................. custom_releases/2019/R3_cb6cad9663aea3d282e0e8b3e0bf359df665d5d0\n\tDescription ....... API\n[ INFO ] Parsing input parameters\n[ INFO ] Parsing input parameters\n[ INFO ] Files were added: 1\n[ INFO ]     /opt/intel/openvino/deployment_tools/demo/car.png\n[ INFO ] Creating Inference Engine\n\tCPU\n\tMKLDNNPlugin version ......... 2.1\n\tBuild ........... 30677\n\n[ INFO ] Loading network files\n[ INFO ] Preparing input blobs\n[ WARNING ] Image is resized from (787, 259) to (227, 227)\n[ INFO ] Batch size is 1\n[ INFO ] Loading model to the device\n[ INFO ] Create infer request\n[ INFO ] Start inference (10 asynchronous executions)\n[ INFO ] Completed 1 async request execution\n[ INFO ] Completed 2 async request execution\n[ INFO ] Completed 3 async request execution\n[ INFO ] Completed 4 async request execution\n[ INFO ] Completed 5 async request execution\n[ INFO ] Completed 6 async request execution\n[ INFO ] Completed 7 async request execution\n[ INFO ] Completed 8 async request execution\n[ INFO ] Completed 9 async request execution\n[ INFO ] Completed 10 async request execution\n[ INFO ] Processing output blobs\n\nTop 10 results:\n\nImage /opt/intel/openvino/deployment_tools/demo/car.png\n\nclassid probability label\n------- ----------- -----\n817     0.8364176   sports car, sport car\n511     0.0945683   convertible\n479     0.0419195   car wheel\n751     0.0091233   racer, race car, racing car\n436     0.0068038   beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon\n656     0.0037315   minivan\n586     0.0025940   half track\n717     0.0016044   pickup, pickup truck\n864     0.0012045   tow truck, tow car, wrecker\n581     0.0005833   grille, radiator grille\n\n[ INFO ] Execution successful\n\n[ INFO ] This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool\n</code></pre></div></div>\n\n<ul>\n  <li>終了</li>\n</ul>\n\n<p>もういっちょでも実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh\n</code></pre></div></div>\n\n<p>やってることは前のと同じ。<br />\nこっちはopenVINOのモデルをダウンロードするので、モデル変換はない。<br />\n最終的に実行しているデモプログラムはこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./security_barrier_camera_demo -d CPU -d_va CPU -d_lpr CPU -i /opt/intel/openvino/deployment_tools/demo/car_1.bmp -m ~/openvino_models/ir/FP16/intel/vehicle-license-plate-detection-barrier-0106/FP16/vehicle-license-plate-detection-barrier-0106.xml -m_lpr ~/openvino_models/ir/FP16/intel/license-plate-recognition-barrier-0001/FP16/license-plate-recognition-barrier-0001.xml -m_va ~/openvino_models/ir/FP16/intel/vehicle-attributes-recognition-barrier-0039/FP16/vehicle-attributes-recognition-barrier-0039.xml \n</code></pre></div></div>\n\n<h2 id=\"gpuやncstick使わないから以下スキップ\">GPUやNCStick使わないから以下スキップ</h2>\n\n<!--\n## 「Run a Sample Application」\n\nNCStickなどVPUベースの環境で実行するにはFP16モデルが必要\nデフォルトはFP32\n\nFP16: 16bit浮動小数点\nFP32: 32bit浮動小数点\n====\nmkdir ~/squeezenet1.1_FP16\ncd ~/squeezenet1.1_FP16\npython3 /opt/intel/openvino/deployment_tools/model_optimizer/mo.py --input_model ~/openvino_models/models/FP32/classification/squeezenet/1.1/caffe/squeezenet1.1.caffemodel --data_type FP16 --output_dir .\n\n====\n\n\n\n\n./classification_sample_async -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/squeezenet1.1_FP16/squeezenet1.1.xml -d CPU\n-->\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その7)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その7)</h1>\n      <p>Node-REDのメモ 応用編 GPIO+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIOの入出力データをWebsocketで飛ばして、Dashboardから操作/Dashboardで表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"gpio入出力データをwebsocketで送受信raspberrypi\">GPIO入出力データをWebsocketで送受信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>RaspberryPiでGPIO出力</strong>、<strong>RaspberryPiでGPIO入力</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>、<strong>Websocketでデータを受信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、GPIO入力データをそのまま送信すると、受け取り側で「0はON?それともOFF?」となってしまうので、GPIO入力の0/1をON/OFFの文字列に変換するファンクションノードを追加している。\n  また、GPIO出力側も同様に、送信側から送られてきたON/OFFの文字列をGPIO出力データの1/0の数値に変換するファンクションノードを挿入している。<br />\n  ターゲットボードの正論理/負論理が変更になった場合はこれらのファンクションノードで調整すれば良い。</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"6e229d5a.774af4\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"109b9bce.e015e4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 730,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4834db5b.5c24d4\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": true,\n        \"x\": 190,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"3ff59514.52c732\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7d90bda.d7b4b8\",\n        \"type\": \"websocket in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"47e24d88.c603e4\",\n        \"x\": 280,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"a38bd8a1.0a5bd8\",\n                \"5e99ea44.cfdac4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9bc37a7.e1e9808\",\n        \"type\": \"websocket out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"c4985621.1edb48\",\n        \"x\": 830,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"a38bd8a1.0a5bd8\",\n        \"type\": \"debug\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 730,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3ff59514.52c732\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"1/0→OFF/ON\",\n        \"func\": \"if (msg.payload) {\\n    msg.payload = 'OFF';\\n}\\nelse {\\n    msg.payload = 'ON';\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"9bc37a7.e1e9808\",\n                \"a38bd8a1.0a5bd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5e99ea44.cfdac4\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"OFF/ON→0/1\",\n        \"func\": \"if (msg.payload == 'OFF') {\\n    msg.payload = 0;\\n}\\nelse {\\n    msg.payload = 1;\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"109b9bce.e015e4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47e24d88.c603e4\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/led0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"c4985621.1edb48\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/sw0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからgpio入出力データを送受信サーバ\">WebsocketからGPIO入出力データを送受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータ送信(サーバ)</strong>、<strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノードに<strong>その4</strong> の <strong>Dashboard のUIを作成する(ボタン)</strong>、<strong>Dashboardでテキストを表示する</strong>で作成したノードを接続すれば良い。</li>\n</ul>\n\n<p>この状態でRaspberryPi側でスイッチをON/OFFすると、Dashboardの「SW」の文字列のON/OFFが切り替わる。\nまた、DashboardのLLED_ON/LED_OFFのボタンをクリックすると、LEDが点灯/消灯する</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"ca6a740f.4d43b8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_GPIO\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"ac19aeee.9f8f5\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 260,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"2098e31e.e6832c\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 270,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8db70b6.86a1178\",\n        \"type\": \"ui_text\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 610,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f45af19.269e\",\n        \"type\": \"websocket in\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"fad64a63.6141a\",\n        \"client\": \"\",\n        \"x\": 270,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"8db70b6.86a1178\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"299e8287.226e6e\",\n        \"type\": \"websocket out\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"d7b33218.4a1f28\",\n        \"client\": \"\",\n        \"x\": 630,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"95b08556.d2cce\",\n        \"type\": \"debug\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 610,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"b7e42e0e.52bdb\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"1b4acf7b.a194c9\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"fad64a63.6141a\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/sw0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"d7b33218.4a1f28\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/led0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"1b4acf7b.a194c9\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ3\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その6)</h1>\n      <p>Node-REDのメモ MQTT編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでMQTT通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"mqttでデータを送受信\">MQTTでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにmosquitto broker および mosquitto client toolsを使うこととします。<br />\nこれらは以下のコマンドでインストールできます。</p>\n\n<p>Ubuntuで動作確認。RaspberryPiでも大丈夫なはず。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mosquitto mosquitto-clients\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータ送信publish\">MQTTでデータ送信(Publish)</h2>\n\n<p>MQTTでデータを送信してみます</p>\n\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要なら「名前」を設定\n            <ul>\n              <li>省略するとサーバアドレスとポート番号が表示される</li>\n            </ul>\n          </li>\n          <li>「サーバ」 でブローカのアドレス(またはホスト名)を設定(例: PiDev25.local)</li>\n          <li>「ポート」 でポート番号を設定(一般的な設定なら1883のままで大丈夫)</li>\n          <li>SSL/TLS接続を使用する場合は「SSL/TLS接続を使用」のチェックを入れる</li>\n          <li>クライアントIDを指定したい場合は「クライアント」に設定。通常は空欄で大丈夫</li>\n          <li>キープアライブ時間を「キープアライブ時間」に設定</li>\n          <li>「セッションの初期化」?とりあえず初期設定のままで</li>\n          <li>「旧MQTT 3.1のサポート」?とりあえず初期設定のままで</li>\n          <li>「セキュリティ」タブ、「メッセージ」タブの内容は必要なら設定する。設定しなくても大丈夫</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に送信するトピックを設定\n        <ul>\n          <li>省略すると、トリガノードの出力に設定されているtopicが使用される</li>\n        </ul>\n      </li>\n      <li>「QoS」を「0」/「1」/「2」から選択</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される\n            <ul>\n              <li>トピックも省略されている場合はmqttと表示される</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のようにsubscriberコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> 《トピック》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカからすべてのトピック(“#”)を取得するよう指定しています。<br />\n-v 指定により、対象メッセージのトピックも表示されます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> Pidev25.local <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> <span class=\"s2\">\"#\"</span>\n</code></pre></div></div>\n<p>Node-RED側で mqttの送信をトリガするとmosquitto_subの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>test_data 0\ntest_data 1\ntest_data true\ntest_data false\ntest_data 文字列\ntest_data {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"f580f01a.f771f\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_publish\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"33450bad.82764c\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ea6d9236.74e038\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d7baa4c.08385\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"82148e63.4b97e\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d0b1ac7f.0ac0b\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7e6180b5.f29098\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"test_data\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6f26fe46.a01f58\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"バッファ\",\n        \"topic\": \"test_data\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 140,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d5a5b2db.83462\",\n        \"type\": \"debug\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 500,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"e6218cda.844308\",\n        \"type\": \"mqtt out\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"\",\n        \"qos\": \"\",\n        \"retain\": \"\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 570,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータを受信subscribe\">MQTTでデータを受信(subscribe)</h2>\n\n<p>MQTTでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に受信するトピックを設定\n        <ul>\n          <li>すべてのトピックを受信するには#を設定</li>\n          <li>省略することはできない</li>\n        </ul>\n      </li>\n      <li>「QoS」を設定</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>デプロイ後、ターミナル or コンソールで以下のようにpublisherコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-t</span> 《トピック》 <span class=\"nt\">-m</span> 《メッセージ》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカへ、トピック test_data で、メッセージ test を送信しています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> PiDev25.local <span class=\"nt\">-t</span> <span class=\"s2\">\"test_data\"</span> <span class=\"nt\">-m</span> <span class=\"s2\">\"test\"</span>\n</code></pre></div></div>\n\n<p>コマンドを実行するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"13f22fdd.2e009\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_subscribe\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1760f49a.fd2d3b\",\n        \"type\": \"debug\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 420,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"30229cea.13aba4\",\n        \"type\": \"mqtt in\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"#\",\n        \"qos\": \"2\",\n        \"datatype\": \"auto\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 150,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"1760f49a.fd2d3b\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その5)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをWebsocketで飛ばして、Dashboardでグラフ表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"bme280データをwebsocketで送信raspberrypi\">BME280データをWebsocketで送信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>BME280を使用するフローを作成する</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、送信されるデータはmsg.payloadなので、文字列ではなく、object。<br />\n  (WebsocketのパケットにはobjectをJSON文字列化したものが入る)</p>\n  </li>\n  <li>BME280のデータを送信するためのトリガとなるノードをBME280ノードの入力に接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"411d9021.cb1948\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"72021e21.cce078\",\n        \"type\": \"Bme280\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"571951b6.480168\",\n        \"type\": \"websocket out\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"f24a6df3.ed0608\",\n        \"x\": 660,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4ce01eb0.f1d438\",\n        \"type\": \"debug\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 570,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"480f869f.968e18\",\n        \"type\": \"function\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"DummyData\",\n        \"func\": \"msg.payload = {\\n\\t\\t\\\"temperature_C\\\": Math.floor((Math.random() * (  40 - (-30)) * 100) / 100) + (-30),\\n\\t\\t\\\"humidity\\\":      Math.floor((Math.random() * ( 100 -    0 ) * 100) / 100) +    0,\\n\\t\\t\\\"pressure_hPa\\\":  Math.floor((Math.random() * (1100 -  800 ) * 100) / 100) +  800,\\n\\t\\t\\\"model\\\":\\\"DUMMY\\\"\\n}\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 310,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"c6ba67a3.1c69c\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"72021e21.cce078\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ab623444.9c5148\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"480f869f.968e18\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f24a6df3.ed0608\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/bme280\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからbme280データを受信サーバ\">WebsocketからBME280データを受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノード</li>\n</ul>\n\n<p>これだけでWebsocketからデータは受信できる。<br />\nこのとき、Websocketの受信ノードのmag.payloadはJSON文字列なので、objectに変換してやらないと後段で使用できない。<br />\nそのため、Websocketのノードの出力をjsonノードで変換してやる必要がある。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「json」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「json」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「動作」で「常にJavascriptオブジェクトに変換」を選択</li>\n      <li>プロパティは「msg.payload」を設定(デフォルトのまま)</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとjsonが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力側にWebsocketのノードを接続</li>\n  <li>\n    <p>出力側に受信データを処理するノードを接続</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>この状態でRaspberryPi側でBME280のデータ送信をトリガすれば、受信したデータで処理ノードが実行される</p>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その1サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その1)(サーバ)</h1>\n\n<p>上記、<strong>WebsocketからBME280データを受信(サーバ)</strong>の処理ノードとして</p>\n<ul>\n  <li><strong>その4</strong> の <strong>Dashboardでゲージグラフを表示する</strong>の手順で作成したノードを接続すれば良い。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nこれで理屈的には大丈夫なハズなんだけど、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.pressure_hPa}}</code>を指定すると、値は正常に表示されるけど、グラフが正常に表示されないことがある。。。<br />\nどうやら、この形で指定すると、値が1000を超えるとグラフ表示がおかしくなるようだ。バグか?<br />\n下の(その2)の方法で回避可能。</p>\n</blockquote>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"61238c01.1e1fdc\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"2163c454.8e4654\",\n        \"type\": \"json\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"8a687382.d3a38\",\n                \"54ecaf20.30611\",\n                \"1e9e6439.3de04c\",\n                \"54f5a1ee.e4fb5\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"de53f105.be0bb\",\n        \"type\": \"websocket in\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"2163c454.8e4654\",\n                \"8a687382.d3a38\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8a687382.d3a38\",\n        \"type\": \"debug\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 530,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54ecaf20.30611\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{msg.payload.temperature_C | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 510,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1e9e6439.3de04c\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度\",\n        \"label\": \"%\",\n        \"format\": \"{{msg.payload.humidity| number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 510,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54f5a1ee.e4fb5\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧\",\n        \"label\": \"hPa\",\n        \"format\": \"{{msg.payload.pressure_hPa| number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 510,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"9912b800.6921d8\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その2サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その2)(サーバ)</h1>\n\n<p><strong>(その1)</strong>での不具合を回避するため、msg.payloadのオブジェクト内のそれぞれの変数をバラすfunctionノードを追加する</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「function」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら名前にノード名を設定</li>\n      <li>コードを設定(下記参照)</li>\n      <li>出力数に「3」を設定</li>\n      <li>右上の「完了」をクリック。</li>\n    </ul>\n  </li>\n  <li>これでfunctionノードの出力端子が3個になり、上から温度、湿度、気圧データが出力される。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>// make deep copy\nvar msg_temp  <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_hum   <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_press <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\n\nmsg_temp.topic    <span class=\"o\">=</span> <span class=\"s2\">\"temperature_C\"</span><span class=\"p\">;</span>\nmsg_temp.payload  <span class=\"o\">=</span> msg.payload.temperature_C<span class=\"p\">;</span>\nmsg_hum.topic     <span class=\"o\">=</span> <span class=\"s2\">\"humidity\"</span><span class=\"p\">;</span>\nmsg_hum.payload   <span class=\"o\">=</span> msg.payload.humidity<span class=\"p\">;</span>\nmsg_press.topic   <span class=\"o\">=</span> <span class=\"s2\">\"pressure_hPa\"</span><span class=\"p\">;</span>\nmsg_press.payload <span class=\"o\">=</span> msg.payload.pressure_hPa<span class=\"p\">;</span>\n\n<span class=\"k\">return</span> <span class=\"o\">[</span>msg_temp, msg_hum, msg_press]<span class=\"p\">;</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">var msg_temp  = msg;</code>などとしてはいけない。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">msg_temp</code>は<code class=\"language-plaintext highlighter-rouge\">msg</code>の浅いコピーとなってしまうため、その下で<code class=\"language-plaintext highlighter-rouge\">msg_temp.payload</code>を変更すると、<code class=\"language-plaintext highlighter-rouge\">msg.payload</code>も変更されてしまうことになる。<br />\nこれを防ぐため、深いコピーを作成している。これには<code class=\"language-plaintext highlighter-rouge\">msg</code>をJSON文字列化して、再度パースすることで対応している。</p>\n</blockquote>\n\n<p>フローエディタ上で、どの端子がどの信号か分からなくなるのを防ぐため、端子に名前を付けることができる。<br />\n(付けなくても動作上は問題ない)</p>\n\n<ul>\n  <li>「function」ノードをダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>右上の「完了」ボタンの下にある「外観」ボタン(ウィンドウ表示のアイコン)をクリック</li>\n      <li>ポートラベルの下の出力の下、1、2、3に対して、それぞれ分かりやすい名前を付ける</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>functionノードの入力にjsonノードの出力を接続</li>\n  <li>functionノードのそれぞれの出力にそれぞれを表示するゲージグラフノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"9c09bf08.8c36a8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280_2\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1e53a14c.4133a7\",\n        \"type\": \"json\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"855491ee.723a88\",\n                \"3cee4c1c.c6861c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ada05d07.d2d8b\",\n        \"type\": \"websocket in\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"1e53a14c.4133a7\",\n                \"855491ee.723a88\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"855491ee.723a88\",\n        \"type\": \"debug\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 690,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"51b57ef4.80809\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度2\",\n        \"label\": \"℃\",\n        \"format\": \"{{value | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 670,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"be7cac56.7bcc4\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度2\",\n        \"label\": \"%\",\n        \"format\": \"{{value | number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 670,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"f36e338d.e77e6\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧2\",\n        \"label\": \"hPa\",\n        \"format\": \"{{value | number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 670,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3cee4c1c.c6861c\",\n        \"type\": \"function\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"BME280\",\n        \"func\": \"// make deep copy\\nvar msg_temp  = JSON.parse(JSON.stringify(msg));\\nvar msg_hum   = JSON.parse(JSON.stringify(msg));\\nvar msg_press = JSON.parse(JSON.stringify(msg));\\n\\nmsg_temp.topic    = \\\"temperature_C\\\";\\nmsg_temp.payload  = msg.payload.temperature_C;\\nmsg_hum.topic     = \\\"humidity\\\";\\nmsg_hum.payload   = msg.payload.humidity;\\nmsg_press.topic   = \\\"pressure_hPa\\\";\\nmsg_press.payload = msg.payload.pressure_hPa;\\n\\nreturn [msg_temp, msg_hum, msg_press];\",\n        \"outputs\": 3,\n        \"noerr\": 0,\n        \"x\": 460,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"51b57ef4.80809\"\n            ],\n            [\n                \"be7cac56.7bcc4\"\n            ],\n            [\n                \"f36e338d.e77e6\"\n            ]\n        ],\n        \"inputLabels\": [\n            \"BME280データ\"\n        ],\n        \"outputLabels\": [\n            \"温度\",\n            \"湿度\",\n            \"気圧\"\n        ]\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"34e8ddba.6c67fa\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ2\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その4)</h1>\n      <p>Node-REDのメモ Dashboard編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでDashboardでUIを作成するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"dashboardをインストールする\">Dashboardをインストールする</h1>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-dashboard」と入力</li>\n  <li>下に検索結果が出るので。「node-red-dashboard」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するボタン\">Dashboard のUIを作成する(ボタン)</h1>\n\n<ul>\n  <li>パレット(左側のペイン)の「dashboard」の下の「button」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「button」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「名前」は適当に設定</li>\n          <li>「タブ」 で「新規に ui_tab を追加…」を選択してその右の編集ボタンをクリック\n            <ul>\n              <li>適当に値を設定する</li>\n              <li>右上の「追加」をクリック</li>\n            </ul>\n          </li>\n          <li>または、既存のタブを選択</li>\n          <li>右上の「追加」をクリック</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Icon」「Tooltip」「Colour」「Background」はオプションなので空欄のままで可</li>\n      <li>「Payload」 に クリックされたときに送信するデータを設定</li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"ブラウザでdashboardのuiに接続する\">ブラウザでDashboardのUIに接続する</h1>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/ui に接続\n    <ul>\n      <li>Dashboardが表示されるハズ\n        <ul>\n          <li>複数のタブがある場合、左上の3本線メニュー(≡)から切り替えられる</li>\n        </ul>\n      </li>\n      <li>ボタンをクリックしたらフローが動作する。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するスライダ\">Dashboard のUIを作成する(スライダ)</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「slider」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「slider」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Tooltip」はオプションなので空欄のままで可</li>\n      <li>「Range」に値の最小値、最大値、刻みを設定</li>\n      <li>「Output」を設定\n        <ul>\n          <li>「continuously while sliding」:操作中、一定時間ごとにメッセージを出力</li>\n          <li>「only on release」:スライダを離したとき(値を確定したとき)にメッセージを出力</li>\n        </ul>\n      </li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"dashboardでゲージグラフを表示する\">Dashboardでゲージグラフを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「guage」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「guage」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>デフォルトの<code class=\"language-plaintext highlighter-rouge\">{{value}}</code>では受信したデータのpayload(<code class=\"language-plaintext highlighter-rouge\">msg.payload</code> )が使用される</li>\n          <li>payloadがobjectの場合、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.XXX}}</code>のように指定すると特定の変数が表示できる</li>\n          <li>このとき、<code class=\"language-plaintext highlighter-rouge\">{{</code> と <code class=\"language-plaintext highlighter-rouge\">}}</code> は波括弧を2つ重ねたもの。波括弧1つだと正常に処理されないので、注意</li>\n          <li>表示する数値の有効桁数を設定したい場合は以下のようにフィルタを設定\n            <ul>\n              <li>小数点以下1桁まで表示:<code class=\"language-plaintext highlighter-rouge\">{{value | number:1 }}</code></li>\n              <li>整数部のみ表示:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:0 }}</code></li>\n              <li>10の位へ丸める:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:-1 }}</code></li>\n            </ul>\n          </li>\n          <li>単位を表示するなど、決まった文字列を追加したい場合は「<code class=\"language-plaintext highlighter-rouge\">{{・・・}}℃</code>」のように波括弧の外側に追加</li>\n        </ul>\n      </li>\n      <li>「units」 で単位を設定する。温度なら「℃」など。これは数値表示には表示されず、グラフ内部の単位情報として表示される</li>\n      <li>「Range」 でグラフの値の範囲を指定する。「-20」~「40」など。\n        <ul>\n          <li>入力値が範囲外になった場合はグラフが上下限に張り付くだけで、エラーなどにはならない。また値そのものは数値表示される</li>\n        </ul>\n      </li>\n      <li>「Colour gradient」 でグラフの色を指定する。3つの色は下で設定するSectors の範囲に対応する</li>\n      <li>「Sectors」 で 上で指定した色を表示する範囲を設定する\n        <ul>\n          <li>これはオプションなので設定しなくても良い。指定しなかった場合は上の「Range」で指定した値の範囲を3等分して使用される</li>\n        </ul>\n      </li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nValue formatのフィルタの詳細は<a href=\"https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters\">https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters</a>を見ろと書かれていましたが、残念ながら私にはよく分かりませんでした…</p>\n</blockquote>\n\n<h1 id=\"dashboardでテキストを表示する\">Dashboardでテキストを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「text」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「text」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>上記参照</li>\n        </ul>\n      </li>\n      <li>「Layout」でレイアウトを選択。お好みで</li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a226513f.c36b1\",\n        \"type\": \"tab\",\n        \"label\": \"Dashboard_1\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"160486fa.dc7159\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e89b8821.ec65e8\",\n        \"type\": \"debug\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 580,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d4346336.cf1228\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e403fdac.aa3748\",\n        \"type\": \"ui_slider\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"label\": \"温度\",\n        \"tooltip\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 4,\n        \"width\": 0,\n        \"height\": 0,\n        \"passthru\": true,\n        \"outs\": \"all\",\n        \"topic\": \"\",\n        \"min\": \"-30\",\n        \"max\": \"50\",\n        \"step\": 1,\n        \"x\": 140,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"78c10ecb.1eb67\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"78c10ecb.1eb67\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 6,\n        \"width\": 4,\n        \"height\": 4,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{value}}℃\",\n        \"min\": \"-20\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 570,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"84bd2adf.3b5df8\",\n        \"type\": \"ui_text\",\n        \"z\": \"a226513f.c36b1\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 560,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1127e563.00001b\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"6547952b.517b34\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"6547952b.517b34\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ1\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"dashboard-のレイアウトを修正する\">Dashboard のレイアウトを修正する</h1>\n\n<p>ボタンのサイズを小さくしたり、複数のボタンを横に並べたい場合はレイアウトの修正を行う。</p>\n\n<ul>\n  <li>サイドバー(右側のペイン)の「dashboard」ボタン(グラフのアイコン)をクリック</li>\n  <li>配置タブをクリック</li>\n  <li>タブの部分(「ホーム」など)をマウスでポイントし、「レイアウト」をクリック\n    <ul>\n      <li>表示領域の幅を変更するには、右上の「幅」の設定値を変更する。(単位はグリッド数)</li>\n      <li>各要素をドラッグすると、表示位置を入れ替えられる。</li>\n      <li>各要素のサイズを変更するには、\n        <ul>\n          <li>右上の鍵アイコンをクリックして閉じた状態にする(鍵が開いた状態では表示領域幅に一致するように自動変更される)</li>\n          <li>右下に矢印アイコンが表示されるので、これをつまんでサイズを変更</li>\n        </ul>\n      </li>\n      <li>各要素を横並びにしたい場合は、各要素をドラッグして移動する(表示幅に収まらない場合は移動できない)</li>\n      <li>各要素のサイズ/位置はグリッド単位でのみ可能</li>\n      <li>右上の完了をクリック\nー デプロイする</li>\n    </ul>\n  </li>\n</ul>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その3)</h1>\n      <p>Node-REDのメモ TCP通信編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでTCP通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"udpで送信\">UDPで送信</h1>\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「送信」で出力するメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト)/「ブロードキャストメッセージ」/「マルチキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で送信先ポート番号を設定\n        <ul>\n          <li>受信プログラムが待ち受けしているポート番号を指定</li>\n        </ul>\n      </li>\n      <li>「アドレス」に送信先アドレス(名前 or IPアドレス)を指定</li>\n      <li>さらにその右で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>特定のポートから送信したいときは「ローカルポートを使用」を選択し、その右に送信元ポート番号を指定する\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n          <li>通常は「ローカルポートをランダムに使用」で大丈夫</li>\n        </ul>\n      </li>\n      <li>入力データがBase64エンコードされたBufferオブジェクトの場合は「Base64形式のペイロードを複合」にチェックを入れる\n        <ul>\n          <li>入力データがBase64文字列かをチェックするだけで、ここでデータを変換するわけではない(?)</li>\n          <li>通常はチェックしないでOK</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると送信先アドレスとポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>送信データを作成するノードを接続\n    <ul>\n      <li>UDPノードはmsg.payloadを送信する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"udpで受信\">UDPで受信</h1>\n<ul>\n  <li>パレットの「入力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「待ち受け」で受信待ちするするメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト or マルチキャスト)/「ブロードキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で受信待ちポート番号を設定\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n        </ul>\n      </li>\n      <li>「種類」で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>「出力」で受信したデータをどのような形式で次段のノードに出力するかを選択する\n        <ul>\n          <li>「バイナリバッファ」を選択すると受信したデータをそのままbufferオブジェクトとして出力</li>\n          <li>「文字列」を選択すると受信したデータをStringオブジェクトにデコードする</li>\n          <li>「Base64文字列」を選択すると受信したデータをBase64 Stringオブジェクトにデコードする</li>\n          <li>「Base64文字列」と「文字列」は内部でtoStringのencodingに’base64’を指定するか’utf8’を指定するかの違い(?)</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると受信待ちポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>受信データを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"2506be7d.1b5332\",\n        \"type\": \"tab\",\n        \"label\": \"UDP\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"44364ec0.0b59b8\",\n        \"type\": \"udp out\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"addr\": \"localhost\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"outport\": \"\",\n        \"base64\": false,\n        \"multicast\": \"false\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"20cee006.2fee4\",\n        \"type\": \"inject\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"\",\n        \"payloadType\": \"date\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 150,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"44364ec0.0b59b8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"eb875fd8.7aa5f8\",\n        \"type\": \"udp in\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"multicast\": \"false\",\n        \"group\": \"\",\n        \"datatype\": \"utf8\",\n        \"x\": 160,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"a6b72636.514e2\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a6b72636.514e2\",\n        \"type\": \"debug\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 140,\n        \"wires\": []\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"httpでrest-api\">HTTPでREST API</h1>\n\n<h2 id=\"http入力ノードの作成\">HTTP入力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「入力」の下の「http」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「メソッド」でメソッド種別を選択\n        <ul>\n          <li>ここでは「GET」で設定を進める(他のメソッドは他所で調べてね)</li>\n        </ul>\n      </li>\n      <li>「URL」でエンドポイント(要はパス)を設定</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとメソッドとURLが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>レスポンスを作成するノード(下記)を接続</li>\n</ul>\n\n<h2 id=\"レスポンス生成ノードの作成\">レスポンス生成ノードの作成</h2>\n\n<p>ここでは、簡単にfunctionノードで固定文字列を返すものを作っています。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると空欄になるので、なるべく識別できる名前を付けましょう</li>\n        </ul>\n      </li>\n      <li>「コード」に処理するプログラムを記述\n        <ul>\n          <li>msg.payloadに表示するページの本文を設定する</li>\n          <li>例えば以下</li>\n        </ul>\n      </li>\n      <li>「名前」の横のアイコンをクリックすると作成したノードの保存/読み込みが出来る\n        <ul>\n          <li>コードは <code class=\"language-plaintext highlighter-rouge\">~/.node-red/lib/functions/</code> に指定したフォルダとファイル名で保存される</li>\n          <li>保存したコードは別のノードで読み込むことができる</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"dl\">\"</span><span class=\"s2\"><h1> ぼ~っと生きてんじゃね~よ! </H1></span><span class=\"dl\">\"</span><span class=\"p\">;</span>\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h2 id=\"http出力ノードの作成\">HTTP出力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「出力」の下の「http response」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「http」と表示される</li>\n        </ul>\n      </li>\n      <li>必要なら「状態コード」を設定</li>\n      <li>必要なら「ヘッダ」を設定</li>\n      <li>シンプルな処理の場合、何も設定しなくてもOK</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"入力レスポンス生成出力を接続\">入力、レスポンス生成、出力を接続</h2>\n\n<ul>\n  <li>上記で作成したノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"ブラウザでアクセス接続\">ブラウザでアクセス接続</h2>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/《HTTP入力ノードに設定したURL》 に接続\n    <ul>\n      <li>ブラウザにレスポンス生成ノードで作成したメッセージが表示される</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"7508e635.c8bf48\",\n        \"type\": \"tab\",\n        \"label\": \"HTTP_REST\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c7938d8a.3ae9d\",\n        \"type\": \"http in\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"url\": \"/rest_api_1\",\n        \"method\": \"get\",\n        \"upload\": false,\n        \"swaggerDoc\": \"\",\n        \"x\": 160,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"fb01d5fd.b76918\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fb01d5fd.b76918\",\n        \"type\": \"function\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"ぼ~っと生きてんじゃね~よ!\",\n        \"func\": \"msg.payload = \\\"<h1> ぼ~っと生きてんじゃね~よ! </H1>\\\";\\nreturn msg;\\n\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 430,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"8d3518af.f9da7\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d3518af.f9da7\",\n        \"type\": \"http response\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"statusCode\": \"\",\n        \"headers\": {},\n        \"x\": 690,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"86c0f820.b0a56\",\n        \"type\": \"debug\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 700,\n        \"y\": 120,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"websocketでデータを送受信\">Websocketでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにwscatを使うこととします。<br />\nwscat は 以下のコマンドでインストールできます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> wscat\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信クライアント\">Websocketでデータ送信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「種類」 で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「URL」 でサーバのURLを設定(例: ws://PiDev25.local:5000/ws/data01)</li>\n          <li>「送信/受信」でペイロードのみ送受信するか、メッセージ全体を送受信するかを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5000で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5000\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5000 (press CTRL+C to quit)\nclient connected\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"75e44664.73e018\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"49b725b6.0e0934\",\n        \"type\": \"websocket out\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"99ad88ce.8bcf7\",\n        \"x\": 600,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"762ccf62.73a48\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fe2498d8.71c17\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47ef3c99.d6eefc\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f97b4d60.afc278\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6d15d519.6289ec\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"87c94e6f.db3458\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"175e465.15aaa3a\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e7c2219c.07acf8\",\n        \"type\": \"debug\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"99ad88ce.8bcf7\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5000/ws/data01\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信サーバ\">Websocketでデータ送信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata1 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest1で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wstest1\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-3\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"22d6d63b.99a952\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"d64e2a6a.27ead8\",\n        \"type\": \"websocket out\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"server\": \"d7536de3.b48578\",\n        \"client\": \"\",\n        \"x\": 520,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"79358fcc.5a5a68\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"cd6acb87.0a77\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7991d417.429124\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ee88046b.37b298\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7eac2c2e.6fa39c\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"650517e9.5e34a8\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d197151e.8b01e\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5871022e.6bbb1c\",\n        \"type\": \"debug\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d7536de3.b48578\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wstest1\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信クライアント\">Websocketでデータを受信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>URL でサーバのURLを設定(例: ws://PiDev25.local:5002/ws/wsdata2)</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-2\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5002で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5002\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5002 (press CTRL+C to quit)\nclient connected\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-4\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a45bd125.622fb8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"24a93730.cf2a7\",\n        \"type\": \"websocket in\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"server\": \"45ba6028.84fc88\",\n        \"client\": \"\",\n        \"x\": 220,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"15576052.1536\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"15576052.1536\",\n        \"type\": \"debug\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"45ba6028.84fc88\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5002/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信サーバ\">Websocketでデータを受信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata2 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-3\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest2で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wsdata2\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-5\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"15604b9.9721eb4\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"80f59585.469758\",\n        \"type\": \"websocket in\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"server\": \"11528a5d.783b0e\",\n        \"client\": \"\",\n        \"x\": 140,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"f37c8fe9.6307c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f37c8fe9.6307c\",\n        \"type\": \"debug\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"11528a5d.783b0e\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その1)</h1>\n      <p>Node-REDのインストール他のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDをインストールや、フローを作成する際の手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"ubuntu-に-node-red-をインストールする\">ubuntu に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejsとnpmのインストール\">Node.jsとnpmのインストール</h2>\n\n<p>自動起動とかやらないなら、Node.js は nodenv とか使っても良い気がするが、\n念のためシステムに直接インストールしておく。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">apt install</code> だと古いバージョンになってしまうので、<br />\nnコマンド をインストールし、<br />\nnコマンドで安定版をインストールする。<br />\nその後、<code class=\"language-plaintext highlighter-rouge\">apt</code> でインストールしたNode.jsは削除。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n\n<span class=\"c\"># nコマンドのインストール</span>\n<span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> n\n\n<span class=\"c\"># 安定版のインストール</span>\n<span class=\"nb\">sudo </span>n stable\n\n<span class=\"c\"># aptでインストールしたnode.jsをアンインストール</span>\n<span class=\"nb\">sudo </span>apt purge <span class=\"nt\">-y</span> nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h2 id=\"node-redのインストール\">Node-REDのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> <span class=\"nt\">--unsafe-perm</span> node-red node-red-admin\n</code></pre></div></div>\n\n<p>どうも、ノードの追加とかすると、npmのキャッシュをアクセスするときにpermission deniedと言われてしまうみたいなので、\n以下のコマンドで .npm ディレクトリ以下の所有権を自分にしておく。<br />\n(キャッシュだから削除しても良い気がするが)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> ~/.npm\n</code></pre></div></div>\n\n<h2 id=\"起動\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"停止\">停止</h2>\n\n<p>CTRL-Cで停止する。</p>\n\n<h2 id=\"参考\">参考</h2>\n\n<p><a href=\"https://qiita.com/seibe/items/36cef7df85fe2cefa3ea\">https://qiita.com/seibe/items/36cef7df85fe2cefa3ea</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"windows10-に-node-red-をインストールする\">Windows10 に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npmの-インストール\">Node.js と npmの インストール</h2>\n\n<ul>\n  <li><a href=\"https://nodejs.org/ja/\">Node.jsのサイト</a>からWindows版をダウンロードします。\n  推奨版(2019/09/16現在、10.16.3 LTS)をダウンロードしてください。<br />\n  (もし、別のプラットフォームのものが必要なら上部のメニューの「ダウンロード」からダウンロードします)</li>\n  <li>ダウンロードしたnode-vXX.XX.XX-YY.msiを実行してインストーラを起動し、インストールします。\n  特に迷うところはないと思います。大体、そのまま「次へ」で大丈夫。</li>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell を起動します。\n  念のため、<code class=\"language-plaintext highlighter-rouge\">node -v</code> を実行して、<code class=\"language-plaintext highlighter-rouge\">v10.16.3</code>と表示されることを確認します。\n  次にnpmのアップデートを行います。以下のコマンドを実行してください。( 2019/09/16現在、6.11.3 でした)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g npm\n</code></pre></div></div>\n<h2 id=\"node-redのインストール-1\">Node-REDのインストール</h2>\n\n<ul>\n  <li>コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してインストールします。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g --unsafe-perm node-red\n</code></pre></div></div>\n\n<ul>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してNode-REDを起動します。<br />\n実行したウィンドウは閉じないでください。閉じるとNode-REDが終了してしまいます。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>なお、初めてNode-REDを起動したとき、\n『このアプリの機能のいくつかがWindows Defender ファイアウォールでブロックされています』\nと警告が表示されることがある。</p>\n\n<p>この場合、\n「通信を許可するネットワーク」を選択して「アクセスを許可する」をクリック\nすれば良い。</p>\n\n<h2 id=\"ちょっとヒトコトメモ\">ちょっとヒトコトメモ</h2>\n\n<p>(ぜんぜんヒトコトじゃないけど。。。)</p>\n\n<p>Node-REDを起動したPCからのアクセス(ブラウザ接続など)は成功するのに、\n外部PCやRaspberryPi(もちろん、同一サブネット上の)からのアクセス(ブラウザやWebsocket接続)が失敗する場合がある。</p>\n\n<p>考えられる原因は色々あるが、最も多そうな原因のひとつにファイアウォールでのブロックが考えられる。<br />\n上の警告ダイアログでアクセス許可した際に、プライベートネットワークのみに通信を許可していて、\nかつ、現在接続されているネットワークがパブリックネットワークである場合である。</p>\n\n<p>ファイアウォールでのブロックされているかは<strong>Node-REDを起動した状態</strong>で以下のコマンドで確認できる。</p>\n\n<ul>\n  <li>RaspberryPiの場合</li>\n</ul>\n\n<p>以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 《IPアドレス》 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 192.168.1.2 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、コマンドが終了しないので、CTRL+Cで終了する。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">Connection to 《IPアドレス》 《ポート番号》port [tcp/*] succeeded!</code>と表示される。</p>\n\n<ul>\n  <li>Windowsの場合</li>\n</ul>\n\n<p>Windows Poewrshellで(コマンドプロンプトでは不可)以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 《IPアドレス》  <span class=\"nt\">-port</span> 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 192.168.1.2 <span class=\"nt\">-port</span> 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : False</code>と表示される。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : True</code>と表示される。</p>\n\n<p>これを解決するには、Node-REDを実行しているWindows PCで<br />\n「コントロールパネル」→「Windows Defender ファイアウォール」を開き、<br />\n左側のリストから「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック<br />\n「設定の変更」をクリック\n下のリストから「Node.js: Server-side JavaScript」の右側 パブリックのチェックボックスにチェックを入れる<br />\n「OK」をクリック</p>\n\n<p>この状態で再度RaspberryPi または PCからファイアウォールでのブロックの確認を実行し、ブロックされていないことを確認してください。</p>\n\n<h1 id=\"raspbian-に-node-red-をインストールする\">Raspbian に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npm-と-node-red-のインストール\">Node.js と npm と Node-RED のインストール</h2>\n\n<p>インストールスクリプトを実行すればイッパツで解決。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストールスクリプトの取得</span>\nwget  https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered\n\n<span class=\"c\"># 必要なら中身確認してね</span>\n\n<span class=\"c\"># インストールスクリプトの実行</span>\nbash update-nodejs-and-nodered \n</code></pre></div></div>\n\n<h2 id=\"起動-1\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-start \n</code></pre></div></div>\n<p>CTRL-Cでログ表示のみ止まる(Node-RED自体は動作したまま)</p>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"ログ表示\">ログ表示</h2>\n\n<p>Node-RED で console.log などを実行したときは、ログに表示される。<br />\n<code class=\"language-plaintext highlighter-rouge\">node-red-start</code>したままなら表示されるが、CTRL-Cでログ表示を止めていた場合は\n以下のコマンドでログ表示を再開できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-log\n</code></pre></div></div>\n\n<h2 id=\"停止-1\">停止</h2>\n\n<p>Node-RED自体を停止する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-stop\n</code></pre></div></div>\n\n<h2 id=\"参考-1\">参考</h2>\n\n<p><a href=\"https://qiita.com/utaani/items/7155c62d6c5e96822afb\">https://qiita.com/utaani/items/7155c62d6c5e96822afb</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"フローの操作\">フローの操作</h1>\n\n<h2 id=\"フローを保存するエクスポート\">フローを保存する(エクスポート)</h2>\n\n<p>作成したフローは保存することができます。<br />\nしばらく使わないフローを削除したり、別の環境にコピーする場合に保存しておくと良いでしょう。</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「書き出し」→「クリップボード」をクリック →書き出しダイアログが表示される\n    <ul>\n      <li>書き出す範囲を「現在のタブ」「すべてのタブ」から選択。(フローの一部を選択していた場合は「選択したフロー」も選択可能)</li>\n      <li>その下にはその時のJSONファイルの内容が表示されていますので、ここから</li>\n      <li>さらにその下で出力形式を「インデントのないJSONフォーマット」「インデント付きのJSONフォーマット」から選択。多少ファイルサイズが増減しますが、どちらを選んでも特に問題になるようなことはないでしょう。「インデント付き」の方が目視で確認しやすいと思います。</li>\n      <li>「ダウンロード」をクリックすると、ブラウザのファイル保存(ダウンロード)ダイアログが開くので、保存処理を行う(このときのファイル名はflows.json固定なので、必要に応じて保存後リネームしてください)</li>\n      <li>または、「書き出し」をクリックすると、クリップボードへコピーされるので、直接 別の環境の読み込みダイアログやエディタへペーストすることも可能</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"フローを読み込むインポート\">フローを読み込む(インポート)</h2>\n\n<p>保存したフローは読み込んで使用することができます(当然か)</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「読み込み」→「クリップボード」をクリック →読み込みダイアログが表示される\n    <ul>\n      <li>「読み込むファイルを選択してください」をクリックして読み込むファイルを選択 → ファイルの内容がその下のエディットボックスに表示される</li>\n      <li>または、その下のエディットボックスにJSONデータをペースト</li>\n      <li>読み込み先を「現在のタブ」「新規のタブ」から選択(「選択したフロー」で保存してないとどっちでも同じ気がする)</li>\n      <li>「読み込み」をクリック</li>\n    </ul>\n  </li>\n  <li>読み込まれるので、内容を確認。必要なら修正。</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"フローを削除する\">フローを削除する</h2>\n\n<p>使用しなくなったフローをいつまでも残しておくとトラブルの元ですから、削除しましょう。<br />\n(念のため保存しておくのを忘れずに)</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、削除したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>左上の「削除」をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(次回デプロイするまで処理は残っているので注意)</li>\n</ul>\n\n<h2 id=\"フローを一時的に停止する\">フローを一時的に停止する</h2>\n\n<p>後で使うから削除したくはないけど、今デバッグしてる作業の邪魔になる、というような場合、\n作成したフローを削除せずに一時的に停止することができます。</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、停止したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>状態を「無効」にする</li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(デプロイしないといつまで経っても停止しないので注意)</li>\n</ul>\n\n<p>再開する場合は上記手順と同じで、状態を「有効」にする。</p>\n\n<h2 id=\"フローを全削除する\">フローを全削除する</h2>\n\n<p>色々フローを作成したけど、一回チャラにしてやりなおしたいときは、\n一旦Node-REDを停止(ブラウザ切断だけじゃなく、サーバプログラムを停止)して\n以下の2つのファイルを削除する</p>\n\n<ul>\n  <li>~/.node-red/flows_《ホスト名》.json</li>\n  <li>~/.node-red/.flows_《ホスト名》.json.backup</li>\n</ul>\n\n<p>もちろん、念のためバックアップ取っておくのが好ましい。<br />\nバックアップから復元すれば元通りになるはず。</p>\n\n<p>その後、Node-Redを起動すると、フローが綺麗さっぱり消えているハズ。</p>\n\n<h2 id=\"その2以降のフローの例について\">その2以降の「フローの例」について</h2>\n\n<p>「フローの例」に書かれたJSONコードはテスト用に作成したフローをエクスポート(書き出し)したものです。<br />\nこのコードの表示部分にマウスを乗せると、右上に「Copy」ボタンが表示されますので、このボタンをクリックしてください。JSONコードがクリップボードにコピーされます(マウスをドラッグしての選択は不要)。</p>\n\n<p>この状態で、上記<strong>フローを読み込む(インポート)</strong>に示した方法でフローをインポートするとフローがコピーされます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n複数のフローをインポートした場合、既に存在するノードと同名のノードは別のノードとして生成されます。このとき、名前に「(_1)」などの別ノードを識別できるような記号は付きません。<br />\n特に、WebsocketのノードやDashboardのタブ/グループはシステムの動作や見た目に影響しますので、注意してください。<br />\n自動でよしなにする方法はありませんので、手動でチマチマと修正してください。<br />\nサイドバー(右側のペイン)の「▼」ボタンをクリックし、ノードの設定を表示でノードの設定を表示し、<br />\n各ノードの右側の数字をクリックすると、そのノードを参照しているノードの一覧が表示されます。<br />\nさらにそのノード一覧の各ノードをダブルクリックすると、そのノードが点滅表示されるので、そのノードのプロパティで参照先を変更すれば良いでしょう。</p>\n\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git + samba環境</title>\n  </head>\n  <body>\n    <header>\n      <h1>git + samba環境</h1>\n      <p>gitのローカルリポジトリをsamba環境で使用する際の注意事項</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>gitのローカルリポジトリをsamba経由で見ると、ファイルのAttributeの実行属性が変更されたと誤検出してしまうことがある。\nそんなときは、以下のコマンドでファイルのAttributeを無視するように設定すれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--unset</span> core.filemode\ngit config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>サーバ側は以下を一回だけ実行しておけばサーバ側でのAttributeの管理は有効になる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<p>意図的に実行属性を設定したい場合などは、サーバ側で<code class=\"language-plaintext highlighter-rouge\">git add</code>する。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのローカル環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのローカル環境での実行</h1>\n      <p>github pagesをローカル環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行することができる。</p>\n\n<p>以下の手順はUbuntu 16.04で動作確認した。他のバージョンでは、特にインストールの準備に微妙な違いがあるかもしれない。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<p>apt または rbenvでrubyをインストールしておく。</p>\n\n<p>aptの場合は以下(nativeなライブラリを使うので-devパッケージをインストール) 。<br />\nrbenvの場合は<a href=\"/memoBlog/2019/07/07/rbenv.html\">rbenvのインストール</a>参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ruby-dev\n</code></pre></div></div>\n\n<p>bundlerをインストールする。bundlerはNode.jsでいうところのnpmのうち、package.jsonでローカルインストールしたモジュールを管理する部分に相当するもの(かな?)。<br />\naptでrubyをインストールした場合はrootでインストール必要があるので、<code class=\"language-plaintext highlighter-rouge\">sudo</code>を付けて実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem <span class=\"nb\">install </span>bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span>\n</code></pre></div></div>\n\n<p>モジュールをローカルにインストールすることもできる。<br />\nその場合は以下で。<br />\n–pathオプションのパラメータはお好みで変更してちょ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span> <span class=\"nt\">--path</span> gems\n</code></pre></div></div>\n\n<p>このとき、<code class=\"language-plaintext highlighter-rouge\">_config.yml</code>の以下の部分にモジュールのインストール先(上の例では<code class=\"language-plaintext highlighter-rouge\">gems</code>)を追加しておく(追加しないとjekyll実行時にエラーになる)。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<div style=\"text-align: center;\">↓</div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [gems, server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n\n<h2 id=\"サーバ起動\">サーバ起動</h2>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./server.sh\n</code></pre></div></div>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>ブラウザ(firefoxとchromeで動作確認した。IEでは動かない。Edgeはよーわからん)を起動し、サーバを起動しているマシンのport 4000に接続。このとき、ブラウザはサーバと同じマシンである必要はない。</p>\n\n<h2 id=\"サーバの停止\">サーバの停止</h2>\n\n<p>CTRL+cで停止。</p>\n\n<h2 id=\"サーバの-listen-port-の変更\">サーバの listen port の変更</h2>\n\n<p>必要ならサーバの listen port を変更できる。<br />\nserver.sh 内のコマンドの <code class=\"language-plaintext highlighter-rouge\">--port</code> オプションを変更すればOK.</p>\n\n<h1 id=\"ディレクトリ構成\">ディレクトリ構成</h1>\n\n<p>ディレクトリ構成は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── _config.yml                             jekyllの設定ファイル\n├── Gemfile                                 bundlerの管理ファイル\n├── _layouts                                ページレイアウト用HTMLファイル置き場\n│   ├── default.html                           デフォルト使用\n│   ├── toppage.html                           トップページ用\n│   └── debug.html                             デバッグページ用\n│                                                 どのレイアウトを使うかは各MarkdownファイルのFront-matterで指定する\n├── _includes                               共通で使用するレイアウトはここに置いておく\n│   └── footer.html\n├── _posts                                   投稿記事置き場\n│   ├── 2019-06-22-asyncawait.md\n│   ├── ・・・・\n│   └── YYYY-MM-DD-title.md                     ブログの投稿記事  ファイル名は年-月-日-タイトル とする。\n├── _sass                                    sassのインクルードファイルを置いておく\n│   └── _my_theme.scss                          大本のテーマ設定用sassファイル\n├── assets\n│   ├── css\n│   │   ├── jquery.floatingscroll.css      jQuery の floatingscroll プラグインのCSSファイル\n│   │   └── style.scss                     このページのメインのcssになるsassファイル\n│   └── js\n│       ├── jquery.floatingscroll.min.js    jQuery の floatingscroll プラグインのスクリプトファイル\n│       └── main.js                         各ページで実行するjavascriptファイル\n├── index.md                                 トップページ\n├── misc                                     以下にその他のページデータを置く\n│   ├── debug.md\n│   └── sample.md\n├── favicon.ico                              favicon画像\n├── compile.sh                               サイト構築のみ行うスクリプト\n├── server.sh                                サーバ起動用スクリプト(サイト構築も同時に行う)\n└── _site                                    以下にサイト構築データが生成される\n</code></pre></div></div>\n\n<h1 id=\"投稿記事のファイル名\">投稿記事のファイル名</h1>\n\n<p>投稿記事のファイル名は<code class=\"language-plaintext highlighter-rouge\">YYYY-MM-DD-title.拡張子</code>とする。<br />\nそれ以外のファイル名を付けると無視される。</p>\n\n<p>日付、タイトルは後述のFrontMatterに設定があればそちらが優先される。</p>\n\n<h1 id=\"front-matterの構成\">Front Matterの構成</h1>\n\n<p>Front Matterの主な項目は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>---\ntitle: XXXX                タイトル  指定無ければファイル名のタイトル部分が使用される\ndate: 2019-07-07           日付 指定無ければファイル名の日付部分が使用される\ntags: [\"YYY\",\"ZZZ\"]        タグを指定  このタグでトップページでカテゴリを選択できる 大文字/小文字は区別される\nlayout: toppage            使用するレイアウト 指定無ければdefaultが使用される\nexcerpt: xxxxxx            抜粋  トップページのタイトルの下に表示される\n---\n</code></pre></div></div>\n\n<h1 id=\"あとはお好きに変更してちょ\">あとはお好きに変更してちょ</h1>\n\n<p>自分のリポジトリにpushして、そのリポジトリの設定でgithub pagesを有効にすればいっちょ上がり。</p>\n\n<p>ちなみに、ファイルが一つもないリポジトリではgithub pagesを有効にできないので、ダミーでもいいからファイルをpushしてから設定すること。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>rbenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>rbenvのインストール</h1>\n      <p>rbenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonに対するpyenvのようにrubyのバージョンを変更したり、個別にモジュールを管理したりできるrbenvを導入する。<br />\nあと、モジュールをインストールする <code class=\"language-plaintext highlighter-rouge\">gem install</code> に <code class=\"language-plaintext highlighter-rouge\">sudo</code> を付けなくても良いのも地味に便利。<br />\ngemset(pyenvの仮想環境のようなもの)を作って個別にモジュール管理すれば、色々インストールして訳わからん状態になったときでも、一旦チャラにして観光構築をやりなおせる。</p>\n\n<p>なお、rbenvはrubyをバイナリインストールできなくて、ソースからコンパイルするので、インストールにはそれなりに時間がかかる。</p>\n\n<p>以下の手順はUbuntu 16.04で動作確認した。他のバージョンでは、特にインストールの準備に微妙な違いがあるかもしれない。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>インストールに必要なモジュールをインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>git autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev\n</code></pre></div></div>\n\n<h2 id=\"rbenv本体とプラグインのインストール\">rbenv本体とプラグインのインストール</h2>\n\n<p>rbenv本体とプラグインをインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">RBENV_ROOT</span><span class=\"o\">=</span>/proj/.rbenv    <span class=\"c\"># 環境に合わせて修正してね</span>\ngit clone https://github.com/sstephenson/rbenv.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/sstephenson/ruby-build.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/ruby-build\ngit clone git://github.com/jf/rbenv-gemset.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-gemset\ngit clone https://github.com/sstephenson/rbenv-gem-rehash.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-gem-rehash\ngit clone https://github.com/rkh/rbenv-update.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-update\n</code></pre></div></div>\n<p>rbenv-gemset をインストールすることで、個別のモジュール環境を構築できる。pyenvのvirtualenvみたいな感じ。<br />\nrbenv-gem-rehashをインストールすることで、バージョン切り替えやgemのインストールの度にrbenv rehash を実行しなくてもよくなる。<br />\nrbenv-updateをインストールすることで、<code class=\"language-plaintext highlighter-rouge\">rbenv uppppdate</code> でrbenvと各プラグインのアップデートができる。</p>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>rbenvの設定のため、~/.bashrc に以下を追加。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">RBENV_ROOT</span><span class=\"o\">=</span>/proj/.rbenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$RBENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>rbenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h1 id=\"設定と使い方\">設定と使い方</h1>\n\n<h3 id=\"rbenvでインストールできるバージョンの一覧を表示\">rbenvでインストールできるバージョンの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span>\n</code></pre></div></div>\n\n<h3 id=\"rubyのインストール\">rubyのインストール</h3>\n\n<p>インストールしたいバージョンを指定して実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">install </span>2.6.3\n</code></pre></div></div>\n\n<p>・・・ 気長に待つ。 ・・・</p>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<p>デフォルトで使用したいバージョンを指定して実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv global 2.6.3\n</code></pre></div></div>\n\n<p>念のため指定したバージョンが実行されることを確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ruby <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h3 id=\"gemsetの作成\">gemsetの作成</h3>\n\n<p>色々試したあとに、インストールしたモジュールをチャラにしたいときを考えて、gemset(仮想環境みたいなもん)を構築しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset create 《ベースバージョン》 《gemset名》\n</code></pre></div></div>\n\n<p>例えば、ruby 2.6.3 に test1 という名前のgemsetを作成する場合。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset create 2.6.3 test1\n</code></pre></div></div>\n\n<p>gemsetはインストールされた各バージョンに紐づいて作成される。</p>\n\n<h3 id=\"gemsetの設定\">gemsetの設定</h3>\n\n<p>gemsetはディレクトリ毎に指定する。<br />\nカレントディレクトリに設定されたgemset(なければその親、さらに親と探す)と\nカレントのRubyバージョンが使用される。<br />\nカレントのRubyのバージョンに指定されたgemsetが存在しなければ新しくgemsetを作成するが、中身は空。<br />\nなので、gemsetを指定したときは、同時に <code class=\"language-plaintext highlighter-rouge\">rbenv local</code> でローカルバージョンも指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> 《設定したいディレクトリ》\nrbenv <span class=\"nb\">local</span> 《バージョン》\nrbenv gemset init 《gemset名》\n</code></pre></div></div>\n<p>gemset名を省略するとカレントディレクトリ名と同じ名前でgemsetが作成され、そのgemsetに設定される</p>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\nrbenv gemset init test1\n</code></pre></div></div>\n\n<h3 id=\"作成されたgemsetの一覧表示\">作成されたgemsetの一覧表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset list\n</code></pre></div></div>\n<p>こんな感じで表示される。Rubyのバージョンが異なれば同名のgemsetも作成できる。<br />\nただし、中身は別物。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>rbenv gemset list\n2.3.8:\n  test1\n2.6.3:\n  test1\n</code></pre></div></div>\n\n<h3 id=\"カレントディレクトリで有効なgemsetの確認\">カレントディレクトリで有効なgemsetの確認</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset active\n</code></pre></div></div>\n\n<p>ついでにRubyのバージョンも確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv version\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>rbenv gemset active\nenv1 global\n<span class=\"nv\">$ </span>rbenv version\n2.6.3 <span class=\"o\">(</span><span class=\"nb\">set </span>by /*******/.ruby-version<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"gemsetの指定を無効にするにはrbenv-gemsets-ファイルを削除する\">gemsetの指定を無効にするには.rbenv-gemsets ファイルを削除する</h3>\n\n<p>コマンドで指定を無効にできないので、指定ファイルを手動で削除する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> .rbenv-gemsets\n</code></pre></div></div>\n<p>使用するgemsetを変更したい場合、すでにgemset設定済みのディレクトリでは再設定できない。<br />\n一旦gemsetの指定を無効にしてから、再度 <code class=\"language-plaintext highlighter-rouge\">rbenv gemset init ~</code> する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n\n<h3 id=\"gem関連の設定を確認\">gem関連の設定を確認</h3>\n\n<p>gem関連の設定(GEM_PATHSなど)を確認したいときは以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem <span class=\"nb\">env</span>\n</code></pre></div></div>\n<h3 id=\"helpの表示\">helpの表示</h3>\n\n<p>rbenv 全体のヘルプ(コマンドの確認など)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">help</span>\n</code></pre></div></div>\n\n<p>各コマンドのヘルプ(パラメータやオプションの確認など)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">help</span> 《コマンド》\n</code></pre></div></div>\n\n<h1 id=\"メモ\">メモ</h1>\n\n<h3 id=\"rehashについて\">rehashについて</h3>\n\n<p>設定を変えたりした場合は以下を実行する必要があるが、rbenv-gem-rehashをインストールしてあれば必要なタイミングで自動で行われるので不要。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv rehash \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 16.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 16.04のインストール</h1>\n      <p>Ubuntu 16.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 16.04 のインストール手順のメモです。<br />\nVirtualBox へのインストール前提で書いてます。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-1604-インストール媒体の入手\">Ubuntu 16.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら</p>\n\n<p><a href=\"http://old-releases.ubuntu.com/releases/16.04.5/\">http://old-releases.ubuntu.com/releases/16.04.5/</a></p>\n\n<p>ファイル一覧の下の方の<br />\n<a href=\"http://old-releases.ubuntu.com/releases/16.04.5/ubuntu-16.04.5-desktop-amd64.iso\">「ubuntu-16.04.5-desktop-amd64.iso」</a><br />\nを選択する</p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを1024MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動し、画面の明るさとロックを選択<br />\n「次の時間アイドル状態が続けば画面をオフにする」を「しない」に設定。<br />\n「ロックする」を「オフ」に設定。</p>\n</blockquote>\n\n<h3 id=\"ap-getよりaptが使いやすい\">ap-getよりaptが使いやすい</h3>\n\n<p>最初から入ってたっけ??<br />\n入ってなかったら以下で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>apt\n</code></pre></div></div>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"nb\">sudo </span>apt dist-upgrade <span class=\"o\">(</span>必要なら<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p>終わったらリブート</p>\n\n<h3 id=\"gccとかmakeとかは最初からインストールされているはず\">gccとかmakeとかは最初からインストールされているはず</h3>\n\n<p>入っていない場合は以下でインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<h4 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h2 id=\"使わないパッケージをアンインストール\">使わないパッケージをアンインストール</h2>\n\n<p>使わないパッケージはディスクの肥やしになるだけでなく、余計なアップデートで時間を食うので、以下の感じでアンインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove <package name>\n</code></pre></div></div>\n<p>インストール済みのパッケージは以下で確認できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--manual-installed</span>\n</code></pre></div></div>\n\n<p>依存関係によってインストールされたパッケージも含めて確認するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span>\n</code></pre></div></div>\n\n<h4 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-panel\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n一旦ログアウトして<br />\nサインインボタン横のUbuntuアイコンで「GNOME Flashback (Compiz)」を選択してログインする<br />\n選択した内容は次回起動時も覚えている。</p>\n</blockquote>\n\n<h4 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h4>\n<blockquote>\n  <p>[!TIP]\n端末を起動し、メニューの「編集」→「設定」を選択<br />\n「プロファイル」タブを選択<br />\n使用中のプロファイル(最初のは「default」)を選択し、「編集」をクリック<br />\n「全般」タブの「フォントを指定する」 にチェックを入れ、その右側でフォントを選ぶ<br />\n        Takao ゴシック Regular あたりがおススメ<br />\nついでに「起動時の端末サイズ」も修正しておくとよい</p>\n</blockquote>\n\n<h4 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj\n<span class=\"nb\">sudo mkdir</span> /work1\n<span class=\"nb\">sudo mkdir</span> /work2\n<span class=\"nb\">sudo mkdir</span> /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h4 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h4>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h4 id=\"bashの設定変更\">bashの設定変更</h4>\n<p>~/.bashrcに以下を追記</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n</code></pre></div></div>\n\n<h4 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>compizconfig-settings-manager \n</code></pre></div></div>\n<p>アプリケーション→システムツール→Preference→CompizeConfigSettingsManager でプログラム起動<br />\nウィンドウ・マネジメントのGridのチェックをはずす</p>\n\n<h4 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferenceを選択<br />\n    auto-rise             false<br />\n    focus-mode            sloppy or mouse<br />\n    rise-on-click         true</p>\n</blockquote>\n\n<h4 id=\"ウィンドウのボタンの位置を右側にする\">ウィンドウのボタンの位置を右側にする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferenceを選択<br />\n    「button-layout」に 「menu:minimize,maximize,close」を設定</p>\n</blockquote>\n\n<h4 id=\"日本語入力\">日本語入力</h4>\n<ul>\n  <li>アプリケーション→システムツール→システム設定→言語サポートを選択</li>\n  <li>「言語サポートが完全にはインストールされていません」と出るので<br />\n「インストール」をクリック</li>\n  <li>一旦ログアウトして再ログイン</li>\n  <li>アプリケーション→システムツール→システム設定→テキスト入力設定を選択</li>\n  <li>入力ソースタブを選択</li>\n  <li>左下の+ボタンを押してMozc(Fcitx)を選択して追加ボタンを押す</li>\n</ul>\n\n<h4 id=\"sambaのインストール\">sambaのインストール</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h4 id=\"nfsのインストール\">NFSのインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認(IPアドレスは環境に合わせて変更してね)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h4 id=\"apache-のインストール\">apache のインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>apache2\n<span class=\"nb\">mkdir</span> /proj/wwwroot\n</code></pre></div></div>\n\n<p>/etc/apache2/apache2.conf に以下を追加<br />\n<Directory ~と書いてあるところがあるので、その並びに追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><Directory /proj/wwwroot/>\n    Options Indexes FollowSymLinks\n    AllowOverride None\n    Require all granted\n</Directory>\n</code></pre></div></div>\n\n<p>/etc/apache2/sites-available/000-default.conf の以下を修正</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>DocumentRoot /proj/wwwroot\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/apache2 restart\n</code></pre></div></div>\n\n<h3 id=\"以上でインストールは終了\">以上でインストールは終了</h3>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"nmcliが入ってなかったら以下でインストール\">nmcliが入ってなかったら以下でインストール</h3>\n\n<p>入ってたか、入れたか、何かの依存関係で入ったか覚えてない…</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>network-manager\n</code></pre></div></div>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hostnameを直接エディタで書き換えても可。</p>\n</blockquote>\n\n<h3 id=\"etchosts-の変更\">/etc/hosts の変更</h3>\n<p>旧ホスト名を「old_hostname」、新しいホスト名を「new_hostname」とした場合、以下のコマンドで書き換えられる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/old_hostname/new_hostname/'</span> /etc/hosts\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nエディタで書き換えても可。/etc/hostsを開いて旧ホスト名を新しいものに書き換える。</p>\n</blockquote>\n\n<h3 id=\"ipアドレスの変更固定アドレスにしたい場合\">IPアドレスの変更(固定アドレスにしたい場合)</h3>\n<blockquote>\n  <p>[!TIP]\nシステム設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん。<br />\nなんかこんな感じ。</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"各接続の設定値の表示\">各接続の設定値の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show  <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n<p>「”有線接続 2”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n<p>「”有線接続 2”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n<p>「”有線接続 3”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h1 id=\"共有フォルダの設定とマウント\">共有フォルダの設定とマウント</h1>\n\n<h2 id=\"virtualboxでの共有フォルダの設定\">VirtualBoxでの共有フォルダの設定</h2>\n\n<ul>\n  <li>仮想マシン→設定で設定ダイアログを表示\n    <ul>\n      <li>「共有フォルダ」で「共有フォルダの追加」ボタンをクリック\n        <ul>\n          <li>「フォルダーのパス」に共有するフォルダを指定</li>\n          <li>「フォルダ名」に名前を付ける(例:Share))</li>\n          <li>その他は空欄のまま</li>\n          <li>「OK」をクリック</li>\n        </ul>\n      </li>\n      <li>「OK」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"マウントポイントの作成\">マウントポイントの作成</h2>\n\n<p>マウントポイントを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /Share\n</code></pre></div></div>\n\n<h2 id=\"手動でマウント\">手動でマウント</h2>\n\n<p>以下のコマンドでマウントできる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> vboxsf Share /Share/\n</code></pre></div></div>\n\n<p>アンマウントするときはこちら。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount /Share/\n</code></pre></div></div>\n\n<h2 id=\"自動でマウント\">自動でマウント</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/fstab</code> に以下の内容を追加。\nこれで、起動時に自動でマウントされる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Share /Share vboxsf defaults 0 0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>nodenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>nodenvのインストール</h1>\n      <p>nodenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonのpyenvと同様にNode.jsのバージョン管理システムのnodenvを使用する。<br />\n(両方インストールするくらいならanyenvを使えという説もあるが…)</p>\n\n<p>他にもnvmやnodebrewなんてのもあるらしい。nodenvはディレクトリごとにローカルバージョンを設定できてとても便利なのでおススメ。<br />\nnodeenv(eが2つ)という超マイナーなのもあるけど、間違わないように。</p>\n\n<p>Node.jsはリポジトリにバイナリパッケージが用意されているバージョンはバイナリインストールできる。用意されていないバージョンはソースからコンパイルされるが、必要なライブラリ類のインストールなど必要。ここでは手順は割愛。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>インストールに必要なモジュールをインストールする。インストール済みならスキップして可。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>git\n</code></pre></div></div>\n\n<h2 id=\"nodenv本体のインストール\">nodenv本体のインストール</h2>\n\n<p>nodenv本体をインストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\ngit clone git://github.com/nodenv/nodenv.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/nodenv/node-build.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>nodenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"nodenvでインストールできるバージョンの一覧を表示\">nodenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install</span> <span class=\"nt\">-l</span>\n</code></pre></div></div>\n<p>バイナリインストールできるか確認したい場合は以下。<br />\nバイナリがなければソースからコンパイルされるが、時間がかかるのが嫌な場合に(大抵のバージョンはバイナリが用意されているようだ)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"nt\">-r</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/share/\n<span class=\"c\"># ただし、uname -m が x86_64 | amd64 | i686-64 のときはx64に置き換える</span>\n</code></pre></div></div>\n\n<h3 id=\"nodejsのインストール\">Node.jsのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install </span>10.15.3 \n</code></pre></div></div>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv global 10.15.3\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境について\">仮想環境について</h3>\n\n<p>pyenvと異なり、nodenvは仮想環境をサポートしていない。<br />\nNode.jsはローカルモジュールのインストールが簡単なので、仮想環境を構築しなくても個々のディレクトリでローカルモジュールをインストールすることで仮想環境相当のことが実現できる。</p>\n\n<h3 id=\"npmのバージョンアップ\">npmのバージョンアップ</h3>\n\n<p>「npmが古い~」と言われる前にバージョンアップ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> npm\n</code></pre></div></div>\n\n<h3 id=\"ローカルで使用するバージョンの設定\">ローカルで使用するバージョンの設定</h3>\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは9.11.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">local</span> <バージョン名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv shell <バージョン名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"nodenvのバージョンアップ\">nodenvのバージョンアップ</h1>\n\n<p>Node.jsの新しいバージョンがリリースされ、それをインストールしたい場合など、nodenvのバージョンアップが必要。<br />\n<strong>下記その2の方がおススメ。こっちの手順は参考までに。</strong></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/\ngit pull\n</code></pre></div></div>\n<p>実行後、ターミナルを開きなおす</p>\n\n<h1 id=\"nodenvのバージョンアップ-その2\">nodenvのバージョンアップ その2</h1>\n<p>nodenv-updateをインストールしておけば、<code class=\"language-plaintext highlighter-rouge\">nodenv update</code>を実行するだけですべてのプラグインを含めてバージョンアップしてくれるので、おススメ。インストール方法は下記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/nodenv/nodenv-update.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/nodenv-update\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのnodejsを使いたい場合\">システムのNode.jsを使いたい場合</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv version\n</code></pre></div></div>\n\n<h3 id=\"nodenvでインストールされているnodejsのバージョンを確認\">nodenvでインストールされているNode.jsのバージョンを確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"nodenv自体のバージョン確認\">nodenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"nodenvで使用できるコマンドの確認\">nodenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv commands\n</code></pre></div></div>\n\n<h3 id=\"nodenvのヘルプの表示\">nodenvのヘルプの表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">help</span>\n\n<span class=\"c\"># 各コマンドのヘルプを表示するには以下</span>\nnodenv <span class=\"nb\">help</span> <<span class=\"nb\">command</span><span class=\"o\">></span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのインストール</h1>\n      <p>pyenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>システムのpythonのバージョンを変更したり、モジュールの変更をしたりするとシステム上のスクリプトの動作に影響が出る場合があるので、pyenvで個別のpython環境を構築するのがベター。<br />\nさらに、virtualenvプラグインを使うと、同じpythonのバージョンでもそれぞれに別のモジュールをインストールできる、仮想環境を構築できる。</p>\n\n<p>なお、pyenvはpythonをバイナリインストールできなくて、ソースからコンパイルするので、インストールにはそれなりに時間がかかる(RasPi2で1~2時間くらい?)。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<h3 id=\"必要なモジュールをインストール\">必要なモジュールをインストール</h3>\n<p>インストールに必要なモジュールをインストールする。</p>\n<ul>\n  <li>Bullseye以降ではこちら<br />\n(<code class=\"language-plaintext highlighter-rouge\">python-openssl</code> →  <code class=\"language-plaintext highlighter-rouge\">python3-openssl</code>)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>Buster以前ではこちら\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"bluetoothを使用する場合\">bluetoothを使用する場合</h3>\n<p>bluetoothを使用する場合は以下も必要</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以前、 ubuntuの場合は以下と書いていたが、<code class=\"language-plaintext highlighter-rouge\">libbluetooth3-dev</code>は<code class=\"language-plaintext highlighter-rouge\">libbluetooth-dev</code>の別名定義だったので上のコマンドでOKのはず。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth3-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"pyenv本体とvirtualenvプラグインのインストール\">pyenv本体とvirtualenvプラグインのインストール</h2>\n\n<p>pyenv本体とvirtualenvプラグインをインストール。<br />\nついでにupdateプラグインも入れとく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>pyenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n<span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>Raspbianでは以下も追加<br />\nnumpyをimportしたとき、undefined symbol: PyFPE_jbuf でエラーになる対策。<br />\n参考: <a href=\"https://research.itplants.com/?p=2437\">https://research.itplants.com/?p=2437</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"--enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-fpectl\"</span>\n</code></pre></div></div>\n\n<p>Ubuntuでは以下を追加しておく(デフォルトだとShared Library のimportでエラーになる)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h2 id=\"sudoでpyenv環境を実行するように設定する\">sudoでpyenv環境を実行するように設定する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo</code>でpythonを実行すると、pyenvの設定に関係なくsystemのpythonが実行されてしまいます。<br />\nこれを防ぐためには、<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers</code>の<code class=\"language-plaintext highlighter-rouge\">Defaults secure_path</code>に以下のpathを追加します。</p>\n\n<ul>\n  <li>«pyenvインストール先»/plugins/pyenv-virtualenv/shims:</li>\n  <li>«pyenvインストール先»shims:</li>\n  <li>«pyenvインストール先»/bin:</li>\n</ul>\n\n<p>具体的には以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 変更前\nDefaults  secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n    ↓\n# 変更後\nDefaults  secure_path=\"/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n</code></pre></div></div>\n<ul>\n  <li></li>\n</ul>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"pyenvでインストールできるバージョンの一覧を表示\">pyenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span> \n</code></pre></div></div>\n\n<h3 id=\"pythonのインストール\">pythonのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.4\n</code></pre></div></div>\n\n<p>・・・ 気長に待つ。 ・・・</p>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global 3.6.4\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-V</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境の構築\">仮想環境の構築</h3>\n\n<p>色々試したあとに、インストールしたモジュールをチャラにしたいときを考えて、仮想環境を構築しておく。<br />\nここでは、python 3.6.4を使用して 仮想環境名 mypython を作成。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.6.4 mypython\n</code></pre></div></div>\n\n<p>デフォルトをmypythonに変更する場合は以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global mypython\n</code></pre></div></div>\n\n<h3 id=\"pipのバージョンアップ\">pipのバージョンアップ</h3>\n\n<p>「pipが古い~」と言われる前にバージョンアップ。ついでにsetuptoolsとwheelも。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n<blockquote>\n  <p>[!IMPORTANT]\nベース環境をバージョンアップしても、仮想環境に引き継がれないので、仮想環境毎に実行が必要。</p>\n</blockquote>\n\n<h3 id=\"ローカルバージョンの設定\">ローカルバージョンの設定</h3>\n\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは3.4.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">local</span> <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"i2cを使用する場合raspi\">I2Cを使用する場合(RasPi)</h1>\n\n<p>RaspberryPi環境で、I2Cを使うためのsmbusモジュールは、通常 <code class=\"language-plaintext highlighter-rouge\">sudo apt install python3-smbus</code> でインストールするが、これだとpyenv環境にインストールできない。<br />\nこれはsmbus2をインストールして使用することで回避できる。\nインストールは以下のように実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>smbus2\n</code></pre></div></div>\n<p>ちなみに、pyenv 環境へのモジュールのインストールには <code class=\"language-plaintext highlighter-rouge\">sudo</code> は不要。/usr 下へのインストールではないので。</p>\n\n<p>で、プログラムソース側はsmbusのインストール部分を以下のように修正。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus</span>\n<span class=\"k\">except</span> <span class=\"nb\">ImportError</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus2</span> <span class=\"k\">as</span> <span class=\"n\">smbus</span>\n</code></pre></div></div>\n\n<p>smbus2 だけにしても良いけど、smbus でも動作できるようにしておくのがベターかな。</p>\n\n<h1 id=\"pyenvのバージョンアップ\">pyenvのバージョンアップ</h1>\n<p>pythonの新しいバージョンがリリースされ、それをインストールしたい場合など、pyenvのバージョンアップが必要。<br />\npyenv-updateをインストールしておけば(上記手順でインストール済み)、以下のコマンドですべてのプラグインを含めてバージョンアップしてくれる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv update\n</code></pre></div></div>\n\n<h2 id=\"古い方法\">古い方法</h2>\n<p>pyenv-updateをインストールしていない場合は以下の手順でそれぞれのリポジトリをpullする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit pull\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのpythonを使いたい場合は以下のように実行\">システムのpythonを使いたい場合は以下のように実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv version\n</code></pre></div></div>\n\n<h3 id=\"pyenvでインストールされているpythonのバージョン仮想環境を確認\">pyenvでインストールされているpythonのバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"pyenv自体のバージョン確認\">pyenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"pyenvで使用できるコマンドの確認\">pyenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv commands\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 18.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 18.04のインストール</h1>\n      <p>Ubuntu 18.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Facebook noteに書いておいたら、消されちゃったみたいなので、メモから再度作成<br />\nメモから書き起こしているので、細かいところが違うかも。<br />\n最新版では変更されている箇所があるかも。</p>\n\n<p>VirtualBox へのインストール前提で書いてます。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-1804-インストール媒体の入手\">Ubuntu 18.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら</p>\n\n<p><a href=\"https://www.ubuntulinux.jp/download)\">https://www.ubuntulinux.jp/download)</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを2048MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシーを選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"nb\">sudo </span>apt dist-upgrade <span class=\"o\">(</span>必要なら<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが</p>\n\n<h4 id=\"amazonなんちゃらのやつ\">amazonなんちゃらのやつ</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove ubuntu-web-launchers\n</code></pre></div></div>\n\n<h4 id=\"ツール類\">ツール類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n</code></pre></div></div>\n\n<h4 id=\"ゲーム類\">ゲーム類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h4 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-panel\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n一旦再起動して<br />\nサインインボタン横の歯車ボタンで「GNOME Flashback (Metacity)」を選択してログインする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!IMPORTANT]\n「GNOME Flashback(Compiz)」だとうまく動かない。<br />\n以前はログアウトだけで良かったはずなんだけど、<br />\n再起動しないとダメみたい</p>\n</blockquote>\n\n<h4 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h4>\n<blockquote>\n  <p>[!TIP]\n端末を起動し、メニューの「編集」→「Preferences」を選択<br />\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\nCustom font にチェックを入れ、その右側でフォントを選ぶ<br />\n    Ubuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n</blockquote>\n\n<h4 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj\n<span class=\"nb\">sudo mkdir</span> /work1\n<span class=\"nb\">sudo mkdir</span> /work2\n<span class=\"nb\">sudo mkdir</span> /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h4 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h4>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h4 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h4 id=\"bashの設定変更\">bashの設定変更</h4>\n<p>~/.bashrcに以下を追記</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n</code></pre></div></div>\n\n<h4 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/metacity/edge-tiling                false<br />\n       /org/gnome/mutter/edge-tiling                  false<br />\n       /org/gnome/shell/overrides/edge-tiling         false</p>\n</blockquote>\n\n<h4 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferences/auto-rise             false<br />\n       /org/gnome/descktop/wm/preferences/focus-mode            sloppy or mouse<br />\n       /org/gnome/descktop/wm/preferences/rise-on-click         true</p>\n</blockquote>\n\n<h4 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/nautilus/desktop/trash-icon-visible         false<br />\n       /org/gnome/nautilus/desktop/home-icon-visible          false</p>\n</blockquote>\n\n<h4 id=\"日本語入力\">日本語入力</h4>\n<ul>\n  <li>右上のJaまたはMoと書かれたアイコンをクリック→テキスト入力設定を選択</li>\n  <li>インストールされている言語の管理をクリック</li>\n  <li>「言語サポートが完全にはインストールされていません」と出るので<br />\n「インストール」をクリック</li>\n  <li>一旦log offして再log in</li>\n  <li>右上のJaまたはMoと書かれたアイコンをクリック\n    <ul>\n      <li>Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)</li>\n    </ul>\n  </li>\n  <li>キーボードの全角/半角キーで切り替えられるようになる</li>\n</ul>\n\n<h4 id=\"sambaのインストール\">sambaのインストール</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h4 id=\"nfsのインストール\">NFSのインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h4 id=\"apache-のインストール\">apache のインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>apache2\n<span class=\"nb\">mkdir</span> /proj/wwwroot\n</code></pre></div></div>\n\n<p>/etc/apache2/apache2.conf に以下を追加<br />\n<Directory ~と書いてあるところがあるので、その並びに追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><Directory /proj/wwwroot/>\n    Options Indexes FollowSymLinks\n    AllowOverride None\n    Require all granted\n</Directory>\n</code></pre></div></div>\n\n<p>/etc/apache2/sites-available/000-default.conf の以下を修正</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>DocumentRoot /proj/wwwroot\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/apache2 restart\n</code></pre></div></div>\n\n<h3 id=\"以上でインストールは終了\">以上でインストールは終了</h3>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hosts は書き換えられないので、手動で書き換える</p>\n</blockquote>\n\n<p>IPアドレスの変更(固定アドレスにしたい場合)</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>python の async/await</title>\n  </head>\n  <body>\n    <header>\n      <h1>python の async/await</h1>\n      <p>python の async/awaitってどう動くんだっけ?</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h2 id=\"python-の-asyncawaitってどう動くんだっけ\">python の async/awaitってどう動くんだっけ?</h2>\n\n<p>と思ったので、ちょっとテストプログラムを書いて試してみた。</p>\n\n<p>asyncioはnon-preemptiveなので、最近のpreemptiveに慣れ切った脳ミソにはややこしい。</p>\n\n<p>preemptiveなプログラムを書きたければ、threadingを使えば良い。適材適所というやつだ。</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">asyncio</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n\n<span class=\"n\">argvs</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span>  <span class=\"c1\"># コマンドライン引数を格納したリストの取得\n</span><span class=\"n\">argc</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">)</span> <span class=\"c1\"># 引数の個数\n</span>\n<span class=\"k\">if</span> <span class=\"n\">argc</span> <span class=\"o\">></span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"mi\">5</span>        <span class=\"c1\"># テストケース\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"testCase = \"</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">testCase</span><span class=\"p\">))</span>\n\n<span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>           <span class=\"c1\"># 念のため宣言だけしておく\n</span>\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">sub</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub start        \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub wakeup       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"mi\">42</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"n\">task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">sub</span><span class=\"p\">())</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"k\">await</span> <span class=\"n\">task</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">task</span>\n    \n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main wakeup      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main2</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 start      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 wakeup     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n\n<span class=\"c1\"># =============================================================================\n</span><span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>     <span class=\"c1\"># 開始時刻を記憶\n</span><span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">or</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">4</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">wait</span><span class=\"p\">([</span><span class=\"n\">main</span><span class=\"p\">(),</span> <span class=\"n\">main2</span><span class=\"p\">()]))</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">5</span> <span class=\"p\">:</span>\n    <span class=\"n\">loop</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">get_event_loop</span><span class=\"p\">()</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"unknown test case!!\"</span><span class=\"p\">)</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n\n<p>以下のようにコマンドラインからテストケース番号を指定して実行する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python test.py <testCase>\n</code></pre></div></div>\n\n<h2 id=\"実行結果\">実行結果</h2>\n<h3 id=\"testcase1\">testCase=1</h3>\n\n<p>基本的なパターン、というか、全然非同期実行になってないけど。。。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code>→ <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p>awaitが付いていると、その場でタスクに実行権を渡し、そのタスクが終了するまで待つ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 1\ntestCase <span class=\"o\">=</span>  1\nbefor create     0.00026416778564453125\nafter create     0.00034689903259277344\nbefor call       0.00040340423583984375\nsub start        0.00047469139099121094\nsub wakeup       2.0033931732177734\nafter call       2.0035252571105957\nmain wakeup      3.004753351211548\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase2\">testCase=2</h3>\n\n<p>基本的なパターン、こっちが非同期実行として本命。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code>を実行するときに<code class=\"language-plaintext highlighter-rouge\">await</code>を付けない。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">await</code>が付いていないと、その場でタスクに実行権を渡さず、自分の実行を中断する部分か終了するまでそのまま実行する。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> 呼び出し箇所では即時実行されず、sleep(2)で <code class=\"language-plaintext highlighter-rouge\">main</code> の実行が中断されたところで <code class=\"language-plaintext highlighter-rouge\">sub</code> へ切り替わる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> で <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> が実行されると実行されるタスクがなくなるので、イベントループは実行可能タスク待ちになる。</p>\n\n<p>1秒後、<code class=\"language-plaintext highlighter-rouge\">main</code> が起床するので、そのままmainが終了される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> で イベントループは <code class=\"language-plaintext highlighter-rouge\">main</code> の終了を待っているので、<code class=\"language-plaintext highlighter-rouge\">sub</code> が実行中でも無関係にイベントループを終了してしまい、\n <code class=\"language-plaintext highlighter-rouge\">sub</code> の残りは実行されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 2\ntestCase <span class=\"o\">=</span>  2\nbefor create     0.0002646446228027344\nafter create     0.00034308433532714844\nbefor call       0.00039768218994140625\nafter call       0.0004489421844482422\nsub start        0.0005385875701904297\nmain wakeup      1.0014407634735107\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase3\">testCase=3</h3>\n\n<p>testCase=2 でsubの残りも実行するには?と思って試したパターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で、即座に <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main2())</code> を実行してみた。</p>\n\n<p>見事失敗。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→ <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p>どうやら、 <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で イベントループは一旦 <code class=\"language-plaintext highlighter-rouge\">close</code> されてしまうらしい。</p>\n\n<p>単にtestCase=2の後ろにmain2の実行を付け加えただけになってしまった。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 3\ntestCase <span class=\"o\">=</span>  3\nbefor create     0.00029540061950683594\nafter create     0.0003790855407714844\nbefor call       0.0004353523254394531\nafter call       0.00048828125\nsub start        0.0005817413330078125\nmain wakeup      1.0015552043914795\nmain2 start      1.0021519660949707\nmain2 wakeup     4.0038042068481445\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase4\">testCase=4</h3>\n\n<p>testCase=3 の失敗挽回パターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でmainとmain2をまとめてみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でまとめたタスクがすべて終了するまでイベントループは<code class=\"language-plaintext highlighter-rouge\">close</code> されないので、<code class=\"language-plaintext highlighter-rouge\">sub</code>は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> と <code class=\"language-plaintext highlighter-rouge\">main2</code> のどちらが先に実行されるかは規定されていない様子。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 4\ntestCase <span class=\"o\">=</span>  4\nmain2 start      0.0003325939178466797\nbefor create     0.0004305839538574219\nafter create     0.0005018711090087891\nbefor call       0.0005679130554199219\nafter call       0.0006389617919921875\nsub start        0.0007307529449462891\nmain wakeup      1.002068042755127\nsub wakeup       2.002253293991089\nmain2 wakeup     3.003903388977051\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase5\">testCase=5</h3>\n\n<p>testCase=3 の失敗挽回パターン その2。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.get_event_loop()</code> でイベントループを取得し、<code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> でそれぞれのタスクを実行してみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> → イベントループ終了\nとなっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> ではタスクが終了してもイベントループはcloseされないので、同じイベントループで<code class=\"language-plaintext highlighter-rouge\">main2</code>が実行される。\n結果、<code class=\"language-plaintext highlighter-rouge\">sub</code> は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> が終了するまで <code class=\"language-plaintext highlighter-rouge\">main2</code> は実行(起動)されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 5\ntestCase <span class=\"o\">=</span>  5\nbefor create     0.0002574920654296875\nafter create     0.0003345012664794922\nbefor call       0.00038933753967285156\nafter call       0.0004410743713378906\nsub start        0.0005307197570800781\nmain wakeup      1.0010528564453125\nmain2 start      1.0011804103851318\nsub wakeup       2.002350330352783\nmain2 wakeup     4.002865314483643\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "RaspberryPi": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(Bookworm)のインストール(Raspberry Pi Imager)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(Bookworm)のインストール(Raspberry Pi Imager)</h1>\n      <p>Raspberry Pi OS(bookworm)のRaspberry Pi Imagerを使用したインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>RaspberrypiOSがBookwormになったので、インストール方法のメモ。<br />\n基本的にBullseyeのときと変わらないけど、ちょっと変わったところもあるので。<br />\n<a href=\"/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Bullseyeのときの手順メモ</a>も参照してください。</p>\n\n<h1 id=\"sdカードへの書き込み\">SDカードへの書き込み</h1>\n<p>Raspberry Pi Imager で書き込み。<br />\n使い方はあちこちに書いてあるけど、例えばこちら。</p>\n<ul>\n  <li><a href=\"https://qiita.com/mmake/items/576a2f60dffcd9291da3/\" target=\"_blank\">Raspberry Pi Imager のインストールと使い方</a></li>\n</ul>\n\n<p>バージョン変わると微妙に手順が変わったりするので、最新情報はぐぐってちょ。</p>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n<blockquote>\n  <p>[!NOTE]\n下記の変更をイッパツで行うスクリプトは以下。<br />\nWindowsのコマンドプロンプトで実行すると想定。  Windows版python必要。<br />\nそれぞれの<code class=\"language-plaintext highlighter-rouge\">F=</code>の部分を対象のドライブレターに変更する。</p>\n\n  <ul>\n    <li>UARTにUARTコネクタを使用する場合はこちら\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import re;F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">onfig.txt';a=open(F).read();a=re.sub(r'</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">(?!.*</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">)', '[pi5]</span><span class=\"se\">\\n</span><span class=\"s2\">dtparam=uart0</span><span class=\"se\">\\n\\n</span><span class=\"s2\">[all]</span><span class=\"se\">\\n</span><span class=\"s2\">enable_uart=1</span><span class=\"se\">\\n</span><span class=\"s2\">', a, flags=re.DOTALL);open(F, 'w').write(a)\"</span>\npython <span class=\"nt\">-c</span> <span class=\"s2\">\"F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">mdline.txt';a=open(F).read();a=a.replace(' quiet', '').replace(' splash', '').replace(' plymouth.ignore-serial-consoles', '')+' ipv6.disable=1';open(F, 'w').write(a)\"</span>\n</code></pre></div>      </div>\n    </li>\n    <li>UARTに40pinヘッダのpin8/10(GPIOs 14 & 15)を使用する場合はこちら\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import re;F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">onfig.txt';a=open(F).read();a=re.sub(r'</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">(?!.*</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">)', '[pi5]</span><span class=\"se\">\\n</span><span class=\"s2\">dtparam=uart0_console</span><span class=\"se\">\\n\\n</span><span class=\"s2\">[all]</span><span class=\"se\">\\n</span><span class=\"s2\">enable_uart=1</span><span class=\"se\">\\n</span><span class=\"s2\">', a, flags=re.DOTALL);open(F, 'w').write(a)\"</span>\npython <span class=\"nt\">-c</span> <span class=\"s2\">\"F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">mdline.txt';a=open(F).read();a=a.replace(' quiet', '').replace(' splash', '').replace(' plymouth.ignore-serial-consoles', '')+' ipv6.disable=1';open(F, 'w').write(a)\"</span>\n</code></pre></div>      </div>\n    </li>\n  </ul>\n</blockquote>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行を以下に変更</p>\n\n<ul>\n  <li>UARTにUARTコネクタを使用する場合はこちら</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[pi5]\ndtparam=uart0\n\n[all]\nenable_uart=1\n</code></pre></div></div>\n\n<ul>\n  <li>UARTに40pinヘッダのpin8/10(GPIOs 14 & 15)を使用する場合はこちら</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[pi5]\ndtparam=uart0_console\n\n[all]\nenable_uart=1\n</code></pre></div></div>\n\n<h2 id=\"ipv6の無効化\">IPv6の無効化</h2>\n<p>IPv6を無効化しておきたいときは、\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する。<br />\nこのファイルは1行で書かないといけないので、改行してはいけない。</p>\n\n<h2 id=\"ブートログの表示\">ブートログの表示</h2>\n\n<p>ブートログが見えないと不安な人は、<br />\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> から <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code>\nを削除しておくとよい。</p>\n<blockquote>\n  <p>[!NOTE]\nLITE版では<code class=\"language-plaintext highlighter-rouge\">quiet</code>を削除(それ以外は指定されていないので)</p>\n</blockquote>\n\n<h1 id=\"最初の起動\">最初の起動</h1>\n<p>書き込んだSDカードをRaspberry Piに挿入して電源ON。<br />\nごちょごちょと設定したあと、起動する(途中2回ほどrebootしてるらしい)</p>\n\n<h1 id=\"お約束\">お約束</h1>\n\n<p>ソフト類を最新版にする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n<span class=\"nb\">sudo </span>reboot \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <h4 id=\"ウィンドウマネージャをopenboxに変更したい場合\">ウィンドウマネージャをOpenboxに変更したい場合</h4>\n  <p>VNCに不具合がるなどの理由で以前のバージョンと同じX11ベースのOpenboxに変更したい場合は以下の手順で変更する。<br />\nちなみにOpenboxに変更したい場合は以下のコマンドで変更できる。<br />\nVNCを有効化した後にウィンドウマネージャを変更すると動作が不安定になることがあるので、VNCを有効化する前に変更するのがベター。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config nonint do_wayland W1\n<span class=\"nb\">sudo </span>reboot \n</code></pre></div>  </div>\n\n  <p>VNC有効化後、以下のコマンドでデフォルトのウィンドウマネージャ(wayfire)が無効になっていることを確認する。<br />\nなにも表示されなければOK</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pgrep wayfire\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"お好みで\">お好みで</h1>\n\n<p>その他お好み設定は\n<a href=\"/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</a>\nと同じ。<br />\nめんどくさいのでスクリプトを実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.githubusercontent.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c/raw/pi_setup1.sh\nbash pi_setup1.sh \n<span class=\"c\"># 途中sambaのパスワード設定がある  </span>\n<span class=\"nb\">sudo </span>reboot \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nIpV6無効の環境でwayfireでVNCを有効にする場合、VNCを有効化する前に\n以下のコマンドでwayfireでIPv4を使用するように設定する必要がある。<br />\nこの処理は上の<code class=\"language-plaintext highlighter-rouge\">pi_setup1.sh</code>の処理に含まれている。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /etc/wayvnc/config /etc/wayvnc/config.org\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s/</span><span class=\"se\">\\:\\:</span><span class=\"s2\">/0</span><span class=\"se\">\\.</span><span class=\"s2\">0</span><span class=\"se\">\\.</span><span class=\"s2\">0</span><span class=\"se\">\\.</span><span class=\"s2\">0/g\"</span> /etc/wayvnc/config\n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">/etc/wayvnc/config</code>の2行目の<code class=\"language-plaintext highlighter-rouge\">address=::</code>を<code class=\"language-plaintext highlighter-rouge\">address=0.0.0.0</code>に変更している。</p>\n</blockquote>\n\n<h1 id=\"pyenvのインストール\">pyenvのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<p>ここで一旦ログアウト&再ログイン</p>\n\n<h1 id=\"pythonのインストール\">pythonのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.11.9\npyenv shell 3.11.9 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\npyenv shell <span class=\"nt\">--unset</span> \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi で Text To Speech(音声合成)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi で Text To Speech(音声合成)</h1>\n      <p>Raspberry Pi でpythonを使用してText To Speech(音声合成)を試す</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi でText To Speech(音声合成)をofflineで実行することを試してみます。<br />\n(初回実行時は辞書データをダウンロードするのでインターネットにつながっている必要があります)</p>\n\n<blockquote>\n  <p>[!NOTE]\n環境変数 DISPLAY が設定されている場合、変数が示すマシンでXサーバが実行されている必要があります。<br />\n実行されていない場合は、オーディオ再生の際、コマンドがハングアップします、<br />\nその際は対象マシンでXサーバを実行するか、<code class=\"language-plaintext highlighter-rouge\">unset DISPLAY</code>で環境変数を削除してください。</p>\n</blockquote>\n\n<h1 id=\"スピーカの準備\">スピーカの準備</h1>\n<p>Raspberry Pi5ではオーディオジャックがなくなったので、\n将来のことを考えてUSBスピーカ(USBヘッドセット)を使用することにします。</p>\n\n<h2 id=\"スピーカの接続\">スピーカの接続</h2>\n\n<p>まず、USBスピーカをUSBポートに接続し、スピーカが認識されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>lsusb\nBus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub\nBus 001 Device 003: ID 0c76:161f JMTek, LLC. USB PnP Audio Device   ← これ\nBus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub\nBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub\n</code></pre></div></div>\n\n<h2 id=\"カード番号とデバイス番号の確認\">カード番号とデバイス番号の確認</h2>\n<p>使用するカード番号/デバイス番号を確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay <span class=\"nt\">-l</span>\n<span class=\"k\">****</span> ハードウェアデバイス PLAYBACK のリスト <span class=\"k\">****</span>\nカード 0: vc4hdmi0 <span class=\"o\">[</span>vc4-hdmi-0], デバイス 0: MAI PCM i2s-hifi-0 <span class=\"o\">[</span>MAI PCM i2s-hifi-0]\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\nカード 1: vc4hdmi1 <span class=\"o\">[</span>vc4-hdmi-1], デバイス 0: MAI PCM i2s-hifi-0 <span class=\"o\">[</span>MAI PCM i2s-hifi-0]\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\nカード 2: Headphones <span class=\"o\">[</span>bcm2835 Headphones], デバイス 0: bcm2835 Headphones <span class=\"o\">[</span>bcm2835 Headphones]\n  サブデバイス: 8/8\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\n  サブデバイス <span class=\"c\">#1: subdevice #1</span>\n  サブデバイス <span class=\"c\">#2: subdevice #2</span>\n  サブデバイス <span class=\"c\">#3: subdevice #3</span>\n  サブデバイス <span class=\"c\">#4: subdevice #4</span>\n  サブデバイス <span class=\"c\">#5: subdevice #5</span>\n  サブデバイス <span class=\"c\">#6: subdevice #6</span>\n  サブデバイス <span class=\"c\">#7: subdevice #7</span>\nカード 3: Device <span class=\"o\">[</span>USB PnP Audio Device], デバイス 0: USB Audio <span class=\"o\">[</span>USB Audio]         ← これ\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\n</code></pre></div></div>\n\n<p>カード番号が 3 または ‘Device’、デバイス番号が0であることが分かります</p>\n\n<h2 id=\"テスト再生\">テスト再生</h2>\n<p>テスト再生してみます。<br />\n-D オプションのパラメータは、<code class=\"language-plaintext highlighter-rouge\">plughw:</code>に続けて上で調べたカード番号、<code class=\"language-plaintext highlighter-rouge\">,</code>を挟んでデバイス番号を指定します。<br />\nwavファイルは何でもかまいません。下記はデフォルトでインストール済みのファイルなのでそれを使いました。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay <span class=\"nt\">-D</span> plughw:Device,0 /usr/share/sounds/alsa/Front_Center.wav\n再生中 WAVE <span class=\"s1\">'/usr/share/sounds/alsa/Front_Center.wav'</span> : Signed 16 bit Little Endian, レート 48000 Hz, モノラル\n</code></pre></div></div>\n\n<h2 id=\"デフォルトのオーディオデバイスの設定\">デフォルトのオーディオデバイスの設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">sudo raspi-config</code> を実行し、以下の順で選択します。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">1 System Options</code>\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">S2 Audio</code>\n        <ul>\n          <li>使用するオーディオデバイス( <code class=\"language-plaintext highlighter-rouge\">71 USB PnP Audio Device</code>など )</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">Finish</code>で終了</li>\n</ul>\n\n<p>デフォルト設定が変更されたことを確認するため、上記テスト再生のコマンドから-Dオプションを削除して再生されることを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay /usr/share/sounds/alsa/Front_Center.wav\n再生中 WAVE <span class=\"s1\">'/usr/share/sounds/alsa/Front_Center.wav'</span> : Signed 16 bit Little Endian, レート 48000 Hz, モノラル\n</code></pre></div></div>\n\n<h1 id=\"python仮想環境の作成とモジュールのインストール\">python仮想環境の作成とモジュールのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openjtalk\n<span class=\"nb\">cd</span> /work/openjtalk\n\npyenv virtualenv 3.11.9 openjtalk\npyenv <span class=\"nb\">local </span>openjtalk \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># pyopenjtalkのインストールに必要なのでcmakeをインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n\n<span class=\"c\"># pyopenjtalkのインストールbuildが実行されるので時間がかかる</span>\npip <span class=\"nb\">install </span>pyopenjtalk\n\n<span class=\"c\"># wavファイルの保存に使用するのでscipyもインストール</span>\npip <span class=\"nb\">install </span>scipy\n\n<span class=\"c\"># marineを使う場合は以下も実行</span>\npip <span class=\"nb\">install </span>pyopenjtalk[marine]\n</code></pre></div></div>\n\n<h1 id=\"pyopenjtalk-を実行してみる\">pyopenjtalk を実行してみる</h1>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  talk_test1.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">pyopenjtalk</span>\n<span class=\"kn\">from</span> <span class=\"nn\">scipy.io</span> <span class=\"kn\">import</span> <span class=\"n\">wavfile</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"c1\"># marineを使用する場合はrun_marineをTrueにする\n</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">sr</span> <span class=\"o\">=</span> <span class=\"n\">pyopenjtalk</span><span class=\"p\">.</span><span class=\"n\">tts</span><span class=\"p\">(</span><span class=\"s\">\"おめでとうございます\"</span><span class=\"p\">,</span> <span class=\"n\">run_marine</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n<span class=\"n\">wavfile</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">\"test1.wav\"</span><span class=\"p\">,</span> <span class=\"n\">sr</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">int16</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python talk_test1.py\n</code></pre></div></div>\n\n<p>再生します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>aplay test1.wav\n</code></pre></div></div>\n\n<p>スピーカーから「おめでとうございます」と聞こえたら成功です。おめでとうございます。</p>\n\n<h1 id=\"pythonからオーディオ再生する\">pythonからオーディオ再生する</h1>\n\n<p>オーディオ再生のためのモジュールは色々ありますが、\n下の直接再生に使用するにはnumpyデータを入力できることが必須となるので\nsimpleaudioを使用してみます。</p>\n\n<p>モジュールをインストールします。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># simpleaudioのインストールに必要なパッケージのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libasound2-dev\n\n<span class=\"c\"># インストール</span>\npip <span class=\"nb\">install </span>simpleaudio\n</code></pre></div></div>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  play_test1.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">simpleaudio</span>\n\n<span class=\"n\">wav_obj</span> <span class=\"o\">=</span> <span class=\"n\">simpleaudio</span><span class=\"p\">.</span><span class=\"n\">WaveObject</span><span class=\"p\">.</span><span class=\"n\">from_wave_file</span><span class=\"p\">(</span><span class=\"s\">\"test1.wav\"</span><span class=\"p\">)</span>\n<span class=\"n\">play_obj</span> <span class=\"o\">=</span> <span class=\"n\">wav_obj</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n<span class=\"n\">play_obj</span><span class=\"p\">.</span><span class=\"n\">wait_done</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python play_test1.py\n</code></pre></div></div>\n<h1 id=\"pyopenjtalkで作成した音声を直接再生する\">pyopenjtalkで作成した音声を直接再生する</h1>\n\n<p>逐一wavファイルを作成するのは面倒なので、合成したらすぐ再生するようにしてみます。</p>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  talk_test2.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">pyopenjtalk</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">simpleaudio</span>\n\n<span class=\"c1\"># marineを使用する場合はrun_marineをTrueにする\n</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">sr</span> <span class=\"o\">=</span> <span class=\"n\">pyopenjtalk</span><span class=\"p\">.</span><span class=\"n\">tts</span><span class=\"p\">(</span><span class=\"s\">\"直接再生します\"</span><span class=\"p\">,</span> <span class=\"n\">run_marine</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n<span class=\"c1\"># x : waveform\n# sr: sampling rate\n</span>\n<span class=\"n\">wav_obj</span> <span class=\"o\">=</span> <span class=\"n\">simpleaudio</span><span class=\"p\">.</span><span class=\"n\">WaveObject</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">int16</span><span class=\"p\">),</span> <span class=\"n\">num_channels</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">bytes_per_sample</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">sample_rate</span><span class=\"o\">=</span><span class=\"n\">sr</span><span class=\"p\">)</span>\n<span class=\"n\">play_obj</span> <span class=\"o\">=</span> <span class=\"n\">wav_obj</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n<span class=\"n\">play_obj</span><span class=\"p\">.</span><span class=\"n\">wait_done</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python talk_test2.py\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINO 2022.1のbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1はRaspberry Pi OS(64bit)向けのバイナリがリリースされていないので、自力でbuildしてみます。</p>\n\n<p>今回もUbuntu上のDockerコンテナを使用しましたが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思います。</p>\n\n<p>前回はPythonを諦めてクロスコンパイルする方法とbuild時間を諦めてセルフコンパイル(エミュレーション)する方法を使いましたが、<br />\n今回はPython以外をクロスコンパイル、Python関連部をセルフコンパイル(エミュレーション)して生成物をマージする方法をとってみます。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_2022.1_pi64 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_2022.1_pi64\n</code></pre></div></div>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>workディレクトリを作成し、openvino と openvino_contrib のリポジトリをcloneします。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 2022.1.1 <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib checkout 1a28b530ab40d2ad79ab29021dfddfbbc7d2db0b\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の2022.1だと一部のノードが未対応とエラーになるため、対応済みのcommitを使用します。<br />\ntagが振られていないので、commit IDを指定してcheckoutします。<br />\nこれ以降のcommitではopenvinoのバージョン2022.2が必要になります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ntagやbranchが設定されていない場合はcloneでcheckoutするバージョンを指定できないため、\n一旦cloneしてからcommit IDを指定してcheckoutします。<br />\nsubmoluleのcheckoutは対象のバージョンをcheckoutしてから行います。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の最新commit(試した時点ではcommit ID <code class=\"language-plaintext highlighter-rouge\">fd2ac364435757d23a9b3e91d67235b5e6555bf9</code>)を使用する場合は\nopenvinoのバージョン2022.2を使用する必要がありますが、試した時点で <code class=\"language-plaintext highlighter-rouge\">2022.2.0.dev20220829</code> がリリースされているので\nこれを使用します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0.dev20220829  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit -C ./work/openvino_contrib checkout fd2ac364435757d23a9b3e91d67235b5e6555bf9\ngit -C ./work/openvino_contrib submodule update --init --recursive --depth 1\n</code></pre></div>  </div>\n  <blockquote>\n    <p>2022.2.0正式リリース後はこんな感じになるのかな?</p>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  -b 2022.2    --recursive --depth 1 https://github.com/openvinotoolkit/openvino_contrib.git\n</code></pre></div>    </div>\n  </blockquote>\n\n  <p>この場合、NVIDIA GPUのpluginのbuildでエラーになるため、以下のcmakeのオプションに以下のオプションを追加します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      -D BUILD_nvidia_plugin=OFF\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h1 id=\"openvinoのbuildクロスコンパイル\">openVINOのBuild(クロスコンパイル)</h1>\n\n<p>クロスコンパイルでpython関連以外の部分をbuildします。</p>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir cross</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">cross/Dockerfile</code>を作成します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cross/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates:arm64 <span class=\"se\">\\\n</span>    libboost-regex-dev:arm64 <span class=\"se\">\\\n</span>    libgtk2.0-dev:arm64 <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev:arm64 <span class=\"se\">\\\n</span>    libcairo2-dev:arm64 <span class=\"se\">\\\n</span>    libpango1.0-dev:arm64 <span class=\"se\">\\\n</span>    libglib2.0-dev:arm64 <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev:arm64 <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗します</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeは新しめのをインストールしておきたいので、3.23.2をbuildして使用しています。<br />\nもしかすると、<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたものをそのまま使っても大丈夫かもしれませんが。</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_cross cross\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\ncacheを使わずimage buildしたい場合は<code class=\"language-plaintext highlighter-rouge\">--no-cache</code>オプションを追加します。<br />\n以前に作ったイメージのキャッシュを使って<code class=\"language-plaintext highlighter-rouge\">apt install</code>がエラーになったことがあったので。<br />\n(デフォルトのリポジトリに変更があったらしい)</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_cross_2 ov_2022.1_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_cross_2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_2022.1_pi64_cross_2 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/cmake/arm64.toolchain.cmake <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_BEH_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLDNN</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_FUNCTIONAL_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">THREADING</span><span class=\"o\">=</span>SEQ <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">CONTRIB_TOP</span><span class=\"k\">}</span>/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span> 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=${WORK_DIR}/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"クロスコンパイル終了\">クロスコンパイル終了</h3>\n<p>クロスコンパイルはここまでなので、コンテナから抜ける。</p>\n\n<h1 id=\"openvinoのbuildセルフコンパイル\">openVINOのBuild(セルフコンパイル)</h1>\n\n<p>セルフコンパイルでpython関連部分をbuildします。<br />\ncythonを使うときにクロスコンパイルする方法が分からないので、セルフコンパイルで。</p>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir emu</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">emu/Dockerfile</code>を作成します。</p>\n\n<p>python部だけなので、こんなにライブラリとか要らない気もしますが、全部セルフコンパイルするときのことも考えて\n全部入りのイメージを作っておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  emu/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates <span class=\"se\">\\\n</span>    libboost-regex-dev <span class=\"se\">\\\n</span>    libgtk2.0-dev <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev <span class=\"se\">\\\n</span>    libcairo2-dev <span class=\"se\">\\\n</span>    libpango1.0-dev <span class=\"se\">\\\n</span>    libglib2.0-dev <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_emu emu\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_emu_2 ov_2022.1_pi64_emu /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_emu_2\n</code></pre></div></div>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成-1\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build_python <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build_python\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">InferenceEngineDeveloperPackage_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/build <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/src/bindings/python 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">CMAKE_INSTALL_PREFIX</code>の設定はクロスコンパイルのときと同じ設定にしてください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npyenvでインストールしたpythonなど、デフォルトでないpythonを使用する場合に指定します。<br />\n(以下の設定値はubuntu 22.04の標準インストールの場合のパスなのであまり参考にならないかも)</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  -D PYTHON_EXECUTABLE=/usr/bin/python3.8 \\\n  -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.8.so \\\n  -D PYTHON_INCLUDE_DIR=/usr/include/python3.8 \\\n  -D PYTHON_MODULE_EXTENSION=\".so\" \\\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"make-1\">make</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。</p>\n\n<h3 id=\"セルフコンパイル終了\">セルフコンパイル終了</h3>\n<p>セルフコンパイルはここまでなので、コンテナから抜けます。</p>\n\n<h1 id=\"インストール媒体の作成\">インストール媒体の作成</h1>\n\n<p>ホスト側の<code class=\"language-plaintext highlighter-rouge\">work</code>ディレクトリ内を見ると、<code class=\"language-plaintext highlighter-rouge\">intel</code>ディレクトリが出来ているので、ここをtarなどで固めておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>work\n<span class=\"nb\">tar </span>czvf ov1.tar.gz intel/\n</code></pre></div></div>\n\n<p>この<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiにコピーして展開します。</p>\n\n<h1 id=\"raspberrypiへのインストール\">RaspberryPiへのインストール</h1>\n\n<h2 id=\"インストール\">インストール</h2>\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiの適当なディレクトリに展開します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/proj</code>ディレクトリに展開しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /proj/\n<span class=\"nb\">tar </span>xzvf ov1.tar.gz \n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<p>これで<code class=\"language-plaintext highlighter-rouge\">/proj/intel/openvino</code>ディレクトリにインストールされました。</p>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n<p>環境変数の設定のため、以下を実行します。<br />\nshell起動の度に実行が必要なので<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>などに書いておくと良いです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/intel/openvino/setupvars.sh \n</code></pre></div></div>\n\n<h2 id=\"udevルールの設定\">udevルールの設定</h2>\n<p>以下のスクリプトを実行すればNCS2を挿せば認識されるようになります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/proj/intel/openvino/install_dependencies/install_NCS_udev_rules.sh \n</code></pre></div></div>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n<p>openCVの必要になるので、インストールしておきます。<br />\n今回はお手軽にpipでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認用のプログラムは<a href=\"https://github.com/ippei8jp/ov_trial_2022.1\" target=\"_blank\">https://github.com/ippei8jp/ov_trial_2022.1</a> とかにあります。<br />\nでもモデルのダウンロード/コンバートはRaspberryPiではできないので、UbuntuやWondowsで実行したものをコピーして使用してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</h1>\n      <p>Raspberry Pi OS(64bit)のRaspberry Pi Imagerを使用したインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>また手順が変わったみたいなので、メモも更新。<br />\n(2023/10/15 最新版での試行結果を反映)</p>\n\n<h1 id=\"sdカードへの書き込み\">SDカードへの書き込み</h1>\n\n<p>Raspberry Pi Imager なるツールを使うようになったらしい。<br />\n使い方はあちこちに書いてあるけど、例えばこちら。</p>\n<ul>\n  <li><a href=\"https://ascii.jp/elem/000/004/094/4094421/\" target=\"_blank\">Raspberry Pi Imagerの使い方 ― v1.7.2以降 対応版</a></li>\n  <li><a href=\"https://www.mikan-tech.net/entry/raspi-imager-headless-setup\" target=\"_blank\">Raspberry Pi Imagerが新しくなった!Lite版もらくらくHeadless Setup</a></li>\n</ul>\n\n<p>これを使うと、最初のユーザを自由に設定できるので、これまでのpiユーザを変更するなんてことはやらなくて済む。<br />\nWi-Fiの設定やSSHの設定も(なんかWindowsが適切に設定されてれば公開鍵が自動で設定されるみたい)ここでできる。</p>\n\n<p>パスワードが設定ファイルに書き出されるので(さすがに平文ではない、最初の起動が終わったら削除される)、<br />\nセキュリティ上気になる場合は仮パスワードを設定しておいて<br />\n最初にログインしたときに変更する、なんてことをやった方が良いと言ってる解説ページもあった。</p>\n\n<blockquote>\n  <p>[!WARNING]\n<del>なぜかSSHの認証方法が毎回「パスワード認証を使う」になってしまうので、公開鍵を使うときは再度設定が必要。</del> \n(1.7.5では改善された模様)</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\n<del>(少なくとも)2023/10以降のバージョンはopenSSHのバージョンがRSA非対応になっているので、 \n 鍵ファイル作成の際はRSA以外(ed25519など)で作成する必要がある。</del> <br />\n(2023/10/21 誤解してたので書き直し)<br />\n(少なくとも)2023/10以降のバージョンはopenSSHのバージョンが SSH-RSA 非対応になっているので、<br />\nTeraterm Ver4.106以前など RSA-SHA2未対応の環境ではRSA鍵では繋がらない。 \nその場合は RSA以外(ed25519など)で作成すれば良い。<br />\nssh-keygenのデフォルトはRSAなので、<code class=\"language-plaintext highlighter-rouge\">ssh-keygen -t ed25519</code> などとする。<br />\nもちろん、Teraterm Ver4.107以降に変更するという手もある。</p>\n</blockquote>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1\n</code></pre></div></div>\n<h2 id=\"ipv6の無効化\">IPv6の無効化</h2>\n<p>IPv6を無効化しておきたいときは、\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する。<br />\nこのファイルは1行で書かないといけないので、改行してはいけない。</p>\n\n<blockquote>\n  <p>[!WARNING]\n<del>以前はこれで無効化できていたはずだけど、2023/10現在 この手順では無効化できないらしい。<br />\n下でセットアップスクリプトで無効化処理を実行するように変更した。</del> <br />\n(2023/10/21 間違ってたので削除)</p>\n</blockquote>\n\n<h2 id=\"ブートログの表示\">ブートログの表示</h2>\n\n<p>ブートログが見えないと不安な人は、<br />\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> から <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code>\nを削除しておくとよい。</p>\n<blockquote>\n  <p>[!NOTE]\nLITE版では<code class=\"language-plaintext highlighter-rouge\">quiet</code>を削除(それ以外は指定されていないので)</p>\n</blockquote>\n\n<h1 id=\"最初の起動\">最初の起動</h1>\n<p>書き込んだSDカードをRaspberry Piに挿入して電源ON。<br />\nごちょごちょと設定したあと、起動する(途中2回ほどrebootしてるらしい)</p>\n\n<p>あとは起動後の設定。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># アップデート実行\nsudo apt update\nsudo apt upgrade\n\n# リブート\nsudo reboot\n</code></pre></div></div>\n\n<h1 id=\"カスタマイズ\">カスタマイズ</h1>\n\n<blockquote>\n  <p>[!NOTE]\n以降の処理をスクリプトにまとめました。<br />\n<a href=\"https://gist.github.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c\" target=\"_blank\">Raspberry Pi セットアップスクリプト </a><br />\n以下の手順で実行できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.githubusercontent.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c/raw/pi_setup1.sh\nbash pi_setup1.sh\n</code></pre></div>  </div>\n  <p>LITE版を使うときは変数<code class=\"language-plaintext highlighter-rouge\">LITE_OS</code>に<code class=\"language-plaintext highlighter-rouge\">1</code>を設定して実行します。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> <span class=\"nv\">LITE_OS</span><span class=\"o\">=</span>1 bash pi_setup1.sh\n</code></pre></div>  </div>\n\n  <p>途中でパスワード入力しないといけないので、完全自動じゃないけど、かなり手間は省けるはず。<br />\n実行後、<code class=\"language-plaintext highlighter-rouge\">pi_setup1.sh</code>は不要なので削除して可。<br />\n実行が終わったらリブートすること。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>reboot\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h2 id=\"resizeスクリプトの取得\">resizeスクリプトの取得</h2>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/4f39afbcd8471426421944b597f3a5f2963984c6/resize.py\n\n<span class=\"nb\">chmod</span> +x resize.py\n\n./resize.py\n</code></pre></div></div>\n\n<h2 id=\"ロケールの変更\">ロケールの変更</h2>\n<p>日本語表示のため、ロケールを変更する。<br />\n(imagerだとキーボードレイアウトの変更はやってくれるけど、ロケールの変更はやってくれないらしいので)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ロケールの変更</span>\n<span class=\"nb\">sudo </span>raspi-config nonint do_change_locale ja_JP.UTF-8\n\n<span class=\"c\"># リブートまでとりあえずLANGのみ変更で日本語表示</span>\n<span class=\"nb\">export </span><span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF-8\n</code></pre></div></div>\n\n<h2 id=\"bashrc-の変更\">.bashrc の変更</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n</code></pre></div></div>\n\n<h2 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h2>\n\n<p>物理キーボード接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]<br />\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n\n</blockquote>\n\n<h2 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h2>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h2 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h2>\n\n<p>まずはワークディレクトリの作成</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown $USER:$USER /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a $USER\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo service smbd reload\nsudo service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"vncサーバの有効化\">VNCサーバの有効化</h2>\n\n<p>リモートデスクトップを使うために、VNCサーバの有効化を行う。<br />\nLITE版では不要。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    # VNCサーバの有効化\n    3 Interfacing Options\n        I3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>\n            The VNC Server is enabled\n            と表示されるので <Ok>\n\n    # VNC解像度の設定\n    2 Display Options\n        D5 VNC Resolution\n        \n            解像度が色々表示されるので、\n            使いたい解像度を選択(例えば 1920x1080 )して<Select>\n            The resolution is set to «選択した解像度»\n            と表示されるので <Ok>\n    # 設定終了\n    <Finish>\n</code></pre></div></div>\n\n<h2 id=\"ipv6-の無効化\">IPv6 の無効化</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code>での設定では無効化できなくなったと思ったけど、勘違いだった。<br />\nなので、上記の<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する方法でOK。</p>\n\n<p>でも、その時に<code class=\"language-plaintext highlighter-rouge\">mncli</code>コマンドで無効化するスクリプトを作ったので、せっかくなので残しておく。</p>\n\n<p>接続名一覧を取得し、 それぞれに対して無効化するコマンドを実行する。<br />\n接続名に「有線接続 1」と空白が含まれている接続があるので、一時的に空白をセミコロンに置換して処理を行っている。<br />\n(これをやらないと「有線接続」と「1」に分けて処理されてしまう)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 接続一覧を取得</span>\n<span class=\"nv\">conn_data</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli <span class=\"nt\">-t</span> connection<span class=\"si\">)</span>\n\n<span class=\"c\"># 空白を\";\"に置換(配列代入時に誤動作するのを防止)</span>\n<span class=\"nv\">conn_data</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">conn_data</span><span class=\"p\">// /</span><span class=\"s2\">\";\"</span><span class=\"k\">}</span>\n\n<span class=\"c\"># ':'区切りで1列目をconnections配列に格納</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"s2\">\"</span><span class=\"nv\">$conn_data</span><span class=\"s2\">\"</span> | <span class=\"nb\">cut</span> <span class=\"nt\">-d</span><span class=\"s2\">\":\"</span> <span class=\"nt\">-f1</span><span class=\"si\">)</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 配列の要素を処理</span>\n<span class=\"k\">for </span>connection <span class=\"k\">in</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[@]</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 上で;に置換した空白を戻す</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"p\">//</span><span class=\"s2\">\";\"</span><span class=\"p\">/</span><span class=\"s2\">\" \"</span><span class=\"k\">}</span>\n\n    <span class=\"k\">if</span> <span class=\"o\">[[</span> <span class=\"s2\">\"</span><span class=\"nv\">$connection</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s1\">'lo'</span> <span class=\"o\">]]</span><span class=\"p\">;</span> <span class=\"k\">then</span>    <span class=\"c\"># loデバイスは無効にできないので除外</span>\n      <span class=\"nb\">echo</span> <span class=\"s2\">\"disable </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span> \n      <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> ipv6.method </span><span class=\"se\">\\\"</span><span class=\"s2\">disabled</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n      <span class=\"c\"># 有効にする場合はこちら</span>\n      <span class=\"c\"># cmd=\"sudo nmcli connection modify \\\"${connection}\\\" ipv6.method \\\"auto\\\"\"</span>\n      <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n      <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone</span>\n</code></pre></div></div>\n\n<h1 id=\"splash-screenの再有効化\">Splash screenの再有効化</h1>\n\n<p>セットアップ時にブートログが表示されるようにしたけど、<br />\nやっぱり表示したくなくなった(Splash screenを表示)、てなときは以下で。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S6 Splash Screen\n            Would you like to show the splash screen at boot?\n            と聞かれるので有効化するときは <Yes> を選択\n            Splash screen at boot is enabled)\n            と表示されるので <Ok>\n\n    Would you like to reboot now?\n    と聞かれるので、その場でリブートしてよければ<Yes>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n直接<code class=\"language-plaintext highlighter-rouge\">/boot/cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code> を追加しても良い。<br />\nLITE版では <code class=\"language-plaintext highlighter-rouge\">quiet</code>のみ追加。</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Pythonのasyncioでnon-blockingなコンソール入力</title>\n  </head>\n  <body>\n    <header>\n      <h1>Pythonのasyncioでnon-blockingなコンソール入力</h1>\n      <p>Pythonのasyncioでnon-blockingなコンソール入力を行うためのクラス</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでasyncioを使ったときにnon-blockingなコンソール入力(キーボード入力)ができなくて困ったので、実現するためのクラスを作ってみた。</p>\n\n<p>もともと Linux用に作ったら、Windowsだとうまく動かない。<br />\nちょっと汚い方法だけど、とりあえず動くようにしてお茶を濁しておく。<br />\n(あんまりテストしてないから動かなかったらごめん)</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/5033eec9b9b774ede4f87604a51fb162.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>お試しならこのソースをそのまま実行すると実行できます。<br />\n<code class=\"language-plaintext highlighter-rouge\">char_mode = False</code> の部分を変更すると、1行入力モードと1文字入力モードを切り替えられます。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout_mode = True</code> の部分を変更すると、タイムアウトなしとタイムアウトありを切り替えられます。</p>\n\n<p>実際に使用するには、このソースをimportして使ってください。</p>\n\n<h1 id=\"注意\">注意</h1>\n\n<p>Linuxで1文字入力モードを使っている場合は、終了時(例外で死んだ場合も含めて)<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行しないと悲しいことになります。<br />\n(ターミナルの入力モードが変更されてしまうので、うまく入力できなくなる)<br />\nそのために、<code class=\"language-plaintext highlighter-rouge\">atexit.retister()</code>で終了処理ルーチンを登録し、その中で<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行するようにしています。</p>\n\n<h1 id=\"ひとりごと\">ひとりごと</h1>\n\n<p>asyncioのサンプルって、タスク1個で動かしてることが多いからあんまり ありがたみが分からんのかな…<br />\nあと、タスクとコルーチンが同じように語られていて分かり難いのもあると思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi で python で PWM</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi で python で PWM</h1>\n      <p>Raspberry Pi 上で python で PWMの制御を行うブログラムの雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Piでロボットアームを制御するのに、PWMのテストを行ったときのプログラムソースを貼っておく。<br />\n使ったロボットアーム: <a href=\"https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1\" target=\"_blank\">https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1</a></p>\n\n<p>ソフトウェアPWMだと他の処理の負荷によってジッタが発生し、ガタガタいうのでこの使い方はあまり実用的ではない。<br />\nハードウェアPWMを使う(pigpio か wiringpi が必要)、PWM制御を担うMCUを用意してコマンド通信(TCP/IPやBluetoothなど経由)で制御するのが現実的かも。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>PRi.GPIOを使うので、インストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>RPi.GPIO\n</code></pre></div></div>\n\n<p>プログラムの設定にあわせてGPIOとサーボモータを接続しておく(または接続に合わせてプログラム修正)。<br />\nスイッチで調整できるようにしてあるけど、キーボードから調整できるのでスイッチの接続は必須ではない。</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/0e8eeedb37d59c85b6ae6085da2a2cb4.js\"></script>\n</dev>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">GPIO.add_event_detect()</code>には<code class=\"language-plaintext highlighter-rouge\">bouncetime=«チャタリング除去時間(msec)»</code>を追加しておくのが良いかも。<br />\n参考: <a href=\"https://tomosoft.jp/design/?p=8685\" target=\"_blank\">GPIOエッジ検出コールバック関数 | TomoSoft</a></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n公式マニュアルは存在しないらしい。<br />\n唯一以下のページがそれっぽい情報を掲載している。<br />\n<a href=\"https://sourceforge.net/p/raspberry-gpio-python/wiki/Examples/\" target=\"_blank\">raspberry-gpio-python / Wiki / Examples</a><br />\nあとはソース読むしかないんだけど、python - C インタフェースを理解してないと苦しい…<br />\nソース全体を<code class=\"language-plaintext highlighter-rouge\">python function</code>で検索すると出てくるけど全部じゃない…<br />\nソースはここ: <a href=\"https://pypi.org/project/RPi.GPIO/#files\" target=\"_blank\">RPi.GPIO · PyPI</a></p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>プログラム実行して、スイッチかキーボードで出力値変えてみる。<br />\n設定値の範囲は個体差があるので、適当に変更必要。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINOのクロスコンパイル</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINOのクロスコンパイル</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild(クロスコンパイル環境)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi OS(64bit)向けにopenVINOをクロスコンパイルする方法についてまとめた。<br />\nセルフコンパイル(Docker使用)については『<a href=\"/memoBlog/2022/03/07/openVINO_build_2.html\" target=\"_blank\">openVINO(Raspberry Pi OS(64bit)向け)のbuild</a>』を参照。<br />\nただ、クロスコンパイルだとセルフコンパイルの10倍くらい速い(環境によるけど)ので、クロスコンパイルがおススメ。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_cross <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_cross\n</code></pre></div></div>\n\n<h2 id=\"ソースの取得\">ソースの取得</h2>\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h3>\n<p>以下の1つのpatchファイルを作成する。<br />\nサンプル(テスト?)プログラムのBuildを抑制してコンパイル時間の短縮を計っている。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"opencv-の-gitリポジトリを-clone\">openCV の gitリポジトリを clone</h3>\n<p>opencv のリポジトリをcloneする(opencvのBuildを行わない場合は不要)。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libgtk-3-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_cross <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_cross_1 ov_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_cross_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_cross_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n<p>ここからコンテナ内</p>\n\n<h2 id=\"buildディレクトリの作成\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openvino/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/openvino/build\n</code></pre></div></div>\n\n<h2 id=\"cmake実行\">cmake実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm64.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_SAMPLES</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLANG_FORMAT</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_OPENCV</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n    .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>サンプルはBuildしないので、ENABLE_SAMPLES=OFF を設定</li>\n    <li>ソースをいじるわけではないので、ENABLE_CLANG_FORMAT=OFF を設定</li>\n    <li>openCVインストールされていないので、ENABLE_OPENCV=OFF を設定<br />\n(サンプルのBuildしないのでopenCVなくても大丈夫)</li>\n  </ul>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nログには いくつかWarningがあるが、とくに問題はなさそう</p>\n</blockquote>\n\n<h2 id=\"make\">make</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h2 id=\"その他細々したところ\">その他細々したところ</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"c\"># クロスコンパイルを反映したファイル名になっていないので修正</span>\n<span class=\"nb\">mv</span> /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-x86_64-linux-gnu.so /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-aarch64-linux-gnu.so\n\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>CPU Extentionは<code class=\"language-plaintext highlighter-rouge\">make install</code>でコピーされないので手動でインストールする。</li>\n    <li>バイナリリリースに<code class=\"language-plaintext highlighter-rouge\">inference_engine</code>のシンボリックリンクがあるので同様に作成しておく。</li>\n    <li>ngraphのライブラリファイルのファイル名がx86_64(ホスト環境の名前)になっているので、aarch64に修正。<br />\nバイナリ自体はaarch64になっているので、ファイル名のリネームだけでOK。<br />\n本来はファイル名決めてるところで対処するのが良いのだろうけど、とりあえず力技で。</li>\n  </ul>\n</blockquote>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<p>openCVのBuild方法についてもメモっておく。<br />\npythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。<br />\nその場合は、ここはスキップしても大丈夫。<br />\nopenVINOをBuildしたDockerコンテナで引き続き作業を行う</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk-3-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libjpeg-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libpng-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev:arm64\n</code></pre></div></div>\n<h2 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n</code></pre></div></div>\n<h2 id=\"cmakeの実行\">cmakeの実行</h2>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PKG_CONFIG_LIBDIR</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_ENABLE_PKG_CONFIG</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_FIND_ROOT_PATH</span><span class=\"o\">=</span>/ <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span>/work/opencv/platforms/linux/aarch64-gnu.toolchain.cmake <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_NUMPY_INCLUDE_DIRS</span><span class=\"o\">=</span>/usr/lib/python3/dist-packages/numpy/core/include <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n       .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあらかじめ環境変数<code class=\"language-plaintext highlighter-rouge\">PKG_CONFIG_LIBDIR</code>を設定して<code class=\"language-plaintext highlighter-rouge\">pkg-config</code>でaarch64のライブラリとNativeのツール類を参照するように設定しておく。<br />\nこれをやらないと、libjpegとかをインストールしてあることを検出できない</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeのオプションに <code class=\"language-plaintext highlighter-rouge\">-D CMAKE_FIND_DEBUG_MODE=1</code>を追加すると\ncmake中の<code class=\"language-plaintext highlighter-rouge\">find_xxx</code>の動作のログが出力されるので、パッケージのサーチなどの検索パスの確認などが容易になる。</p>\n</blockquote>\n\n<h2 id=\"make-1\">make</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install-1\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino/opencv</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/opencv</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-D CMAKE_INSTALL_PREFIX=/work/opt/intel/openvino/opencv</code>の部分を変更すれば良いけど、ここはopenVINOのインストール先と合わせておかないとうまく動かない。</p>\n\n<h1 id=\"実機へのインストール\">実機へのインストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">opt</code>ディレクトリ以下を丸ごとアーカイブする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<p>作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>をRaspberryPiの適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"コンテナから出る\">コンテナから出る</h1>\n<p>Dockerコンテナは作業終了したら終了しておく。<br />\nCTRL-D でshell終了</p>\n\n<h1 id=\"補足\">補足</h1>\n<p>コンテナにインストールされているパッケージは以下の通り。<br />\nバージョン違いで動かなくなることもあるかもしれんので、念のため。</p>\n\n<p>こんな感じで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span> | <span class=\"nb\">grep</span> <span class=\"nt\">-v</span> automatic\n</code></pre></div></div>\n\n<p>で、こんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>build-essential/stable,now 12.9 amd64 [installed]\ncmake/stable,now 3.18.4-2+deb11u1 amd64 [installed]\ncrossbuild-essential-arm64/stable,stable,now 12.9 all [installed]\ncython3/stable,now 0.29.21-3+b1 amd64 [installed]\ngit/stable,now 1:2.30.2-1 amd64 [installed]\nlibavcodec-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibavformat-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibgstreamer-plugins-base1.0-dev/stable,now 1.18.4-2 arm64 [installed]\nlibgstreamer1.0-dev/stable,now 1.18.4-2.1 arm64 [installed]\nlibgtk-3-dev/stable,now 3.24.24-4 arm64 [installed]\nlibjpeg-dev/stable,now 1:2.0.6-4 arm64 [installed]\nlibpng-dev/stable,now 1.6.37-3 arm64 [installed]\nlibprotobuf-dev/stable,now 3.12.4-1 arm64 [installed]\nlibprotoc-dev/stable,now 3.12.4-1 arm64 [installed]\nlibpython3-dev/stable,now 3.9.2-3 arm64 [installed]\nlibswscale-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibtiff-dev/stable,now 4.2.0-1 arm64 [installed]\nlibusb-1.0-0-dev/stable,now 2:1.0.24-3 arm64 [installed]\nlibwebp-dev/stable,now 0.6.1-2.1 arm64 [installed]\nprotobuf-compiler/stable,now 3.12.4-1 amd64 [installed]\npython3-minimal/stable,now 3.9.2-3 amd64 [installed]\npython3-numpy/stable,now 1:1.19.5-1 amd64 [installed]\npython3-pip/stable,stable,now 20.3.4-4 all [installed]\nscons/stable,stable,now 4.0.1+dfsg-2 all [installed]\nwget/stable,now 1.21-1+deb11u1 amd64 [installed]\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>aspberry Pi OS(64bit)がリリースされたが、openVINOのBuild済みモジュールはまだこれに対応していない。<br />\nそのうち対応されると思うけど、とりあえず自前でBuildする方法を調べてみた。<br />\nついでにCPU Extensionも作成しておく。<br />\nなお、Raspberry Pi OS(32bit Buster)向けのBuild手順については、\n『<a href=\"/memoBlog/2021/10/28/openVINO_build.html\" target=\"_blank\">openVINO(Raspberry Pi向け)のbuild</a>』を参照。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<p>今回もARM版Dockerコンテナを使用してセルフコンパイルする方法で行う。<br />\n手順そのものは特殊なことはないので、Raspberry Pi上のNative環境でもBuildできそうだけど、\nディスク容量とかスワップ領域とか気にしないといけないかもしれないので試してない。<br />\n(今回はクロスコンパイル環境はなし。cythonの出力モジュールも使いたかったので)</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_emu\n</code></pre></div></div>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h2 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h2>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n32bit版との差分はこんな感じ。<br />\nあれ?32bit版の<code class=\"language-plaintext highlighter-rouge\">python-minimal</code>って間違ってる?<br />\n<code class=\"language-plaintext highlighter-rouge\">python3-numpy</code>で依存モジュールとしてインストールされて事なきを得たのか?<br />\n実質、ベースイメージを変更してるだけだな。</p>\n\n  <div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- Dockerfile.old\t2022-03-01 07:26:28.774187231 +0900\n</span><span class=\"gi\">+++ Dockerfile\t2022-03-01 07:19:45.668393598 +0900\n</span><span class=\"p\">@@ -1,4 +1,4 @@</span>\n<span class=\"gd\">-FROM arm32v7/debian:buster\n</span><span class=\"gi\">+FROM arm64v8/debian:bullseye\n</span> \n USER root\n \n<span class=\"p\">@@ -18,7 +18,7 @@</span>\n     libprotobuf-dev libprotoc-dev protobuf-compiler \\\n     cmake \\\n     python3-pip \\\n<span class=\"gd\">-    python-minimal \\\n</span><span class=\"gi\">+    python3-minimal \\\n</span>     python3-numpy cython3 scons\n \n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_emu_1 ov_pi64_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<p>数時間レベルでかかるので、のんびり待ちましょう。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"その他細々したところ\">その他細々したところ</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コメント\">コメント</h3>\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール\">実機へのインストール</h2>\n\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>を適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>ついでにopenCVのBuild方法についてもメモっておく。</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>openCVのリポジトリをcloneしておく。<br />\n指定するタグは適宜変更してください。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n<p>新しいDockerコンテナ作っても良いけど、別にその必要もないので上記のコンテナをそのまま使用する。</p>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n  <h2 id=\"本番-1\">本番</h2>\n</blockquote>\n\n<h3 id=\"準備-2\">準備</h3>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk2.0-dev  libjpeg-dev libpng-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev\n</code></pre></div></div>\n\n<h3 id=\"build\">Build</h3>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n\n<span class=\"c\"># インストール</span>\nmake <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf opencv.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コンテナから出る-1\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール-1\">実機へのインストール</h2>\n<p>openVINOをBuildしたコンテナで続けてBuildした場合は<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>にopenVINO、openCVがインストールされている。<br />\nこれを適当なディレクトリに展開して環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば良い。</p>\n\n<p>別のコンテナを使用したり、openVINOのBuild結果を削除していた場合は、<br />\n最終的に作成した<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>をopenVINOをインストールしたディレクトリに展開する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール</h1>\n      <p>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロード\">ダウンロード</h1>\n\n<p><a href=\"https://www.raspberrypi.com/software/operating-systems/\" target=\"_blank\">Raspberry Pi OS</a>ページの <br />\n「Manually install an operating system image」の「See all download options」をクリック、<br />\n「Raspberry Pi OS (64-bit)」の「Raspberry Pi OS with desktop」の「Download」をクリックしてダウンロード<br />\n試したのは Release date: January 28th 2022</p>\n\n<blockquote>\n  <p>[!NOTE]\n「Archive」リンクから過去のリリースも入手できる</p>\n</blockquote>\n\n<p>なんか見るたびにページ構成変わるよなぁ….😩💨</p>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nシリアルコンソールの送信改行コードはCRにしておくこと。<br />\nそうしないと、ビミョーに悲しいことが起こる場合がある。</p>\n\n</blockquote>\n\n<h2 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h2>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>の  最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group</code>と<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>については使用するモニタに合わせる。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group=2</code>はモニタ種別でDMT(一般的にモニタディスプレイ)、<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_mode=82</code>が 1920x1080 60Hz(1080p)を示している。<br />\n設定値の内容については、<a href=\"https://www.raspberrypi.com/documentation/computers/config_txt.html#hdmi-mode\" target=\"_blank\">HDMI Mode</a>を参照。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>はテキストモードで表示したいサイズに合わせる。1920と1080とか、1280と720とか。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># display resolution force setting</span>\n<span class=\"nv\">hdmi_group</span><span class=\"o\">=</span>2\n<span class=\"nv\">hdmi_mode</span><span class=\"o\">=</span>82\n<span class=\"nv\">framebuffer_width</span><span class=\"o\">=</span>1920\n<span class=\"nv\">framebuffer_height</span><span class=\"o\">=</span>1080\n<span class=\"nv\">hdmi_force_hotplug</span><span class=\"o\">=</span>1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nHDMIディスプレイを常に接続しているなら設定しなくても問題ないが、\nHDMIディスプレイをはずしてVNCでリモート接続だけする場合は設定しておかないと\n解像度が1024x768までしか設定できなくなるので注意。</p>\n</blockquote>\n\n<h3 id=\"vncが遅い問題対応\">VNCが遅い問題対応</h3>\n<p>このバージョンではHDMIディスプレイを繋いでいない状態でVNCで接続すると表示がとても遅くなる問題がある。<br />\n回避するには、<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code>に以下追記する。<br />\n<code class=\"language-plaintext highlighter-rouge\">1920x1080@60D</code>の部分は上記の<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>や<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>の設定値に合わせる。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>video=HDMI-A-1:1920x1080@60D\n</code></pre></div></div>\n\n<p>具体的にはこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>console=serial0,115200 console=tty1 root=PARTUUID=b635b4ec-02 rootfstype=ext4 fsck.repair=yes video=HDMI-A-1:1920x1080@60D rootwait\n</code></pre></div></div>\n\n<p>参考URL:<a href=\"https://forums.raspberrypi.com/viewtopic.php?p=1935714#p1935711\">Re: Bullseye vncserver is very slow without display</a></p>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。<br />\nSSID名は ダブルクォーテーションで囲む。<br />\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://qiita.com/mt08/items/2da1cce534dfdc84f5e3#%E7%92%B0%E5%A2%83\" target=\"_blank\">[メモ] (らずぱい)Windows上から固定IP設定 (Raspberry Pi Static IP)</a>\nにWindows版の<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase.exe</code>へのリンクがある。<br />\nワタシはUbuntuや別のRasberryPiで作ったから使ってないけど…</p>\n</blockquote>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase \"SSID名\" \"暗号化キー\"\n        ↓ 実行結果\nnetwork={\n        ssid=\"SSID名\"\n        #psk=\"暗号化キー\"\n        psk=ほにゃらら~~~ほにゃらら~~~\n}\n</code></pre></div></div>\n\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。<br />\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<blockquote>\n  <p>[!NOTE]\n起動後、公開鍵ファイルの設置を行うには、<br />\n<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">ubuntuにSSHサーバをセットアップする</a> <br />\nの「秘密鍵と公開鍵の生成と公開鍵ファイルの設置」の部分を参照。<br />\n(ページはUbuntuについて書いてあるけど、サーバがセットアップ済みなことを除けばRaspberry Pi OSでも同じ)</p>\n</blockquote>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># アップデート実行\nsudo apt update\nsudo apt upgrade\n# リブート\nsudo reboot\n</code></pre></div></div>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S7 Splash Screen\n            Would you like to show the splash screen at boot?\n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこの操作で/boot/cmdline.txtが書き換えられるらしい。</p>\n\n</blockquote>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# 新ユーザのパスワード変更する\npasswd\n《パスワードを設定》\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\" target=\"_blank\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n            B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/4f39afbcd8471426421944b597f3a5f2963984c6/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nresize.pyは以前python2ベースで作ってあったが、<br />\nこのバージョンからpython2がデフォルトでインストールされなくなったので、<br />\npython3ベースに修正したのでURLが変更されています。</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n\n<p>物理キーボード接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]<br />\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n\n</blockquote>\n\n<h1 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h1>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n\n<p>まずはワークディレクトリの作成</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo service smbd reload\nsudo service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo vi /etc/hostname\nsudo vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>s``udo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    3 Interfacing Options\n        I3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>\n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n\n<p>Windows側のクライアントは、<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a>\nから VNC Viewerをダウンロード。\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。\n日本語化の手順はこちらを参考に。 <a href=\"http://xn--u9j0md1592aqmt715c.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>SDカードイメージのバックアップを取るならこちら。<br />\n<a href=\"/memoBlog/2021/07/18/sd_image_2.html\" target=\"_blank\">Raspbian SDカードイメージファイルの作成(改訂版)</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>BLEでアプリケーションパラメータ設定</title>\n  </head>\n  <body>\n    <header>\n      <h1>BLEでアプリケーションパラメータ設定</h1>\n      <p>ESP32 BLEを使用してアプリケーションパラメータの設定を変更する処理の雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>アプリケーションを作成したとき、マシン名のように端末毎に変更を変更したり、\nサーバ名のように設置条件によって変更したいパラメータってありますよね。<br />\nいつもは起動時に設定モードに入ったり、動作中に簡易シェルを動かしてコンソール(UART)から設定していましたが、<br />\n実装面積などの関係でUARTが接続できなかったりした場合、それ以外の方法としてBLEで設定する方法を考えました。<br />\n(ESP32の場合、Flash書き換えでUART使うので繋がない訳にはいかないのですが…)</p>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nを参考にカスタムプロファイルでアプリケーションパラメータをread/writeできるようにしてみました。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは<a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a><br />\nにあるのでcloneしてください。</p>\n\n<p>このプログラムではアプリケーションはWi-Fiに接続するだけの処理です。<br />\nうまくパラメータが設定できて、nvsに保存しておけば、2回目以降はBLEによる設定なしにWi-Fiに接続することができます。<br />\n接続できれば、外部マシンからpingを打って応答があることが確認できます。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a> のREADME.mdを参照してください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nパラメータの設定はRaspberryPiのpythonから行っていますが、その気になればAndroidのBLE接続確認ツールなどからでも設定できます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n設定パラメータにループインターバルがありますが、プログラム中では参照していません。<br />\n数値を設定する例として入れてあります。</p>\n</blockquote>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>設定したいパラメータが増えてたら、Characteristicを増やしていけばいくらでも対応できるハズ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>pythonでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に pythonスクリプトでアクセスしてみる方法についてのメモ。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<p>pythonスクリプトはRaspberryPiで動作している(実際に試したのはPi4だが、Pi3/Pi0wでも同様)。<br />\nubuntu-PCでも同様にできるはずだが、うちのマシンは内蔵Bluetoothのバージョンが古くてBLE非対応だったので試してない。<br />\nwindows-PCはよくわからん…</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/test1\n<span class=\"nb\">cd</span> /work/ble/test1\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.9.10 bluepy\npyenv <span class=\"nb\">local </span>bluepy\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>bluepy\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/9bbdfa53526411967975097cfbcc66e6.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>ESP32側はAdvertising 開始状態にしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>python ble_hr.py\n</code></pre></div></div>\n<p>デバイスのスキャンを行うので<code class=\"language-plaintext highlighter-rouge\">sudo</code>が必要。</p>\n<blockquote>\n  <p>[!NOTE]\nもし、scanせずにアドレスを指定して実行するだけの処理に書き換えれば<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要になる。</p>\n</blockquote>\n\n<h1 id=\"説明\">説明</h1>\n\n<h2 id=\"ble_hr_delegateクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR_Delegate</code>クラス</h2>\n<p>Notifyを受け取っての処理は<code class=\"language-plaintext highlighter-rouge\">bluepy.btle.DefaultDelegate</code>クラスを継承したクラスを作成して登録する必要がある。<br />\n処理自体は<code class=\"language-plaintext highlighter-rouge\">handleNotification</code>メソッドをオーバーライドして定義する。<br />\n受け取るデータ<code class=\"language-plaintext highlighter-rouge\">data</code>はbytes型なので、数値として使用する場合は<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換してやる必要があるが、<br />\nこの時のエンディアンは接続しているデバイスのFW仕様によるので、どちらを使うかはあらかじめ確認しておく必要がある。<br />\n(大抵はFWを動かしているCPUのエンディアンなのかな?)</p>\n\n<h2 id=\"ble_hrクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR</code>クラス</h2>\n<p>peripheralを操作するための処理をクラス化してある。<br />\nクラス化は必須ではないけど、処理をまとめておいた方が分かりやすいかな?と思ったので。</p>\n\n<p>コンストラクタ、接続、Characteristicのリード/ライト、Notifyの有効化/無効化/ポーリング、切断などの処理がある。</p>\n\n<h2 id=\"main関数\"><code class=\"language-plaintext highlighter-rouge\">main</code>関数</h2>\n<p>メイン処理。<br />\n処理の流れはこんな感じ。</p>\n<ul>\n  <li>デバイスのスキャン</li>\n  <li>スキャン結果から指定されたUUIDを持つデバイスを探す\n    <ul>\n      <li>UUIDやデバイス名が必ずしも同じところにあるとは限らないので色々読んでみる必要がある</li>\n    </ul>\n  </li>\n  <li>複数のデバイスを同時に操作することも可能だが、今回は最初の1個だけを決め打ちで使う</li>\n  <li>接続</li>\n  <li>Characteristicのリード\n    <ul>\n      <li>ここもリード結果はbytes型なので、<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換する</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト\n    <ul>\n      <li>ライトデータはbytes型に変換する必要があるが、この処理は、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.write()</code>で変換しているのでここではそのまま。</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト結果の確認\n    <ul>\n      <li>ライトできたか確認するために、再度リードしている</li>\n    </ul>\n  </li>\n  <li>Notifyの有効化</li>\n  <li>Notifyが通知されることを確認するために少し待つ\n    <ul>\n      <li>Notifyを待つ間、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.waitForNotifications()</code>(<code class=\"language-plaintext highlighter-rouge\">Peripheral.waitForNotifications()</code>のラッパ)をコールし続ける必要がある。<br />\nこれをコールしないとNotifyを受信できない(キューイングされるがコールバックは実行されない)。</li>\n    </ul>\n  </li>\n  <li>Notifyの無効化\n    <ul>\n      <li>Notifyが入らないことを確認するためにちょっと待つ</li>\n    </ul>\n  </li>\n  <li>切断</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry PiでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry PiでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に Raspberry Pi からアクセスしてみる方法についてのメモ。</p>\n\n<p>Androidでアクセスすると、色々とブラックボックスで処理されてどうなってるのか分かり難いので理解を深める意味で試してみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"メモ\">メモ</h1>\n\n<p>ここにあるように、BLEでは「ボンディング(参照先ではペアリングと表記)なし」で実行するのが無難と思われる<br />\n<a href=\"https://www.musen-connect.co.jp/blog/course/trial-production/ble-beginner-8/\" target=\"_blank\">【サルでもわかるBLE入門】(8) ペアリング</a></p>\n\n<p>Wiresharkによるパケットキャプチャの解説(たぶん、そんなレイヤでデバッグすることはないと思うけど)<br />\n<a href=\"https://re-engines.com/2021/08/16/ble-secure/\" target=\"_blank\">BLEのペアリングをWiresharkでキャプチャしながら学ぶ</a></p>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<h1 id=\"ペリフェラル機器をスキャン\">ペリフェラル機器をスキャン</h1>\n\n<p>まずは接続可能デバイスをスキャンしないと始まらないので、スキャンする。<br />\nもちろん、ESP32側はAdvertising 開始状態である必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo timeout </span>5s hcitool lescan        ← 5秒間スキャンしてみる\nLE Scan ...\n48:BA:7E:24:D0:AA <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n50:17:FC:8C:D1:87 ESP_BLE_HR            ←見つかった\nE4:9A:9F:40:AD:09 <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\nC4:49:BB:8A:7F:6C EX-ZR1800-8A7F6B\nC4:49:BB:8A:7F:6C <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hcitool lescan</code>の実行には<code class=\"language-plaintext highlighter-rouge\">sudo</code>必須。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout 5s</code> を付けずにCTRL+Cで停止しても良い。</p>\n\n<h1 id=\"対象デバイスにアクセスしてみる\">対象デバイスにアクセスしてみる</h1>\n\n<blockquote>\n  <p>[!NOTE]\n<strong>UUIDについて</strong></p>\n\n  <p>16bit UUIDは以下のXXXXの部分(それ以外の部分が一致しないものは128bit UUID)<br />\n<code class=\"language-plaintext highlighter-rouge\">0000XXXX-0000-1000-8000-00805f9b34fb</code></p>\n\n  <p>16bit UUIDは 以下のページを参照<br />\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a></p>\n</blockquote>\n\n<h2 id=\"コマンド起動と接続\">コマンド起動と接続</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">gatttool</code>の実行に<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要。<br />\n<code class=\"language-plaintext highlighter-rouge\">«アドレス»</code> には上でみつけたアドレスを指定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>gatttool <span class=\"nt\">-t</span> random <span class=\"nt\">-I</span> <span class=\"nt\">-b</span> «アドレス»             ← ツールの実行   以下、インタラクティブモードに入る\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> connect                  ← 接続 \nAttempting to connect to 50:17:FC:8C:D1:87\nConnection successful                             ← 接続成功  \n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"サービス一覧を取得\">サービス一覧を取得</h2>\n\n<p>サービスの一覧を取得してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> primary\nattr handle: 0x0001, end grp handle: 0x0005 uuid: 00001801-0000-1000-8000-00805f9b34fb\nattr handle: 0x0014, end grp handle: 0x001c uuid: 00001800-0000-1000-8000-00805f9b34fb\nattr handle: 0x0028, end grp handle: 0xffff uuid: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<p>それぞれこんな意味</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>UUID</th>\n      <th>種別</th>\n      <th>ハンドル範囲</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>1801</td>\n      <td>Generic Attribute</td>\n      <td>0x0001 ~ 0x0005</td>\n    </tr>\n    <tr>\n      <td>1800</td>\n      <td>Generic Acces</td>\n      <td>0x0014 ~ 0x001c</td>\n    </tr>\n    <tr>\n      <td>180d</td>\n      <td>Heart Rate</td>\n      <td>0x0028 ~ 0xffff</td>\n    </tr>\n  </tbody>\n</table>\n\n<h2 id=\"generic-accesを調べてみる\">Generic Accesを調べてみる</h2>\n\n<p>上で調べたGeneric Acces のハンドル範囲を指定して実行。<br />\n表示されるUUIDを\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a>\nで探して右側にメモっておいた。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x14 0x1c\nhandle: 0x0014, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0015, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb        ← device name\nhandle: 0x0017, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb        ← Appearance\nhandle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb        ← Central Address Resolution\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"device-name-を読んでみる\">device name を読んでみる</h2>\n\n<p>とりあえず devece nameを読んでみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x016                       ← handle 0x16<span class=\"o\">(</span>device name<span class=\"o\">)</span> のリード\nCharacteristic value/descriptor: 45 53 50 5f 42 4c 45 5f 48 52     ← 結果\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<p>このままだとなんだかわからん…<br />\n別ウィンドゥで以下を実行。<br />\nただし、<code class=\"language-plaintext highlighter-rouge\">nkf</code>はデフォルトでインストールされていないので<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールする。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">echo</code>の中身には上でリードした結果をコピペする。<br />\nこれを<code class=\"language-plaintext highlighter-rouge\">xxd</code>コマンドでバイナリに変換、<br />\n<code class=\"language-plaintext highlighter-rouge\">nkf</code>で文字コード変換を行う(これだとUTF-8→UTF-8なのであんまり意味ない気が…)。<br />\n結果は改行されずに、プロンプトが続けて表示されるので注意。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">echo</span> <span class=\"s2\">\"45 53 50 5f 42 4c 45 5f 48 52\"</span>  | xxd <span class=\"nt\">-p</span> <span class=\"nt\">-r</span>  | nkf <span class=\"nt\">-WwmQ</span>\nESP_BLE_HR        ← おぉ、読めてる\n<span class=\"nv\">$ </span>\n</code></pre></div></div>\n\n<h2 id=\"heart-rateサービスを調べてみる\">Heart Rateサービスを調べてみる</h2>\n<p>同様にHeart Rateサービスについて調べてみる。<br />\nUUIDについてのメモも同様。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x0028 0xffff\nhandle: 0x0028, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0029, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002a, uuid: 00002a37-0000-1000-8000-00805f9b34fb        ← Heart Rate Measurement\nhandle: 0x002b, uuid: 00002902-0000-1000-8000-00805f9b34fb        ← Client Characteristic Configuration\nhandle: 0x002c, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002d, uuid: 00002a38-0000-1000-8000-00805f9b34fb        ← Body Sensor Location\nhandle: 0x002e, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002f, uuid: 00002a39-0000-1000-8000-00805f9b34fb        ← Heart Rate Control Point\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"heart-rate-control-point-を読み書きしてみる\">Heart Rate Control Point を読み書きしてみる</h2>\n\n<p>Characteristicの読み書きを試すため、Heart Rate Control Point(ハンドル0x2f;c<code class=\"language-plaintext highlighter-rouge\">har-desc</code>の結果から取得)にアクセスしてみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 読んでみる\nCharacteristic value/descriptor: 00                   ← 読めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 01       ← 書いてみる\nCharacteristic value was written successfully         ← 書けた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 確認してみる\nCharacteristic value/descriptor: 01                   ← 書けてる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 0x02     ← 書き込み値に0xを付けたらエラーになる\nError: Characteristic Write Request failed: Attribute value length is invalid\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<h2 id=\"notificationを有効にしてみる\">Notificationを有効にしてみる</h2>\n\n<p>NotificationをONにするにはCCCを操作する。<br />\nNotificationで受信したデータは自動で表示される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 00 00                ← Notification OFFになってる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0100     ← Notification ON にしてみる<span class=\"o\">(</span>0100を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\nNotification handle <span class=\"o\">=</span> 0x002a value: 50 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 51 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 52 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 01 00                ← Notification ONになってる\nNotification handle <span class=\"o\">=</span> 0x002a value: 53 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 54 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 55 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 56 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 57 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0000     ← Notification OFF にしてみる<span class=\"o\">(</span>0000を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>                              ← 以降、Notificationは停止\n</code></pre></div></div>\n\n<h2 id=\"書き込み禁止のcharacteristicに書き込んでみる\">書き込み禁止のCharacteristicに書き込んでみる</h2>\n\n<p>書き込み禁止のCharacteristicに書き込んでみるとどうなるか試してみる。<br />\n当然エラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>50:17:FC:8C:D1:87][LE]> char-write-req 0x2d 01         ← Body Sensor Locationに書き込んでみる\nError: Characteristic Write Request failed: Attribute can<span class=\"s1\">'t be written   ← エラーになった\n</span></code></pre></div></div>\n\n<h2 id=\"切断する\">切断する</h2>\n\n<p>操作が終わったら切断する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> disconnect                        ← 切断\n<span class=\"o\">(</span>gatttool:1840<span class=\"o\">)</span>: GLib-WARNING <span class=\"k\">**</span>: 12:55:27.500: Invalid file descriptor.   ← なんか言われるけど無視して良い\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> <span class=\"nb\">exit</span>                              ← インタラクティブモードの終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る\n</code></pre></div></div>\n\n<h1 id=\"bluetoothctlでアクセス参考\">bluetoothctlでアクセス(参考)</h1>\n\n<p>「ボンディングする」設定の場合、bluetoothctlでアクセスする必要がある。<br />\nボンディングしない設定で使う分には関係ないが、せっかく調べたのでメモっておく。</p>\n\n<p>ボンディング前後でアドレス違ったりしてイマイチ使いにくい。<br />\nどうしても「ボンディングする」にしなければならない場合は、自身のアドレスをパブリックアドレスにしておけばちょっとマシかも。</p>\n\n<h2 id=\"メモ-1\">メモ</h2>\n\n<p>bluetoothctlのコマンド <br />\n<a href=\"https://qiita.com/noraworld/items/55c0cb1eb52cf8dccc12\" target=\"_blank\">bluetoothctl のコマンド一覧と使い方をまとめてみた</a></p>\n\n<p>bluetoothctlだとGATTへのアクセスができないっぽいので、ボンディングの登録/解除以外は使えないっぽいな…</p>\n\n<h2 id=\"前提-1\">前提</h2>\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス           (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングする                           (ESP_LE_AUTH_REQ_SC_MITM_BOND)</li>\n  <li>IO capabilityはcapabilityはDisplayYesNo    (ESP_IO_CAP_IO)</li>\n</ul>\n\n<h2 id=\"起動\">起動</h2>\n\n<p>ツールの起動。<br />\n<code class=\"language-plaintext highlighter-rouge\">sudo</code>必要<br />\n以下インタラクティブモードで操作。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo </span>bluetoothctl                                        ← 起動\n</code></pre></div></div>\n\n<h2 id=\"スキャン\">スキャン</h2>\n\n<p>接続可能デバイスを見つけるためにスキャンする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# scan on                                       ← スキャン開始\nDiscovery started\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>NEW] Device 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\n<span class=\"o\">[</span>NEW] Device 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\n<span class=\"o\">[</span>NEW] Device 62:D1:88:DD:4F:7C リビングルーム\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E RSSI: <span class=\"nt\">-38</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower: 3\n・・・\n<span class=\"o\">[</span>bluetooth]# scan off                                      ← スキャン停止\nDiscovery stopped\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: no\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower is nil\n・・・\n<span class=\"o\">[</span>bluetooth]# devices                                       ← 接続可能デバイスの表示\nDevice 5A:E1:9A:05:96:E0 ESP_BLE_HR                        ← これがESP32<span class=\"o\">(</span>ランダムアドレスなので起動の度に変化する<span class=\"o\">)</span>\nDevice 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\nDevice 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\nDevice 62:D1:88:DD:4F:7C リビングルーム\n\n</code></pre></div></div>\n\n<h2 id=\"agentの登録\">agentの登録</h2>\n\n<p>ボンディングのために、agentを登録する(数字を入力したり、Yes/Noを選択したりするやつ)。<br />\nこちらの設定と相手側の設定の組み合わせで最終的にどの方法が使われるか決定される。<br />\nたとえば、こちら側を NoInputNoOutput に設定しておけば、相手側が DisplayYesNo であってもYes/Noの入力は求められない。<br />\n逆の設定でも同様。</p>\n\n<p>登録された状態で他のCapabilityで登録しようとしても「既に登録済み」と言われるので、念のため一旦登録解除してから登録しておく。<br />\nこのあたり、情報少なくてイマイチよく分からない…</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# agent off                                    ← 一旦agentの登録解除\nAgent unregistered                                         ← 解除された\n<span class=\"o\">[</span>ESP_BLE_HR]# agent DisplayYesNo                           ← DisplayYesNoで登録\nAgent registered                                           ← 登録された\n</code></pre></div></div>\n\n<h2 id=\"接続\">接続</h2>\n\n<p>接続する。<code class=\"language-plaintext highlighter-rouge\">connect</code>でなく、<code class=\"language-plaintext highlighter-rouge\">pair</code>で実行。<br />\n<code class=\"language-plaintext highlighter-rouge\">connect</code>による接続は後述。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# pair 5A:E1:9A:05:96:E0                       ← 接続\nAttempting to pair with 5A:E1:9A:05:96:E0\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 Connected: <span class=\"nb\">yes\n</span>Request confirmation\n<span class=\"o\">[</span>agent] Confirm passkey 680456 <span class=\"o\">(</span><span class=\"nb\">yes</span>/no<span class=\"o\">)</span>:                   ← agentがYes/Noを聞いてくる\n<span class=\"o\">[</span>NEW] Primary Service                                      ← これが自動的に表示されて上の質問を見失うので注意!!\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001\n        00001801-0000-1000-8000-00805f9b34fb\n        Generic Attribute Profile\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001/char0002\n        00002a05-0000-1000-8000-00805f9b34fb\n        Service Changed\n・・・\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0028/char002e\n        00002a39-0000-1000-8000-00805f9b34fb\n        Heart Rate Control Point\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001800-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001801-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 ServicesResolved: <span class=\"nb\">yes\nyes</span>                                                         ← yesを入力<span class=\"o\">(</span>同時に相手側でもyes入力<span class=\"o\">)</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Address: 94:B9:7E:65:AF:5E\nPairing successful                                         ← 接続された\n<span class=\"o\">[</span>ESP_BLE_HR]# paired-devices                               ← ボンディング結果を確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR                        ← advertisingがランダムアドレスでもパブリックアドレスで登録されるので注意!!\n<span class=\"o\">[</span>ESP_BLE_HR]#                                                以降、接続はこのアドレスを使用する!!\n</code></pre></div></div>\n\n<h2 id=\"切断\">切断</h2>\n\n<p>切断する。<br />\nCharacteristicアクセスできないので、実質ボンディングするのみ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断する\nAttempting to disconnect from 94:B9:7E:65:AF:5E            ← パブリックアドレスが表示されている\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<h2 id=\"再接続\">再接続</h2>\n\n<p>ボンディング済みのデバイスに再接続する場合の手順。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスの表示\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# connect 94:B9:7E:65:AF:5E                     ← 表示されたアドレスで接続\nAttempting to connect to 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: <span class=\"nb\">yes\n</span>Connection successful                                      ← 接続された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断\nAttempting to disconnect from 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<p>ボンディングしてない機器に対して<code class=\"language-plaintext highlighter-rouge\">connect</code>すると、<code class=\"language-plaintext highlighter-rouge\">agent off</code> で <code class=\"language-plaintext highlighter-rouge\">pair</code> したような動作になる模様。</p>\n\n<h2 id=\"ボンディング解除\">ボンディング解除</h2>\n\n<p>ボンディング済みデバイスを登録削除する。<br />\nESP32側も忘れず登録削除しておくこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスを確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# remove 94:B9:7E:65:AF:5E                      ← ボンディング解除\n<span class=\"o\">[</span>DEL] Descriptor                                           ← なんか ずらずらっと削除されたと出る\n        /org/bluez/hci0/dev_5F_76_EF_D2_45_E7/service0001/char0002/desc0004\n        00002902-0000-1000-8000-00805f9b34fb\n        Client Characteristic Configuration\n・・・\nDevice has been removed                                    ← 削除された\n<span class=\"o\">[</span>bluetooth]# paired-devices                                ← 確認\n<span class=\"o\">[</span>bluetooth]#                                               ← 削除されてる\n</code></pre></div></div>\n\n<h2 id=\"ツールの終了\">ツールの終了</h2>\n\n<p>ツールを終了してShellに戻る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# <span class=\"nb\">exit</span>                                          ← またはquitまたはCTRL+Dで終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る \n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi向け)のbuild</h1>\n      <p>Raspberry Pi向けopenVINOのbuild(特にCPU extension)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi用 openVINO は デフォルト状態ではCPUで実行できない(NCS2必須)。<br />\nそこで、オープンソース版openVINOを使用してCPU extensionを作成してみる。<br />\nとはいえ、CPU extension だけサクっと作成できなくて、openVINO全体を作成するハメに…</p>\n\n<p>Raspberry Pi 実機でbuildすると、ディスク容量がバカにならないし、<br />\nあまり実環境を弄りたくなかったので、<br />\nUbuntuマシン上のDockerコンテナで実行する方法を試してみる(Docker Desktop for Windowsでもできると思う)</p>\n\n<h1 id=\"arm版dockerコンテナを使用したセルフコンパイル\">ARM版Dockerコンテナを使用したセルフコンパイル</h1>\n\n<p>Dockerコンテナ全体をQEMU上でARMエミュレーションしてくれるので、特に難しいことを考えずに<br />\nネイティブ環境と変わりなくあつかえる。<br />\nでも、かなり遅い(実機よりちょっと速い?同じくらい?)。<br />\n試した環境では、x86_64な環境でクロスコンパイルした場合の15倍くらいかかった。  <br />\n(M1 Mac上でACVMを使うとかなり早いという噂も…M1 Mac持ってない😢  <a href=\"https://qiita.com/kose3/items/af9edc9c40c9ae8fc5c3\" target=\"_blank\">参考</a>  )</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h3 id=\"qemuのインストール\">qemuのインストール</h3>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_emu\n</code></pre></div></div>\n\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm32v7/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成\">patchファイルを作成</h3>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_emu_1 ov_pi_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n以下のオプションを追加すると少しは速くなるかと思ったが、あまり変わらない。</p>\n  <ul>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_OPENCV=OFF</code></li>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_SAMPLES=OFF</code></li>\n  </ul>\n</blockquote>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。</p>\n\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./inference_engine</code> がない\n    <ul>\n      <li>実体は <code class=\"language-plaintext highlighter-rouge\">deployment_tools/inference_engine</code> なので、シンボリックリンクを作れば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/opencv/</code>からコピーすれば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>opencvのpythonモジュールがない\n        <ul>\n          <li>どこから持ってくれば良いんだろう?</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h3 id=\"実機へのインストール\">実機へのインストール</h3>\n<p>CPU extensionだけなら<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l/</code><br />\nへコピーするだけで良い。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれはmake install してもこれはコピーされないらしい。</p>\n</blockquote>\n\n<p>openVINO全体のインストールなら<code class=\"language-plaintext highlighter-rouge\">work/opt/intel/openvino</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/</code>にコピーすれば良いのだけど、opencvのpythonインタフェースがないので注意。<br />\nということで、実際に試していない…</p>\n\n<blockquote>\n  <p>[!NOTE]\n※※※※ メモ ※※※※ <br />\nopenCVはここでbuildするのではなく、<br />\n<a href=\"https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/\" target=\"_blank\">https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/</a> \nからbuild済みモジュールをダウンロードして<br />\n<code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/</code><br />\nに展開している。</p>\n</blockquote>\n\n<h1 id=\"i386版32bit-x86dockerコンテナを使用したクロスコンパイル\">i386版(32bit x86)Dockerコンテナを使用したクロスコンパイル</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>セルフコンパイルは時間がかかりすぎるので、クロスコンパイルで試してみた。<br />\nかなり早くなったが、一部使えないモジュールが…<br />\n当初の目的のCPU extensionは使えるので、掲載しとく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n当初、64bit版debianをベースに作業しようとしたが、\npybind11のbuildで以下のように怒られる。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Make Error at build/_deps/pybind11-src/tools/FindPythonLibsNew.cmake:127 (message):\n  Python config failure: Python is 64-bit, chosen compiler is 32-bit\nCall Stack (most recent call first):\n  build/_deps/pybind11-src/tools/pybind11Tools.cmake:16 (find_package)\n  build/_deps/pybind11-src/CMakeLists.txt:33 (include)\n</code></pre></div>  </div>\n  <p>以下のような対策が考えられる。</p>\n  <ul>\n    <li>FindPythonLibsNew.cmakeにbit数チェックをしないようにパッチを当てる\n      <ul>\n        <li>やり方がよう分からん…</li>\n      </ul>\n    </li>\n    <li>amd64なdebianに32bitのpythonをインストールする\n      <ul>\n        <li>イマイチうまくインストールできなかった</li>\n      </ul>\n    </li>\n  </ul>\n\n  <p>しかたないので、32bit版debianで作ることにした</p>\n</blockquote>\n\n<h2 id=\"準備-1\">準備</h2>\n\n<h3 id=\"作業用ディレクトリの準備-1\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_buster_32 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_buster_32\n</code></pre></div></div>\n<h3 id=\"openvino-の-gitリポジトリを-clone-1\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> i386/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> armhf <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-armhf <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:armhf <span class=\"se\">\\\n</span>    libgtk-3-dev:armhf <span class=\"se\">\\\n</span>    libavcodec-dev:armhf <span class=\"se\">\\\n</span>    libavformat-dev:armhf <span class=\"se\">\\\n</span>    libswscale-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:armhf <span class=\"se\">\\\n</span>    libpython3-dev:armhf <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python-argparse <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"c\"># aptでインストールするので削除</span>\n<span class=\"c\"># RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.3/cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     tar xzvf cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     (cd cmake-3.21.3 && ./bootstrap --parallel=$(nproc --all) -- -DCMAKE_USE_OPENSSL=OFF && make --jobs=$(nproc --all) && make install) && \\</span>\n<span class=\"c\">#     rm -rf cmake-3.21.3 cmake-3.21.3.tar.gz</span>\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"patchファイルを作成-1\">patchファイルを作成</h3>\n\n<p>以下の2つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch1.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake\nindex 6cb15a0..66a1ef6 100644\n</span><span class=\"gd\">--- a/cmake/dependencies.cmake\n</span><span class=\"gi\">+++ b/cmake/dependencies.cmake\n</span><span class=\"p\">@@ -19,8 +19,9 @@</span> if(CMAKE_CROSSCOMPILING AND CMAKE_HOST_SYSTEM_NAME MATCHES Linux AND CMAKE_HOST_\n     find_program(\n         SYSTEM_PROTOC\n         NAMES protoc\n<span class=\"gd\">-        PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n-        NO_DEFAULT_PATH)\n</span><span class=\"gi\">+        # PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n+        # NO_DEFAULT_PATH)\n+        )\n</span>     if(NOT SYSTEM_PROTOC)\n         message(FATAL_ERROR \"[ONNX IMPORTER] Missing host protoc binary\")\n     endif()\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる-1\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../patch1.patch<span class=\"o\">)</span>\n<span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino apply ../../patch1.patch\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_buster_32 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32_1</code> を使用。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_buster_32_1 ov_pi_buster_32 /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/386) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_buster_32_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_buster_32_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make-1\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n\n<p>コンテナから出て、<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の \n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l</code>/<br />\nへコピーする</p>\n\n<blockquote>\n  <p>[!WARNING]\ncythonの出力がx86のコードを吐くので、pythonモジュールの一部に正常に動作しないものがある。<br />\npythonモジュールを使いたいときはセルフコンパイルするしかないかな?</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian SDカードイメージファイルの作成(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian SDカードイメージファイルの作成(改訂版)</h1>\n      <p>Raspbian SDカードイメージファイルの縮小</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/07/17/raspios_20210507.html\" target=\"_blank\">Raspberry Pi OS(May 7th 2021)のインストール</a> \nでセットアップしたSDカードをバックアップしておけば逐一セットアップ作業を行わなくても環境を復元できます。</p>\n\n<p>ただ、そのままSDカードをイメージファイル化しただけでは復元するSDカードのサイズが微妙に小さい場合などは、復元できなくなってしまいます。<br />\nそこで、バックアップしtイメージファイル内のパーティションサイズを縮小し、イメージファイルを小さくして保存します。</p>\n\n<p>以前、<a href=\"/memoBlog/2019/09/15/sd_image.html\" target=\"_blank\">Raspbian SDカードイメージファイルの縮小</a>、\n<a href=\"/memoBlog/2020/10/25/Jetson_nano_backup.html\" target=\"_blank\">Jetson nano のSDカードをバックアップする</a>\nでも書いていますが、今回はSDカード上でパーティションを縮小する方法にしてみました。<br />\nこれだと、不要な部分のバックアップを行わなくて済むので、ディスク領域/時間敵に有利かと思います。</p>\n\n<p>Windowsでは出来ない操作があるので、Ubuntu PCが必要です。<br />\nWSLではたぶん出来ません。<br />\nVirtualboxだと出来そうな気がしますが、試していません。</p>\n\n<h1 id=\"事前準備\">事前準備</h1>\n<h2 id=\"raspberrypiの準備\">RaspberryPiの準備</h2>\n<p>コピーしたSDカードで初回Boot時にパーティションを拡張するためのスクリプト<code class=\"language-plaintext highlighter-rouge\">expand_partition.sh</code>を\n<a href=\"/memoBlog/misc/stock/diskimage_shrink.sh\" target=\"_blank\">ここ</a> \nから適当なディレクトリにダウンロードしておきます。<br />\n(SDカードのコピーからブートしたあとに実行するので、コピーからブートした環境でダウンロードしても良いですが、\nマスタにダウンロードしておけばコピーの度にダウンロードしなくて済むので。)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/first_boot_settings\n<span class=\"nb\">cd</span>  ~/first_boot_settings\nwget https://ippei8jp.github.io/memoBlog/misc/stock/expand_partition.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPiの場合は<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>でパーティション拡張できるので、このスクリプトはなくても良い。</p>\n</blockquote>\n\n<p>RaspberryPiの電源をOFFし、SDカードを取り外してubuntu PCに挿入しておきます。</p>\n\n<h1 id=\"ubuntu-pcでの操作\">Ubuntu PCでの操作</h1>\n\n<p>以下、SDカードは<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0</code>に割り当てられているものとします。</p>\n\n<blockquote>\n  <p>[!NOTE]\nSDカードが自動マウントされている場合はアンマウントしておいてください。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount /dev/mmcblk0p1\n<span class=\"nb\">sudo </span>umount /dev/mmcblk0p2\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"gpartedのインストール\">gpartedのインストール</h2>\n<p>パーティション操作を行うため、gpartedがインストールされていなければインストールしておきます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gparted\n</code></pre></div></div>\n\n<h2 id=\"gpartedによりパーティションを縮小\">gpartedによりパーティションを縮小</h2>\n<ul>\n  <li>goartedを起動</li>\n  <li>対象デバイスとして<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0</code>を選択。</li>\n  <li>配置図またはパーティション一覧で<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0p2</code>を右クリックし、「リサイズ/移動」を選択</li>\n  <li>ダイアログで「新しいサイズ」に縮小したサイズを設定。 ダイアログ左上に表示されている「最小サイズ」よりも少し多めに。<br />\n(後方の空き領域は自動計算されます)</li>\n  <li>メニューの「編集」→「保留中の全ての操作を適用する」を選択し、パーティションを縮小する</li>\n  <li>gpartedを終了</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\ngpartedによるパーティションの縮小はマウントしたままではできません。<br />\nしたがって、RaspberryPiでは作業できず、Ubuntu PCで行う必要があります。</p>\n</blockquote>\n\n<h2 id=\"データサイズを確認\">データサイズを確認</h2>\n<p>以下のコマンドを実行し、コピーすべきデータサイズを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>parted /dev/mmcblk0 unit MiB print\n</code></pre></div></div>\n<p>以下が実行結果例。<br />\nここで、パーティション2の終了位置をメモ(ここでは<code class=\"language-plaintext highlighter-rouge\">3760</code>)しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>モデル: SD SA16G <span class=\"o\">(</span>sd/mmc<span class=\"o\">)</span>\nディスク /dev/mmcblk0: 14772MiB\nセクタサイズ <span class=\"o\">(</span>論理/物理<span class=\"o\">)</span>: 512B/512B\nパーティションテーブル: msdos\nディスクフラグ: \n\n番号  開始     終了     サイズ   タイプ   ファイルシステム  フラグ\n 1    4.00MiB  260MiB   256MiB   primary  fat32             lba\n 2    260MiB   3760MiB  3500MiB  primary  ext4\n</code></pre></div></div>\n\n<h2 id=\"イメージファイルの作成\">イメージファイルの作成</h2>\n<p>以下のコマンドでSDカードのデータをイメージファイルに保存します。<br />\nここで、<code class=\"language-plaintext highlighter-rouge\">of=</code>で指定しているのが作成するイメージファイル名、<br />\n<code class=\"language-plaintext highlighter-rouge\">count=</code>は上で調べたパーティションの終了位置をしていします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>/dev/mmcblk0 <span class=\"nv\">of</span><span class=\"o\">=</span>hoge1.img <span class=\"nv\">bs</span><span class=\"o\">=</span>1M <span class=\"nv\">count</span><span class=\"o\">=</span>3760 <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div></div>\n\n<p>必要ならzip圧縮しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>zip hoge1.zip hoge1.img \n</code></pre></div></div>\n\n<h1 id=\"新しい環境での起動\">新しい環境での起動</h1>\n\n<h2 id=\"新しいsdカードにバックアップを復元\">新しいSDカードにバックアップを復元</h2>\n\n<p>上で作成したイメージファイルをSDカードに書き込み(WindowsでもUbuntuでもお好きにどうぞ)、</p>\n\n<h2 id=\"最初のブート\">最初のブート</h2>\n<p>RaspberryPiに挿入しBootします(特別な手順は特にありません)。</p>\n\n<h2 id=\"新しいsdカードのパーティションを拡張\">新しいSDカードのパーティションを拡張</h2>\n\n<p>Boot完了したらlog inしてパーティションサイズを変更するために\n以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash first_boot_settings/expand_partition.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nまたは、RaspberryPiにgpartedをインストールして、<br />\nパーティションを縮小したときと同様に最大サイズまでパーティションサイズを拡大しても良いです。<br />\nパーティションの拡大はマウントしたままでも可能。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPiの場合は<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>でパーティション拡張できる</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config --expand-rootfs  \n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">Please reboot</code>と言われたらrebootする。</p>\n</blockquote>\n\n<h2 id=\"その他\">その他</h2>\n<p>必要であれば、ホスト名など必要な変更を行います。</p>\n\n<h2 id=\"リブート\">リブート</h2>\n<p>リブートします。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(May 7th 2021)のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(May 7th 2021)のインストール</h1>\n      <p>Raspberry Pi OS(May 7th 2021)のインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>前にやった <a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\" target=\"_blank\">Raspbian Busterのインストール</a>\nからあまり違わないけど、微妙に違いもあるので、もう一度メモしておく。</p>\n\n<h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspberry Pi OS with desktop」 の 「Download」でダウンロードしてSDカードに書き込む。<br />\n(「・・・ and recommended software」 の方ではない)<br />\n以下の手順は、RaspberryPi4 model B で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の <code class=\"language-plaintext highlighter-rouge\">[pi4]</code>の行の前に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\nシリアルコンソールの送信改行コードは<code class=\"language-plaintext highlighter-rouge\">CR</code>にしておくこと。<br />\nそうしないと、ビミョーに悲しいことが起こる場合がある。</p>\n</blockquote>\n\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>の <code class=\"language-plaintext highlighter-rouge\">[pi4]</code>の行の前に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group</code>と<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>については使用するモニタに合わせる。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group=2</code>はモニタ種別でDMT(一般的にモニタディスプレイ)、<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_mode=82</code>が 1920x1080 60Hz(1080p)を示している。<br />\n設定値の内容については、<a href=\"https://www.raspberrypi.org/documentation/configuration/config-txt/video.md\" target=\"_blank\">Video options in config.txt</a>\nを参照。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>はテキストモードで表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nhdmi_group=2\nhdmi_mode=82\nframebuffer_width=1920\nframebuffer_height=1080\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nHDMIディスプレイを常に接続しているなら設定しなくても問題ないが、<br />\nHDMIディスプレイをはずしてVNCでリモート接続だけする場合は設定しておかないと<br />\n解像度が1024x768までしか設定できなくなるので注意。</p>\n</blockquote>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S7 Splash Screen\n            Would you like to show the splash screen at boot? \n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nこの操作で<code class=\"language-plaintext highlighter-rouge\">/boot/cmdline.txt</code>が書き換えられるらしい。</p>\n</blockquote>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\" target=\"_blank\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n            B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    3 Interfacing Options        \n        P3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>    \n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n<p>Windows側のクライアントは、<br />\n<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a> \nから VNC Viewerをダウンロード。<br />\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。<br />\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。<br />\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。<br />\n日本語化の手順はこちらを参考に。 <a href=\"http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。<br />\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"--enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マウスフォーカスの変更\">マウスフォーカスの変更</h1>\n\n<p>ウィンドウをクリックしないとフォーカスが移動しないのはイライラするので x-mouse相当の設定をする。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/xdg/openbox/lxde-pi-rc.xml</code>の以下の部分をnoからyesに変更。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><followMouse>yes</followMouse>\n</code></pre></div></div>\n\n<h1 id=\"ipv6の無効化\">IPv6の無効化</h1>\n<p>IPv6を無効化したい場合は以下を設定。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/sysctl.conf</code>に以下を追加する\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Disable IPv6\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\n</code></pre></div>    </div>\n  </li>\n  <li>以下を実行する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sysctl <span class=\"nt\">-p</span>\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano のSDカードをバックアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano のSDカードをバックアップする</h1>\n      <p>Jetson nano のSDカードをバックアップする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2020/10/23/Jetson_nano_install.html\">Jetson nano をセットアップする</a> \nでセットアップしたSDカードをバックアップしておけば逐一セットアップ作業を行わなくても環境を復元できます。</p>\n\n<p>ただ、そのままSDカードをイメージファイル化しただけでは復元するSDカードのサイズが微妙に小さい場合などは、復元できなくなってしまいます。<br />\nそこで、バックアップしtイメージファイル内のパーティションサイズを縮小し、イメージファイルを小さくするスクリプトを用意しました。</p>\n\n<p>この作業はubuntu PC上で行います。</p>\n\n<p>この方法、およびスクリプトはRaspberryPi用SDカードでも使用できます。</p>\n\n<h1 id=\"sdカードのバックアップ\">SDカードのバックアップ</h1>\n<blockquote>\n  <p>[!WARNING]\nJetson用SDカードはFATパーティションが存在しないため、<br />\nWindowsPCではバックアップツールがSDカードを認識できず、バックアップできません。</p>\n</blockquote>\n\n<ul>\n  <li>ubuntu PCにバックアップしたいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>SDカードイメージをファイルにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">of</span><span class=\"o\">=</span>«出力ファイル» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n  <li>ubuntu PCからSDカードを抜去</li>\n</ul>\n\n<h1 id=\"ディスクイメージファイルの縮小\">ディスクイメージファイルの縮小</h1>\n\n<p>バックアップしたイメージファイルはSDカード容量と同じサイズになっています。<br />\nディスクイメージを縮小するために <a href=\"/memoBlog/misc/stock/diskimage_shrink.sh\">このスクリプト</a> をダウンロードして実行します。</p>\n\n<p>まず、必要なツールをインストールしておきます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install </span>kpartx\n</code></pre></div></div>\n\n<p>ダウンロードしたスクリプトを実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash diskimage_shrink.sh «入力イメージファイル» «出力イメージファイル» \n</code></pre></div></div>\n<p>出力イメージファイルが既に存在する場合は、上書きするか聞かれますので、yまたはnで指定してください。</p>\n\n<p>最初に入力イメージファイルから出力イメージファイルへコピーを行います。<br />\nコピーが終了すると、<code class=\"language-plaintext highlighter-rouge\">sudo</code>実行するためのパスワードを聞かれますので、入力してください。<br />\n縮小するパーティションサイズを計算した後、\n現在のパーティションサイズと縮小後のパーティションサイズが表示されます。<br />\n各サイズが正しければ、yを入力してパーティションサイズの修正を行いますが、\n一般的に危険な処理なので、「警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?」と再度確認されます。<br />\nyを入力して実行してください。</p>\n\n<p>その後、さらに ファイルサイズを切り詰めます。</p>\n\n<p>処理が終了すると、以下のメッセージが表示されますので、これにしたがって後の処理を行ってください。<br />\nRaspberryPi用SDカードはMBRパーティションなので<code class=\"language-plaintext highlighter-rouge\">gdisk</code>の処理は不要です。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n<p>実行例を以下に示します。<br />\n入力コマンドは<code class=\"language-plaintext highlighter-rouge\"># =========</code>で囲んであります。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># =========================================================================\n/work2$ bash diskimage_shrink.sh jetson_sd_20201022_2.img XXXX.img\n# =========================================================================\nCopy image file...\n>f+++++++++ jetson_sd_20201022_2.img\n 30,953,963,520 100%   26.97MB/s    0:18:14 (xfr#1, to-chk=0/1)\nGet partition info...\n対象パーティション番号 : 1\nImage file mapping...\n[sudo] <<ユーザ>> のパスワード: «パスワードを入力»\nadd map loop18p1 (253:0): 0 60313600 linear 7:18 28672\nadd map loop18p2 (253:1): 0 256 linear 7:18 2048\nadd map loop18p3 (253:2): 0 896 linear 7:18 4096\nadd map loop18p4 (253:3): 0 1152 linear 7:18 6144\nadd map loop18p5 (253:4): 0 128 linear 7:18 8192\nadd map loop18p6 (253:5): 0 384 linear 7:18 10240\nadd map loop18p7 (253:6): 0 768 linear 7:18 12288\nadd map loop18p8 (253:7): 0 128 linear 7:18 14336\nadd map loop18p9 (253:8): 0 896 linear 7:18 16384\nadd map loop18p10 (253:9): 0 896 linear 7:18 18432\nadd map loop18p11 (253:10): 0 1536 linear 7:18 20480\nadd map loop18p12 (253:11): 0 128 linear 7:18 22528\nadd map loop18p13 (253:12): 0 160 linear 7:18 24576\nadd map loop18p14 (253:13): 0 256 linear 7:18 26624\nLOOP device : /dev/mapper/loop18p1\n現在のパーティションサイズ   : 29450MiB\n縮小後のパーティションサイズ : 15637MiB\nパーティションを縮小しますか? [y/N]: y\nPartition shrinking...\ne2fsck 1.44.1 (24-Mar-2018)\nPass 1: Checking iノードs, blocks, and sizes\nPass 2: Checking ディレクトリ structure\nPass 3: Checking ディレクトリ connectivity\nPass 4: Checking reference counts\nPass 5: Checking グループ summary information\n/dev/mapper/loop18p1: 199065/1881264 files (0.2% non-contiguous), 3701166/7539200 blocks\nresize2fs 1.44.1 (24-Mar-2018)\nResizing the filesystem on /dev/mapper/loop18p1 to 4003167 (4k) blocks.\nBegin pass 2 (max = 55)\nRelocating blocks             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nBegin pass 3 (max = 231)\nScanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nThe filesystem on /dev/mapper/loop18p1 is now 4003167 (4k) blocks long.\n\n警告: 管理者権限がありません。パーミッションに注意してください。\n警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?\nはい(Y)/Yes/いいえ(N)/No? y                                               \nTruncate image file size...\nReleas image file mapping...\nloop deleted : /dev/loop18\n******** Done!! ********\n\n\n\n対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\n\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n\n\n\n# =========================================================================\n/work2$ gdisk XXXX.img \n# =========================================================================\nGPT fdisk (gdisk) version 1.0.3\n\nWarning! Disk size is smaller than the main header indicates! Loading\nsecondary header from the last sector of the disk! You should use 'v' to\nverify disk integrity, and perhaps options on the experts' menu to repair\nthe disk.\nCaution: invalid backup GPT header, but valid main header; regenerating\nbackup header from main header.\n\nWarning! Error 25 reading partition table for CRC check!\nWarning! One or more CRCs don't match. You should repair the disk!\n\nPartition table scan:\n  MBR: protective\n  BSD: not present\n  APM: not present\n  GPT: damaged\n\n****************************************************************************\nCaution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\nverification and recovery are STRONGLY recommended.\n****************************************************************************\n\nCommand (? for help): b\nEnter backup filename to save: backup.gpt\nThe operation has completed successfully.\n\nCommand (? for help): r\n\nRecovery/transformation command (? for help): d\n\nRecovery/transformation command (? for help): w\nCaution! Secondary header was placed beyond the disk's limits! Moving the\nheader, but other problems may occur!\n\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\nPARTITIONS!!\n\nDo you want to proceed? (Y/N): y\nOK; writing new GUID partition table (GPT) to XXXX.img.\nWarning: The kernel is still using the old partition table.\nThe new table will be used at the next reboot or after you\nrun partprobe(8) or kpartx(8)\nThe operation has completed successfully.\n\n\n\n# =========================================================================\n/work2$ sudo parted -m XXXX.img unit GiB print\n# =========================================================================\nBYT;\n/work2/XXXX.img:15.3GiB:file:512:512:gpt::;\n2:0.00GiB:0.00GiB:0.00GiB::TBC:;\n3:0.00GiB:0.00GiB:0.00GiB::RP1:;\n4:0.00GiB:0.00GiB:0.00GiB::EBT:;\n5:0.00GiB:0.00GiB:0.00GiB::WB0:;\n6:0.00GiB:0.01GiB:0.00GiB::BPF:;\n7:0.01GiB:0.01GiB:0.00GiB::BPF-DTB:;\n8:0.01GiB:0.01GiB:0.00GiB::FX:;\n9:0.01GiB:0.01GiB:0.00GiB::TOS:;\n10:0.01GiB:0.01GiB:0.00GiB::DTB:;\n11:0.01GiB:0.01GiB:0.00GiB::LNX:;\n12:0.01GiB:0.01GiB:0.00GiB::EKS:;\n13:0.01GiB:0.01GiB:0.00GiB::BMP:;\n14:0.01GiB:0.01GiB:0.00GiB::RP4:;\n1:0.01GiB:15.3GiB:15.3GiB:ext4:APP:;\n\n\n\n# =========================================================================\n/work2$ ls -la jetson_sd_20201022_2.img y.img \n# =========================================================================\n-rw-r--r-- 1 user  user 30953963520 10月 22 15:42 jetson_sd_20201022_2.img\n-rw-r--r-- 1 user  user 16422139904 10月 25 07:00 y.img\n</code></pre></div></div>\n\n<h1 id=\"新しいsdカードにバックアップを復元\">新しいSDカードにバックアップを復元</h1>\n\n<p>イメージファイルからSDカードへのコピーはWindowsマシンで行っても良いですが、ここではubuntu PCで行う方法について記載します。</p>\n\n<ul>\n  <li>ubuntu PCに新しいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>バックアップしたイメージファイルをSDカードにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«入力ファイル» <span class=\"nv\">of</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h1 id=\"新しいsdカードのパーティションを拡張\">新しいSDカードのパーティションを拡張</h1>\n\n<p>バックアップした際にパーティションサイズを縮小してあるため、そのままのSDカードではディスクの残り容量がわずかしかありません。<br />\nそこで、パーティションサイズを拡張して容量を増加させます。</p>\n\n<p>この作業はubuntu PCであらかじめ行うか、またはターゲットマシンでブートした後に行います。</p>\n\n<p>パーティション操作プログラム<code class=\"language-plaintext highlighter-rouge\">gparted</code>を使用します。<br />\nインストールされていない場合は、<code class=\"language-plaintext highlighter-rouge\">sudo apt install gparted</code>でインストールしておいてください。</p>\n\n<ul>\n  <li>gpartedを起動\n    <ul>\n      <li>Libparted Warning ダイアログで”Not all of the space available to ~”と出たらFixをクリック</li>\n      <li>Libparted Warning ダイアログで”The backup GPT table is corrupt, but the primary appears OK, so that will be used.”と出たらOKをクリック<br />\n以降も何度か出るが、以下の操作がすべて終わればbackup GPTが新たに作成されるので問題なし。<br />\n(これは、ディスクイメージを縮小したときにgdiskコマンドを実行しなかった場合に出ます)</li>\n      <li>Gparted→デバイスで<code class=\"language-plaintext highlighter-rouge\">«SDカードデバイス»</code>`を選択</li>\n      <li>図の<code class=\"language-plaintext highlighter-rouge\">«SDカードのパーティション»</code> を右クリック→「リサイズ/移動」をクリック\n        <ul>\n          <li>「新しいサイズ」の欄に上にある「最大サイズ」以下の値を入力</li>\n          <li>「リサイズ」をクリック</li>\n        </ul>\n      </li>\n      <li>「編集(E)」→「保留中の全ての操作を適用する(A)」をクリック\n        <ul>\n          <li>「本当に保留中の操作を適用してもよろしいですか?」と聞かれるので、「適用」をクリック</li>\n        </ul>\n      </li>\n      <li>処理が完了したら「閉じる」をクリック</li>\n    </ul>\n  </li>\n  <li>gpartedを終了</li>\n</ul>\n\n<p>ターゲットマシンで実行している場合は、そのまま使用できます。<br />\nubuntuマシンで実行した場合は、SDカードを取り外してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順はWiresharkで色々操作しないといけないのがめんどっちいので、スクリプトで自動化してみた。</p>\n\n<p>WiresharkのCUI版である、tsharkを使うと出来るらしいとの情報があったので、試してみたときのメモ。<br />\n今回はRaspberryPiだけ。Windowsは対応してません。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_1.html\">WiresharkでUSBパケットをキャプチャするときの注意事項</a> \nの準備は出来ているものとする。(Wiresharkは入ってなくても大丈夫。もちろん 入ってても良いよ。)</p>\n\n<p>tsharkは以下のコマンドイッパツでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tshark \n</code></pre></div></div>\n\n<p>で、あとは以下のスクリプトを\n<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの<code class=\"language-plaintext highlighter-rouge\">json_read.py</code>と同じディレクトリに作成し、実行するだけ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cap.sh\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/usr/bin/env bash</span>\n\n<span class=\"c\"># 第一引数でキャプチャ期間(sec)</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-z</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n  <span class=\"c\"># 引数なしだと2secに設定</span>\n  <span class=\"nv\">period</span><span class=\"o\">=</span>2\n<span class=\"k\">else</span>\n  <span class=\"c\"># 引数のチェック</span>\n  <span class=\"k\">if </span><span class=\"nb\">expr</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> : <span class=\"s1\">'[0-9]*'</span> <span class=\"o\">></span> /dev/null <span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># 数値</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nv\">$1</span> <span class=\"nt\">-lt</span> 1 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n      <span class=\"c\"># 1未満の数値</span>\n      <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n      <span class=\"nb\">exit\n    </span><span class=\"k\">else</span>\n      <span class=\"c\"># 1以上の数値(OK)</span>\n      <span class=\"nv\">period</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span>\n    <span class=\"k\">fi\n  else</span>\n    <span class=\"c\"># 数値でない</span>\n    <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n    <span class=\"nb\">exit\n  </span><span class=\"k\">fi\nfi</span>\n\n<span class=\"c\"># 現在時刻</span>\n<span class=\"nv\">cur_time</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">date</span> <span class=\"s2\">\"+%y%m%d_%H%M%S\"</span><span class=\"sb\">`</span>\n<span class=\"c\"># ファイル名生成</span>\n<span class=\"nv\">fname_base</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span>_<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># USBパケットキャプチャ</span>\n<span class=\"nb\">echo</span> <span class=\"s2\">\"Capture USB packets for </span><span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span><span class=\"s2\"> second from </span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\ntshark <span class=\"nt\">-i</span> usbmon1 <span class=\"nt\">-w</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-a</span> duration:<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># バス番号、デバイス番号の抽出</span>\n<span class=\"nv\">tmp_str</span><span class=\"o\">=</span><span class=\"sb\">`</span>lsusb | <span class=\"nb\">grep </span>WebCam<span class=\"sb\">`</span>\n<span class=\"nv\">bus_and_dev</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">tmp_str</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/Bus </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">Device </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">: ID.*/</span><span class=\"se\">\\1</span><span class=\"s2\"> </span><span class=\"se\">\\2</span><span class=\"s2\">/g\"</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">bus</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[0]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">dev</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[1]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">endpoint</span><span class=\"o\">=</span>1\n<span class=\"nv\">addr</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">bus</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">dev</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">endpoint</span><span class=\"k\">}</span>\n<span class=\"c\"># echo ${addr}</span>\n\n<span class=\"c\"># JSONファイルをエクスポート</span>\n<span class=\"nb\">echo </span>JSON data save to <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json...\ntshark <span class=\"nt\">-r</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-Y</span> <span class=\"s2\">\"usb.src==</span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">addr</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span> <span class=\"nt\">-T</span> json <span class=\"o\">></span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json\n\n<span class=\"c\"># JSON->CSV 変換</span>\npython json_read.py <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.csv\n\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。キャプチャ時間を秒で設定する。省略時は2秒。<br />\n出力されるファイル名は実行時の時刻で作成された文字列に各拡張子を付加したもの。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash cap.sh <span class=\"o\">[</span>キャプチャ時間<span class=\"o\">(</span>sec<span class=\"o\">)]</span>\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>なんかパラメータチェックが一番長いなぁ…😅</p>\n\n<p>33行目でパケットキャプチャ実行。</p>\n\n<p>35~41行目で対象USB機器のアドレス(バス番号、デバイス番号)を取得している。<br />\n36行目の<code class=\"language-plaintext highlighter-rouge\">grep</code>のパラメータは対象となるUSB機器に合わせて変更してちょ。<br />\nエンドポイント番号は対象機器によって固定なので、調べてね。\n分からなかったら、キャプチャしたデータをWiresharkで読み込んで確認してちょ。</p>\n\n<p>46行目でキャプチャしたファイルをJSONファイルにエクスポート。</p>\n\n<p>49行目でJSON→CSV変換。</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>これで<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順をスクリプトイッパツで完了できる。<br />\nま、特定環境でしか試してないから、どんな環境でも使えるとは限らないけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要--背景\">概要 & 背景</h1>\n\n<p>WiresharkでUSBパケットをキャプチャしたとき、実際に転送されてるデータの中身が見たいというニッチな要求があった。<br />\n(送ったデータがちゃんとUSBバスに出てるよね~、という確認がしたいなどの用途)</p>\n\n<p>Wiresharkのセーブデータ渡して「Wiresharkで見てね~」と言ったら「見方が分からん!」と…<br />\nで、Excelで一覧表にしてあげようと思い、エクスポートできんかな~と探してみるも、適当な機能が見つからず…<br />\nしかたなく、変換スクリプトかましてCSVに出力してExcelで読み込んでみよう、と試した時のメモ。</p>\n\n<p>今回はisochronous転送のデータの中身をダンプしている。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<ol>\n  <li>最初に解析したいパケットをキャプチャしておく(これをやらなきゃ始まらん…)。</li>\n  <li>必要なら表示フィルタで解析したいパケットだけ選び出す。</li>\n  <li>それらのパケットの一部だけ(最初の1秒だけ など)解析したい場合はそのパケット群を選択する。<br />\n   RaspberryPiでのやり方が分からん…Windows版なら他のアプリ同様、先頭で左クリック→最後でshift押しながら左クリックでOK。<br />\n   どうしても出来なかったら、RaspberryPiでキャプチャしたのを保存して、そのファイル(pcapngファイル)をWindowsにコピーして、\n   Windows上のWiresharkで読み込んでくだされ…😅</li>\n  <li>メニューの「ファイル」→「パケット解析をエクスポート」→「JSONとして」を選択</li>\n  <li>ファイル操作ダイアログが表示される\n    <ul>\n      <li>真ん中の「ファイル名」を入力</li>\n      <li>左下の「パケットの範囲」で\n        <ul>\n          <li>「表示されたパケット」を選択</li>\n          <li>「すべてのパケット」または「選択されたパケットのみ」を選択<br />\n (ここで「範囲」を選んで入力すれば選択しなくてもいいのかな?試してないので不明)</li>\n        </ul>\n      </li>\n      <li>「保存」をクリック</li>\n    </ul>\n  </li>\n</ol>\n\n<p>これでJSONファイルが保存される。</p>\n\n<h1 id=\"csvファイルに変換\">CSVファイルに変換</h1>\n\n<p>さぁ、このJSONファイルを読み込んで必要な部分を取り出すスクリプトを書けばOKじゃん?と思ったが、<br />\nそうは問屋がおろしてくれない😢<br />\nじつはWiresharkがエクスポートするJSONファイルはJSONファイルの文法からはずれた部分があるのだ…<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">/_source/layers/usb</code> の配下に複数のキー<code class=\"language-plaintext highlighter-rouge\">usb</code>があって、すべてのUSBデータを読み込めない。<br />\n(JSONの仕様では同一階層に複数の同じキーの存在を許さない。pythonのJSONモジュールでは複数あるデータのうち、一つだけが読み込まれる)<br />\nここが配列になってればOKだと気が付いて、チカラワザで変換する処理を追加してみた。</p>\n\n<p>で、pyshonで書いたスクリプトがこちら。<br />\nWindows/RaspberryPi どっちでも大丈夫と思うけど、Windowsでしか試してない。<br />\npythonは3.6以降が必要。3.7.7で動作確認。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  json_read.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"c1\"># テンポラリファイル名\n</span><span class=\"n\">tmp_file</span> <span class=\"o\">=</span> <span class=\"s\">'tmp.json'</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'==== USAGE ========================='</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'    </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> <JSON file> <CSV file>'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'===================================='</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">json_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">csv_file</span>  <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'Error: JSON file not exist!!'</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># \"usb\" キーが複数あるので、これをリストに変換したJSONファイルを作成する\n# かなり力技...\n</span><span class=\"k\">def</span> <span class=\"nf\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_json</span><span class=\"p\">,</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_tmp</span><span class=\"p\">:</span>\n        <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        \n        <span class=\"k\">while</span> <span class=\"n\">line</span><span class=\"p\">:</span>\n            <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"n\">line_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>           <span class=\"c1\"># 行番号\n</span>            <span class=\"c1\"># line = line.rstrip('\\r\\n')              # CRLFを削除\n</span>            <span class=\"k\">if</span> <span class=\"n\">find_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">'\"usb\": '</span><span class=\"p\">,</span> <span class=\"s\">''</span><span class=\"p\">)</span>      <span class=\"c1\"># key名称 \"usb\"を削除\n</span>                <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'START: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          \"usb_data\": [</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">+</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'{'</span><span class=\"p\">)</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">-</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'}'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">brackets</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'END: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          ]</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb.iso.numdesc\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">f_pos</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">tell</span><span class=\"p\">()</span>\n                    <span class=\"n\">next_line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>        <span class=\"c1\"># 次の行を読み込んで\n</span>                    <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"n\">f_pos</span><span class=\"p\">)</span>                   <span class=\"c1\"># ファイル位置を戻す\n</span>                    <span class=\"k\">if</span> <span class=\"n\">next_line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                    <span class=\"c1\"># 括弧の数\n</span>            <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">line</span><span class=\"p\">)</span>\n            <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># JSONファイルの修正\n</span><span class=\"n\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># パケット解析用変数\n</span><span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n<span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># JSONファイルの読み込み\n</span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n    <span class=\"n\">json_load</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(json_load)\n</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">csv_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_csv</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ヘッダの出力\n</span>    <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">'PacketNo,Date,Relative_time,Delta_time,Packet Size,Video Stream Size,Video Stream offset,Frame No,Stream No,Stream Data</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">json_data</span> <span class=\"ow\">in</span> <span class=\"n\">json_load</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フレームデータ\n</span>        <span class=\"n\">frame_data</span>          <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"frame\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_index</span>         <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.number\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_epoc</span>     <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_epoch\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_delta</span>    <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_delta_displayed\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_relative</span> <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_relative\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_dt</span>       <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">fromtimestamp</span><span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">frame_time_epoc</span><span class=\"p\">))</span>\n        <span class=\"n\">frame_time</span>          <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_time_dt</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_len</span>           <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.len\"</span><span class=\"p\">]</span>\n        <span class=\"c1\"># print(f'{frame_index},\"\\'{frame_time}\",{frame_len},', end='')\n</span>        <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_index</span><span class=\"si\">}</span><span class=\"s\">,\"</span><span class=\"se\">\\'</span><span class=\"si\">{</span><span class=\"n\">frame_time</span><span class=\"si\">}</span><span class=\"s\">\",</span><span class=\"si\">{</span><span class=\"n\">frame_time_relative</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_time_delta</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_len</span><span class=\"si\">}</span><span class=\"s\">,'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># USBデータ\n</span>        <span class=\"n\">usb_datas</span>  <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"usb\"</span><span class=\"p\">][</span><span class=\"s\">\"usb_data\"</span><span class=\"p\">]</span>\n        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"k\">for</span> <span class=\"n\">usb_data</span> <span class=\"ow\">in</span> <span class=\"n\">usb_datas</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f',,,,,', end='')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">',,,,,'</span><span class=\"p\">)</span>\n            <span class=\"n\">iso_len</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_len'</span><span class=\"p\">])</span>\n            <span class=\"n\">iso_off</span>  <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_off'</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">iso_len</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">\"usb.iso.data\"</span><span class=\"p\">]</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"s\">'0x'</span><span class=\"o\">+</span><span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">':'</span><span class=\"p\">,</span> <span class=\"s\">',0x'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">stream_number</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_number</span><span class=\"p\">)</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"s\">''</span>\n                \n                <span class=\"c1\"># print(f'{iso_len},{iso_off},{stream_number},{iso_data}')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_number_str</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">stream_number</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_data</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x02'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x03'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"n\">stream_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f'{iso_len},{iso_off},,')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,,</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># テンポラリファイルの削除\n</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。(RaspberryPiだと<code class=\"language-plaintext highlighter-rouge\">python3</code>にしてちょ)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python json_read.py «入力JSONファイル» «出力CSVファイル»\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>やっつけスクリプトなので、エラーチェックはかなりいい加減…</p>\n\n<p>関数<code class=\"language-plaintext highlighter-rouge\">modify_json()</code> が 前述のJSONファイルの不具合をチカラワザで修正する処理。</p>\n\n<p>テンポラリファイルとしてカレントディレクトリに<code class=\"language-plaintext highlighter-rouge\">tmp.json</code>を作成するので、注意。\nファイル名を変更したければ、8行目の<code class=\"language-plaintext highlighter-rouge\">tmp_file</code>を変更。<br />\nこのファイルはスクリプトの最後で削除している。<br />\n作成したテンポラリファイルを残しておきたければ最後の<code class=\"language-plaintext highlighter-rouge\">os.remove(tmp_file)</code>をコメントアウト。</p>\n\n<p>71~72行目で修正したJSONファイルを読み込み。</p>\n\n<p>75行目で書き出すCSVファイルをオープン。</p>\n\n<p>78行目~のforループで各JSONレコードを読み込みながら処理。</p>\n\n<p>82,85~86行目でframe.time_epochから時刻文字列を作成。<br />\n時刻は<code class=\"language-plaintext highlighter-rouge\">frame.time</code>を使用する手もあるが、ここはプラットフォームによって変化するらしいので同じ表示にするためにエポックタイムから生成している。<br />\nその他時刻関連データでは、<code class=\"language-plaintext highlighter-rouge\">frame.time_delta_displayed</code>で「前のパケットからの相対時間」、\n<code class=\"language-plaintext highlighter-rouge\">frame.time_relative</code>で「最初のパケットからの相対時間」を取得している。</p>\n\n<p>94行目~のforループがデータを取り出す部分。<br />\nisochronous転送のデータではないデータを取り出したい場合は、所望のデータのキーに置き換えて取り出せば良い。<br />\n<code class=\"language-plaintext highlighter-rouge\">frame_number</code>と<code class=\"language-plaintext highlighter-rouge\">stream_number</code>は私の解析用の補助データなので気にしないでネ。</p>\n\n<p>あとは、エクスポートされたJSONファイルとスクリプトを見比べてちゃぶだい。(^^ゞ</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>あとは、csvファイルをExcelで読み込むなり、pandasとかを使った別のスクリプトで加工するなりしてちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットをキャプチャするときの注意事項</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットをキャプチャするときの注意事項</h1>\n      <p>WiresharkでUSBパケットをキャプチャしようとしてちょっとハマったのでメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>WiresharkでUSBパケットをキャプチャするための準備(Linux版)<br />\nWindows版はちょっと異なると思うけど試してないので、ググってね😅。</p>\n\n<h1 id=\"wiresharkのインストール実行\">Wiresharkのインストール&実行</h1>\n\n<p>ふつーに<code class=\"language-plaintext highlighter-rouge\">apt install</code>するだけ。<br />\nWindows版と異なり、USBパケットキャプチャのために別途USBキャプチャプログラムをインストールする必要はない。<br />\nついでに<code class=\"language-plaintext highlighter-rouge\">sudo</code>しなくても実行できるように自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>グループを追加しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>wireshark\n<span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> wireshark \n</code></pre></div></div>\n\n<p>ここで一旦ログアウト&再ログイン or 再起動。</p>\n\n<p>このままだとUSBパケットキャプチャのためのプログラム(<code class=\"language-plaintext highlighter-rouge\">usbmon</code>)が動いてないので、動かす必要がある。<br />\n<strong>起動の度に</strong>ターミナルから以下のコマンドを実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbmon\n</code></pre></div></div>\n\n<p>Wiresharkの実行は、ターミナルから<code class=\"language-plaintext highlighter-rouge\">wireshark</code>を実行するか、メニューの「インターネット」→「Wireshark」を選択します。<br />\n(自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>`グループを追加してあるので、メニューからでも実行できます)</p>\n\n<p>起動の度に<code class=\"language-plaintext highlighter-rouge\">usbmon</code>を起動するのは面倒な場合は、以下の手順で自動化できます。</p>\n\n<ol>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/udev/rules.d/99-usbmon.rules</code>を以下の内容で作成\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>SUBSYSTEM==\"usbmon\", GROUP=\"wireshark\", MODE=\"640\"\n</code></pre></div>    </div>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/modules</code> に以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbmon\n</code></pre></div>    </div>\n  </li>\n  <li>リブート</li>\n</ol>\n\n<h1 id=\"wiresharkの使い方\">Wiresharkの使い方</h1>\n\n<p>あちこちのホームページに詳しく解説されているので、ぐぐってちょ(←なんて他力本願…😅)。<br />\nRaspberryPi4の場合、USBのインタフェースはusbmon1とusbmon2があるが、どっちをキャプチャするかは、接続した機器がUSB2.0かUSB3.0による。<br />\nたぶん、usbmon1がUSB2.0(外側/内側)、usbmon2がUSB3.0(内側のみ)だと思う。<br />\n<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)がusbmonYのYにあたるとだと推測。</p>\n\n<h1 id=\"wiresharkでパケット解析\">Wiresharkでパケット解析</h1>\n\n<p>USBのパケットの表示フィルタの書き方がネット上でもなかなか見つからなかったので、簡単なものだけメモ。</p>\n\n<h2 id=\"特定のusb機器のパケットだけ表示\">特定のUSB機器のパケットだけ表示</h2>\n\n<p>実際にはエンドポイントまで指定しているので、複数のエンドポイントを同時に表示したければ、OR(<code class=\"language-plaintext highlighter-rouge\">||</code>)で条件つなげてください。\n(<code class=\"language-plaintext highlighter-rouge\">1.5.*</code>みたいな書き方が出来るのかは不明 )</p>\n\n<p>この例の<code class=\"language-plaintext highlighter-rouge\">1.5.1</code>の<br />\n左の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)、 <br />\n中央の<code class=\"language-plaintext highlighter-rouge\">5</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のデバイス番号(<code class=\"language-plaintext highlighter-rouge\">Device YYY</code>の部分の数字)(<strong>挿抜の度に変わる</strong>)、 <br />\n右の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb -D /dev/bus/usb/XXX/YYY</code>(XXX、YYYは上記のバス番号、デバイス番号。0は省略不可) で表示される情報の <br />\n<code class=\"language-plaintext highlighter-rouge\">bEndpointAddress</code>で確認できるけど、これは機器内部で固定されてるはず。<br />\nと、難しく調べんでも、一度全部キャプチャしたものを表示して欲しいパケットを探してみてそこのアドレスを見れば分かる。</p>\n\n<p>USBホストの吐合は<code class=\"language-plaintext highlighter-rouge\">\"host\"</code>になる。</p>\n\n<h3 id=\"特定の機器の送信パケットだけ表示\">特定の機器の送信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\"\n</code></pre></div></div>\n<h3 id=\"特定の機器の受信パケットだけ表示\">特定の機器の受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n<h3 id=\"特定の機器の送受信パケットだけ表示\">特定の機器の送受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\" || usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのバグ??</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのバグ??</h1>\n      <p>pyenvのバグ??</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>バグかどうかわからんけど、思った通りの動作をしなかったので、メモ。</p>\n\n<h1 id=\"現象\">現象</h1>\n\n<p>pyenv を使う環境で、</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    python script.py <span class=\"nt\">--option</span> /path/to/file\n</code></pre></div></div>\n\n<p>と実行した場合、カレントディレクトリと<code class=\"language-plaintext highlighter-rouge\">/path/to/file</code>の存在するディレクトリで使用するpythonのバージョンが異なる場合、<br />\n(どちらか片方 or 両方で <code class=\"language-plaintext highlighter-rouge\">pyenv local</code>が指定されている)<br />\nカレントディレクトリではなく、/path/to/fileの存在するディレクトリで使用するpythonのバージョンが指定されてしまうらしい。</p>\n\n<p>問題が発生するシチュエーションは そんなに多くないと思うけど、 双方のバージョンでインストールしてるモジュールが違ったりすると困ったことになる。</p>\n\n<h1 id=\"原因\">原因</h1>\n\n<p>色々試行錯誤してみてわかったことを結論だけ。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> を見ると、<br />\nコマンドラインをサーチして最初に見つかったファイルの属する<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読むらしい。<br />\n(以下の部分)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    ・・・\n    <span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"k\">in</span>\n        <span class=\"nt\">-c</span><span class=\"k\">*</span> <span class=\"p\">|</span> <span class=\"nt\">--</span> <span class=\"p\">)</span> <span class=\"nb\">break</span> <span class=\"p\">;;</span>\n        <span class=\"k\">*</span>/<span class=\"k\">*</span> <span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-f</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n                </span><span class=\"nb\">export </span><span class=\"nv\">PYENV_FILE_ARG</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span>\n                <span class=\"nb\">break\n            </span><span class=\"k\">fi</span>\n            <span class=\"p\">;;</span>\n    <span class=\"k\">esac</span>\n    ・・・\n</code></pre></div></div>\n<p>本来ならスクリプトファイルのあるディレクトリの<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読んでほしいはずなのに…<br />\n<code class=\"language-plaintext highlighter-rouge\">*/* )</code> でなく、<code class=\"language-plaintext highlighter-rouge\">*)</code> じゃないのかな? なんか深い訳があるのかもしれんけど…</p>\n\n<h1 id=\"対処方法\">対処方法</h1>\n\n<p>で、以下のいずれかの方法で対処できる。</p>\n\n<ul>\n  <li>オプションの場合は、オプションとオプションパラメータの間をスペースでなく、<code class=\"language-plaintext highlighter-rouge\">=</code>にする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  python script.py <span class=\"nt\">--option</span><span class=\"o\">=</span>/path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>ただし、パーサが<code class=\"language-plaintext highlighter-rouge\">argparse.ArgumentParser</code>など、オプションとオプションパラメータの区切りに<code class=\"language-plaintext highlighter-rouge\">=</code>が使えるものでなければダメ。</li>\n      <li>しかも、そもそもオプションパラメータでなくコマンドパラメータだったらどうしようもない…orz…</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pyenv shell</code>で使用するバージョンを指定する\n    <ul>\n      <li>メンドクサイ…</li>\n    </ul>\n  </li>\n  <li>スクリプトファイルの前に<code class=\"language-plaintext highlighter-rouge\">--</code>を追加してやる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">--</span> script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> では<code class=\"language-plaintext highlighter-rouge\">-c</code>か<code class=\"language-plaintext highlighter-rouge\">--</code>が見つかったら<code class=\"language-plaintext highlighter-rouge\">PYENV_FILE_ARG</code>を探すループを抜けてくれるので。</li>\n      <li>ちょっとめんどくさい…</li>\n    </ul>\n  </li>\n  <li>スクリプト名の前に./を追加する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ./script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>これが一番シンプルかな?</li>\n      <li>てか、コレしかないっしょ。 常に<code class=\"language-plaintext highlighter-rouge\">./</code>付けるクセ付ければいいし。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"免責のツモリ\">免責(のツモリ)</h1>\n\n<p>あくまで自分のメモなんで、、、  ゴニョゴニョ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その6</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その6</h1>\n      <p>tensorflow lite で色々なSSDモデルを使う手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はソースが大半なので、githubにリポジトリ作った。<br />\n内容は各ディレクトリのREADME.mdを見てチョ。<br />\n<a href=\"https://github.com/ippei8jp/tflite_trial\">https://github.com/ippei8jp/tflite_trial</a></p>\n\n<p>順序は <code class=\"language-plaintext highlighter-rouge\">download_models</code> → <code class=\"language-plaintext highlighter-rouge\">mk_tflite_ssd</code> → <code class=\"language-plaintext highlighter-rouge\">images</code> → <code class=\"language-plaintext highlighter-rouge\">ssd</code> が良いと思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その5</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その5</h1>\n      <p>Tensorflow v1.15のインストールとソースからのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はUbuntuだけ。</p>\n\n<h1 id=\"tensorflow-115-のインストール\">Tensorflow 1.15 のインストール</h1>\n\n<p>Tensorflow1系でないと動かない環境とかサンプルとかあるので、<br />\nTensorflow v1.15をインストールする。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_1.15.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_1.15.0\n<span class=\"nb\">cd</span> /work/tf_1.15.0\npyenv <span class=\"nb\">local </span>tf_1.15.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"tensorflow-115-ライブラリのインストール\">Tensorflow 1.15 ライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>1.15\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nGPU使わないので-cpu付きパッケージを選択する</p>\n</blockquote>\n\n<h1 id=\"tensorflow-115-のbuild\">Tensorflow 1.15 のbuild</h1>\n\n<p>Tensorflowのpythonライブラリは<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできるが、\nソースからbuildしないと使えないツールもあるのでbuild環境を整える。</p>\n\n<p>参考: <a href=\"https://www.tensorflow.org/install/source?hl=ja\">ソースからのビルド | Tensorflow</a></p>\n\n<h2 id=\"bazelのインストール\">Bazelのインストール</h2>\n\n<p>Tensorflow をソースからbuildするには<code class=\"language-plaintext highlighter-rouge\">bazel</code>が必要なので、インストールしておく。</p>\n<blockquote>\n  <p>[!NOTE]\nBazelはVer.0.26.1 以下 を使用しないといけない<br />\nVer. 0.26.1はaptでインストールできない</p>\n</blockquote>\n\n<p>参考: <a href=\"https://docs.bazel.build/versions/0.26.0/install-ubuntu.html\">Installing Bazel on Ubuntu</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/bazelbuild/bazel/releases/download/0.26.1/bazel-0.26.1-installer-linux-x86_64.sh\n<span class=\"nb\">chmod</span> +x bazel-0.26.1-installer-linux-x86_64.sh\n./bazel-0.26.1-installer-linux-x86_64.sh <span class=\"nt\">--user</span>\n</code></pre></div></div>\n\n<p>実行ファイルは、<code class=\"language-plaintext highlighter-rouge\">~/bin/bazel</code> になるので、pathが~/binに通ってない場合は、一旦 ログアウトして 再ログイン\n(pathが通ってない場合、configureでエラーになる)</p>\n\n<h2 id=\"必要なpipパッケージのインストール\">必要なpipパッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>six numpy wheel mock <span class=\"s1\">'future>=0.17.1'</span>\npip <span class=\"nb\">install </span>keras_applications <span class=\"nt\">--no-deps</span>\npip <span class=\"nb\">install </span>keras_preprocessing <span class=\"nt\">--no-deps</span>\n</code></pre></div></div>\n\n<h2 id=\"tennsorflowのソースを取得\">tennsorflowのソースを取得</h2>\n\n<p>githubからcloneして V1.15.3 をチェックアウトしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/\ngit clone https://github.com/tensorflow/tensorflow.git\n<span class=\"nb\">cd </span>tensorflow\ngit checkout <span class=\"nt\">-b</span> v1.15.3 refs/tags/v1.15.3\n</code></pre></div></div>\n\n<h1 id=\"buildの設定\">buildの設定</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\n./configure\n<span class=\"c\"># いくつか質問されるので、すべてデフォルト(リターン)を入力</span>\n</code></pre></div></div>\n\n<h1 id=\"buildの実行\">buildの実行</h1>\n<h2 id=\"実行のひな形\">実行のひな形</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build //《対象ディレクトリ》:《ターゲット》\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n※ 対象ディレクトリはカレントディレクトリからの相対パス<br />\n※ ターゲットは対象ディレクトリのBUILDファイルで確認</p>\n</blockquote>\n\n<h2 id=\"例えばこんな感じ\">例えばこんな感じ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel build //tensorflow/lite/toco:toco\nbazel build //tensorflow/python/tools:freeze_graph\nbazel build //tensorflow/tools/graph_transforms:summarize_graph\nbazel build //tensorflow/tools/graph_transforms:transform_graph\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRAMは4GB以上必要かな?<br />\nオプション<code class=\"language-plaintext highlighter-rouge\">--local_ram_resources=2048</code>を指定すると使用するRAMを2GBに限定できる(指定する数値はMB単位)。<br />\n使用するPCのスペックによってかかる時間はマチマチ。<br />\nNativeなUbuntuで4コア8スレッドでも3~4時間程度かかる。<br />\nVirtualboxで1コア使用だと24時間とかかかることも。</p>\n</blockquote>\n\n<h2 id=\"buildしたファイルの実行\">buildしたファイルの実行</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">bazel run</code> で実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nオプションをbazelではなく実行するコマンドに渡すため、<code class=\"language-plaintext highlighter-rouge\">--</code> を入れる必要がある。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel run //tensorflow/lite/toco:toco <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:summarize_graph <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:transform_graph <span class=\"nt\">--</span> «オプション»\n</code></pre></div></div>\n\n<p>絶対パスで実行するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph «オプション»\n</code></pre></div></div>\n\n<p>パスが長いので、以下を設定しておくと便利。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">alias            </span><span class=\"nv\">toco</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">summarize_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">transform_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph'</span>\n</code></pre></div></div>\n\n<h2 id=\"おまけ\">おまけ</h2>\n\n<p>フツーはこっちがメインだが…(^^ゞ<br />\npipでインストールすれば必要ないが、Tensorflowのpipパッケージを作成するにはこちら。<br />\n(オプション変更したいときとか)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build <span class=\"nt\">--config</span><span class=\"o\">=</span>v1 //tensorflow/tools/pip_package:build_pip_package\n./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg\npip <span class=\"nb\">install</span> /tmp/tensorflow_pkg/tensorflow-1.15.3-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その4</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その4</h1>\n      <p>tensorflowのモデルファイル(*.pbや*.tflite)の可視化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>tensorflowのモデルファイル( <code class=\"language-plaintext highlighter-rouge\">*.pb</code> や <code class=\"language-plaintext highlighter-rouge\">*.tflite</code> )を可視化する方法について。<br />\n<code class=\"language-plaintext highlighter-rouge\">tensorboard</code> を使う方法などもあるが、最もお手軽と思われる <code class=\"language-plaintext highlighter-rouge\">netron</code> を使用する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれやらなくても、<a href=\"https://lutzroeder.github.io/netron/\">https://lutzroeder.github.io/netron/</a> にアクセスすれば使える。</p>\n</blockquote>\n\n<h1 id=\"netron-の-インストール\">netron の インストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code>をインストールする。<br />\n<code class=\"language-plaintext highlighter-rouge\">netron</code> はtensorflowのバージョンに依存しない(そもそもtensorflow自体に依存してない)のでTensorflow1系、Tenorflow2系 どちらの環境にインストールしてもよい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>netron\n</code></pre></div></div>\n\n<h1 id=\"netron-の-実行\">netron の 実行</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code> を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>netron <span class=\"nt\">--host</span> 0.0.0.0 <span class=\"o\">[</span><span class=\"nt\">--port</span> xxxx]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--host</code> オプションを指定しないとlocalhostからしか接続できないので、他のマシンから接続するときは指定する。<br />\n<code class=\"language-plaintext highlighter-rouge\">--port</code> オプションのデフォルトは8080なので、変更したいときは指定する。</p>\n\n<h1 id=\"モデルファイルの表示\">モデルファイルの表示</h1>\n\n<p>ブラウザ(Winマシンからで可)で実行したマシンのポート8008(またはオプションで指定したxxxx)に接続。<br />\n例:<code class=\"language-plaintext highlighter-rouge\">http://ncc-1701u.local:8080/</code></p>\n\n<p>表示された画面でOpen Model…をクリックして表示するモデルファイルを選ぶ。<br />\nしばらく待つと表示される。<br />\nモデルファイルはブラウザからアップロードするので、ブラウザから参照できる場所になければならない(サーバ側にあってもダメ)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">*.pb</code> ファイルが大きいとうまく表示できないみたい。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その3</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その3</h1>\n      <p>Tensorflow 2.2.0をインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Edge-TPUを直接操作するわけではないが、Tensorflowで作成されたモデルファイルをtflite用に変換する準備として<br />\ntensorflowをインストールする。<br />\nここではVersion 2.2.0を使用する。</p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<p>coral環境に追加インストールでも良いが、今回は別の環境を用意する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_2.2.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_2.2.0\n<span class=\"nb\">cd</span> /work/tf_2.2.0\npyenv <span class=\"nb\">local </span>tf_2.2.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"tensorflow-220-のインストール\">tensorflow 2.2.0 のインストール</h1>\n\n<p>インストールするパッケージはGPUを使わないので-cpu付きパッケージを選択する。<br />\nTensorflowはバージョンによって機能差が激しいので、インストールするバージョンを指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>2.2.0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その2</h1>\n      <p>Google Coral USB Accelerator で SSD(Single Shot MultiBox Detector)を実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n一部を除き、基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<h1 id=\"tflite-の-モデルファイルをedgetpu使用モデルに変換する方法\">tflite の モデルファイルをEdgeTPU使用モデルに変換する方法</h1>\n<p>通常のtfliteのモデルファイルはCPUのみ(またはCPU+GPU)を使用するように構成されていて、\nそのまま実行してもEdge-TPUは使用されない。<br />\nそこで、Edge-TPU使用モデルに変換するため、edgetpu_compilerを使用する必要がある。<br />\n(ただし、Ubuntuのみ。RasPi不可。)</p>\n\n<h2 id=\"edgetpu_compiler-のインストール\">edgetpu_compiler のインストール</h2>\n\n<p>CPU使用モデルからEdge-TPU使用モデルに変換するツール<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code>をインストールする。<br />\naptリポジトリの登録はTPUライブラリインストール時に行っているので不要(以下ではコメントアウトしてある)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -</span>\n<span class=\"c\"># echo \"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list</span>\n<span class=\"c\"># sudo apt update</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>edgetpu-compiler\n</code></pre></div></div>\n\n<h2 id=\"使用方法\">使用方法</h2>\n<p>基本的に以下。<br />\ntfliteファイルを喰わせるとファイル名に<code class=\"language-plaintext highlighter-rouge\">_edgetpu</code>を付加したファイルが作成される。<br />\nこれがEdge-TPU使用するモデルファイル。<br />\n詳細は<a href=\"https://coral.ai/docs/edgetpu/compiler/\">Edge TPU Compiler</a> を参照。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>edgetpu_compiler [options] model...\n</code></pre></div></div>\n\n<h1 id=\"事前準備\">事前準備</h1>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n\n<p>openCVをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"ssdを実行してみる\">SSDを実行してみる</h1>\n\n<h2 id=\"作業用ディレクトリの作成移動\">作業用ディレクトリの作成&移動</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral/ssd/\n<span class=\"nb\">cd</span> /work/coral/ssd/\n</code></pre></div></div>\n\n<h2 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h2>\n\n<p>用意されているSSDのモデルをダウンロードし、Edge-TPU使用モデルを作成する。<br />\n実行が終了すると、<code class=\"language-plaintext highlighter-rouge\">models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite</code> ができる。</p>\n\n<ul>\n  <li>ダウンロード元: <a href=\"https://www.tensorflow.org/lite/models/object_detection/overview\">Object detection</a>\nの 「Get Started」の「Download starter model and labels」</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl <span class=\"nt\">-O</span> https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip\nunzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip \n<span class=\"nb\">mv </span>detect.tflite coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># リネームしなくてもいいけど、後でわからなくならないようにリネームしておく</span>\n<span class=\"nb\">mv </span>labelmap.txt coco_ssd_mobilenet_v1_1.0_quant.labels   <span class=\"c\"># 同上</span>\nedgetpu_compiler coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># EdgeTPU使用モデルに変換</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"テスト用画像の準備\">テスト用画像の準備</h2>\n\n<p>適当な画像を<code class=\"language-plaintext highlighter-rouge\">image</code>ディレクトリに用意しておく。<br />\n使用できるファイル形式は<code class=\"language-plaintext highlighter-rouge\">jpg</code>と<code class=\"language-plaintext highlighter-rouge\">mp4</code></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>images\n<span class=\"nb\">cd </span>images/\n<span class=\"c\"># 適当な画像ファイルをダウンロードする</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"ssdのプログラムソース\">SSDのプログラムソース</h2>\n\n<p>以下の内容を<code class=\"language-plaintext highlighter-rouge\">object_detection_demo_ssd.py</code>として保存しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">tflite_runtime.interpreter</span> <span class=\"k\">as</span> <span class=\"n\">tflite</span>\n\n<span class=\"c1\"># shared library\n</span><span class=\"n\">EDGETPU_SHARED_LIB</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n  <span class=\"s\">'Linux'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.so.1'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Darwin'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.1.dylib'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Windows'</span><span class=\"p\">:</span> <span class=\"s\">'edgetpu.dll'</span>\n<span class=\"p\">}[</span><span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">system</span><span class=\"p\">()]</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># interpreter の生成\n</span><span class=\"k\">def</span> <span class=\"nf\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">):</span>\n    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"o\">=</span><span class=\"n\">model_file</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span>\n                <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">model_file</span><span class=\"p\">,</span>\n                <span class=\"n\">experimental_delegates</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n                    <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">load_delegate</span><span class=\"p\">(</span><span class=\"n\">EDGETPU_SHARED_LIB</span><span class=\"p\">)</span>\n                <span class=\"p\">])</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    \n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">output_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_output_details</span><span class=\"p\">()</span>\n    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n\n    <span class=\"n\">tflite_results1</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Locations (Top, Left, Bottom, Right)\n</span>    <span class=\"n\">tflite_results2</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Classes (0=Person)\n</span>    <span class=\"n\">tflite_results3</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Scores\n</span>    <span class=\"n\">tflite_results4</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Number of detections\n</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">tflite_results4</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])):</span>\n        <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        \n        <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>        <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n\n        <span class=\"n\">prob</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results3</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">prob</span> <span class=\"o\">>=</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'Class=</span><span class=\"si\">{</span><span class=\"n\">class_name</span><span class=\"si\">:</span><span class=\"mi\">15</span><span class=\"si\">}</span><span class=\"s\">    Probability=</span><span class=\"si\">{</span><span class=\"n\">prob</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    Location=(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)-(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n            <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span>    <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span>   <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span>  <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 表示色\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 対象物の枠とラベルの描画\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"n\">bottom</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">20</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"o\">+</span><span class=\"mi\">160</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"s\">\"{} ({:.3f})\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">class_name</span><span class=\"p\">,</span> <span class=\"n\">prob</span><span class=\"p\">),</span>\n                        <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># interpreterの構築\n</span>    <span class=\"n\">interpreter</span> <span class=\"o\">=</span> <span class=\"n\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">allocate_tensors</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">input_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()</span>\n    \n    <span class=\"c1\"># 入力データ\n</span>    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">org_frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>                 <span class=\"c1\"># オリジナルのフレームレート\n</span>    <span class=\"n\">org_frame_time</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span> <span class=\"o\">/</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>                <span class=\"c1\"># オリジナルのフレーム時間\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">org_frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルの読み込み\n</span>        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルがない場合\n</span>        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># フレーム数\n</span>    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 実行時間測定用変数の初期化\n</span>    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n    <span class=\"c1\"># フレーム測定用タイマ\n</span>    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># モデルの入力サイズ\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># 画像の前処理 =============================================================================\n</span>        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                          <span class=\"c1\"># 前処理開始時刻\n</span>        \n        <span class=\"c1\"># 画像の読み込み\n</span>        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレームを作成\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># モデル入力用にリサイズ\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>   <span class=\"c1\"># input size of coco ssd mobilenet?\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">]]</span>                          <span class=\"c1\"># BGR -> RGB\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">in_frame</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>                 <span class=\"c1\"># 3D -> 4D\n</span>        \n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>     <span class=\"c1\"># 前処理にかかった時間\n</span>        \n        <span class=\"c1\"># 推論実行 =============================================================================\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"c1\"># 推論本体\n</span>        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">set_tensor</span><span class=\"p\">(</span><span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">],</span> <span class=\"n\">in_frame</span><span class=\"p\">)</span>\n        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">invoke</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>                          <span class=\"c1\"># 推論処理にかかった時間\n</span>        \n        <span class=\"c1\"># 検出結果の解析 =============================================================================\n</span>        <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                               <span class=\"c1\"># 解析処理開始時刻\n</span>        <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n        <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>                    <span class=\"c1\"># 解析処理にかかった時間\n</span>        \n        <span class=\"c1\"># 結果の表示 =============================================================================\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 表示処理開始時刻\n</span>        \n        <span class=\"c1\"># 測定データの表示\n</span>        <span class=\"n\">frame_number_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'frame_number   : </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span>\n        <span class=\"k\">if</span> <span class=\"n\">frame_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span>  <span class=\"s\">'Frame time     : ---'</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Frame time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms    </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> fps'</span>\n        <span class=\"n\">inf_time_message</span>        <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Inference time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">render_time_message</span>     <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Rendering time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">parsing_time_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'parse time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        \n        <span class=\"c1\"># 結果の書き込み\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_number_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>     <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>   <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像の保存\n</span>        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>                 <span class=\"c1\"># 表示処理にかかった時間\n</span>        \n        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"c1\"># フレーム処理終了 =============================================================================\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_key_code</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"make_interpretermodel_file\">make_interpreter(model_file)</h3>\n\n<p>interpreter(認識エンジン)を構築する処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>モデルファイル内に<code class=\"language-plaintext highlighter-rouge\">\"edgetpu-custom-op\"</code>という文字列が含まれていたらTPU使用モデルと判定してTPU使用のための共有ライブラリをダウンロードして初期化する。<br />\nそうでなければCPUのみ使用モデルなので、 共有ライブラリなしで初期化する。</p>\n\n<p>もっと単純にモデルファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>が含まれていたらTPU使用モデルと判定しても良いかもしれない(<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code> は出力ファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>を付加するので)。</p>\n\n<h3 id=\"parse_resultinterpreter-frame-labels_map-args\">parse_result(interpreter, frame, labels_map, args)</h3>\n\n<p>認識結果の解析と結果の表示(検出枠とラベルの描画)</p>\n\n<p>認識結果から検出した座標、クラスID、スコアを取得し、出力画像に描画している。</p>\n\n<p>出力データの構成は<a href=\"https://www.tensorflow.org/lite/models/object_detection/overview#output\">ここ</a>を参照。</p>\n\n<p>どうやらこのモデルは検出個数が10個に設定されているようだ。</p>\n\n<h3 id=\"main\">main()</h3>\n\n<p>メインルーチン</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>タイミング調整部分は、認識処理が速かった場合に結果表示画像の表示時間を実際の入力画像の表示時間に合わせるため、ちょっと小細工を入れてある。</p>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--help</span>\nusage: object_detection_demo_ssd.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT <span class=\"o\">[</span><span class=\"nt\">-l</span> LABELS]\n                                    <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> LABELS, <span class=\"nt\">--labels</span> LABELS\n                        Optional. Labels mapping file\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合edge-tpu使用\">静止画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合edge-tpu使用\">動画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n再生が終了するか、画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n<h2 id=\"静止画の場合cpuのみ\">静止画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合cpuのみ\">動画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その1</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その1</h1>\n      <p>Google Coral USB Acceleratorのインストールメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<p>参考サイト:\n<a href=\"https://qiita.com/rhene/items/7b34f60b73645d430789\">RaspberryPi 4でCoral USB TPU Accelerator(EdgeTPU)をとりあえず使う</a></p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<h2 id=\"edgetpu用ライブラリのインストール\">EdgeTPU用ライブラリのインストール</h2>\n\n<p>下記コマンドを実行して、EdgeTPU用ライブラリ(ドライバ類)をインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/coral-edgetpu.list\ncurl https://packages.cloud.google.com/apt/doc/apt-key.gpg | <span class=\"nb\">sudo </span>apt-key add -\n\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># 通常版をインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libedgetpu1-std\n<span class=\"c\"># または、最大クロック版</span>\n<span class=\"c\"># sudo apt install libedgetpu1-max</span>\n</code></pre></div></div>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 coral\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral\n<span class=\"nb\">cd</span> /work/coral\npyenv <span class=\"nb\">local </span>coral \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<p>numpyのinstallで失敗するので、以下を実行しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n</code></pre></div></div>\n\n<h2 id=\"tfliteモジュールのインストール\">TFLiteモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install  </span>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nどれをインストールするかは<a href=\"https://www.tensorflow.org/lite/guide/python\">Python quickstart</a>で確認<br />\n========= 例えば、ubuntu/raspbianのときはpythonのバージョンに応じて以下のどれかを指定 ==============</p>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (x86-64)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl</td>\n      </tr>\n    </tbody>\n  </table>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (ARM 32)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl</td>\n      </tr>\n    </tbody>\n  </table>\n</blockquote>\n\n<h2 id=\"coral-usb-acceleratorの接続と確認\">Coral USB Acceleratorの接続と確認</h2>\n\n<p>USBポートに Coral USB Accelerator を接続する</p>\n\n<p>認識されたことを確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下の表示があったら正常に認識されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>«省略»\nBus XXX Device YYY: ID 1a6e:089a Global Unichip Corp. \n«省略»\n</code></pre></div></div>\n\n<h1 id=\"動作確認サンプルプログラム\">動作確認(サンプルプログラム)</h1>\n\n<h2 id=\"サンプルソースのインストール\">サンプルソースのインストール</h2>\n\n<p>Githubからソースをダウンロードする</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/\ngit<span class=\"k\">**</span> clone https://github.com/google-coral/tflite.git\n</code></pre></div></div>\n\n<h2 id=\"サンプルプログラムの実行その1-classification\">サンプルプログラムの実行(その1) classification</h2>\n\n<h3 id=\"プログラムディレクトリへの移動\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/classification/\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh \n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py \n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n<p>結果の例は以下。<br />\n結果は「Ara macao(コンゴウインコ)」と表示されている。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference on Edge TPU is slow because it includes loading the model into Edge TPU memory.\n12.4ms\n4.2ms\n4.1ms\n4.2ms\n4.2ms\n-------RESULTS--------\nAra macao (Scarlet Macaw): 0.77734\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n\n<p><a id=\"CPUonlydiff\"> </a></p>\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合もCoral USB Acceleratorを接続しておかないとエラーになる。<br />\n接続しなくても実行できるようにするには以下のパッチを適用し、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">-cpu</code>オプションを指定する。</p>\n\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/python/examples/classification/classify_image.py b/python/examples/classification/\n</span><span class=\"gi\">> classify_image.py\n</span><span class=\"gh\">index 75f1d76..44fb798 100644\n</span><span class=\"gd\">--- a/python/examples/classification/classify_image.py\n</span><span class=\"gi\">+++ b/python/examples/classification/classify_image.py\n</span><span class=\"p\">@@ -12,7 +12,7 @@</span>\n<span class=\"err\">#</span> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n # See the License for the specific language governing permissions and\n # limitations under the License.\n<span class=\"gd\">-r\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span><span class=\"gi\">+\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span>\n    To run this code, you must attach an Edge TPU attached to the host and\n    install the Edge TPU runtime (`libedgetpu.so`) and `tflite_runtime`. For\n<span class=\"p\">@@ -64,9 +64,12 @@</span> def load_labels(path, encoding='utf-8'):\n       return {index: line.strip() for index, line in enumerate(lines)}\n\n\n<span class=\"gd\">-def make_interpreter(model_file):\n</span><span class=\"gi\">+def make_interpreter(model_file, cpu=False):\n</span>   model_file, *device = model_file.split('@')\n<span class=\"gd\">-  return tflite.Interpreter(\n</span><span class=\"gi\">+  if cpu :\n+    return tflite.Interpreter(model_path=model_file)\n+  else :\n+    return tflite.Interpreter(\n</span>       model_path=model_file,\n       experimental_delegates=[\n           tflite.load_delegate(EDGETPU_SHARED_LIB,\n<span class=\"p\">@@ -92,11 +95,19 @@</span> def main():\n   parser.add_argument(\n       '-c', '--count', type=int, default=5,\n       help='Number of times to run inference')\n<span class=\"gi\">+  parser.add_argument(\n+      '--cpu', action='store_true',\n+      help='use cpu only(default:use with TPU)')\n</span>   args = parser.parse_args()\n\n+  if args.cpu :\n<span class=\"gi\">+    print('**** USE CPU ONLY!! ****')\n+  else :\n+    print('**** USE WITH TPU ****')\n+\n</span>   labels = load_labels(args.labels) if args.labels else {}\n\n-  interpreter = make_interpreter(args.model)\n<span class=\"gi\">+  interpreter = make_interpreter(args.model, args.cpu)\n</span>   interpreter.allocate_tensors()\n\n   size = classify.input_size(interpreter)\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"サンプルプログラムの実行その2-detection\">サンプルプログラムの実行(その2) detection</h2>\n\n<h3 id=\"プログラムディレクトリへの移動-1\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/detection\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール-1\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh\n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行-1\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<p>結果の例は以下。<br />\n以下の表示と同時に認識結果の画像が別ウィンドウで表示される。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference is slow because it includes loading the model into Edge TPU memory.\n27.90 ms\n11.59 ms\n11.36 ms\n11.89 ms\n11.10 ms\n-------RESULTS--------\ntie\n  id:     31\n  score:  0.83984375\n  bbox:   BBox(xmin=226, ymin=417, xmax=290, ymax=539)\nperson\n  id:     0\n  score:  0.83984375\n  bbox:   BBox(xmin=2, ymin=5, xmax=507, ymax=590)\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行-1\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションを指定すると、結果画像を保存するとともに、表示を行う。<br />\n指定しなければ認識だけ行う(結果の画像表示もしない)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションによる出力ファイルの形式は指定した拡張子で決定される。jpgやbmpなど。<br />\nrawデータで出力した場合(拡張子rgb)は、以下のコマンドでjpgやbmpに変換できる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.jpg\n</code></pre></div>  </div>\n\n  <p>または</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.bmp\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合でCoral USB Acceleratorを接続していなくてエラーになる場合は<br />\n<a href=\"#CPUonlydiff\">こちら</a>を参照</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD(その2)</h1>\n      <p>openVINOのSSDのサンプルプログラムのモデルデータを変更してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> でSSDを動かしてみたが、\n検出できるオブジェクトの種類が少なくてちょっと寂しかったので、別のモデルがないか探してみた。</p>\n\n<p>で、調べてみると、openCVのopen_model_zoo以外にもTensorFlowの公式モデルなどをダウンロードして変換するスクリプトが用意されていた。<br />\nで、以下手順。</p>\n\n<h1 id=\"モデルのダウンロードモデルのirへの変換\">モデルのダウンロード&モデルのIRへの変換</h1>\n\n<h4 id=\"テンポラリディレクトリの作成移動\">テンポラリディレクトリの作成&移動</h4>\n\n<p>とりあえず作業用のディレクトリを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/temp\n<span class=\"nb\">cd</span> /work/temp\n</code></pre></div></div>\n\n<h3 id=\"使用できるモデルの一覧を表示\">使用できるモデルの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py  <span class=\"nt\">--print_all</span>\n</code></pre></div></div>\n\n<p>ちなみに、モデル毎の設定は以下にあるので、雰囲気で解読してちょ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>${INTEL_OPENVINO_DIR}/deployment_tools/open_model_zoo/models/public/${modelname}/model.yml\n</code></pre></div></div>\n\n<h3 id=\"このへんのモデルを使ってみる\">このへんのモデルを使ってみる</h3>\n\n<p>なんとなく、mobilenetが小さそうなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssd_mobilenet_v2_coco\n</code></pre></div></div>\n\n<p>または</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssdlite_mobilenet_v2\n</code></pre></div></div>\n\n<p>ssdlightの方がモデルデータが小さい。その分精度は落ちるらしい。<br />\n検出できるオブジェクトの種類は同じ。<br />\n出力は90種類だが、途中欠番があるみたいなので実質80種類くらい。<br />\n変わったところでは「テディベア」なんてのもある。試してみたらちゃんと認識した(あたりまえか…)。<br />\ncocoデータセット<a href=\"http://cocodataset.org/#home\">http://cocodataset.org/#home</a>なので、有名どころですね。<br />\nあ、「80 object categories 91 stuff categories」ってちゃんと書いてある…</p>\n\n<h3 id=\"ダウンロード\">ダウンロード</h3>\n\n<p>まずはダウンロード。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/</code>にモデルがダウンロードされる。</p>\n\n<h3 id=\"モデルデータをirファイルへ変換\">モデルデータをIRファイルへ変換</h3>\n\n<p>もとのモデルデータはTensorFlowで使用するProtocolBuffer形式なので、openVINOで使用できるIR形式に変換する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/converter.py <span class=\"nt\">--precisions</span> FP16 <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/FP16/</code>にIRモデルが出来る。</p>\n\n<h3 id=\"そのままの場所で使用しても良いが他のモデルとまとめておく\">そのままの場所で使用しても良いが、他のモデルとまとめておく</h3>\n\n<p>モデルがあちこちにあると管理しずらくなるので、他のモデルと同じところに置いておく。<br />\n必要なのはxmlとbin。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>public/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>/FP16/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>.<span class=\"o\">{</span>xml,bin<span class=\"o\">}</span> /work/NCS2/openvino_models/FP16/\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">.{xml,bin}</code>のところにスペースなどを入れてしまうとうまく動かないので注意。<br />\n結構「あとで読みやすいように」と入れてしまいがち(特にスクリプト書くとき)なので注意。</p>\n\n<h3 id=\"ラベルファイルの作成\">ラベルファイルの作成</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/work/NCS2/openvino_models/FP16/${modelname}.labels</code>にラベルデータを作成しておく。<br />\nなくても可。<br />\n作り方は後述。</p>\n\n<h3 id=\"実行\">実行</h3>\n\n<p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> の「デモ実行」と同じ手順で\nモデルファイルを差し替えて(<code class=\"language-plaintext highlighter-rouge\">--model</code>オプション)実行すれば良い。</p>\n\n<h1 id=\"ラベルファイルの作成方法\">ラベルファイルの作成方法</h1>\n\n<p>ラベルデータはモデルデータには含まれていないようなので、作成する方法を検討してみた。</p>\n\n<h3 id=\"tensorflowのmodelsモジュールをダウンロード\">tensorflowのmodelsモジュールをダウンロード</h3>\n\n<p>まず、モデルデータの作成情報のあるモジュールをダウンロードしておく。<br />\ngitでなくてもzipをダウンロードして展開しておいても可(ちょっとデカいので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git models_tf\n</code></pre></div></div>\n\n<h3 id=\"作業ディレクトリに移動\">作業ディレクトリに移動</h3>\n\n<p>あとでpythonプログラムを作成するときに色々面倒がないので、作業ディレクトリはココで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models_tf/research\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">object_detection/samples/configs</code>から対応するconfigファイルを探して(なんとなく雰囲気で探せ!)表示<br />\n<code class=\"language-plaintext highlighter-rouge\">label_map_path</code>に記載されたファイルがlabel_mapファイル<br />\nこのとき、PATH_TO_BE_CONFIGURED は <code class=\"language-plaintext highlighter-rouge\">object_detection/data</code> に読み替えること</p>\n\n<p>ssd_mobilenet_v2_cocoの場合は以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/samples/configs/ssd_mobilenet_v2_coco.config\n</code></pre></div></div>\n\n<p>上記ファイルの場合、label_mapは以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/data/mscoco_label_map.pbtxt\"\n</code></pre></div></div>\n\n<p>こにファイルにIDとラベルが定義されているが、そのままラベルファイルとしては認識できない。<br />\nIDには途中抜けがあるので注意(そのままgrepで抜き出してはダメ)</p>\n\n<h2 id=\"ラベルデータ変換プログラムを作成する\">ラベルデータ変換プログラムを作成する</h2>\n\n<p>label_map.pbtxtからラベル一覧を取得するのを手作業で行うのは大変なので、プログラムを作成する。</p>\n\n<h3 id=\"protocのインストール\">protocのインストール</h3>\n\n<p>まずは必要なモジュールのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n</code></pre></div></div>\n\n<h3 id=\"protoファイルからpythonモジュールを作成する\">protoファイルからpythonモジュールを作成する</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>protoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"変換プログラムのソース\">変換プログラムのソース</h3>\n\n<p>label_mapからテーブルを作成するスクリプト(labelmap2labels.py)をカレントディレクトリに作成する。<br />\nやっつけ仕事なので、かなりテキトー(笑)、、、</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">object_detection.utils</span> <span class=\"kn\">import</span> <span class=\"n\">label_map_util</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"==== USAGE ====\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"    python </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> label_map_file\"</span><span class=\"p\">)</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># パラメータが1個でない\n</span>    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_map_file = \"object_detection/data/mscoco_complete_label_map.pbtxt\"\n</span><span class=\"n\">label_map_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># 第一パラメータのファイルが存在しない\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"error: '</span><span class=\"si\">{</span><span class=\"n\">label_map_file</span><span class=\"si\">}</span><span class=\"s\">' not exist</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_mapからカテゴリインデックスを作成\n</span><span class=\"n\">category_index</span> <span class=\"o\">=</span> <span class=\"n\">label_map_util</span><span class=\"p\">.</span><span class=\"n\">create_category_index_from_labelmap</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span>\n\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># print(i)\n</span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">category_index</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">\"name\"</span><span class=\"p\">]</span>\n    <span class=\"k\">except</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'{name}\\t# {i}')\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n    \n<span class=\"c1\"># 個数確認のためにダミーを出力\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スクリプトの実行\">スクリプトの実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.py label_map_file\n</code></pre></div></div>\n\n<p>結果は標準出力へ出力されるので、ファイルにcastして使用する</p>\n\n<p>例:</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.pyobject_detection/data/mscoco_complete_label_map.pbtxt <span class=\"o\">></span> mscoco_complete.labels\n</code></pre></div></div>\n\n<p>出来上がったlabelsファイルを必要なところへコピーして使ってちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO で顔検出(特定人物識別)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO で顔検出(特定人物識別)</h1>\n      <p>openVINOの顔検出(特定人物識別)のサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOで顔検出(特定人物識別)するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"ソースをワークディレクトリにコピー\">ソースをワークディレクトリにコピー</h1>\n\n<p>ファイルのオーナがrootなので、編集しやすいようにワークディレクトリにソースをコピーし、そこで作業する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>face_recognition_demo/\n</code></pre></div></div>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p>いくつかのモデルデータが必要になるので、ダウンロードする。<br />\nワイルドカードでファイル指定したかったので、wgetでなくcurlを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/landmarks-regression-retail-0009/FP16/landmarks-regression-retail-0009.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-reidentification-retail-0095/FP16/face-reidentification-retail-0095.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\n<span class=\"nb\">cd</span> ..\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ncurlは「カレントディレクトリにターゲットと同じファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-O</code> と 「任意のファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-o</code>オプションしかなく、\nwgetの「ターゲットと同じファイル名で保存先ディレクトリを指定して保存」の<code class=\"language-plaintext highlighter-rouge\">-P</code>に相当するオプションがないので、\nカレントディレクトリを保存先に移動してから<code class=\"language-plaintext highlighter-rouge\">-O</code> オプションでコマンドを実行する。</p>\n</blockquote>\n\n<h1 id=\"足りないモジュールのインストール\">足りないモジュールのインストール</h1>\n\n<p>使用するモジュールでこれまでのお試しで未インストールのモジュールがあるのでインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>scipy\n</code></pre></div></div>\n\n<h1 id=\"ソースの修正\">ソースの修正</h1>\n\n<p>ソースはそのままで問題ないが、ちょっと修正しておく。</p>\n\n<p>主な変更内容は以下の通り。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code> オプションの追加と関連処理</li>\n  <li>Unknownと識別できた場合で検出枠の色を変える</li>\n  <li>入力ファイルを絶対パスに変換(不具合対策)</li>\n  <li>出力ファイルのフォーマットのmp4対応を追加(オリジナルはaviのみ対応)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur face_recognition_demo.org/face_recognition_demo.py face_recognition_demo/face_recognition_demo.py\n</span><span class=\"gd\">--- face_recognition_demo.org/face_recognition_demo.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/face_recognition_demo.py\t2019-11-27 06:29:07.507574900 +0900\n</span><span class=\"p\">@@ -62,6 +62,10 @@</span>\n     gallery.add_argument('--run_detector', action='store_true',\n                          help=\"(optional) Use Face Detection model to find faces\" \\\n                          \" on the face images, otherwise use full images.\")\n<span class=\"gi\">+    gallery.add_argument('--run_detector_no_save', action='store_true',\n+                         help=\"(optional) Use Face Detection model to find faces\" \\\n+                         \" on the face images, otherwise use full images.\" \\\n+                         \" not save detected face image.\")\n</span> \n     models = parser.add_argument_group('Models')\n     models.add_argument('-m_fd', metavar=\"PATH\", default=\"\", required=True,\n<span class=\"p\">@@ -142,7 +146,7 @@</span>\n         log.info(\"Building faces database using images from '%s'\" % (args.fg))\n         self.faces_database = FacesDatabase(args.fg, self.face_identifier,\n                                             self.landmarks_detector,\n<span class=\"gd\">-                                            self.face_detector if args.run_detector else None, args.no_show)\n</span><span class=\"gi\">+                                            self.face_detector if args.run_detector or args.run_detector_no_save else None, args.no_show, args.run_detector_no_save)\n</span>         self.face_identifier.set_faces_database(self.faces_database)\n         log.info(\"Database is built, registered %s identities\" % \\\n             (len(self.faces_database)))\n<span class=\"p\">@@ -261,9 +265,8 @@</span>\n             .face_identifier.get_identity_label(identity.id)\n \n         # Draw face ROI border\n<span class=\"gd\">-        cv2.rectangle(frame,\n-                      tuple(roi.position), tuple(roi.position + roi.size),\n-                      (0, 220, 0), 2)\n</span><span class=\"gi\">+        color1 = (0, 220, 0) if identity.id == FaceIdentifier.UNKNOWN_ID else (0, 0, 220)\n+        cv2.rectangle(frame, tuple(roi.position), tuple(roi.position + roi.size), color1, 2)\n</span> \n         # Draw identity label\n         text_scale = 0.5\n<span class=\"p\">@@ -398,19 +401,17 @@</span>\n         try:\n             stream = int(path)\n         except ValueError:\n<span class=\"gd\">-            pass\n</span><span class=\"gi\">+            # 数字でなければ絶対パスに変換\n+            stream = osp.abspath(path)\n</span>         return cv2.VideoCapture(stream)\n \n     @staticmethod\n     def open_output_stream(path, fps, frame_size):\n         output_stream = None\n         if path != \"\":\n<span class=\"gd\">-            if not path.endswith('.avi'):\n-                log.warning(\"Output file extension is not 'avi'. \" \\\n-                        \"Some issues with output can occur, check logs.\")\n</span><span class=\"gi\">+            forcc = cv2.VideoWriter.fourcc(*'mp4v') if path.endswith('.mp4') else cv2.VideoWriter.fourcc(*'MJPG')\n</span>             log.info(\"Writing output to '%s'\" % (path))\n<span class=\"gd\">-            output_stream = cv2.VideoWriter(path,\n-                                            cv2.VideoWriter.fourcc(*'MJPG'), fps, frame_size)\n</span><span class=\"gi\">+            output_stream = cv2.VideoWriter(path, forcc, fps, frame_size)\n</span>         return output_stream\n \n \n<span class=\"gh\">diff -ur face_recognition_demo.org/faces_database.py face_recognition_demo/faces_database.py\n</span><span class=\"gd\">--- face_recognition_demo.org/faces_database.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/faces_database.py\t2019-11-20 06:31:13.481819754 +0900\n</span><span class=\"p\">@@ -36,10 +36,11 @@</span>\n         def cosine_dist(x, y):\n             return cosine(x, y) * 0.5\n \n<span class=\"gd\">-    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False):\n</span><span class=\"gi\">+    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False, no_db_save=False):\n</span>         path = osp.abspath(path)\n         self.fg_path = path\n         self.no_show = no_show\n<span class=\"gi\">+        self.no_db_save = no_db_save\n</span>         paths = []\n         if osp.isdir(path):\n             paths = [osp.join(path, f) for f in os.listdir(path) \\\n<span class=\"p\">@@ -96,7 +97,7 @@</span>\n                     self.add_item(descriptor, label)\n \n     def ask_to_save(self, image):\n<span class=\"gd\">-        if self.no_show:\n</span><span class=\"gi\">+        if self.no_show or self.no_db_save:\n</span>             return None\n         save = False\n         label = None\n<span class=\"p\">@@ -209,12 +210,14 @@</span>\n             match = len(self.database)-1\n         else:\n             filename = \"{}-{}.jpg\".format(label, len(self.database[match].descriptors)-1)\n<span class=\"gd\">-        filename = osp.join(self.fg_path, filename)\n-\n-        log.debug(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n-        if osp.exists(filename):\n-            log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n-        cv2.imwrite(filename, image)\n</span><span class=\"gi\">+        \n+        if name :\n+            filename = osp.join(self.fg_path, filename)\n+            log.info(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n+            if osp.exists(filename):\n+                log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n+            else :\n+                cv2.imwrite(filename, image)\n</span>         return match\n \n     def add_item(self, desc, label):\n</code></pre></div></div>\n\n<h1 id=\"前準備\">前準備</h1>\n\n<p>識別したい顔の画像を適当なディレクトリに保存しておく。ファイル形式はjpgまたはpng。<br />\n一人ずつ1画像で顔部分のみ切り出しておく。<br />\n複数の人の顔を識別したい場合はそれぞれ別々に保存しておく。</p>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"実行用スクリプトの作成\">実行用スクリプトの作成</h2>\n\n<p>実行コマンドが長ったらしくて入力が面倒なので、以下のスクリプト(demo.sh)を作成しておく。<br />\nUbuntuとRaspberrypiを識別して自動でコマンドオプションを変更するようにしてある。 \n作成したら実行属性を付与しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/bin/bash</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"face_recognition_demo.py\"</span>\n\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"       -m_fd models/face-detection-retail-0004.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_lm models/landmarks-regression-retail-0009.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_reid models/face-reidentification-retail-0095.xml\"</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"o\">==</span> <span class=\"s2\">\"armv7l\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Raspberry Pi\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_fd MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_lm MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_reid MYRIAD\"</span>\n<span class=\"k\">else\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Ubuntu\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> --cpu_lib /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so\"</span>\n<span class=\"k\">fi\n\n\nif</span> <span class=\"o\">[</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 0 <span class=\"nt\">-o</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 1 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n\t<span class=\"c\"># パラメータなし/1個はエラー</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\n</span><span class=\"s2\">==== usage ====\"</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"nv\">$0</span><span class=\"s2\"> database_dir input_file [other option(s)]</span><span class=\"se\">\\n\\n\\n</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">exit </span>1\n<span class=\"k\">else\n    </span><span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -fg </span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\"> --input </span><span class=\"k\">${</span><span class=\"nv\">2</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    <span class=\"c\"># 3番目以降すべてのパラメータを追加</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"p\">@</span>:3:<span class=\"p\">(</span><span class=\"nv\">$#-2</span><span class=\"p\">)</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi\n</span><span class=\"nb\">echo</span> <span class=\"s2\">\"python </span><span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\npython <span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n\n<p>第1パラメータに識別子する顔画像を保存したディレクトリ、第2パラメータに入力ビデオファイル名を指定する。<br />\nこれらのパラメータは省略不可。<br />\n追加でオプションを指定したい場合は第3パラメータ以降に指定する。<br />\nたとえば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo.sh data data/video.mp4  <span class=\"nt\">--output</span> result.mp4\n</code></pre></div></div>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python face_recognition_demo.py <span class=\"nt\">-h</span>\nusage: face_recognition_demo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-i</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-o</span> PATH] <span class=\"o\">[</span><span class=\"nt\">--no_show</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-tl</span><span class=\"o\">]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-cw</span> CROP_WIDTH] <span class=\"o\">[</span><span class=\"nt\">-ch</span> CROP_HEIGHT] <span class=\"nt\">-fg</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">--run_detector</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--run_detector_no_save</span><span class=\"o\">]</span>\n                                <span class=\"nt\">-m_fd</span> PATH <span class=\"nt\">-m_lm</span> PATH <span class=\"nt\">-m_reid</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-l</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-c</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]]\n                                <span class=\"o\">[</span><span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]] <span class=\"o\">[</span><span class=\"nt\">-exp_r_fd</span> NUMBER]\n                                <span class=\"o\">[</span><span class=\"nt\">--allow_grow</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit\n\n</span>General:\n  <span class=\"nt\">-i</span> PATH, <span class=\"nt\">--input</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to the input video <span class=\"o\">(</span><span class=\"s1\">'0'</span> <span class=\"k\">for </span>the\n                        camera, default<span class=\"o\">)</span>\n  <span class=\"nt\">-o</span> PATH, <span class=\"nt\">--output</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to save the output video to\n  <span class=\"nt\">--no_show</span>             <span class=\"o\">(</span>optional<span class=\"o\">)</span> Do not display output\n  <span class=\"nt\">-tl</span>, <span class=\"nt\">--timelapse</span>      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Auto-pause after each frame\n  <span class=\"nt\">-cw</span> CROP_WIDTH, <span class=\"nt\">--crop_width</span> CROP_WIDTH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this width\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n  <span class=\"nt\">-ch</span> CROP_HEIGHT, <span class=\"nt\">--crop_height</span> CROP_HEIGHT\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this height\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n\nFaces database:\n  <span class=\"nt\">-fg</span> PATH              Path to the face images directory\n  <span class=\"nt\">--run_detector</span>        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images.\n  <span class=\"nt\">--run_detector_no_save</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images. not save\n                        detected face image.\n\nModels:\n  <span class=\"nt\">-m_fd</span> PATH            Path to the Face Detection model XML file\n  <span class=\"nt\">-m_lm</span> PATH            Path to the Facial Landmarks Regression model XML file\n  <span class=\"nt\">-m_reid</span> PATH          Path to the Face Reidentification model XML file\n\nInference options:\n  <span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Detection model\n                        <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Facial Landmarks\n                        Regression model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Reidentification\n                        model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> PATH, <span class=\"nt\">--cpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For MKLDNN <span class=\"o\">(</span>CPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to a shared library with custom layers\n                        implementations\n  <span class=\"nt\">-c</span> PATH, <span class=\"nt\">--gpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For clDNN <span class=\"o\">(</span>GPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to the XML file with descriptions of the\n                        kernels\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> Be more verbose\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_stats</span>     <span class=\"o\">(</span>optional<span class=\"o\">)</span> Output detailed per-layer performance stats\n  <span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Probability threshold <span class=\"k\">for </span>face\n                        detections<span class=\"o\">(</span>default: 0.6<span class=\"o\">)</span>\n  <span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Cosine distance threshold between two\n                        vectors <span class=\"k\">for </span>face identification <span class=\"o\">(</span>default: 0.3<span class=\"o\">)</span>\n  <span class=\"nt\">-exp_r_fd</span> NUMBER      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Scaling ratio <span class=\"k\">for </span>bboxes passed to face\n                        recognition <span class=\"o\">(</span>default: 1.15<span class=\"o\">)</span>\n  <span class=\"nt\">--allow_grow</span>          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Allow to grow faces gallery and to dump on\n                        disk. Available only <span class=\"k\">if</span> <span class=\"nt\">--no_show</span> option is off.\n</code></pre></div></div>\n\n<p>主なオプションの意味は以下の通り。</p>\n\n<h3 id=\"-m_fd\"><code class=\"language-plaintext highlighter-rouge\">-m_fd</code></h3>\n\n<p>必須。<br />\n顔位置検出モデルファイル</p>\n\n<h3 id=\"ーm_lm\"><code class=\"language-plaintext highlighter-rouge\">ーm_lm</code></h3>\n\n<p>必須。<br />\n顔特徴点検出モデルファイル</p>\n\n<h3 id=\"-m_reid\"><code class=\"language-plaintext highlighter-rouge\">-m_reid</code></h3>\n\n<p>必須。<br />\n顔識別モデルファイル</p>\n\n<h3 id=\"-d_fd\"><code class=\"language-plaintext highlighter-rouge\">-d_fd</code></h3>\n\n<p>顔位置検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_lm\"><code class=\"language-plaintext highlighter-rouge\">-d_lm</code></h3>\n\n<p>顔特徴点検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_reid\"><code class=\"language-plaintext highlighter-rouge\">-d_reid</code></h3>\n\n<p>顔識別に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"--cpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--cpu_lib</code></h3>\n\n<p>CPU用カスタムレイヤライブラリ(?)ファイル</p>\n\n<h3 id=\"--gpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--gpu_lib</code></h3>\n\n<p>GPU用カスタムレイヤライブラリ(?)ファイル(使ったことないからワカラン)</p>\n\n<h3 id=\"-fg\"><code class=\"language-plaintext highlighter-rouge\">-fg</code></h3>\n\n<p>必須。<br />\n識別する顔画像を格納したディレクトリ<br />\nこのディレクトリ内のjpg、pngファイルのみ抽出してくれるので、他のファイルが混在しても大丈夫。</p>\n\n<h3 id=\"--input\"><code class=\"language-plaintext highlighter-rouge\">--input</code></h3>\n\n<p>必須。<br />\n入力ファイル(動画ファイル)を指定する。 <br />\n静止画でもエラーにならないが、一瞬で消えるので、オプション –timelapse でキー入力待ちにするか、\nオプション –outputでファイル出力すると確認できる。<br />\n省略時はカメラが指定される。</p>\n\n<h3 id=\"--output\"><code class=\"language-plaintext highlighter-rouge\">--output</code></h3>\n\n<p>認識結果をファイルに出力する。<br />\n指定しなければファイルは作成されない(表示のみ)。 \n拡張子がmp4のときはMP4(追加した処理)。<br />\nそれ以外はMJPEGで保存(aviにするのが望ましい。それ以外だとffmpegがなんか言うがファイルはできてるっぽい)。</p>\n\n<h3 id=\"--no_show\"><code class=\"language-plaintext highlighter-rouge\">--no_show</code></h3>\n\n<p>画像表示しない。<br />\n通常は–outputと組み合わせて使う。</p>\n\n<h3 id=\"--timelapse\"><code class=\"language-plaintext highlighter-rouge\">--timelapse</code></h3>\n\n<p>1フレーム表示するごとにキー入力待ちになる。</p>\n\n<h3 id=\"--crop_width--crop_height\"><code class=\"language-plaintext highlighter-rouge\">--crop_width</code>、<code class=\"language-plaintext highlighter-rouge\">--crop_height</code></h3>\n\n<p>入力画像を指定したサイズに切り取る。切り取る場所は元画像の中心。<br />\n両方指定しないと無効。</p>\n\n<h3 id=\"--run_detector\"><code class=\"language-plaintext highlighter-rouge\">--run_detector</code></h3>\n\n<p>オプションを指定するとデータベース作成時に顔検出して新たに顔画像を作成してくれる。<br />\nデータベースファイルが全身画像だったり、複数人数が一緒に写っていてもOK。<br />\n1回指定すれば画像が残っているので以降は指定しなくても良い。</p>\n\n<h3 id=\"--run_detector_no_save\"><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code></h3>\n\n<p>追加したオプション<br />\n指定するとデータベース作成時に顔検出するが、顔画像の保存はしない。</p>\n\n<h3 id=\"--verbose\"><code class=\"language-plaintext highlighter-rouge\">--verbose</code></h3>\n\n<p>指定するとloglevelがDEBUGになる</p>\n\n<h3 id=\"--perf_stats\"><code class=\"language-plaintext highlighter-rouge\">--perf_stats</code></h3>\n\n<p>指定するとフレーム毎にパフォーマンスステータスを表示する</p>\n\n<h3 id=\"-t_fd\"><code class=\"language-plaintext highlighter-rouge\">-t_fd</code></h3>\n\n<p>顔位置検出に使用する閾値。省略時は0.6。</p>\n\n<h3 id=\"-t_reid\"><code class=\"language-plaintext highlighter-rouge\">-t_reid</code></h3>\n\n<p>顔識別に使用する閾値。省略時は0.3。</p>\n\n<h3 id=\"-exp_r_fd\"><code class=\"language-plaintext highlighter-rouge\">-exp_r_fd</code></h3>\n\n<p>顔位置検出した枠のサイズを何倍にするか。ギリギリだとうまく行かないから?省略時は1.15</p>\n\n<h3 id=\"--allow_grow\"><code class=\"language-plaintext highlighter-rouge\">--allow_grow</code></h3>\n\n<p>認識画像で知らない顔が出てきたらその都度登録するか確認する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbianのディスクイメージのアーカイブ</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbianのディスクイメージのアーカイブ</h1>\n      <p>Raspbianのディスクイメージのアーカイブのありかをすぐ忘れてしまうのでメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"メモ\">メモ</h1>\n\n<p>Raspbianのディスクイメージのアーカイブは以下にある。<br />\n各バージョン(日付)別にディレクトリ分けされている。<br />\nミラーサイトが爆速なのでおススメ。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>項目</th>\n      <th>URL</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>最新版</td>\n      <td><a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(本家)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_armhf/images/\">https://downloads.raspberrypi.org/raspios_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Full版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_full_armhf/images/\">https://downloads.raspberrypi.org/raspios_full_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_lite_armhf/images/\">https://downloads.raspberrypi.org/raspios_lite_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(ミラーサイト)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Full版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(2020/02以前版)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspbian/images/\">https://downloads.raspberrypi.org/raspbian/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspbian_lite/images/\">https://downloads.raspberrypi.org/raspbian_lite/images/</a></td>\n    </tr>\n  </tbody>\n</table>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でYOLO(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でYOLO(その2)</h1>\n      <p>openVINOのYOLOのプログラムをちょこっと改変</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> のソースを\n<a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> のソースと形状を合わせたもの。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">math</span> <span class=\"kn\">import</span> <span class=\"n\">exp</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-iout\"</span><span class=\"p\">,</span> <span class=\"s\">\"--iou_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Intersection over union threshold for overlapping \"</span>\n                                                       <span class=\"s\">\"detections filtering\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-ni\"</span><span class=\"p\">,</span> <span class=\"s\">\"--number_iter\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Number of inference iterations\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pc\"</span><span class=\"p\">,</span> <span class=\"s\">\"--perf_counts\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Report performance counters\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span>\n                      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-r\"</span><span class=\"p\">,</span> <span class=\"s\">\"--raw_output_message\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Output inference results raw values showing\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">YoloParams</span><span class=\"p\">:</span>\n    <span class=\"c1\"># ------------------------------------------- Extracting layer parameters ------------------------------------------\n</span>    <span class=\"c1\"># Magic numbers are copied from yolo samples\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">param</span><span class=\"p\">,</span> <span class=\"n\">side</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"mi\">3</span> <span class=\"k\">if</span> <span class=\"s\">'num'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'num'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">=</span> <span class=\"mi\">4</span> <span class=\"k\">if</span> <span class=\"s\">'coords'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'coords'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">classes</span> <span class=\"o\">=</span> <span class=\"mi\">80</span> <span class=\"k\">if</span> <span class=\"s\">'classes'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'classes'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">10.0</span><span class=\"p\">,</span> <span class=\"mf\">13.0</span><span class=\"p\">,</span> <span class=\"mf\">16.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">33.0</span><span class=\"p\">,</span> <span class=\"mf\">23.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">61.0</span><span class=\"p\">,</span> <span class=\"mf\">62.0</span><span class=\"p\">,</span> <span class=\"mf\">45.0</span><span class=\"p\">,</span> <span class=\"mf\">59.0</span><span class=\"p\">,</span> <span class=\"mf\">119.0</span><span class=\"p\">,</span> <span class=\"mf\">116.0</span><span class=\"p\">,</span> <span class=\"mf\">90.0</span><span class=\"p\">,</span> <span class=\"mf\">156.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">198.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">373.0</span><span class=\"p\">,</span> <span class=\"mf\">326.0</span><span class=\"p\">]</span> <span class=\"k\">if</span> <span class=\"s\">'anchors'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"p\">[</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">a</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'anchors'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n\n        <span class=\"k\">if</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">:</span>\n            <span class=\"n\">mask</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">idx</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'mask'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">mask</span><span class=\"p\">)</span>\n\n            <span class=\"n\">maskedAnchors</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n            <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">mask</span><span class=\"p\">:</span>\n                <span class=\"n\">maskedAnchors</span> <span class=\"o\">+=</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"n\">maskedAnchors</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">=</span> <span class=\"n\">side</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"o\">=</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span>  <span class=\"c1\"># Weak way to determine but the only one.\n</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">log_params</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># params_to_print = {'classes': self.classes, 'num': self.num, 'coords': self.coords, 'anchors': self.anchors}\n</span>        <span class=\"c1\"># [log.info(\"         {:8}: {}\".format(param_name, param)) for param_name, param in params_to_print.items()]\n</span>        <span class=\"k\">pass</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">entry_index</span><span class=\"p\">(</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">coord</span><span class=\"p\">,</span> <span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">location</span><span class=\"p\">,</span> <span class=\"n\">entry</span><span class=\"p\">):</span>\n    <span class=\"n\">side_power_2</span> <span class=\"o\">=</span> <span class=\"n\">side</span> <span class=\"o\">**</span> <span class=\"mi\">2</span>\n    <span class=\"n\">n</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">//</span> <span class=\"n\">side_power_2</span>\n    <span class=\"n\">loc</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">%</span> <span class=\"n\">side_power_2</span>\n    <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">side_power_2</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">coord</span> <span class=\"o\">+</span> <span class=\"n\">classes</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">entry</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">loc</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"p\">,</span> <span class=\"n\">h_scale</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"p\">):</span>\n    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">w</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">y</span> <span class=\"o\">-</span> <span class=\"n\">h</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">w</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">+</span> <span class=\"n\">h</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"nb\">dict</span><span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"o\">=</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"o\">=</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"o\">=</span><span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"o\">=</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">blob</span><span class=\"p\">,</span> <span class=\"n\">resized_image_shape</span><span class=\"p\">,</span> <span class=\"n\">original_im_shape</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">threshold</span><span class=\"p\">):</span>\n    <span class=\"c1\"># ------------------------------------------ Validating output parameters ------------------------------------------\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    <span class=\"k\">assert</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">==</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"s\">\"Invalid size of output blob. It sould be in NCHW layout and height should \"</span> \\\n                                     <span class=\"s\">\"be equal to width. Current height = {}, current width = {}\"</span> \\\n                                     <span class=\"s\">\"\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ------------------------------------------ Extracting layer parameters -------------------------------------------\n</span>    <span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">orig_im_w</span> <span class=\"o\">=</span> <span class=\"n\">original_im_shape</span>\n    <span class=\"n\">resized_image_h</span><span class=\"p\">,</span> <span class=\"n\">resized_image_w</span> <span class=\"o\">=</span> <span class=\"n\">resized_image_shape</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">predictions</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">flatten</span><span class=\"p\">()</span>\n    <span class=\"n\">side_square</span> <span class=\"o\">=</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n\n    <span class=\"c1\"># ------------------------------------------- Parsing YOLO Region output -------------------------------------------\n</span>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">side_square</span><span class=\"p\">):</span>\n        <span class=\"n\">row</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">//</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"n\">col</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">%</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"k\">for</span> <span class=\"n\">n</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">num</span><span class=\"p\">):</span>\n            <span class=\"n\">obj_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">)</span>\n            <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">scale</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"n\">box_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n            <span class=\"c1\"># Network produces location predictions in absolute coordinates of feature maps.\n</span>            <span class=\"c1\"># Scale it to relative coordinates.\n</span>            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">col</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">0</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">row</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"c1\"># Value for exp is very big number in some cases so following construction is using here\n</span>            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">w_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n                <span class=\"n\">h_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">3</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n            <span class=\"k\">except</span> <span class=\"nb\">OverflowError</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"c1\"># Depends on topology we need to normalize sizes by feature maps (up to YOLOv3) or by input shape (YOLOv3)\n</span>            <span class=\"n\">w</span> <span class=\"o\">=</span> <span class=\"n\">w_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_w</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"n\">h</span> <span class=\"o\">=</span> <span class=\"n\">h_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_h</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">):</span>\n                <span class=\"n\">class_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span>\n                                          <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">+</span> <span class=\"n\">j</span><span class=\"p\">)</span>\n                <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"n\">scale</span> <span class=\"o\">*</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">class_index</span><span class=\"p\">]</span>\n                <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                    <span class=\"k\">continue</span>\n                <span class=\"n\">objects</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">=</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">=</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"o\">=</span><span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"o\">=</span><span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">j</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">,</span>\n                                          <span class=\"n\">h_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_w</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"n\">objects</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n    <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">height_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span>\n    <span class=\"k\">if</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">height_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">*</span> <span class=\"n\">height_of_overlap_area</span>\n    <span class=\"n\">box_1_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">box_2_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">area_of_union</span> <span class=\"o\">=</span> <span class=\"n\">box_1_area</span> <span class=\"o\">+</span> <span class=\"n\">box_2_area</span> <span class=\"o\">-</span> <span class=\"n\">area_of_overlap</span>\n    <span class=\"k\">if</span> <span class=\"n\">area_of_union</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"mi\">0</span>\n    <span class=\"k\">return</span> <span class=\"n\">area_of_overlap</span> <span class=\"o\">/</span> <span class=\"n\">area_of_union</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>                 <span class=\"c1\"># 冒頭でinputは一つでなければエラーになってるので決め打ちで[0]\n</span>    <span class=\"n\">in_frame_shape</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">:]</span>       <span class=\"c1\"># HWC→BCHWに変更してあるので、height/widthはshape[2:]で取得\n</span>    <span class=\"k\">for</span> <span class=\"n\">layer_name</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">.</span><span class=\"n\">items</span><span class=\"p\">():</span>\n        <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">parents</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]].</span><span class=\"n\">shape</span><span class=\"p\">)</span>\n        <span class=\"n\">layer_params</span> <span class=\"o\">=</span> <span class=\"n\">YoloParams</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n        <span class=\"c1\"># log.info(\"Layer {} parameters: \".format(layer_name))\n</span>        <span class=\"n\">layer_params</span><span class=\"p\">.</span><span class=\"n\">log_params</span><span class=\"p\">()</span>\n        <span class=\"n\">objects</span> <span class=\"o\">+=</span> <span class=\"n\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">out_blob</span><span class=\"p\">,</span> \n                                        <span class=\"n\">in_frame_shape</span><span class=\"p\">,</span>\n                                        <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">],</span> \n                                        <span class=\"n\">layer_params</span><span class=\"p\">,</span>\n                                        <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Filtering overlapping boxes with respect to the --iou_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">sorted</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">,</span> <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"k\">lambda</span> <span class=\"n\">obj</span> <span class=\"p\">:</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">reverse</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">iou_threshold</span><span class=\"p\">:</span>\n                <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># Drawing objects with respect to the --prob_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">obj</span> <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span> <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">Detected boxes for batch {}:\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">))</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\" Class ID | Confidence | XMIN | YMIN | XMAX | YMAX | COLOR \"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">origin_im_size</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Validation bbox of detected object\n</span>        <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"c1\"># color = (int(min(obj['class_id'] * 12.5, 255)),\n</span>        <span class=\"c1\">#          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span>        <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n        <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]]</span> <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"ow\">and</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">>=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]</span> <span class=\"k\">else</span> \\\n            <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">])</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span>\n                <span class=\"s\">\"{:^9} | {:10f} | {:4} | {:4} | {:4} | {:4} | {} \"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">det_label</span><span class=\"p\">,</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">color</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]),</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span>\n                    <span class=\"s\">\"#\"</span> <span class=\"o\">+</span> <span class=\"n\">det_label</span> <span class=\"o\">+</span> <span class=\"s\">' '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"s\">' %'</span><span class=\"p\">,</span>\n                    <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.6</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"c1\"># YOLOのoutputsは1ではない\n</span>    \n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Sample supports only YOLO V3 based single input topologies\"</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>     <span class=\"c1\"># inputは一つだけなので決め打ちで[0]\n</span>    \n    <span class=\"c1\">#  Defaulf batch_size is 1\n</span>    <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n    \n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n        \n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span> <span class=\"o\">=</span>      <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span> <span class=\"o\">=</span>   <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span>  <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_yolov3_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                             <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                             <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                             <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-iout</span> IOU_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-ni</span> NUMBER_ITER] <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-r</span><span class=\"o\">]</span>\n                                             <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG]\n                                             <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n  <span class=\"nt\">-iout</span> IOU_THRESHOLD, <span class=\"nt\">--iou_threshold</span> IOU_THRESHOLD\n                        Optional. Intersection over union threshold <span class=\"k\">for\n                        </span>overlapping detections filtering\n  <span class=\"nt\">-ni</span> NUMBER_ITER, <span class=\"nt\">--number_iter</span> NUMBER_ITER\n                        Optional. Number of inference iterations\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_counts</span>    Optional. Report performance counters\n  <span class=\"nt\">-r</span>, <span class=\"nt\">--raw_output_message</span>\n                        Optional. Output inference results raw values showing\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD</h1>\n      <p>openVINOのSSDのサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>YOLOとは別のアルゴリズムSSDで物体認識するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_ssd_async</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">models.list</code>によると、以下のモデルデータが使用できるらしい。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>face-detection-adas-????\nface-detection-adas-binary-????\nface-detection-retail-????\npedestrian-and-vehicle-detector-adas-????\npedestrian-detection-adas-????\npedestrian-detection-adas-binary-????\nperson-detection-retail-????\nvehicle-detection-adas-????\nvehicle-detection-adas-binary-????\nvehicle-license-plate-detection-barrier-????\n</code></pre></div></div>\n\n<p>ここでは、vehicle-detection-adas-binary-????を使ってみることにする。</p>\n\n<p>以下の手順でモデルデータをダウンロードする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/pedestrian-and-vehicle-detector-adas-0001/FP16/pedestrian-and-vehicle-detector-adas-0001\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>ラベルデータは用意されていないので、ラベルデータを以下の内容で、<code class=\"language-plaintext highlighter-rouge\">${models_diir}/pedestrian-and-vehicle-detector-adas-0001.labels</code>のファイル名で作成する。<br />\nオリジナルでは<code class=\"language-plaintext highlighter-rouge\">--label</code>オプションでラベルデータファイルを指定するようになっているが、\nモデルデータファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものをデフォルトのラベルデータファイルとして認識するように変更しておいた。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>UNKNOWN\nvehicles\npedestrians\nUNKNOWN\n</code></pre></div></div>\n\n<p>どのIDが何を示すか書いてる場所を見つけられなかったんだよなぁ~。<br />\nとりあえず、結果表示から推測するしかないか。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<p>ちょっとのつもりで改造してたら、結構たくさんの変更になったので、ソース全体を掲載しておく。<br />\n(RaspberryPiにはソース入ってないし)<br />\nおもな変更点は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--save</code> <code class=\"language-plaintext highlighter-rouge\">--log</code> <code class=\"language-plaintext highlighter-rouge\">--sync</code> <code class=\"language-plaintext highlighter-rouge\">--no_disp</code> オプションの追加</li>\n  <li>結果解析部分の関数化(後でYOLOと比較しやすいように)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># print(res[out_blob].shape)\n</span>    <span class=\"c1\">#  -> (1, 1, 200, 7)        200:バウンディングボックスの数\n</span>    <span class=\"c1\"># データ構成は\n</span>    <span class=\"c1\"># https://docs.openvinotoolkit.org/2019_R1/_pedestrian_and_vehicle_detector_adas_0001_description_pedestrian_and_vehicle_detector_adas_0001.html\n</span>    <span class=\"c1\"># の「outputs」を参照\n</span>    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"n\">out_blob</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]:</span>     <span class=\"c1\"># このループは200回まわる\n</span>        <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>                       <span class=\"c1\"># confidence for the predicted class(スコア)\n</span>        <span class=\"k\">if</span> <span class=\"n\">conf</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">:</span>      <span class=\"c1\"># 閾値より大きいものだけ処理\n</span>            <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n            <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 表示色\n</span>            <span class=\"c1\"># color = (min(class_id * 12.5, 255), min(class_id * 7, 255), min(class_id * 5, 255))\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>            <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># バウンディングボックスとラベル、スコアを表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">det_label</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">conf</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">%\"</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Demo supports only single output topologies\"</span>\n\n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"c1\"># SSDのinputsは1とは限らないのでスキャンする\n</span>    <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">for</span> <span class=\"n\">blob_name</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">:</span>\n        <span class=\"c1\"># print(f'{blob_name}   {net.inputs[blob_name].shape}')\n</span>        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">4</span><span class=\"p\">:</span>\n            <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">2</span><span class=\"p\">:</span>\n            <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"nb\">RuntimeError</span><span class=\"p\">(</span><span class=\"s\">\"Unsupported {}D input layer '{}'. Only 2D and 4D input layers are supported\"</span>\n                               <span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">),</span> <span class=\"n\">blob_name</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    <span class=\"k\">if</span> <span class=\"n\">img_info_input_blob</span><span class=\"p\">:</span>\n        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">img_info_input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n\n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span>     <span class=\"o\">=</span> <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span>  <span class=\"o\">=</span> <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span> <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_ssd_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                          <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                          <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO(C++版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO(C++版)</h1>\n      <p>tinyYOLOのC++版デモプログラムのbuildと実行</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nのpythonで実行したデモプログラムのC++版をbuild&実行してみる。</p>\n\n<h1 id=\"ubuntu環境での実行\">ubuntu環境での実行</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h2 id=\"デモのソースプログラム\">デモのソースプログラム</h2>\n\n<p>ドライバのインストール先 <code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/deployment_tools/open_model_zoo/demos</code> にあるので、そのまま参照しても良いが、\nソース修正に備えて、ソースをコピっておく(オーナーも変更)と何かと便利。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++/openvino_demo <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos <span class=\"nb\">.</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> demos/\n</code></pre></div></div>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>出力文字列のサイズと位置を調整</li>\n  <li>-saveオプションの追加と認識結果画像ファイルの保存処理の追加</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.hpp.org\t2019-10-31 14:39:14.757039048 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.hpp\t2019-10-31 06:16:49.178945707 +0900\n</span><span class=\"p\">@@ -93,6 +93,7 @@</span>\n /// \\brief Define a flag to disable showing processed video<br>\n /// It is an optional parameter\n DEFINE_bool(no_show, false, no_show_processed_video);\n<span class=\"gi\">+DEFINE_bool(save, false, \"Optional. save image file.\");\n</span> \n /**\n * \\brief This function shows a help message\n<span class=\"p\">@@ -115,4 +116,5 @@</span>\n     std::cout << \"    -iou_t                    \" << iou_thresh_output_message << std::endl;\n     std::cout << \"    -auto_resize              \" << input_resizable_message << std::endl;\n     std::cout << \"    -no_show                  \" << no_show_processed_video << std::endl;\n<span class=\"gi\">+    std::cout << \"    -save                     \" << \"Optional. save image file.\" << std::endl;\n</span> }\n</code></pre></div></div>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.org\t2019-10-31 05:46:38.515000000 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"p\">@@ -197,6 +197,21 @@</span>\n         }\n         // -----------------------------------------------------------------------------------------------------\n \n<span class=\"gi\">+        // =====================================================================================\n+        // 動画ファイルを書き出すためのオブジェクトを宣言する\n+        cv::VideoWriter writer;\n+        // =====================================================================================\n+        // =====================================================================================\n+        if (FLAGS_save) {\n+            double fps    = cap.get(cv::CAP_PROP_FPS);\t\t\t\t// フレームレートを取得\n+            int fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v');\t\t// MP4形式を指定\n+            // * エンコード形式 \"XVID\" = AVI, \"MP4V\" = MPEG4, \"WMV1\" = WMV\n+\n+            // 動画ファイルを書き出すためのファイルをオープンする\n+            writer.open(\"result.mp4\", fourcc, fps, cv::Size(width, height));\n+        }\n+        // =====================================================================================\n+\n</span>         // --------------------------- 1. Load inference engine -------------------------------------\n         slog::info << \"Loading Inference Engine\" << slog::endl;\n         Core ie;\n<span class=\"p\">@@ -356,17 +371,17 @@</span>\n                 std::ostringstream out;\n                 out << \"OpenCV cap/render time: \" << std::fixed << std::setprecision(2)\n                     << (ocv_decode_time + ocv_render_time) << \" ms\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 25), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 255, 0));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 15), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 255, 0));\n</span>                 out.str(\"\");\n                 out << \"Wallclock time \" << (isAsyncMode ? \"(TRUE ASYNC):      \" : \"(SYNC, press Tab): \");\n                 out << std::fixed << std::setprecision(2) << wall.count() << \" ms (\" << 1000.f / wall.count() << \" fps)\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 50), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 0, 255));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 30), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 0, 255));\n</span>                 if (!isAsyncMode) {  // In the true async mode, there is no way to measure detection time directly\n                     out.str(\"\");\n                     out << \"Detection time  : \" << std::fixed << std::setprecision(2) << detection.count()\n                         << \" ms (\"\n                         << 1000.f / detection.count() << \" fps)\";\n<span class=\"gd\">-                    cv::putText(frame, out.str(), cv::Point2f(0, 75), cv::FONT_HERSHEY_TRIPLEX, 0.6,\n</span><span class=\"gi\">+                    cv::putText(frame, out.str(), cv::Point2f(0, 45), cv::FONT_HERSHEY_TRIPLEX, 0.4,\n</span>                                 cv::Scalar(255, 0, 0));\n                 }\n \n<span class=\"p\">@@ -410,7 +425,7 @@</span>\n                         cv::putText(frame,\n                                 (label < static_cast<int>(labels.size()) ?\n                                         labels[label] : std::string(\"label #\") + std::to_string(label)) + conf.str(),\n<span class=\"gd\">-                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 1,\n</span><span class=\"gi\">+                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.4,\n</span>                                     cv::Scalar(0, 0, 255));\n                         cv::rectangle(frame, cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin)),\n                                       cv::Point2f(static_cast<float>(object.xmax), static_cast<float>(object.ymax)), cv::Scalar(0, 0, 255));\n<span class=\"p\">@@ -420,6 +435,11 @@</span>\n             if (!FLAGS_no_show) {\n                 cv::imshow(\"Detection results\", frame);\n             }\n<span class=\"gi\">+            // =====================================================================================\n+            if (FLAGS_save) {\n+                writer << frame;\n+            }\n+            // =====================================================================================\n</span> \n             t1 = std::chrono::high_resolution_clock::now();\n             ocv_render_time = std::chrono::duration_cast<ms>(t1 - t0).count();\n<span class=\"p\">@@ -457,6 +477,11 @@</span>\n         if (FLAGS_pc) {\n             printPerformanceCounts(*async_infer_request_curr, std::cout, getFullDeviceName(ie, FLAGS_d));\n         }\n<span class=\"gi\">+        // =====================================================================================\n+        if (FLAGS_save) {\n+            writer.release();\n+        }\n+        // =====================================================================================\n</span>     }\n     catch (const std::exception& error) {\n         std::cerr << \"[ ERROR ] \" << error.what() << std::endl;\n\n</code></pre></div></div>\n\n<h2 id=\"buildディレクトリの作成とbuild\">buildディレクトリの作成とbuild</h2>\n\n<p>cmakeの実行とbuild</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<p>ちょっと時間がかかる。</p>\n\n<h2 id=\"モデルデータ\">モデルデータ</h2>\n\n<p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nで作成したモデルデータをそのまま使用する。<br />\nラベルデータファイルのファイル名はモデルデータのxmlファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものに固定だが、モデルデータ作成時にコピー済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./intel64/Release/</code>に作成される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./intel64/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-l</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> ../../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>-save オプションを指定すると、認識結果の動画をresult.mp4(ファイル名は固定)に保存する。</p>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>デモプログラムはRasspberryPiでも動作させることができる。<br />\nソースはRaspberryPi側にはないので、ubuntuからコピーする。</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>ubuntuで作成した /work/NCS2/c++/openvino_demo/demos ディレクトリと/work/NCS2/openvino_models ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"buildディレクトリの作成とbuild-1\">buildディレクトリの作成とbuild</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a -Wno-psabi\"</span> ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./armv7l/Release/</code>に作成される。<br />\n入力ファイル(-i オプション)はフルパスで指定すること。相対パスだとファイルが見つからないと怒られる。<br />\n※ 下のパッチを当てると相対パスでも大丈夫になる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./armv7l/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-d</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> /work/NCS2/data/testvideo3.mp4 \n</code></pre></div></div>\n\n<p>なぜか-saveオプションが効かない。。。</p>\n\n<h2 id=\"入力ファイル名に相対パスを使用できるようにするためのパッチ\">入力ファイル名に相対パスを使用できるようにするためのパッチ</h2>\n\n<p>入力ファイル名をrealpath()で絶対パスに変換して使用することで対応。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.1\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-11-01 11:25:29.720856218 +0900\n</span><span class=\"p\">@@ -30,6 +30,9 @@</span>\n #include <ext_list.hpp>\n #endif\n \n<span class=\"gi\">+#include <limits.h>\n+#include <unistd.h>\n+\n</span> using namespace InferenceEngine;\n \n bool ParseAndCheckCommandLine(int argc, char *argv[]) {\n<span class=\"p\">@@ -180,7 +183,23 @@</span>\n \n         slog::info << \"Reading input\" << slog::endl;\n         cv::VideoCapture cap;\n<span class=\"gd\">-        if (!((FLAGS_i == \"cam\") ? cap.open(0) : cap.open(FLAGS_i.c_str()))) {\n</span><span class=\"gi\">+\n+        bool open_status;\n+        if (FLAGS_i == \"cam\") {\n+            open_status = cap.open(0);\n+        }\n+        else {\n+            std::string input_filename;\n+            char input_filename_char[PATH_MAX+1];\n+            if (!realpath(FLAGS_i.c_str(), input_filename_char)) {\n+                throw std::logic_error(\"Cannot get realpath\");\n+            }\n+            input_filename = input_filename_char;\n+            slog::info << \"input filename :\" + input_filename << slog::endl;\n+            open_status = cap.open(input_filename.c_str());\n+\n+        }\n+        if (!open_status) {\n</span>             throw std::logic_error(\"Cannot open input file or camera: \" + FLAGS_i);\n         }\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO</h1>\n      <p>darknetのモデルデータをopenVINOのモデルデータに変換し、tinyYOLOで画像認識を行う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOの2019 R3.1 がリリー(2019.10.29現在、ubuntu用のみ)スされ、YOLOのサンプルプログラムが用意されていたので、tinyYOLOを実行してみた。</p>\n\n<p>参考:<a href=\"https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html\">https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html</a></p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"darknetのモデルデータをopenvinoのモデルデータに変換\">darknetのモデルデータをopenVINOのモデルデータに変換</h1>\n\n<p>上記参考サイトの手順に従って、darknetのtinyYOLOモデルデータをopenVINOのモデルデータに変換する。</p>\n\n<h2 id=\"darknet--tensorflow-変換のためのプログラム取得\">darknet → tensorflow 変換のためのプログラム取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2\ngit clone https://github.com/mystic123/tensorflow-yolo-v3.git\n<span class=\"nb\">cd </span>tensorflow-yolo-v3/\ngit checkout ed60b90\n</code></pre></div></div>\n\n<h2 id=\"darknet-tinyyoloモデルデータ取得\">darknet tinyYOLOモデルデータ取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://raw.githubusercontent.com/pjreddie/darknet/master/data/coco.names\nwget https://pjreddie.com/media/files/yolov3-tiny.weights\n</code></pre></div></div>\n\n<h1 id=\"darknet--tensorflow-モデルデータ変換\">darknet → tensorflow モデルデータ変換</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python convert_weights_pb.py <span class=\"nt\">--class_names</span> coco.names <span class=\"nt\">--data_format</span> NHWC <span class=\"nt\">--weights_file</span> yolov3-tiny.weights <span class=\"nt\">--tiny</span>\n<span class=\"nb\">mv </span>frozen_darknet_yolov3_model.pb yolo_v3_tiny.pb\n</code></pre></div></div>\n\n<h2 id=\"モデルデータを変換\">モデルデータを変換</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP16 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div></div>\n\n<p>/work/NCS2/openvino_models/FP16ディレクトリに yolo_v3_tiny.bin yolo_v3_tiny.mapping yolo_v3_tiny.xml の3つが出来る</p>\n\n<blockquote>\n  <p>[!NOTE]\nFP32で計算する場合はこちら<br />\nNCStick使用時はFP16のみサポートなので、FP16で作っておくと使い回しできて楽。<br />\nそんなに認識精度が変わるわけでもなさそうだし。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP32\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP32 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"ラベルデータもコピー\">ラベルデータもコピー</h2>\n\n<p>pbファイルにはラベルデータが入っているはずだが、この後の変換でラベルデータは欠落するらしい。<br />\n後のプログラムのためにファイル名変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>coco.names <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels\n</code></pre></div></div>\n\n<h2 id=\"デモプログラムをコピー\">デモプログラムをコピー</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ..\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_yolov3_async <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>object_detection_demo_yolov3_async/\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>MP4ファイルのパスが絶対パスでないと正常にオープンできない対策(ubuntuではやらなくても大丈夫)</li>\n  <li>1フレームあたりの処理時間の計測と表示処理を追加</li>\n  <li>認識枠の表示色変更(ちょっと見難かったので)</li>\n  <li>計測データ表示処理の並べ替え(ソースが見難かったので。フレーム時間の追加以外の動作は変更なし)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py.org\t2019-10-29 05:08:34.982999999 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"p\">@@ -210,7 +210,8 @@</span>\n     else:\n         labels_map = None\n \n<span class=\"gd\">-    input_stream = 0 if args.input == \"cam\" else args.input\n</span><span class=\"gi\">+    # input_stream = 0 if args.input == \"cam\" else args.input\n+    input_stream = 0 if args.input == \"cam\" else os.path.abspath(args.input)\n</span> \n     is_async_mode = True\n     cap = cv2.VideoCapture(input_stream)\n<span class=\"p\">@@ -234,6 +235,8 @@</span>\n     next_request_id = 1\n     render_time = 0\n     parsing_time = 0\n<span class=\"gi\">+    frame_time = 0\n+    prev_time = time()\n</span> \n     # ----------------------------------------------- 6. Doing inference -----------------------------------------------\n     log.info(\"Starting inference...\")\n<span class=\"p\">@@ -263,6 +266,8 @@</span>\n \n         # Start inference\n         start_time = time()\n<span class=\"gi\">+        frame_time = start_time - prev_time         # 1フレームの処理時間\n+        prev_time = start_time\n</span>         exec_net.start_async(request_id=request_id, inputs={input_blob: in_frame})\n         det_time = time() - start_time\n \n<span class=\"p\">@@ -303,8 +308,9 @@</span>\n             # Validation bbox of detected object\n             if obj['xmax'] > origin_im_size[1] or obj['ymax'] > origin_im_size[0] or obj['xmin'] < 0 or obj['ymin'] < 0:\n                 continue\n<span class=\"gd\">-            color = (int(min(obj['class_id'] * 12.5, 255)),\n-                     min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span><span class=\"gi\">+            # color = (int(min(obj['class_id'] * 12.5, 255)),\n+            #          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n+            color = (255, 128, 128)\n</span>             det_label = labels_map[obj['class_id']] if labels_map and len(labels_map) >= obj['class_id'] else \\\n                 str(obj['class_id'])\n \n<span class=\"p\">@@ -322,16 +328,17 @@</span>\n         # Draw performance stats over frame\n         inf_time_message = \"Inference time: N\\A for async mode\" if is_async_mode else \\\n             \"Inference time: {:.3f} ms\".format(det_time * 1e3)\n<span class=\"gi\">+        frame_time_message = \"Frame time: {:.3f} ms\".format(frame_time * 1e3)\n</span>         render_time_message = \"OpenCV rendering time: {:.3f} ms\".format(render_time * 1e3)\n         async_mode_message = \"Async mode is on. Processing request {}\".format(cur_request_id) if is_async_mode else \\\n             \"Async mode is off. Processing request {}\".format(cur_request_id)\n         parsing_message = \"YOLO parsing time is {:.3f}\".format(parsing_time * 1e3)\n \n<span class=\"gd\">-        cv2.putText(frame, inf_time_message, (15, 15), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200, 10, 10), 1)\n-        cv2.putText(frame, render_time_message, (15, 45), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n-        cv2.putText(frame, async_mode_message, (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5,\n-                    (10, 10, 200), 1)\n-        cv2.putText(frame, parsing_message, (15, 30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n</span><span class=\"gi\">+        cv2.putText(frame, inf_time_message,    (15, 15),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, parsing_message,     (15, 30),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, render_time_message, (15, 45),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, frame_time_message,  (10, int(origin_im_size[0] - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, async_mode_message,  (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n</span> \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n</code></pre></div></div>\n\n<p>上のパッチ内容をa.patchとして保存したとして、以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch object_detection_demo_yolov3_async.py a.patch \n\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\n入力ファイルをmp4に変えるだけ。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしいが、カメラないので未確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>RaspberryPi用はopenVINO 2019R3のまま(2019.10.29現在、R3.1はリリースされていない)だけど、問題なし。</p>\n\n<p>ubuntuで作成した object_detection_demo_yolov3_async ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"静止画の場合-1\">静止画の場合</h2>\n\n<p>実行コマンドは以下。  ubuntuの実行コマンドと比べて、以下の変更がある。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--device MYRIAD</code>を追加</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">--cpu_extension</code>を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合-1\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\nこちらも入力ファイルをmp4に変えるだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p>openCVではMP4ファイルを保存することができる。<br />\nobject_detection_demo_yolov3_async.py に以下の変更を加えることで、認識結果をMP4ファイルに保存することができる。</p>\n\n<p>以下の修正ファイルは簡易的に保存する処理を追加したため、保存ファイル名は決め打ち。 <br />\n汎用的にするなら、オプションで指定できるようにしてもいいかもね。</p>\n\n<p>ただし、実際に保存するタイミングとMP4ファイルのタイムインデックスが一致するわけではないので、\n処理時の見た目と保存ファイルを再生したときの見た目は異なるので注意が必要。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"gi\">+++ record.py\t2019-10-29 11:35:37.296005608 +0900\n</span><span class=\"p\">@@ -218,6 +218,18 @@</span>\n     number_input_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n     number_input_frames = 1 if number_input_frames != -1 and number_input_frames < 0 else number_input_frames\n \n<span class=\"gi\">+    # =====================================================================================\n+    # 幅と高さを取得\n+    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n+    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n+    size = (width, height)\n+    # フレームレート(1フレームの時間単位はミリ秒)の取得\n+    frame_rate = int(cap.get(cv2.CAP_PROP_FPS))\n+    # フォーマット\n+    fmt = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')\n+    writer = cv2.VideoWriter('./outtest.mp4', fmt, frame_rate, size)\n+    # =====================================================================================\n+\n</span>     wait_key_code = 1\n \n     # Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n<span class=\"p\">@@ -342,6 +354,9 @@</span>\n \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n<span class=\"gi\">+        # =====================================================================================\n+        writer.write(frame)\n+        # =====================================================================================\n</span>         render_time = time() - start_time\n \n         if is_async_mode:\n<span class=\"p\">@@ -359,6 +374,10 @@</span>\n             is_async_mode = not is_async_mode\n             log.info(\"Switched to {} mode\".format(\"async\" if is_async_mode else \"sync\"))\n \n<span class=\"gi\">+    # =====================================================================================\n+    writer.release()\n+    # =====================================================================================\n+\n</span>     cv2.destroyAllWindows()\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PythonでIntel NCStick2</title>\n  </head>\n  <body>\n    <header>\n      <h1>PythonでIntel NCStick2</h1>\n      <p>PythonでIntel NCStick2を操作する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"事前準備\">事前準備</h1>\n<p>何はなくともPythonが必要。<br />\n実際には3.7.4を使用して動作確認。</p>\n\n<p>Pythonはpyenvでインストールしておくのが便利。インストール方法は \n<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a> を参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\npyenvとの相性が悪いらしく、pyenvで3.7.xがインストールされていると\n(python3.7コマンド自体は存在するので;実行自体はエラーで返ってくるが)、\nsetupvars.shでPYTHONPATHにpython3.7用pathが設定されてしまう。\nプログラム中で<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>でpathを追加しても、sys.pathの末尾に追加されてしまい、\n先に設定された3.7用モジュールがインポートされてしまう。\nもし、他のバージョンのpythonで実行する場合は<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">sys.path.insert</code>で\npathの先頭に追加するようにしないといけないようだ(試してないけど)。</p>\n\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n    <span class=\"err\">↓</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>ということで、下のプログラムソースの<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>の行は不要。</p>\n</blockquote>\n\n<h2 id=\"モジュールのインストール\">モジュールのインストール</h2>\n\n<p>必要なモジュール類をインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgfortran-6-dev\npip <span class=\"nb\">install </span>numpy\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h2 id=\"ワークディレクトリ\">ワークディレクトリ</h2>\n\n<p>色々共通で使いたいサイズのでっかいファイルがあるので、ワークディレクトリを以下の構成で作成しておく。<br />\n以降のopenVINO関連の投稿もこのディレクトリ構成を使うようにする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># C++プログラム湯尾</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++\n<span class=\"c\"># pythonプログラム用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/python\n<span class=\"c\"># モデルデータ用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP16\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP32\n</code></pre></div></div>\n\n<h1 id=\"参考\">参考</h1>\n\n<p><del>パクった</del> 参考にしたのは以下のあたり<br />\n解説や実行方法などはこっちを参照してちょ(相変わらずの他力本願ぶり…))</p>\n\n<ul>\n  <li><a href=\"http://jellyware.jp/openvino/\">JELLYWARE ゼロから学ぶディープラーニング推論</a>\n    <ul>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c07_ie_emotion.html\">Inference Engineを学んで感情分類</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c08_face_detection.html\">リアルタイム顔検出</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c09_emotion_app.html\">リアルタイム感情分析アプリ</a></li>\n    </ul>\n  </li>\n</ul>\n\n<p>顔検出+感情分類の参照元はカメラキャプチャした画像を処理しているけど、手元に適当なカメラがなかったので、JPEGファイルで実行するようにしてある(こっちの方が余計な処理なくて分かりやすいかな、と思ったのもある)。</p>\n\n<h1 id=\"感情分類\">感情分類</h1>\n\n<p>感情分類のプログラムを試す。</p>\n\n<h3 id=\"準備\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/emotions-recognition-retail-0003/FP16/emotions-recognition-retail-0003\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する顔画像(顔部分のみ切り出し)をPHOTO/face.jpgとして保存しておく。</p>\n\n<h3 id=\"プログラム\">プログラム</h3>\n\n<p>試したソースはこちら。<br />\nPCのubuntuで実行するための処理も追加済み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/face.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 結果取り出し\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>\n<span class=\"c1\"># 結果の最大値を持つインデックスを取得\n</span><span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 結果表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">結果'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">index_max</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"c1\"># 結果の詳細表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">詳細'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'スコア:</span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出\">顔検出</h1>\n\n<p>顔検出のプログラムを試す。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-1\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-1\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n\n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-1\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_detect.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_detect.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_detect.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出感情分類\">顔検出+感情分類</h1>\n\n<p>上の2つを合体させ、顔検出した結果に感情分類を実行する。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-2\">準備</h3>\n\n<p>モデルデータは上の2つをそのまま使用。</p>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-2\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出 + 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n# 日本語表示にはPillow使うとかしないといけないので、英語で。\n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# バウンティングボックスとラベルを表示する関数\n</span><span class=\"k\">def</span> <span class=\"nf\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ラベル領域サイズ\n</span>    <span class=\"n\">LABEL_W</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">12</span>    <span class=\"c1\"># 等幅フォントじゃないので正確ではないけど、大体こんな感じ\n</span>    <span class=\"n\">LABEL_H</span> <span class=\"o\">=</span> <span class=\"mi\">14</span>                <span class=\"c1\"># こっちもトライアンドエラーで微調整\n</span>    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">IMAGE_W</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">IMAGE_H</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># バウンディングボックス表示 \n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ラベル表示位置(X)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">IMAGE_W</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">IMAGE_W</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_W</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">xmin</span>\n    \n    <span class=\"c1\"># ラベル表示位置(Y)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span>\n    \n    <span class=\"c1\"># 文字列背景描画(塗りつぶし)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">label_x</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 文字列描画(座標は文字の左下)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX_SMALL</span><span class=\"p\">,</span> <span class=\"mf\">0.8</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n    \n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。特にminは補正しないとエラーになる\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 顔領域のみ切り出し \n</span>    <span class=\"n\">frame_face</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">[</span> <span class=\"n\">ymin</span><span class=\"p\">:</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">:</span><span class=\"n\">xmax</span> <span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 入力データフォーマットへ変換 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame_face</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span>   <span class=\"c1\"># サイズ変更 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">img_face</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img_face</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>    \n    <span class=\"c1\"># 推論実行 \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img_face</span><span class=\"p\">})</span>\n    \n    <span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>    \n    <span class=\"c1\"># 出力値が最大のインデックスを得る \n</span>    <span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"c1\"># print(list_emotion[index_max])\n</span>    <span class=\"n\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-2\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<h1 id=\"考察\">考察</h1>\n\n<p>基本パターンはこんな感じ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># モジュールのロード\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># 初期化\n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"s\">\"MYRIAD\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み\n</span><span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"s\">'xmlファイル'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"s\">'binファイル'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 推論実行 \n# imgは入力データ、Numpy配列 ndarray型\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># outが出力データ、Numpy配列 ndarray型\n</span>\n</code></pre></div></div>\n\n<p>入出力データの並びは読み込んだモデルに依存する。<br />\n入力データのサイズやRGB並び順などを合わせる。<br />\n(モデルに入力する際にリサイズすれば、元の画像ファイルのサイズは任意で良い。)<br />\n出力データはそのままでは「何のこっちゃ?」なので、きちんと整形してやる必要がある。</p>\n\n<p>ここに学習済みデータが色々登録されているらしい。<br />\n<a href=\"https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html\">https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html</a></p>\n\n<p>TensorflowやCaffeで作成した学習済みデータを変換することもできるらしいが、やり方はこれから調査。</p>\n\n<h1 id=\"参考情報\">参考情報</h1>\n<p><a href=\"https://software.intel.com/en-us/articles/OpenVINO-RelNotes\">openVINO toolkit リリースノート</a><br />\n<a href=\"https://git.uni-paderborn.de/rnagle/dldt/tree/noctua_plugin_develop\">openVINO toolkit リポジトリ</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その9)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その9)</h1>\n      <p>Node-REDのメモ 応用編 Google spreadsheet Read</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGoogle spreadsheet からデータを取得したときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><strong>その8</strong> に従って準備済みであるものとする。</p>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で作成済みの認証情報を選択するか、「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に操作対象のスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:zzz」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n          <li>Rangeのフォーマットはシート名!開始セル:終了セル\n            <ul>\n              <li>開始セルと終了セルを両方省略することは可能(片方のみ省略は不可のよう)。<br />\nこの場合、シート全体が取得される。ただし、↑のように特定のシート名はダメかもしれない。</li>\n              <li>開始セル/終了セルはカラム名と行番号で構成されるが、カラム名か行番号は省略可能。\nたぶん、こんな感じ。\n                <ul>\n                  <li>開始カラム名を省略するとAが指定されたとみなす</li>\n                  <li>開始行番号を省略すると1が指定されたとみなす</li>\n                  <li>終了カラム名を省略すると最終カラム(zzz?)が指定されたとみなす</li>\n                  <li>終了行番号を省略すると最終行が指定されたとみなす</li>\n                </ul>\n              </li>\n              <li>大きな範囲を指定しても、以降空白セルであった場合は無視される(有効なデータがある範囲だけ読み込まれる)</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n          <li>プロパティ名はシート名_開始セル_終了セル</li>\n          <li>globalに記録しておけば、キャッシュとして使用出来て、なんども同じデータを読まなくて済む、という使い方かな?</li>\n        </ul>\n      </li>\n      <li>\n        <p>「Action」に「Get Data」を選択し、その右は「By line」を選択</p>\n      </li>\n      <li>「Labels」の「First line for labels」を選択しすると、outputの型がDictionaryになる。指定したセル範囲の開始カラム(シート全体の開始カラムではない)がキー名となる。<br />\n 選択しなければ、outputの型がArrayになる</li>\n      <li>「Labels」の「First column for labels」を選択しすると、outputの各要素の型がDictionaryになる。指定したセル範囲の開始行(シート全体の開始行ではない)の内容がキー名となる。<br />\n 選択しなければ、outputの各要素の型がArrayになる</li>\n      <li>\n        <p>この2つ、なんか逆な気もするけど…</p>\n      </li>\n      <li>outputにリード結果が入る。とりあえず「msg」を選択し、「_output」にしておく\n内容は「Labels」の設定内容によって変わる</li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>設定内容と取得内容の関係はよくワカランので、色々試してみてください。<br />\n現実的には、細かくデータを取得してどうこうするより、シート全体を取得して処理するような使い方になるのかな??</p>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、スプレッドシートの内容が取得されるハズ。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"5eb2475f.ea747\",\n        \"type\": \"tab\",\n        \"label\": \"spreadsheet_read\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"60d62f37.80a8a\",\n        \"type\": \"inject\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"bba510f2.5bb2d8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e183b4f0.c372f\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"37bd743e.1ca96c\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"bba510f2.5bb2d8\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"spreadsheet read\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:zzz\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"get\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": true,\n        \"fields\": \"all\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"\",\n        \"output\": \"_output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 290,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"e183b4f0.c372f\"\n            ],\n            [\n                \"37bd743e.1ca96c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その8)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その8)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Google spreadsheet</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをGoogle spreadsheet に記録するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"google-spreadsheet用ノードのインストール\">Google spreadsheet用ノードのインストール</h2>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-contrib-viseo-google-」と入力</li>\n  <li>下に検索結果が出るので、「node-red-contrib-viseo-google-authentication」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら続けて「node-red-contrib-viseo-google-spreadsheet」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h2 id=\"googleの準備\">Googleの準備</h2>\n\n<p><a href=\"https://techblog.lclco.com/entry/2018/11/30/120000\">具体的な手順はこちらを参考にしてくだされ。</a> (コードの実装の手前まで)  <br />\nただし、<span style=\"color: red; \">有効にするAPI</span>は「Google Drive API」ではなく、「<span style=\"color: red; \">Google Sheets API</span>」なので、注意!!</p>\n\n<h3 id=\"認証情報の作成\">認証情報の作成</h3>\n\n<ul>\n  <li><a href=\"https://console.developers.google.com/project\">Google Developers Console</a> でプロジェクトを作成</li>\n  <li>Google Sheets APIを有効化</li>\n  <li>認証情報(サービスアカウント キー)を作成</li>\n  <li>保存された認証情報の秘密鍵をダウンロード<br />\n  このファイルはセキュリティ上 <strong>超重要</strong> なので、まちがって公開しないように!!!!<br />\n  ・・・・公開して後悔…なんちゃって(^^ゞ</li>\n</ul>\n\n<h3 id=\"記録用スプレッドシートの作成\">記録用スプレッドシートの作成</h3>\n\n<ul>\n  <li><a href=\"https://drive.google.com/drive/u/0/my-drive\">Google Drive</a>から記録するスプレッドシートを作成する(マイドライブからgoogleスプレッドシートを選択すると新規ファイルが作成される)</li>\n  <li>作成されたスプレッドシートに共有ユーザ(サービスアカウントキーのメールアドレス)を追加。権限を編集者、通知のチェックははずしてOKする</li>\n  <li>必要ならシートの追加や名前の変更を行っておく(以下ではシート名が「BME280」になっているものとして説明)</li>\n  <li>1行目に項目名を入れておく。ここではA列から「epoch」「日付」「温度」「湿度」「気圧」としている</li>\n  <li>B列(「日付」の列)を選択し、メニューから「表示形式」→「数値」→「日時」を選択(これをやらないと時刻が見えない))</li>\n  <li>作成されたスプレッドシートのID(URLの docs.google.com/spreadsheets/d/<span style=\"color: red; \">この部分</span>/edit~)をメモしておく</li>\n</ul>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"bme280ノード\">BME280ノード</h3>\n\n<ul>\n  <li><strong>その2</strong>の<strong>BME280を使用するフローを作成する</strong>と同様の手順でBME280ノードを作成する</li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>出力側にFunctionノードを接続\n  コードは以下。<br />\n  あとで時刻を使用しやすいようにエポック時刻で記録するようにしている。<br />\n  また、エポック時刻のままだとスプレッドシーで見たときに日時が分かり難いので、エポック時刻から日時に変更する計算式を入れておく。(ここで直接文字列にすることもできるが)<br />\n  また、Google Sheetsノードの入力はArrayである必要があるようで、Ayyayでラップしておく。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">var</span> <span class=\"nx\">date</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">epoch</span> <span class=\"o\">=</span> <span class=\"nx\">date</span><span class=\"p\">.</span><span class=\"nx\">getTime</span><span class=\"p\">();</span>\n<span class=\"c1\">// msg.payload.date  = date.toString();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">date</span>  <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">=indirect(\"R[0]C[-1]\", false) / (1000*60*60*24) + (9/24) + DATE(1970, 1, 1)</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">];</span>\n\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に上でメモっておいたスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:z」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>set dataのときは使用されないようだ</li>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n        </ul>\n      </li>\n      <li>「Action」に「Set Data」を選択し、その右は「Append」を選択</li>\n      <li>「input」は「msg」を選択し、「payload」を入力</li>\n      <li>「Fields」で「Select」を選択</li>\n      <li>その下に「key」と入力欄が表示されるので、「epoch」と入力し、「追加」をクリック</li>\n      <li>「date」と入力し、「追加」をクリック</li>\n      <li>「temperature_C」と入力し、「追加」をクリック</li>\n      <li>「humidity」と入力し、「追加」をクリック</li>\n      <li>「pressure_hPa」と入力\n        <ul>\n          <li>このデータの並びが入力のプロパティ名とスプレッドシートのセルの並びに対応する</li>\n        </ul>\n      </li>\n      <li>outputもよー分からんけど、とりあえず「msg」を選択し、「_output」にしておく\n        <ul>\n          <li>set dataのときは処理結果が入るようだ</li>\n          <li>get dataのときはリード結果が入るようだ</li>\n        </ul>\n      </li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>このノードの入力にファンクションノードの出力を接続</li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、温度等を測定、スプレッドシートに送信される。<br />\nスプレッドシートを確認すれば、そのデータが記録されているハズである。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1a4f21c6.53e09e\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+spreadsheet\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"b4e73f33.99aec8\",\n        \"type\": \"Bme280\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 220,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"a54ed898.2a114\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"b74c37d3.63a48\",\n        \"type\": \"inject\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 90,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"b4e73f33.99aec8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a54ed898.2a114\",\n        \"type\": \"function\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"データ整形\",\n        \"func\": \"var date = new Date();\\nmsg.payload.epoch = date.getTime();\\n// msg.payload.date  = date.toString();\\n// msg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\",false)/1000/60/60/24 + 9/24 + DATE(1970,1,1)';\\nmsg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\", false) / (1000*60*60*24) + (9 / 24) + DATE(1970, 1, 1)';\\n\\nmsg.payload = [msg.payload];\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 390,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"6a4f8cc4.882e54\",\n                \"adad9a.88697a68\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6a4f8cc4.882e54\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:z\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"set\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": false,\n        \"fields\": \"select\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"epoch\",\n            \"date\",\n            \"temperature_C\",\n            \"humidity\",\n            \"pressure_hPa\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"payload\",\n        \"output\": \"__output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 620,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"93209cb1.cd86\"\n            ],\n            [\n                \"9a8717a8.88bae8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"93209cb1.cd86\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9a8717a8.88bae8\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 220,\n        \"wires\": []\n    },\n    {\n        \"id\": \"adad9a.88697a68\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 850,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node.jsでGoogle spreadsheet にデータを書き込む</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node.jsでGoogle spreadsheet にデータを書き込む</h1>\n      <p>Node.jsでGoogle spreadsheet にデータを書き込む</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Node.jsでGoogle spreadsheet にデータを書き込む方法。<br />\nサンプルプログラムを<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>に置きました。</p>\n\n<p>Google Drive API を サービスアカウントで操作する方法を取りました。</p>\n\n<p>OAuth認証を使う方法は事前準備がめんどっちいので、パス。<br />\nAPIキー認証はリードはできたけど、ライトが出来んかった。あと、シートを公開しないといけないが、やな感じだった。</p>\n\n<h1 id=\"詳細\">詳細</h1>\n\n<p>詳細は\n<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>\nのREADME おひび ソースコードを参照してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その7)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その7)</h1>\n      <p>Node-REDのメモ 応用編 GPIO+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIOの入出力データをWebsocketで飛ばして、Dashboardから操作/Dashboardで表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"gpio入出力データをwebsocketで送受信raspberrypi\">GPIO入出力データをWebsocketで送受信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>RaspberryPiでGPIO出力</strong>、<strong>RaspberryPiでGPIO入力</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>、<strong>Websocketでデータを受信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、GPIO入力データをそのまま送信すると、受け取り側で「0はON?それともOFF?」となってしまうので、GPIO入力の0/1をON/OFFの文字列に変換するファンクションノードを追加している。\n  また、GPIO出力側も同様に、送信側から送られてきたON/OFFの文字列をGPIO出力データの1/0の数値に変換するファンクションノードを挿入している。<br />\n  ターゲットボードの正論理/負論理が変更になった場合はこれらのファンクションノードで調整すれば良い。</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"6e229d5a.774af4\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"109b9bce.e015e4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 730,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4834db5b.5c24d4\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": true,\n        \"x\": 190,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"3ff59514.52c732\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7d90bda.d7b4b8\",\n        \"type\": \"websocket in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"47e24d88.c603e4\",\n        \"x\": 280,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"a38bd8a1.0a5bd8\",\n                \"5e99ea44.cfdac4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9bc37a7.e1e9808\",\n        \"type\": \"websocket out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"c4985621.1edb48\",\n        \"x\": 830,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"a38bd8a1.0a5bd8\",\n        \"type\": \"debug\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 730,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3ff59514.52c732\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"1/0→OFF/ON\",\n        \"func\": \"if (msg.payload) {\\n    msg.payload = 'OFF';\\n}\\nelse {\\n    msg.payload = 'ON';\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"9bc37a7.e1e9808\",\n                \"a38bd8a1.0a5bd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5e99ea44.cfdac4\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"OFF/ON→0/1\",\n        \"func\": \"if (msg.payload == 'OFF') {\\n    msg.payload = 0;\\n}\\nelse {\\n    msg.payload = 1;\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"109b9bce.e015e4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47e24d88.c603e4\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/led0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"c4985621.1edb48\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/sw0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからgpio入出力データを送受信サーバ\">WebsocketからGPIO入出力データを送受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータ送信(サーバ)</strong>、<strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノードに<strong>その4</strong> の <strong>Dashboard のUIを作成する(ボタン)</strong>、<strong>Dashboardでテキストを表示する</strong>で作成したノードを接続すれば良い。</li>\n</ul>\n\n<p>この状態でRaspberryPi側でスイッチをON/OFFすると、Dashboardの「SW」の文字列のON/OFFが切り替わる。\nまた、DashboardのLLED_ON/LED_OFFのボタンをクリックすると、LEDが点灯/消灯する</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"ca6a740f.4d43b8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_GPIO\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"ac19aeee.9f8f5\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 260,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"2098e31e.e6832c\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 270,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8db70b6.86a1178\",\n        \"type\": \"ui_text\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 610,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f45af19.269e\",\n        \"type\": \"websocket in\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"fad64a63.6141a\",\n        \"client\": \"\",\n        \"x\": 270,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"8db70b6.86a1178\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"299e8287.226e6e\",\n        \"type\": \"websocket out\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"d7b33218.4a1f28\",\n        \"client\": \"\",\n        \"x\": 630,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"95b08556.d2cce\",\n        \"type\": \"debug\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 610,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"b7e42e0e.52bdb\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"1b4acf7b.a194c9\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"fad64a63.6141a\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/sw0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"d7b33218.4a1f28\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/led0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"1b4acf7b.a194c9\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ3\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian SDカードイメージファイルの縮小</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian SDカードイメージファイルの縮小</h1>\n      <p>Raspbian SDカードイメージファイルの縮小</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2020/10/25/Jetson_nano_backup.html\">Jetson nano のSDカードをバックアップする</a> \nに改訂版を公開しました。そちらを参照してください。</p>\n\n<h1 id=\"イメージファイルの縮小\">イメージファイルの縮小</h1>\n\n<h3>『イメージファイルの縮小』はUbuntuで実行することを前提に書いてあります。</h3>\n\n<p>SDカードに作成した、RaspberryPiのオリジナルのカスタムブートディスク\n(<a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\">Raspbian Busterのインストール</a>、\n<a href=\"/memoBlog/2019/09/13/raspbian_buster_2.html\">Raspbian Buster Lite版のインストール</a>参照)\nは、イメージファイルにバックアップしておくと、\n再度カスタマイズ作業を行わなくても同じ環境を作成できる。</p>\n\n<p>ただ、このイメージファイルはSDカードを丸ごとファイル化するので、元のSDカードより小さなSDカードにコピーできない。<br />\n(スペック上同じ容量のSDカードでも微妙にサイズが違ったりするので入らないことがある)</p>\n\n<p>そこで、イメージファイルを縮小しておけば、小さなSDカードにもコピーできる(コピー時間も短縮できて一石二鳥)。<br />\nこのとき、ディスクイメージ内部のパーティション情報/ファイルシステム情報をきちんと縮小処理しておかないと\nファイルシステムエラーになってしまうので、注意が必要。</p>\n\n<p>今回はSDカードから作成したイメージファイルを<strong>Ubuntuで</strong>縮小処理するスクリプトを書いてみた。<br />\nとりあえず、手元の環境では動いているが、詳細評価したわけではないので、\n実行する場合は自己責任で。</p>\n\n<p>また、途中<strong>エラーチェックは行っていない</strong>ので、エラーが発生していないか、実行結果を注意深く確認すること。</p>\n\n<h2 id=\"virtualbox-共有フォルダのマウント\">Virtualbox 共有フォルダのマウント</h2>\n\n<p>SDカードのイメージファイルは大きいので、共有フォルダを使ってWindows側のフォルダをアクセスできるようにしておけばディスク領域を圧迫しなくて済む。<br />\nVirtualbox側で共有フォルダ「Share」を作成済みで、/Shareディレクトリにマウントする場合は以下のコマンドで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> vboxsf Share /Share/\n</code></pre></div></div>\n\n<h2 id=\"ツールのインストール\">ツールのインストール</h2>\n\n<p>イメージファイル内のパーティションをそれぞれloopデバイスに割り当てるツールを使用する。<br />\n以下のコマンドでインストールできる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>kpartx\n</code></pre></div></div>\n\n<h2 id=\"スクリプト\">スクリプト</h2>\n\n<p>以下のスクリプトを適当な名前(例えば<code class=\"language-plaintext highlighter-rouge\">shrink_img.sh</code>)で保存し、実行する(<code class=\"language-plaintext highlighter-rouge\">bash shrink_img.sh</code>)。<br />\n実行する前に使用するファイル名を設定すること。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: left\">変数</th>\n      <th style=\"text-align: left\">内容</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: left\">WORK_IMG_FILE</td>\n      <td style=\"text-align: left\">作業用イメージファイルのファイル名</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: left\">NEW_IMG_FILE</td>\n      <td style=\"text-align: left\">小さくしたイメージファイルのファイル名</td>\n    </tr>\n  </tbody>\n</table>\n\n<p>WORK_IMG_FILE で指定したファイルは書き変えられるので、オリジナルのイメージファイルは 別途残しておくこと。</p>\n\n<p>内部で<code class=\"language-plaintext highlighter-rouge\">sudo</code>を実行しているので、パスワードを聞かれたら入力する。</p>\n\n<p>途中、『警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?』と聞かれたら「y」を入力する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># イメージファイル</span>\n<span class=\"nv\">WORK_IMG_FILE</span><span class=\"o\">=</span>/Share/tmp.img            <span class=\"c\"># 作業ファイル</span>\n<span class=\"nv\">NEW_IMG_FILE</span><span class=\"o\">=</span>/Share/shrink.img          <span class=\"c\"># 縮小した(作成する)ファイル</span>\n\n<span class=\"c\"># イメージファイルをマッピング(マッピング済みでも問題ない) </span>\n<span class=\"c\"># 前回の操作が終わるのを待つため-sを付けておく</span>\n<span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-asv</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span>\n\n<span class=\"c\"># loopデバイス名を取得</span>\n<span class=\"c\"># 前回の操作が終わるのを待つため-sを付けておく</span>\n<span class=\"nv\">tmp_var</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-ls</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">LOOP_DEV</span><span class=\"o\">=</span>/dev/mapper/<span class=\"k\">${</span><span class=\"nv\">tmp_var</span><span class=\"p\">[6]</span><span class=\"k\">}</span>          <span class=\"c\"># 結果の位置は決め打ちで(姑息だけど)</span>\n\n<span class=\"c\"># 要求するブロックサイズの取得</span>\n<span class=\"nv\">tmp_var</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>resize2fs <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">req_fs_block</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">tmp_var</span><span class=\"p\">[-1]</span><span class=\"k\">}</span>                 <span class=\"c\"># サイズは結果の最後に入っている</span>\n\n<span class=\"c\"># パーティション情報の取得</span>\n<span class=\"nv\">part_info</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>parted <span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> unit B print<span class=\"sb\">`</span>\n<span class=\"c\"># 1行毎に分割</span>\n<span class=\"nv\">line</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">part_info</span><span class=\"p\">//;/ </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># ext4のパーティション番号を探す</span>\n<span class=\"nv\">part_number</span><span class=\"o\">=</span>0\n<span class=\"nv\">part_start</span><span class=\"o\">=</span>0\n<span class=\"nv\">target_type</span><span class=\"o\">=</span><span class=\"s2\">\"ext4\"</span>\n<span class=\"k\">for </span>l <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span> <span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各要素に分割</span>\n    <span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">l</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n    <span class=\"nv\">elm_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[0]</span><span class=\"k\">}</span>             <span class=\"c\"># パーティション番号</span>\n    <span class=\"nv\">elm_start</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[1]//B/</span><span class=\"k\">}</span>          <span class=\"c\"># ついでに最後のBを取り除いておく</span>\n    <span class=\"nv\">elm_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>               <span class=\"c\"># ファイルシステムタイプ</span>\n    <span class=\"c\"># echo $elm_number $elm_start $elm_type</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n        if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n            <span class=\"c\"># 対象のパーティションが見つかった</span>\n            <span class=\"nv\">part_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_number</span><span class=\"k\">}</span>\n            <span class=\"nv\">part_start</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_start</span><span class=\"k\">}</span>\n            <span class=\"nb\">break\n        </span><span class=\"k\">fi\n    fi\ndone\nif</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"o\">=</span> 0 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"s2\">\"のパーティションが見つかりませんでした\"</span>\n<span class=\"k\">else</span>\n    <span class=\"c\"># 新しいパーティション終了位置を計算</span>\n    <span class=\"nv\">new_fs_block</span><span class=\"o\">=</span><span class=\"k\">$((</span>req_fs_block <span class=\"o\">+</span> <span class=\"m\">100000</span><span class=\"k\">))</span>             <span class=\"c\"># 少し余裕(100000block=390MB)を持たせる</span>\n    <span class=\"nv\">new_fs_byte</span><span class=\"o\">=</span><span class=\"k\">$((</span>new_fs_block <span class=\"o\">*</span> <span class=\"m\">4096</span><span class=\"k\">))</span>                <span class=\"c\"># byteに換算</span>\n    <span class=\"nv\">part_end</span><span class=\"o\">=</span><span class=\"k\">$((</span>part_start <span class=\"o\">+</span> new_fs_byte <span class=\"o\">+</span> <span class=\"m\">2048</span><span class=\"k\">))</span>       <span class=\"c\"># さらに少し余裕を持たせる</span>\n    <span class=\"nv\">img_size_mb</span><span class=\"o\">=</span><span class=\"k\">$((</span><span class=\"o\">(</span>part_end <span class=\"o\">/</span> <span class=\"o\">(</span><span class=\"m\">1024</span> <span class=\"o\">*</span> <span class=\"m\">1024</span><span class=\"k\">))</span> + 10<span class=\"o\">))</span>    <span class=\"c\"># MBに換算 ついでにしつこいくらいに余裕を持たせる </span>\n\n    <span class=\"nb\">set</span> <span class=\"nt\">-x</span>          <span class=\"c\">#--------------------------------------</span>\n\n    <span class=\"c\"># ファイルシステムとパーティションの縮小</span>\n    <span class=\"nb\">sudo </span>e2fsck <span class=\"nt\">-f</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span> \n    <span class=\"nb\">sudo </span>resize2fs <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">new_fs_block</span><span class=\"k\">}</span>\n    parted <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> unit B resizepart <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">part_end</span><span class=\"k\">}</span>\n\n    <span class=\"c\"># 縮小コピー</span>\n    <span class=\"nb\">dd </span><span class=\"k\">if</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> <span class=\"nv\">of</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">NEW_IMG_FILE</span><span class=\"k\">}</span> <span class=\"nv\">count</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">img_size_mb</span><span class=\"k\">}</span> <span class=\"nv\">bs</span><span class=\"o\">=</span>1M\n\n    <span class=\"nb\">set</span> +x          <span class=\"c\">#--------------------------------------</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># マッピング解除</span>\n<span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-d</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span>\n \n</code></pre></div></div>\n\n<h1 id=\"新しいイメージファイルでブートsdを作る\">新しいイメージファイルでブートSDを作る</h1>\n\n<p>縮小したイメージファイルから作成したSDカードはSDカードの容量をすべて使用できるようになっていない。<br />\nそこで、コピーしたSDカードでブートした後、パーティションを拡張する必要がある。</p>\n\n<h2 id=\"sdカードへの書き込みは通常通り\">SDカードへの書き込みは通常通り</h2>\n\n<h2 id=\"書き込んだsdカードでブートする\">書き込んだSDカードでブートする</h2>\n\n<h2 id=\"sdカードのパーティション拡張\">SDカードのパーティション拡張</h2>\n\n<p>色々手順がめんどっちいので、スクリプト作成してみた。<br />\nとりあえず、手元の環境では動いているが、詳細評価したわけではないので、\n実行する場合は自己責任で。</p>\n\n<p>以下のスクリプトを適当な名前(例えば<code class=\"language-plaintext highlighter-rouge\">expand_partition.sh</code>)で保存し、実行する(<code class=\"language-plaintext highlighter-rouge\">bash expand_partition.sh</code>)<br />\n成功したらリブートすること。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># ターゲットのデバイス</span>\n<span class=\"nv\">target_device</span><span class=\"o\">=</span>/dev/mmcblk0\n\n<span class=\"c\"># パーティション情報の取得</span>\n<span class=\"nv\">part_info</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>parted <span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span> unit s print free<span class=\"sb\">`</span>\n\n<span class=\"c\"># 1行毎に分割</span>\n<span class=\"nv\">line</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">part_info</span><span class=\"p\">//;/ </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 最終行</span>\n<span class=\"c\"># declare -i last_index=${#line[@]}-1</span>\n<span class=\"c\"># last_line=${line[$last_index]}</span>\n<span class=\"nv\">last_line</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[</span><span class=\"k\">$((${#</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span><span class=\"o\">-</span><span class=\"m\">1</span><span class=\"k\">))</span><span class=\"p\">]</span><span class=\"k\">}</span>\n\n<span class=\"c\"># :で区切られた各要素に分割</span>\n<span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">last_line</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 変数名付け替え</span>\n<span class=\"c\"># last_number=${elm[0]}</span>\n<span class=\"c\"># last_start=${elm[1]}</span>\n<span class=\"nv\">last_end</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[2]</span><span class=\"k\">}</span>\n<span class=\"c\"># last_size=${elm[3]}</span>\n<span class=\"nv\">last_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>\n\n<span class=\"c\"># 確認</span>\n<span class=\"c\"># echo last_number=  $last_number</span>\n<span class=\"c\"># echo last_start=   $last_start</span>\n<span class=\"c\"># echo last_end=     $last_end</span>\n<span class=\"c\"># echo last_size=    $last_size</span>\n<span class=\"c\"># echo last_type=    $last_type</span>\n\n<span class=\"c\"># 最後のパーティションがfreeか確認</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">last_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> free <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># ext4のパーティション番号を探す</span>\n    <span class=\"nv\">part_number</span><span class=\"o\">=</span>0\n    <span class=\"nv\">target_type</span><span class=\"o\">=</span><span class=\"s2\">\"ext4\"</span>\n    <span class=\"k\">for </span>l <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span> <span class=\"p\">;</span> <span class=\"k\">do</span>\n        <span class=\"c\"># 各要素に分割</span>\n        <span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">l</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n        <span class=\"nv\">elm_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[0]</span><span class=\"k\">}</span>\n        <span class=\"nv\">elm_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n            <span class=\"c\"># echo $elm_number $elm_type</span>\n            <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n                </span><span class=\"nv\">part_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_number</span><span class=\"k\">}</span>\n                <span class=\"nb\">break\n            </span><span class=\"k\">fi\n        fi\n    done\n    if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"o\">=</span> 0 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"ext4のパーティションが見つかりませんでした\"</span>\n    <span class=\"k\">else</span>\n        <span class=\"c\"># リサイズの実行</span>\n        <span class=\"nb\">set</span> <span class=\"nt\">-x</span>\n        <span class=\"nb\">sudo </span>parted <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span> resizepart <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">last_end</span><span class=\"k\">}</span>\n        <span class=\"nb\">sudo </span>resize2fs <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span>p2\n        <span class=\"nb\">set</span> +x\n        <span class=\"nb\">echo</span> <span class=\"s2\">\"リブートしてください\"</span>\n    <span class=\"k\">fi\nelse\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"最終パーティションがfreeではありません\"</span>\n<span class=\"k\">fi</span>\n \n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian Buster Lite版のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian Buster Lite版のインストール</h1>\n      <p>Raspbian Buster with desktopのインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspbian Buster Lite」 の 「DownloadZIP」でダウンロードする。<br />\n以下の手順は、RaspberryPi Zero W、「Version: July 2019」 で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>は表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nframebuffer_width=1280\nframebuffer_height=720\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"ロケールやらタイムゾーンやらの設定\">ロケールやらタイムゾーンやらの設定</h1>\n\n<p>日本語表示や時刻を日本時間に設定するための設定を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    4 Localisation Options\n        I1 Change Locale\n            [ ] ja_JP.UTF-8 UTF-8     でスペースを押して[*] にする\n            TABを押して<Ok>を選んでリターン\n                Default locale for~ と聞かれるので、\n                ja_JP.UTF-8          を選択\n                TABを押して<Ok>を選んでリターン\n    4 Localisation Options\n        I2 Change Timezon\n            Asia\n                Tokyo\n    <Finish>\n</code></pre></div></div>\n\n<p>設定変更を有効にするにはrebootが必要。</p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"c\"># export PYENV_ROOT=/proj/.pyenv</span>\n<span class=\"c\"># export PATH=$PYENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(pyenv init -)\"</span>\n<span class=\"c\"># eval \"$(pyenv virtualenv-init -)\"</span>\n\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"c\"># export NODENV_ROOT=/proj/.nodenv</span>\n<span class=\"c\"># export PATH=$NODENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(nodenv init -)\"</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nSSHなら関係ないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"hdmiコンソール用日本語入力表示環境構築\">HDMIコンソール用日本語入力&表示環境構築</h1>\n\n<p>デフォルトのままだと、HDMIコンソールは日本語の入力はおろか、表示もできない。<br />\nそこで、日本語入力&表示環境を整備する。<br />\nHDMIコンソールで日本語を使わないなら本章は設定不要。</p>\n\n<h2 id=\"フォントのインストール\">フォントのインストール</h2>\n\n<p>フォントをインストールしないと表示できないのでまずはフォントのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk \n</code></pre></div></div>\n\n<h2 id=\"ターミナルエミュレータのインストール\">ターミナルエミュレータのインストール</h2>\n\n<p>デフォルトのターミナルは日本語を表示できないので、日本語対応のターミナルエミュレータを使う。<br />\nネット上にはjfbtermを使用する記事が多いが、jfbtermはイマイチらしいのでfbtermを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fbterm\n</code></pre></div></div>\n\n<h2 id=\"日本語変換システムのインストール\">日本語変換システムのインストール</h2>\n\n<p>日本語入力のためのプログラム。Windowsで言うところのMS-IMEやATOKに相当するもの。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>uim-fep uim-anthy\n</code></pre></div></div>\n\n<h2 id=\"fbtermの設定\">fbtermの設定</h2>\n\n<p>fbtermの設定は、 ~/.fbtermrc で行う。<br />\n<strong>HDMIコンソールから</strong> fbtermを一度起動すると ~/.fbtermrc ができるので、設定変更するときはこれを書き換える。<br />\n例えばこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>font-size<span class=\"o\">=</span>18\n</code></pre></div></div>\n\n<p>fbtermを起動したときに<code class=\"language-plaintext highlighter-rouge\">[input] can’t change kernel keymap table ~</code>と表示されるときは以下を実行すると良い。(表示されるだけで実害はないらしい)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>setcap <span class=\"s1\">'cap_sys_tty_config+ep'</span> /usr/bin/fbterm\n</code></pre></div></div>\n\n<p>または、以下でも良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chmod </span>u+s /usr/bin/fbterm\n</code></pre></div></div>\n\n<p>参考: <a href=\"https://qiita.com/mtomoaki_96kg/items/e5a946fd38f7318d3758?fbclid=IwAR2d8ekXNiD9cqvpqycdfinDZMHZ0OcTmaETTsci1UA9T-aDtc3LvfOiaa0\">https://qiita.com/mtomoaki_96kg/items/e5a946fd38f7318d3758?fbclid=IwAR2d8ekXNiD9cqvpqycdfinDZMHZ0OcTmaETTsci1UA9T-aDtc3LvfOiaa0</a></p>\n\n<h2 id=\"uim日本語変換システムの設定\">uim(日本語変換システム)の設定</h2>\n\n<p>uimでCTRL+SPACEでFEPの切り替えの設定。\n~/.uim に以下の内容を記述(なければ新規作成)。<br />\n参考: <a href=\"https://qiita.com/tukiyo3/items/376e3a2895a71ff9bfc7\">https://qiita.com/tukiyo3/items/376e3a2895a71ff9bfc7</a></p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>(define default-im-name 'anthy)\n(define-key generic-on-key? '(\"<Control> \" \"`\"))\n(define-key generic-off-key? '(\"<Control> \" \"`\"))\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n各行のシングルクォーテーションは1個だけ。文字列として区切っている訳ではない。<br />\n余計なシングルクォーテーションを入れると動かなくなるので注意!!</p>\n</blockquote>\n\n<h2 id=\"起動時にfbtermを起動する\">起動時にfbtermを起動する</h2>\n\n<p>起動時にfbtermを起動するには以下を ~/.profile 、 ~/.bashrc に追加</p>\n\n<h3 id=\"profile\">~/.profile</h3>\n\n<p>最後に以下の内容を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"o\">=</span> <span class=\"s2\">\"linux\"</span> <span class=\"o\">]</span>\n<span class=\"k\">then</span>\n<span class=\"c\">#   FBTERM=1 exec fbterm -- uim-fep</span>\n   <span class=\"nv\">FBTERM</span><span class=\"o\">=</span>1 fbterm <span class=\"nt\">--</span> uim-fep\n   <span class=\"nb\">exit\n</span><span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<p>本当はコメントアウトされてる方の exec を使うようにしないといけないが、現状うまく動かないらしい。<br />\n(Strechでは動いていたと思う)<br />\n仕方ないので、fbtermをbashの子プロセスとして実行するようにしてある。<br />\nこれだとうまく動いている(当然、メモリ消費量は増えるけど)。</p>\n\n<p>また、ログアウトの際にCTRL+Dを2回入力しないといけなくなる(fbtermからのexitとbashからのexit)のを回避するため、 fbterm終了時にexitコマンドを実行している。</p>\n\n<h3 id=\"bashrc\">~/.bashrc</h3>\n\n<p>最後に(でなくてもいいけど)、以下を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>linux<span class=\"p\">)</span>\n        <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$FBTERM</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"nb\">export </span><span class=\"nv\">TERM</span><span class=\"o\">=</span>fbterm\n        <span class=\"p\">;;</span>\n    fbterm<span class=\"p\">)</span>\n        <span class=\"c\"># 何もしない</span>\n        <span class=\"p\">;;</span>\n    <span class=\"k\">*</span><span class=\"p\">)</span>\n        <span class=\"c\"># 何もしない</span>\n        <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n</code></pre></div></div>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その6)</h1>\n      <p>Node-REDのメモ MQTT編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでMQTT通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"mqttでデータを送受信\">MQTTでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにmosquitto broker および mosquitto client toolsを使うこととします。<br />\nこれらは以下のコマンドでインストールできます。</p>\n\n<p>Ubuntuで動作確認。RaspberryPiでも大丈夫なはず。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mosquitto mosquitto-clients\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータ送信publish\">MQTTでデータ送信(Publish)</h2>\n\n<p>MQTTでデータを送信してみます</p>\n\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要なら「名前」を設定\n            <ul>\n              <li>省略するとサーバアドレスとポート番号が表示される</li>\n            </ul>\n          </li>\n          <li>「サーバ」 でブローカのアドレス(またはホスト名)を設定(例: PiDev25.local)</li>\n          <li>「ポート」 でポート番号を設定(一般的な設定なら1883のままで大丈夫)</li>\n          <li>SSL/TLS接続を使用する場合は「SSL/TLS接続を使用」のチェックを入れる</li>\n          <li>クライアントIDを指定したい場合は「クライアント」に設定。通常は空欄で大丈夫</li>\n          <li>キープアライブ時間を「キープアライブ時間」に設定</li>\n          <li>「セッションの初期化」?とりあえず初期設定のままで</li>\n          <li>「旧MQTT 3.1のサポート」?とりあえず初期設定のままで</li>\n          <li>「セキュリティ」タブ、「メッセージ」タブの内容は必要なら設定する。設定しなくても大丈夫</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に送信するトピックを設定\n        <ul>\n          <li>省略すると、トリガノードの出力に設定されているtopicが使用される</li>\n        </ul>\n      </li>\n      <li>「QoS」を「0」/「1」/「2」から選択</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される\n            <ul>\n              <li>トピックも省略されている場合はmqttと表示される</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のようにsubscriberコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> 《トピック》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカからすべてのトピック(“#”)を取得するよう指定しています。<br />\n-v 指定により、対象メッセージのトピックも表示されます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> Pidev25.local <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> <span class=\"s2\">\"#\"</span>\n</code></pre></div></div>\n<p>Node-RED側で mqttの送信をトリガするとmosquitto_subの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>test_data 0\ntest_data 1\ntest_data true\ntest_data false\ntest_data 文字列\ntest_data {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"f580f01a.f771f\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_publish\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"33450bad.82764c\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ea6d9236.74e038\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d7baa4c.08385\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"82148e63.4b97e\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d0b1ac7f.0ac0b\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7e6180b5.f29098\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"test_data\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6f26fe46.a01f58\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"バッファ\",\n        \"topic\": \"test_data\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 140,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d5a5b2db.83462\",\n        \"type\": \"debug\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 500,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"e6218cda.844308\",\n        \"type\": \"mqtt out\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"\",\n        \"qos\": \"\",\n        \"retain\": \"\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 570,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータを受信subscribe\">MQTTでデータを受信(subscribe)</h2>\n\n<p>MQTTでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に受信するトピックを設定\n        <ul>\n          <li>すべてのトピックを受信するには#を設定</li>\n          <li>省略することはできない</li>\n        </ul>\n      </li>\n      <li>「QoS」を設定</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>デプロイ後、ターミナル or コンソールで以下のようにpublisherコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-t</span> 《トピック》 <span class=\"nt\">-m</span> 《メッセージ》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカへ、トピック test_data で、メッセージ test を送信しています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> PiDev25.local <span class=\"nt\">-t</span> <span class=\"s2\">\"test_data\"</span> <span class=\"nt\">-m</span> <span class=\"s2\">\"test\"</span>\n</code></pre></div></div>\n\n<p>コマンドを実行するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"13f22fdd.2e009\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_subscribe\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1760f49a.fd2d3b\",\n        \"type\": \"debug\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 420,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"30229cea.13aba4\",\n        \"type\": \"mqtt in\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"#\",\n        \"qos\": \"2\",\n        \"datatype\": \"auto\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 150,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"1760f49a.fd2d3b\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>モバイル ホットスポットでRaspberryPiをネットに接続</title>\n  </head>\n  <body>\n    <header>\n      <h1>モバイル ホットスポットでRaspberryPiをネットに接続</h1>\n      <p>Windows10のモバイル ホットスポットでRaspberryPiをネットに接続する手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>お出かけ先でも RaspberryPi を、常に同じWi-Fi AP で接続できるような方法を考える。</p>\n\n<p>一つの案として、Windows10のモバイル ホットスポットを経由して RaspberryPi をネットワークにつなげる。\nこの場合、PCと RaspberryPi はセットで持ち歩くものと考えれば、 \nRaspberryPi は常にPCのモバイル ホットスポットのAPに接続すれば良いことになる。</p>\n\n<p>一つのWi-Fiアダプタを通常接続用とモバイル ホットスポット用でシェアすることはできないので、<br />\nUSBドングルを追加して使用する。</p>\n\n<ul>\n  <li>内蔵Wi-Fi → 通常接続用</li>\n  <li>USBドングル → モバイル ホットスポット用</li>\n</ul>\n\n<p>USBドングルは BUFFALO WLI-UC-GNM2S で確認\nWindowsはWindows10 ver.1903 で確認</p>\n\n<h1 id=\"windows側の事前準備\">Windows側の事前準備</h1>\n\n<p>内蔵Wi-Fi は 通常通り ルータに接続しておく。<br />\nこのとき、どのルータに繋いでいるかは考慮しなくて良いはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPCのルータ接続ダウン時、モバイル ホットスポットは使えない</p>\n</blockquote>\n\n<p>USBドングル BUFFALO WLI-UC-GNM2S はあらかじめドライバをインストールしてWindowsに認識させておく。<br />\n接続先は設定しなくて大丈夫。</p>\n\n<ul>\n  <li>Windowsで「設定」→「ネットワークとインターネット」→「モバイル ホットスポット」を開く\n    <ul>\n      <li>「インターネット接続を共有する」で、ルータに接続しているアダプタを選択</li>\n      <li>「Wi-Fi」を選択</li>\n      <li>「ネットワーク名」と「ネットワーク パスワード」をメモっておく</li>\n      <li>この状態で一番上のスイッチを「オン」にする\n        <ul>\n          <li>スイッチがアクティブカラーになったら準備完了</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"raspberrypi側の事前準備\">RaspberryPi側の事前準備</h1>\n\n<h2 id=\"etcwpa_supplicantwpa_supplicantconf-の修正\">/etc/wpa_supplicant/wpa_supplicant.conf の修正</h2>\n\n<p>モバイル ホットスポットか通常のルータか、どちらか生きてる方に接続にいくように設定する。<br />\n(いつもの環境ならモバイル ホットスポット使わなくて良いように)</p>\n\n<p>以下の「モバイルホットスポットのSSID名」「パスワード」は<br />\n上記でメモった「ネットワーク名」と「ネットワーク パスワード」を記入する。<br />\nダブルクォーテーションで囲むのを忘れないこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">ctrl_interface</span><span class=\"o\">=</span><span class=\"nv\">DIR</span><span class=\"o\">=</span>/var/run/wpa_supplicant <span class=\"nv\">GROUP</span><span class=\"o\">=</span>netdev\n<span class=\"nv\">update_config</span><span class=\"o\">=</span>1\n<span class=\"nv\">country</span><span class=\"o\">=</span>JP\n\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"デフォルトのSSID名\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span><span class=\"s2\">\"パスワード\"</span>\n        <span class=\"nv\">priority</span><span class=\"o\">=</span>3\n<span class=\"o\">}</span>\n\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"モバイルホットスポットのSSID名\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span><span class=\"s2\">\"パスワード\"</span>\n        <span class=\"nv\">priority</span><span class=\"o\">=</span>5\n<span class=\"o\">}</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npriority設定値は大きい方が優先される。<br />\n上記の場合、モバイルホットスポットが生きていればそちらが優先される</p>\n</blockquote>\n\n<h2 id=\"ap再接続用スクリプト\">AP再接続用スクリプト</h2>\n\n<p>モバイル ホットスポット の Enable/Disable を切り替えたとき、<br />\n(RaspberryPiを起動してからモバイルホットスポットを有効にするのを忘れていたことに気がついたなど)\nRaspberryPiのネットワーク設定は自動的に新しい環境に切り替わらない。<br />\nコマンドをチマチマ入力するのも面倒なので、コマンド イッパツで再接続処理するようにしておく。</p>\n\n<p>まず、 ~/wifi_reconnect.sh を以下の内容で作成する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo </span>wlan0 down..\n<span class=\"nb\">sudo </span>ifconfig wlan0 down\n<span class=\"nb\">sleep </span>1\n\n<span class=\"nb\">echo </span>wlan0 up..\n<span class=\"nb\">sudo </span>ifconfig wlan0 up\n<span class=\"nb\">sleep </span>3\n\n<span class=\"nb\">echo </span>re-get IP address...\n<span class=\"nb\">sudo </span>dhcpcd <span class=\"nt\">-k</span>\n<span class=\"nb\">sleep </span>3\n<span class=\"nb\">sudo </span>dhcpcd <span class=\"nt\">-n</span>\n<span class=\"nb\">sleep </span>15\n\n<span class=\"nb\">echo </span>DONE!!\n</code></pre></div></div>\n\n<p>スクリプトファイルに実行属性をつける。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod</span> +x ~/wifi_reconnect.sh\n</code></pre></div></div>\n\n<p>再接続したいタイミングで <code class=\"language-plaintext highlighter-rouge\">~/wifi_reconnect.sh</code>を実行する。<br />\nDHCPのアドレス確定時間分を待っているので、コマンド実行には20秒強かかる。</p>\n\n<h1 id=\"raspberrypiの起動\">RaspberryPiの起動</h1>\n\n<p>上記の準備が整ったら、RaspberryPiを起動する。<br />\n起動後、<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>(他のコマンドでも良いけど)でIPアドレスを確認する。</p>\n\n<ul>\n  <li>192.168.137.XXX になっていればOK</li>\n</ul>\n\n<p>また、PC側で「設定」→「ネットワークとインターネット」→「モバイル ホットスポット」の<br />\n「接続されているデバイス」にRaspberryPiが表示されているハズ。</p>\n\n<h1 id=\"問題点\">問題点</h1>\n\n<h2 id=\"windows10-pcがルータにつながっていないと使えない\">Windows10 PCがルータにつながっていないと使えない</h2>\n\n<p>ルータにつながっていないと、そもそもモバイル ホットスポット がオンできない。<br />\nこれは、ネットワーク環境がまったくない場合(つまりPCとRaspberryPiだけで箱庭環境だけ作りたいとき)は使えない。<br />\n回避策としては、スマホのテザリングでネットワークにつなぐ?\n間違って外部にアクセスしちゃったら、パケ死しそう。。。</p>\n\n<h2 id=\"pcの外側ルータのサブネット内からraspberrypiにアクセスできない\">PCの外側(ルータのサブネット内)からRaspberryPiにアクセスできない</h2>\n\n<p>モバイル ホットスポットのサブネットとルータのサブネットは別なので、<br />\nモバイル ホットスポットのサブネットの外側から内側へのアクセスはできない。<br />\nもちろん、ルータの外側からもアクセスできない。<br />\nRaspberryPiにアクセスできるのはモバイル ホットスポットを提供しているPCのみ。</p>\n\n<h2 id=\"mdnsが使えない\">mDNSが使えない</h2>\n\n<p>モバイル ホットスポットのサブネットとルータのサブネットは別なので、\nルータを超えられないmDNSは名前を取得できない。<br />\n回避策としては、/etc/hosts を名前エラーが出るたびに名前追加するか?</p>\n\n<p>なお、WindowsPCからRaspberryPiへのmDNS参照はできるが、RaspberryPiからWindowsPCへのmDNS参照はできない。</p>\n\n<h1 id=\"結論\">結論</h1>\n\n<p>とりあえず、RaspberryPiにアクセスするのはWindowsPC 1台のみで、<br />\nRaspberryPiからアクセスするはルータの外側のみ、という条件なら使えそう。</p>\n\n<p>う~ん、良いところまで行くんだけど、微妙に不満の残る結果に。。。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その5)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをWebsocketで飛ばして、Dashboardでグラフ表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"bme280データをwebsocketで送信raspberrypi\">BME280データをWebsocketで送信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>BME280を使用するフローを作成する</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、送信されるデータはmsg.payloadなので、文字列ではなく、object。<br />\n  (WebsocketのパケットにはobjectをJSON文字列化したものが入る)</p>\n  </li>\n  <li>BME280のデータを送信するためのトリガとなるノードをBME280ノードの入力に接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"411d9021.cb1948\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"72021e21.cce078\",\n        \"type\": \"Bme280\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"571951b6.480168\",\n        \"type\": \"websocket out\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"f24a6df3.ed0608\",\n        \"x\": 660,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4ce01eb0.f1d438\",\n        \"type\": \"debug\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 570,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"480f869f.968e18\",\n        \"type\": \"function\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"DummyData\",\n        \"func\": \"msg.payload = {\\n\\t\\t\\\"temperature_C\\\": Math.floor((Math.random() * (  40 - (-30)) * 100) / 100) + (-30),\\n\\t\\t\\\"humidity\\\":      Math.floor((Math.random() * ( 100 -    0 ) * 100) / 100) +    0,\\n\\t\\t\\\"pressure_hPa\\\":  Math.floor((Math.random() * (1100 -  800 ) * 100) / 100) +  800,\\n\\t\\t\\\"model\\\":\\\"DUMMY\\\"\\n}\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 310,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"c6ba67a3.1c69c\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"72021e21.cce078\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ab623444.9c5148\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"480f869f.968e18\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f24a6df3.ed0608\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/bme280\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからbme280データを受信サーバ\">WebsocketからBME280データを受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノード</li>\n</ul>\n\n<p>これだけでWebsocketからデータは受信できる。<br />\nこのとき、Websocketの受信ノードのmag.payloadはJSON文字列なので、objectに変換してやらないと後段で使用できない。<br />\nそのため、Websocketのノードの出力をjsonノードで変換してやる必要がある。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「json」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「json」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「動作」で「常にJavascriptオブジェクトに変換」を選択</li>\n      <li>プロパティは「msg.payload」を設定(デフォルトのまま)</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとjsonが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力側にWebsocketのノードを接続</li>\n  <li>\n    <p>出力側に受信データを処理するノードを接続</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>この状態でRaspberryPi側でBME280のデータ送信をトリガすれば、受信したデータで処理ノードが実行される</p>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その1サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その1)(サーバ)</h1>\n\n<p>上記、<strong>WebsocketからBME280データを受信(サーバ)</strong>の処理ノードとして</p>\n<ul>\n  <li><strong>その4</strong> の <strong>Dashboardでゲージグラフを表示する</strong>の手順で作成したノードを接続すれば良い。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nこれで理屈的には大丈夫なハズなんだけど、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.pressure_hPa}}</code>を指定すると、値は正常に表示されるけど、グラフが正常に表示されないことがある。。。<br />\nどうやら、この形で指定すると、値が1000を超えるとグラフ表示がおかしくなるようだ。バグか?<br />\n下の(その2)の方法で回避可能。</p>\n</blockquote>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"61238c01.1e1fdc\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"2163c454.8e4654\",\n        \"type\": \"json\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"8a687382.d3a38\",\n                \"54ecaf20.30611\",\n                \"1e9e6439.3de04c\",\n                \"54f5a1ee.e4fb5\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"de53f105.be0bb\",\n        \"type\": \"websocket in\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"2163c454.8e4654\",\n                \"8a687382.d3a38\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8a687382.d3a38\",\n        \"type\": \"debug\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 530,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54ecaf20.30611\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{msg.payload.temperature_C | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 510,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1e9e6439.3de04c\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度\",\n        \"label\": \"%\",\n        \"format\": \"{{msg.payload.humidity| number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 510,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54f5a1ee.e4fb5\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧\",\n        \"label\": \"hPa\",\n        \"format\": \"{{msg.payload.pressure_hPa| number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 510,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"9912b800.6921d8\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その2サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その2)(サーバ)</h1>\n\n<p><strong>(その1)</strong>での不具合を回避するため、msg.payloadのオブジェクト内のそれぞれの変数をバラすfunctionノードを追加する</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「function」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら名前にノード名を設定</li>\n      <li>コードを設定(下記参照)</li>\n      <li>出力数に「3」を設定</li>\n      <li>右上の「完了」をクリック。</li>\n    </ul>\n  </li>\n  <li>これでfunctionノードの出力端子が3個になり、上から温度、湿度、気圧データが出力される。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>// make deep copy\nvar msg_temp  <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_hum   <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_press <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\n\nmsg_temp.topic    <span class=\"o\">=</span> <span class=\"s2\">\"temperature_C\"</span><span class=\"p\">;</span>\nmsg_temp.payload  <span class=\"o\">=</span> msg.payload.temperature_C<span class=\"p\">;</span>\nmsg_hum.topic     <span class=\"o\">=</span> <span class=\"s2\">\"humidity\"</span><span class=\"p\">;</span>\nmsg_hum.payload   <span class=\"o\">=</span> msg.payload.humidity<span class=\"p\">;</span>\nmsg_press.topic   <span class=\"o\">=</span> <span class=\"s2\">\"pressure_hPa\"</span><span class=\"p\">;</span>\nmsg_press.payload <span class=\"o\">=</span> msg.payload.pressure_hPa<span class=\"p\">;</span>\n\n<span class=\"k\">return</span> <span class=\"o\">[</span>msg_temp, msg_hum, msg_press]<span class=\"p\">;</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">var msg_temp  = msg;</code>などとしてはいけない。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">msg_temp</code>は<code class=\"language-plaintext highlighter-rouge\">msg</code>の浅いコピーとなってしまうため、その下で<code class=\"language-plaintext highlighter-rouge\">msg_temp.payload</code>を変更すると、<code class=\"language-plaintext highlighter-rouge\">msg.payload</code>も変更されてしまうことになる。<br />\nこれを防ぐため、深いコピーを作成している。これには<code class=\"language-plaintext highlighter-rouge\">msg</code>をJSON文字列化して、再度パースすることで対応している。</p>\n</blockquote>\n\n<p>フローエディタ上で、どの端子がどの信号か分からなくなるのを防ぐため、端子に名前を付けることができる。<br />\n(付けなくても動作上は問題ない)</p>\n\n<ul>\n  <li>「function」ノードをダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>右上の「完了」ボタンの下にある「外観」ボタン(ウィンドウ表示のアイコン)をクリック</li>\n      <li>ポートラベルの下の出力の下、1、2、3に対して、それぞれ分かりやすい名前を付ける</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>functionノードの入力にjsonノードの出力を接続</li>\n  <li>functionノードのそれぞれの出力にそれぞれを表示するゲージグラフノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"9c09bf08.8c36a8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280_2\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1e53a14c.4133a7\",\n        \"type\": \"json\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"855491ee.723a88\",\n                \"3cee4c1c.c6861c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ada05d07.d2d8b\",\n        \"type\": \"websocket in\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"1e53a14c.4133a7\",\n                \"855491ee.723a88\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"855491ee.723a88\",\n        \"type\": \"debug\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 690,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"51b57ef4.80809\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度2\",\n        \"label\": \"℃\",\n        \"format\": \"{{value | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 670,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"be7cac56.7bcc4\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度2\",\n        \"label\": \"%\",\n        \"format\": \"{{value | number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 670,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"f36e338d.e77e6\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧2\",\n        \"label\": \"hPa\",\n        \"format\": \"{{value | number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 670,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3cee4c1c.c6861c\",\n        \"type\": \"function\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"BME280\",\n        \"func\": \"// make deep copy\\nvar msg_temp  = JSON.parse(JSON.stringify(msg));\\nvar msg_hum   = JSON.parse(JSON.stringify(msg));\\nvar msg_press = JSON.parse(JSON.stringify(msg));\\n\\nmsg_temp.topic    = \\\"temperature_C\\\";\\nmsg_temp.payload  = msg.payload.temperature_C;\\nmsg_hum.topic     = \\\"humidity\\\";\\nmsg_hum.payload   = msg.payload.humidity;\\nmsg_press.topic   = \\\"pressure_hPa\\\";\\nmsg_press.payload = msg.payload.pressure_hPa;\\n\\nreturn [msg_temp, msg_hum, msg_press];\",\n        \"outputs\": 3,\n        \"noerr\": 0,\n        \"x\": 460,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"51b57ef4.80809\"\n            ],\n            [\n                \"be7cac56.7bcc4\"\n            ],\n            [\n                \"f36e338d.e77e6\"\n            ]\n        ],\n        \"inputLabels\": [\n            \"BME280データ\"\n        ],\n        \"outputLabels\": [\n            \"温度\",\n            \"湿度\",\n            \"気圧\"\n        ]\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"34e8ddba.6c67fa\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ2\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その4)</h1>\n      <p>Node-REDのメモ Dashboard編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでDashboardでUIを作成するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"dashboardをインストールする\">Dashboardをインストールする</h1>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-dashboard」と入力</li>\n  <li>下に検索結果が出るので。「node-red-dashboard」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するボタン\">Dashboard のUIを作成する(ボタン)</h1>\n\n<ul>\n  <li>パレット(左側のペイン)の「dashboard」の下の「button」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「button」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「名前」は適当に設定</li>\n          <li>「タブ」 で「新規に ui_tab を追加…」を選択してその右の編集ボタンをクリック\n            <ul>\n              <li>適当に値を設定する</li>\n              <li>右上の「追加」をクリック</li>\n            </ul>\n          </li>\n          <li>または、既存のタブを選択</li>\n          <li>右上の「追加」をクリック</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Icon」「Tooltip」「Colour」「Background」はオプションなので空欄のままで可</li>\n      <li>「Payload」 に クリックされたときに送信するデータを設定</li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"ブラウザでdashboardのuiに接続する\">ブラウザでDashboardのUIに接続する</h1>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/ui に接続\n    <ul>\n      <li>Dashboardが表示されるハズ\n        <ul>\n          <li>複数のタブがある場合、左上の3本線メニュー(≡)から切り替えられる</li>\n        </ul>\n      </li>\n      <li>ボタンをクリックしたらフローが動作する。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するスライダ\">Dashboard のUIを作成する(スライダ)</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「slider」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「slider」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Tooltip」はオプションなので空欄のままで可</li>\n      <li>「Range」に値の最小値、最大値、刻みを設定</li>\n      <li>「Output」を設定\n        <ul>\n          <li>「continuously while sliding」:操作中、一定時間ごとにメッセージを出力</li>\n          <li>「only on release」:スライダを離したとき(値を確定したとき)にメッセージを出力</li>\n        </ul>\n      </li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"dashboardでゲージグラフを表示する\">Dashboardでゲージグラフを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「guage」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「guage」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>デフォルトの<code class=\"language-plaintext highlighter-rouge\">{{value}}</code>では受信したデータのpayload(<code class=\"language-plaintext highlighter-rouge\">msg.payload</code> )が使用される</li>\n          <li>payloadがobjectの場合、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.XXX}}</code>のように指定すると特定の変数が表示できる</li>\n          <li>このとき、<code class=\"language-plaintext highlighter-rouge\">{{</code> と <code class=\"language-plaintext highlighter-rouge\">}}</code> は波括弧を2つ重ねたもの。波括弧1つだと正常に処理されないので、注意</li>\n          <li>表示する数値の有効桁数を設定したい場合は以下のようにフィルタを設定\n            <ul>\n              <li>小数点以下1桁まで表示:<code class=\"language-plaintext highlighter-rouge\">{{value | number:1 }}</code></li>\n              <li>整数部のみ表示:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:0 }}</code></li>\n              <li>10の位へ丸める:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:-1 }}</code></li>\n            </ul>\n          </li>\n          <li>単位を表示するなど、決まった文字列を追加したい場合は「<code class=\"language-plaintext highlighter-rouge\">{{・・・}}℃</code>」のように波括弧の外側に追加</li>\n        </ul>\n      </li>\n      <li>「units」 で単位を設定する。温度なら「℃」など。これは数値表示には表示されず、グラフ内部の単位情報として表示される</li>\n      <li>「Range」 でグラフの値の範囲を指定する。「-20」~「40」など。\n        <ul>\n          <li>入力値が範囲外になった場合はグラフが上下限に張り付くだけで、エラーなどにはならない。また値そのものは数値表示される</li>\n        </ul>\n      </li>\n      <li>「Colour gradient」 でグラフの色を指定する。3つの色は下で設定するSectors の範囲に対応する</li>\n      <li>「Sectors」 で 上で指定した色を表示する範囲を設定する\n        <ul>\n          <li>これはオプションなので設定しなくても良い。指定しなかった場合は上の「Range」で指定した値の範囲を3等分して使用される</li>\n        </ul>\n      </li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nValue formatのフィルタの詳細は<a href=\"https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters\">https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters</a>を見ろと書かれていましたが、残念ながら私にはよく分かりませんでした…</p>\n</blockquote>\n\n<h1 id=\"dashboardでテキストを表示する\">Dashboardでテキストを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「text」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「text」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>上記参照</li>\n        </ul>\n      </li>\n      <li>「Layout」でレイアウトを選択。お好みで</li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a226513f.c36b1\",\n        \"type\": \"tab\",\n        \"label\": \"Dashboard_1\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"160486fa.dc7159\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e89b8821.ec65e8\",\n        \"type\": \"debug\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 580,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d4346336.cf1228\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e403fdac.aa3748\",\n        \"type\": \"ui_slider\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"label\": \"温度\",\n        \"tooltip\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 4,\n        \"width\": 0,\n        \"height\": 0,\n        \"passthru\": true,\n        \"outs\": \"all\",\n        \"topic\": \"\",\n        \"min\": \"-30\",\n        \"max\": \"50\",\n        \"step\": 1,\n        \"x\": 140,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"78c10ecb.1eb67\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"78c10ecb.1eb67\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 6,\n        \"width\": 4,\n        \"height\": 4,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{value}}℃\",\n        \"min\": \"-20\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 570,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"84bd2adf.3b5df8\",\n        \"type\": \"ui_text\",\n        \"z\": \"a226513f.c36b1\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 560,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1127e563.00001b\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"6547952b.517b34\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"6547952b.517b34\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ1\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"dashboard-のレイアウトを修正する\">Dashboard のレイアウトを修正する</h1>\n\n<p>ボタンのサイズを小さくしたり、複数のボタンを横に並べたい場合はレイアウトの修正を行う。</p>\n\n<ul>\n  <li>サイドバー(右側のペイン)の「dashboard」ボタン(グラフのアイコン)をクリック</li>\n  <li>配置タブをクリック</li>\n  <li>タブの部分(「ホーム」など)をマウスでポイントし、「レイアウト」をクリック\n    <ul>\n      <li>表示領域の幅を変更するには、右上の「幅」の設定値を変更する。(単位はグリッド数)</li>\n      <li>各要素をドラッグすると、表示位置を入れ替えられる。</li>\n      <li>各要素のサイズを変更するには、\n        <ul>\n          <li>右上の鍵アイコンをクリックして閉じた状態にする(鍵が開いた状態では表示領域幅に一致するように自動変更される)</li>\n          <li>右下に矢印アイコンが表示されるので、これをつまんでサイズを変更</li>\n        </ul>\n      </li>\n      <li>各要素を横並びにしたい場合は、各要素をドラッグして移動する(表示幅に収まらない場合は移動できない)</li>\n      <li>各要素のサイズ/位置はグリッド単位でのみ可能</li>\n      <li>右上の完了をクリック\nー デプロイする</li>\n    </ul>\n  </li>\n</ul>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その3)</h1>\n      <p>Node-REDのメモ TCP通信編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでTCP通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"udpで送信\">UDPで送信</h1>\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「送信」で出力するメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト)/「ブロードキャストメッセージ」/「マルチキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で送信先ポート番号を設定\n        <ul>\n          <li>受信プログラムが待ち受けしているポート番号を指定</li>\n        </ul>\n      </li>\n      <li>「アドレス」に送信先アドレス(名前 or IPアドレス)を指定</li>\n      <li>さらにその右で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>特定のポートから送信したいときは「ローカルポートを使用」を選択し、その右に送信元ポート番号を指定する\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n          <li>通常は「ローカルポートをランダムに使用」で大丈夫</li>\n        </ul>\n      </li>\n      <li>入力データがBase64エンコードされたBufferオブジェクトの場合は「Base64形式のペイロードを複合」にチェックを入れる\n        <ul>\n          <li>入力データがBase64文字列かをチェックするだけで、ここでデータを変換するわけではない(?)</li>\n          <li>通常はチェックしないでOK</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると送信先アドレスとポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>送信データを作成するノードを接続\n    <ul>\n      <li>UDPノードはmsg.payloadを送信する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"udpで受信\">UDPで受信</h1>\n<ul>\n  <li>パレットの「入力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「待ち受け」で受信待ちするするメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト or マルチキャスト)/「ブロードキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で受信待ちポート番号を設定\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n        </ul>\n      </li>\n      <li>「種類」で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>「出力」で受信したデータをどのような形式で次段のノードに出力するかを選択する\n        <ul>\n          <li>「バイナリバッファ」を選択すると受信したデータをそのままbufferオブジェクトとして出力</li>\n          <li>「文字列」を選択すると受信したデータをStringオブジェクトにデコードする</li>\n          <li>「Base64文字列」を選択すると受信したデータをBase64 Stringオブジェクトにデコードする</li>\n          <li>「Base64文字列」と「文字列」は内部でtoStringのencodingに’base64’を指定するか’utf8’を指定するかの違い(?)</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると受信待ちポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>受信データを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"2506be7d.1b5332\",\n        \"type\": \"tab\",\n        \"label\": \"UDP\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"44364ec0.0b59b8\",\n        \"type\": \"udp out\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"addr\": \"localhost\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"outport\": \"\",\n        \"base64\": false,\n        \"multicast\": \"false\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"20cee006.2fee4\",\n        \"type\": \"inject\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"\",\n        \"payloadType\": \"date\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 150,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"44364ec0.0b59b8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"eb875fd8.7aa5f8\",\n        \"type\": \"udp in\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"multicast\": \"false\",\n        \"group\": \"\",\n        \"datatype\": \"utf8\",\n        \"x\": 160,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"a6b72636.514e2\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a6b72636.514e2\",\n        \"type\": \"debug\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 140,\n        \"wires\": []\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"httpでrest-api\">HTTPでREST API</h1>\n\n<h2 id=\"http入力ノードの作成\">HTTP入力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「入力」の下の「http」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「メソッド」でメソッド種別を選択\n        <ul>\n          <li>ここでは「GET」で設定を進める(他のメソッドは他所で調べてね)</li>\n        </ul>\n      </li>\n      <li>「URL」でエンドポイント(要はパス)を設定</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとメソッドとURLが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>レスポンスを作成するノード(下記)を接続</li>\n</ul>\n\n<h2 id=\"レスポンス生成ノードの作成\">レスポンス生成ノードの作成</h2>\n\n<p>ここでは、簡単にfunctionノードで固定文字列を返すものを作っています。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると空欄になるので、なるべく識別できる名前を付けましょう</li>\n        </ul>\n      </li>\n      <li>「コード」に処理するプログラムを記述\n        <ul>\n          <li>msg.payloadに表示するページの本文を設定する</li>\n          <li>例えば以下</li>\n        </ul>\n      </li>\n      <li>「名前」の横のアイコンをクリックすると作成したノードの保存/読み込みが出来る\n        <ul>\n          <li>コードは <code class=\"language-plaintext highlighter-rouge\">~/.node-red/lib/functions/</code> に指定したフォルダとファイル名で保存される</li>\n          <li>保存したコードは別のノードで読み込むことができる</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"dl\">\"</span><span class=\"s2\"><h1> ぼ~っと生きてんじゃね~よ! </H1></span><span class=\"dl\">\"</span><span class=\"p\">;</span>\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h2 id=\"http出力ノードの作成\">HTTP出力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「出力」の下の「http response」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「http」と表示される</li>\n        </ul>\n      </li>\n      <li>必要なら「状態コード」を設定</li>\n      <li>必要なら「ヘッダ」を設定</li>\n      <li>シンプルな処理の場合、何も設定しなくてもOK</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"入力レスポンス生成出力を接続\">入力、レスポンス生成、出力を接続</h2>\n\n<ul>\n  <li>上記で作成したノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"ブラウザでアクセス接続\">ブラウザでアクセス接続</h2>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/《HTTP入力ノードに設定したURL》 に接続\n    <ul>\n      <li>ブラウザにレスポンス生成ノードで作成したメッセージが表示される</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"7508e635.c8bf48\",\n        \"type\": \"tab\",\n        \"label\": \"HTTP_REST\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c7938d8a.3ae9d\",\n        \"type\": \"http in\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"url\": \"/rest_api_1\",\n        \"method\": \"get\",\n        \"upload\": false,\n        \"swaggerDoc\": \"\",\n        \"x\": 160,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"fb01d5fd.b76918\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fb01d5fd.b76918\",\n        \"type\": \"function\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"ぼ~っと生きてんじゃね~よ!\",\n        \"func\": \"msg.payload = \\\"<h1> ぼ~っと生きてんじゃね~よ! </H1>\\\";\\nreturn msg;\\n\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 430,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"8d3518af.f9da7\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d3518af.f9da7\",\n        \"type\": \"http response\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"statusCode\": \"\",\n        \"headers\": {},\n        \"x\": 690,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"86c0f820.b0a56\",\n        \"type\": \"debug\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 700,\n        \"y\": 120,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"websocketでデータを送受信\">Websocketでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにwscatを使うこととします。<br />\nwscat は 以下のコマンドでインストールできます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> wscat\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信クライアント\">Websocketでデータ送信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「種類」 で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「URL」 でサーバのURLを設定(例: ws://PiDev25.local:5000/ws/data01)</li>\n          <li>「送信/受信」でペイロードのみ送受信するか、メッセージ全体を送受信するかを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5000で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5000\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5000 (press CTRL+C to quit)\nclient connected\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"75e44664.73e018\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"49b725b6.0e0934\",\n        \"type\": \"websocket out\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"99ad88ce.8bcf7\",\n        \"x\": 600,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"762ccf62.73a48\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fe2498d8.71c17\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47ef3c99.d6eefc\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f97b4d60.afc278\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6d15d519.6289ec\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"87c94e6f.db3458\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"175e465.15aaa3a\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e7c2219c.07acf8\",\n        \"type\": \"debug\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"99ad88ce.8bcf7\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5000/ws/data01\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信サーバ\">Websocketでデータ送信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata1 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest1で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wstest1\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-3\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"22d6d63b.99a952\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"d64e2a6a.27ead8\",\n        \"type\": \"websocket out\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"server\": \"d7536de3.b48578\",\n        \"client\": \"\",\n        \"x\": 520,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"79358fcc.5a5a68\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"cd6acb87.0a77\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7991d417.429124\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ee88046b.37b298\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7eac2c2e.6fa39c\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"650517e9.5e34a8\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d197151e.8b01e\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5871022e.6bbb1c\",\n        \"type\": \"debug\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d7536de3.b48578\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wstest1\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信クライアント\">Websocketでデータを受信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>URL でサーバのURLを設定(例: ws://PiDev25.local:5002/ws/wsdata2)</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-2\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5002で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5002\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5002 (press CTRL+C to quit)\nclient connected\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-4\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a45bd125.622fb8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"24a93730.cf2a7\",\n        \"type\": \"websocket in\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"server\": \"45ba6028.84fc88\",\n        \"client\": \"\",\n        \"x\": 220,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"15576052.1536\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"15576052.1536\",\n        \"type\": \"debug\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"45ba6028.84fc88\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5002/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信サーバ\">Websocketでデータを受信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata2 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-3\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest2で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wsdata2\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-5\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"15604b9.9721eb4\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"80f59585.469758\",\n        \"type\": \"websocket in\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"server\": \"11528a5d.783b0e\",\n        \"client\": \"\",\n        \"x\": 140,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"f37c8fe9.6307c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f37c8fe9.6307c\",\n        \"type\": \"debug\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"11528a5d.783b0e\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その2)</h1>\n      <p>Node-REDのメモ GPIO & I2C編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIO操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDはRaspberryPiで起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"raspberrypiでgpio出力\">RaspberryPiでGPIO出力</h1>\n<ul>\n  <li>パレット(左側のペイン)の「Raspberry Pi」の下の「rpi gpio」(出力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で出力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「出力形式」で「デジタル出力」を選択</li>\n      <li>デプロイしたときに端子状態を初期化したい場合は「端子の状態を初期化」をチェック\n        <ul>\n          <li>「端子の初期状態レベル」を選択</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「LED_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>トリガノードはGPIOから出力する値(0 または 1)を出力する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"51e0a206.805964\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_OUT\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"597df548.0311f4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"89834ee2.89e27\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b020b32.e26818\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"21621e60.e300ba\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_1\",\n        \"pin\": \"22\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"87abb89b.307418\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7ae7810.959a88\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 220,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでgpio入力\">RaspberryPiでGPIO入力</h1>\n\n<ul>\n  <li>パレットの「Raspberry Pi」の下の「rpi gpio」(入力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で入力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「抵抗」で端子に接続するプルアップ/ダウン種別を選択\n        <ul>\n          <li>端子の初期化時に内部のプルアップ/ダウン抵抗のどちらを有効にするかを選択</li>\n          <li>ボード上で処理してれば「なし」を選ぶ</li>\n        </ul>\n      </li>\n      <li>デバウンスにチャタリング除去時間を設定</li>\n      <li>デプロイしたときに端子状態を読み込みたい場合は「~初期状態を読み込む」をチェック</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「SWITCH_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力信号を処理するノードを接続\n    <ul>\n      <li>処理ノードへはGPIOから入力された値(0 または 1)が入力される</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1385085c.ab8648\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_IN\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"e9177a48.70b74\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"932b0e92.05cdd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"932b0e92.05cdd8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f31f20e.4b6d28\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW1\",\n        \"pin\": \"16\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d27c860d.7de3a8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d27c860d.7de3a8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 160,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでi2cを使用する\">RaspberryPiでI2Cを使用する</h1>\n\n<h2 id=\"事前準備\">事前準備</h2>\n\n<p>以下はターミナルやコンソールでの作業</p>\n\n<ul>\n  <li>I2Cを有効化する\n    <ul>\n      <li>リブートは不要らしい</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config\n    5 Interfacing Options\n        P5 I2C\n            Would you like the ARM I2C interface to be enabled?\n            に対して<はい>を選択\n            The ARM I2C interface is enabled\n            と表示されるので<了解>\n    <Finish>\n</code></pre></div></div>\n<ul>\n  <li>I2Cデバイスアクセス用ツールをインストールする</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>i2c-tools\n</code></pre></div></div>\n\n<ul>\n  <li>i2cバスをスキャンしてみる(RasbberryPi2/3のI2Cバスはバス1が出てる。古いのだと0のもあるらしい)</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#   ↓結果(例)</span>\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00:          <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n10: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n20: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n30: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n40: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n50: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n60: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n70: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> 76 <span class=\"nt\">--</span>\n<span class=\"c\"># 76がBME280(Bosch温湿度センサ)</span>\n</code></pre></div></div>\n\n<ul>\n  <li>I2Cデバイスのレジスタをリードしてみる</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cget <span class=\"nt\">-y</span> 1 0x76 0xd0\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ↓ 結果</span>\n0x60\n<span class=\"c\"># レジスタ 0xd0(CHIP ID)をリードするとデバイスのID 0x60が読める</span>\n</code></pre></div></div>\n\n<h2 id=\"bme280用ノードをインストールする\">BME280用ノードをインストールする</h2>\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「bme280」と入力</li>\n  <li>下に検索結果が出るので。「node-red-contrib-bme280」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\n2019/09/13現在、何やらインストール時にエラーになるが、<br />\nモジュールのコンパイル時にwarning/noteが出ているだけのようなので、インストール自体はできているようだ。<br />\nとりあえず下記サンプルは動いているので、大丈夫でしょう。</p>\n</blockquote>\n\n<h2 id=\"bme280を使用するフローを作成する\">BME280を使用するフローを作成する</h2>\n<ul>\n  <li>パレットの「入力」の下の「Bme280」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Bme280」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略するとBme280が表示される</li>\n        </ul>\n      </li>\n      <li>Bus# にバス番号(1)を設定</li>\n      <li>I2C Address にI2Cアドレス(0x76)を設定</li>\n      <li>Topicが必要なら設定(デフォルトはbme280)</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>信号を処理するノードを出力側に接続\n    <ul>\n      <li>Bme280ノードの出力メッセージの内容は以下の通り</li>\n    </ul>\n  </li>\n</ul>\n\n<table>\n  <thead>\n    <tr>\n      <th>変数名</th>\n      <th>値の例</th>\n      <th>項目</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>msg.topic</td>\n      <td>“bme280”</td>\n      <td>ノードの設定で設定したTopic</td>\n    </tr>\n    <tr>\n      <td>msg.payload.temperature_C</td>\n      <td>34.23</td>\n      <td>温度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.humidity</td>\n      <td>54.402349427117336</td>\n      <td>湿度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.pressure_hPa</td>\n      <td>1013.9016246356634</td>\n      <td>気圧</td>\n    </tr>\n    <tr>\n      <td>msg.payload.model</td>\n      <td>“BME280”</td>\n      <td>センサ名</td>\n    </tr>\n  </tbody>\n</table>\n\n<ul>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n    {\n        \"id\": \"e4065603.3c6dc\",\n        \"type\": \"tab\",\n        \"label\": \"BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c0602bca.110b8\",\n        \"type\": \"Bme280\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"8b845ce5.ec2fd\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b845ce5.ec2fd\",\n        \"type\": \"debug\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 630,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"cdbf55ce.3aa94\",\n        \"type\": \"inject\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"c0602bca.110b8\"\n            ]\n        ]\n    }\n]\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その1)</h1>\n      <p>Node-REDのインストール他のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDをインストールや、フローを作成する際の手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"ubuntu-に-node-red-をインストールする\">ubuntu に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejsとnpmのインストール\">Node.jsとnpmのインストール</h2>\n\n<p>自動起動とかやらないなら、Node.js は nodenv とか使っても良い気がするが、\n念のためシステムに直接インストールしておく。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">apt install</code> だと古いバージョンになってしまうので、<br />\nnコマンド をインストールし、<br />\nnコマンドで安定版をインストールする。<br />\nその後、<code class=\"language-plaintext highlighter-rouge\">apt</code> でインストールしたNode.jsは削除。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n\n<span class=\"c\"># nコマンドのインストール</span>\n<span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> n\n\n<span class=\"c\"># 安定版のインストール</span>\n<span class=\"nb\">sudo </span>n stable\n\n<span class=\"c\"># aptでインストールしたnode.jsをアンインストール</span>\n<span class=\"nb\">sudo </span>apt purge <span class=\"nt\">-y</span> nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h2 id=\"node-redのインストール\">Node-REDのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> <span class=\"nt\">--unsafe-perm</span> node-red node-red-admin\n</code></pre></div></div>\n\n<p>どうも、ノードの追加とかすると、npmのキャッシュをアクセスするときにpermission deniedと言われてしまうみたいなので、\n以下のコマンドで .npm ディレクトリ以下の所有権を自分にしておく。<br />\n(キャッシュだから削除しても良い気がするが)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> ~/.npm\n</code></pre></div></div>\n\n<h2 id=\"起動\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"停止\">停止</h2>\n\n<p>CTRL-Cで停止する。</p>\n\n<h2 id=\"参考\">参考</h2>\n\n<p><a href=\"https://qiita.com/seibe/items/36cef7df85fe2cefa3ea\">https://qiita.com/seibe/items/36cef7df85fe2cefa3ea</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"windows10-に-node-red-をインストールする\">Windows10 に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npmの-インストール\">Node.js と npmの インストール</h2>\n\n<ul>\n  <li><a href=\"https://nodejs.org/ja/\">Node.jsのサイト</a>からWindows版をダウンロードします。\n  推奨版(2019/09/16現在、10.16.3 LTS)をダウンロードしてください。<br />\n  (もし、別のプラットフォームのものが必要なら上部のメニューの「ダウンロード」からダウンロードします)</li>\n  <li>ダウンロードしたnode-vXX.XX.XX-YY.msiを実行してインストーラを起動し、インストールします。\n  特に迷うところはないと思います。大体、そのまま「次へ」で大丈夫。</li>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell を起動します。\n  念のため、<code class=\"language-plaintext highlighter-rouge\">node -v</code> を実行して、<code class=\"language-plaintext highlighter-rouge\">v10.16.3</code>と表示されることを確認します。\n  次にnpmのアップデートを行います。以下のコマンドを実行してください。( 2019/09/16現在、6.11.3 でした)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g npm\n</code></pre></div></div>\n<h2 id=\"node-redのインストール-1\">Node-REDのインストール</h2>\n\n<ul>\n  <li>コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してインストールします。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g --unsafe-perm node-red\n</code></pre></div></div>\n\n<ul>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してNode-REDを起動します。<br />\n実行したウィンドウは閉じないでください。閉じるとNode-REDが終了してしまいます。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>なお、初めてNode-REDを起動したとき、\n『このアプリの機能のいくつかがWindows Defender ファイアウォールでブロックされています』\nと警告が表示されることがある。</p>\n\n<p>この場合、\n「通信を許可するネットワーク」を選択して「アクセスを許可する」をクリック\nすれば良い。</p>\n\n<h2 id=\"ちょっとヒトコトメモ\">ちょっとヒトコトメモ</h2>\n\n<p>(ぜんぜんヒトコトじゃないけど。。。)</p>\n\n<p>Node-REDを起動したPCからのアクセス(ブラウザ接続など)は成功するのに、\n外部PCやRaspberryPi(もちろん、同一サブネット上の)からのアクセス(ブラウザやWebsocket接続)が失敗する場合がある。</p>\n\n<p>考えられる原因は色々あるが、最も多そうな原因のひとつにファイアウォールでのブロックが考えられる。<br />\n上の警告ダイアログでアクセス許可した際に、プライベートネットワークのみに通信を許可していて、\nかつ、現在接続されているネットワークがパブリックネットワークである場合である。</p>\n\n<p>ファイアウォールでのブロックされているかは<strong>Node-REDを起動した状態</strong>で以下のコマンドで確認できる。</p>\n\n<ul>\n  <li>RaspberryPiの場合</li>\n</ul>\n\n<p>以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 《IPアドレス》 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 192.168.1.2 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、コマンドが終了しないので、CTRL+Cで終了する。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">Connection to 《IPアドレス》 《ポート番号》port [tcp/*] succeeded!</code>と表示される。</p>\n\n<ul>\n  <li>Windowsの場合</li>\n</ul>\n\n<p>Windows Poewrshellで(コマンドプロンプトでは不可)以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 《IPアドレス》  <span class=\"nt\">-port</span> 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 192.168.1.2 <span class=\"nt\">-port</span> 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : False</code>と表示される。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : True</code>と表示される。</p>\n\n<p>これを解決するには、Node-REDを実行しているWindows PCで<br />\n「コントロールパネル」→「Windows Defender ファイアウォール」を開き、<br />\n左側のリストから「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック<br />\n「設定の変更」をクリック\n下のリストから「Node.js: Server-side JavaScript」の右側 パブリックのチェックボックスにチェックを入れる<br />\n「OK」をクリック</p>\n\n<p>この状態で再度RaspberryPi または PCからファイアウォールでのブロックの確認を実行し、ブロックされていないことを確認してください。</p>\n\n<h1 id=\"raspbian-に-node-red-をインストールする\">Raspbian に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npm-と-node-red-のインストール\">Node.js と npm と Node-RED のインストール</h2>\n\n<p>インストールスクリプトを実行すればイッパツで解決。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストールスクリプトの取得</span>\nwget  https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered\n\n<span class=\"c\"># 必要なら中身確認してね</span>\n\n<span class=\"c\"># インストールスクリプトの実行</span>\nbash update-nodejs-and-nodered \n</code></pre></div></div>\n\n<h2 id=\"起動-1\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-start \n</code></pre></div></div>\n<p>CTRL-Cでログ表示のみ止まる(Node-RED自体は動作したまま)</p>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"ログ表示\">ログ表示</h2>\n\n<p>Node-RED で console.log などを実行したときは、ログに表示される。<br />\n<code class=\"language-plaintext highlighter-rouge\">node-red-start</code>したままなら表示されるが、CTRL-Cでログ表示を止めていた場合は\n以下のコマンドでログ表示を再開できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-log\n</code></pre></div></div>\n\n<h2 id=\"停止-1\">停止</h2>\n\n<p>Node-RED自体を停止する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-stop\n</code></pre></div></div>\n\n<h2 id=\"参考-1\">参考</h2>\n\n<p><a href=\"https://qiita.com/utaani/items/7155c62d6c5e96822afb\">https://qiita.com/utaani/items/7155c62d6c5e96822afb</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"フローの操作\">フローの操作</h1>\n\n<h2 id=\"フローを保存するエクスポート\">フローを保存する(エクスポート)</h2>\n\n<p>作成したフローは保存することができます。<br />\nしばらく使わないフローを削除したり、別の環境にコピーする場合に保存しておくと良いでしょう。</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「書き出し」→「クリップボード」をクリック →書き出しダイアログが表示される\n    <ul>\n      <li>書き出す範囲を「現在のタブ」「すべてのタブ」から選択。(フローの一部を選択していた場合は「選択したフロー」も選択可能)</li>\n      <li>その下にはその時のJSONファイルの内容が表示されていますので、ここから</li>\n      <li>さらにその下で出力形式を「インデントのないJSONフォーマット」「インデント付きのJSONフォーマット」から選択。多少ファイルサイズが増減しますが、どちらを選んでも特に問題になるようなことはないでしょう。「インデント付き」の方が目視で確認しやすいと思います。</li>\n      <li>「ダウンロード」をクリックすると、ブラウザのファイル保存(ダウンロード)ダイアログが開くので、保存処理を行う(このときのファイル名はflows.json固定なので、必要に応じて保存後リネームしてください)</li>\n      <li>または、「書き出し」をクリックすると、クリップボードへコピーされるので、直接 別の環境の読み込みダイアログやエディタへペーストすることも可能</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"フローを読み込むインポート\">フローを読み込む(インポート)</h2>\n\n<p>保存したフローは読み込んで使用することができます(当然か)</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「読み込み」→「クリップボード」をクリック →読み込みダイアログが表示される\n    <ul>\n      <li>「読み込むファイルを選択してください」をクリックして読み込むファイルを選択 → ファイルの内容がその下のエディットボックスに表示される</li>\n      <li>または、その下のエディットボックスにJSONデータをペースト</li>\n      <li>読み込み先を「現在のタブ」「新規のタブ」から選択(「選択したフロー」で保存してないとどっちでも同じ気がする)</li>\n      <li>「読み込み」をクリック</li>\n    </ul>\n  </li>\n  <li>読み込まれるので、内容を確認。必要なら修正。</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"フローを削除する\">フローを削除する</h2>\n\n<p>使用しなくなったフローをいつまでも残しておくとトラブルの元ですから、削除しましょう。<br />\n(念のため保存しておくのを忘れずに)</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、削除したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>左上の「削除」をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(次回デプロイするまで処理は残っているので注意)</li>\n</ul>\n\n<h2 id=\"フローを一時的に停止する\">フローを一時的に停止する</h2>\n\n<p>後で使うから削除したくはないけど、今デバッグしてる作業の邪魔になる、というような場合、\n作成したフローを削除せずに一時的に停止することができます。</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、停止したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>状態を「無効」にする</li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(デプロイしないといつまで経っても停止しないので注意)</li>\n</ul>\n\n<p>再開する場合は上記手順と同じで、状態を「有効」にする。</p>\n\n<h2 id=\"フローを全削除する\">フローを全削除する</h2>\n\n<p>色々フローを作成したけど、一回チャラにしてやりなおしたいときは、\n一旦Node-REDを停止(ブラウザ切断だけじゃなく、サーバプログラムを停止)して\n以下の2つのファイルを削除する</p>\n\n<ul>\n  <li>~/.node-red/flows_《ホスト名》.json</li>\n  <li>~/.node-red/.flows_《ホスト名》.json.backup</li>\n</ul>\n\n<p>もちろん、念のためバックアップ取っておくのが好ましい。<br />\nバックアップから復元すれば元通りになるはず。</p>\n\n<p>その後、Node-Redを起動すると、フローが綺麗さっぱり消えているハズ。</p>\n\n<h2 id=\"その2以降のフローの例について\">その2以降の「フローの例」について</h2>\n\n<p>「フローの例」に書かれたJSONコードはテスト用に作成したフローをエクスポート(書き出し)したものです。<br />\nこのコードの表示部分にマウスを乗せると、右上に「Copy」ボタンが表示されますので、このボタンをクリックしてください。JSONコードがクリップボードにコピーされます(マウスをドラッグしての選択は不要)。</p>\n\n<p>この状態で、上記<strong>フローを読み込む(インポート)</strong>に示した方法でフローをインポートするとフローがコピーされます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n複数のフローをインポートした場合、既に存在するノードと同名のノードは別のノードとして生成されます。このとき、名前に「(_1)」などの別ノードを識別できるような記号は付きません。<br />\n特に、WebsocketのノードやDashboardのタブ/グループはシステムの動作や見た目に影響しますので、注意してください。<br />\n自動でよしなにする方法はありませんので、手動でチマチマと修正してください。<br />\nサイドバー(右側のペイン)の「▼」ボタンをクリックし、ノードの設定を表示でノードの設定を表示し、<br />\n各ノードの右側の数字をクリックすると、そのノードを参照しているノードの一覧が表示されます。<br />\nさらにそのノード一覧の各ノードをダブルクリックすると、そのノードが点滅表示されるので、そのノードのプロパティで参照先を変更すれば良いでしょう。</p>\n\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WebIOPiをRaspbian Busterで動かす</title>\n  </head>\n  <body>\n    <header>\n      <h1>WebIOPiをRaspbian Busterで動かす</h1>\n      <p>WebIOPiをRaspbian Busterで動かす</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"背景\">背景</h1>\n\n<p>知人がWebIOPiをRaspbian Busterで動かそうとして、Raspbian Stretch では動いたが、Raspbian Busterだと動かないと言っていたので、\n興味本位でデバッグしてみた。</p>\n\n<p>私はこれを使おうと思ってないので、「鳴かぬなら鳴かせてみせようホトトギス」なだけなので、詳しい使い方とかは調べてません。</p>\n\n<h1 id=\"参照\">参照</h1>\n\n<p>そもそものインストール手順は、<br />\n<a href=\"https://www.hiramine.com/physicalcomputing/raspberrypi3/webiopi_install.html\">WebIOPi のインストール</a><br />\n<a href=\"https://www.fabshop.jp/%E9%96%8B%E7%99%BA%E3%81%8C%E7%B5%82%E4%BA%86%E3%81%97%E3%81%9Fwebiopi%E3%82%92%E6%9C%80%E6%96%B0%E3%81%AEraspbian%E3%81%A7%E5%8B%95%E4%BD%9C%E3%81%95%E3%81%9B%E3%82%88%E3%81%86%E3%80%82/?fbclid=IwAR1u1Hq0wSqnDhPnKDeoyf1b2AmrdpO99TLSevUTZ237D5Ny97pliLjlOwU\">開発が終了したWebIOPiを最新のRaspbianで動作させよう。</a><br />\nあたりを参考にしてちょ。</p>\n\n<h1 id=\"いきなり結論\">いきなり結論</h1>\n\n<p>で、まぁ結論から言うと、根本原因は、BusterのPython3がPython3.7にバージョンアップされたこと。<br />\nちなみに、StretchのPython3はPython3.5 。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">python/webiopi/utils/thread.py</code> 内の 関数 <code class=\"language-plaintext highlighter-rouge\">runLoop()</code>の中で<code class=\"language-plaintext highlighter-rouge\">async</code>を変数に使っていたため、SyntaxErrorが発生していた模様。<br />\nPythom3.7では(正確にはPython3.6から)<code class=\"language-plaintext highlighter-rouge\">async</code>は予約語になっているため、エラーとなっていた。</p>\n\n<p>で、変数名を<code class=\"language-plaintext highlighter-rouge\">async</code>からそれ以外(例えば<code class=\"language-plaintext highlighter-rouge\">async_Flag</code>)に変更すれば良い。</p>\n\n<h1 id=\"でpatchファイル\">で、patchファイル</h1>\n\n<p>修正内容のpatchファイルがこちら。<br />\nついでにCプログラムのコンパイルの際に出るワーニングも消すようにちょこっと修正しときました。(こっちの修正は、かなりヤッツケ…)</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/cpuinfo.c WebIOPi-0.7.1/python/native/cpuinfo.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/cpuinfo.c\t2019-09-03 00:04:59.959369913 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/cpuinfo.c\t2019-09-02 23:55:16.207501342 +0900\n</span><span class=\"p\">@@ -35,7 +35,8 @@</span> char *get_cpuinfo_revision(char *revisio\n       return 0;\n \n    while(!feof(fp)) {\n<span class=\"gd\">-      fgets(buffer, sizeof(buffer) , fp);\n</span><span class=\"gi\">+      char* aaa = fgets(buffer, sizeof(buffer) , fp);\n+      aaa = aaa;\n</span>       sscanf(buffer, \"Hardware\t: %s\", hardware);\n       if (strcmp(hardware, \"BCM2708\") == 0)\n          rpi_found = 1;\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/gpio.c WebIOPi-0.7.1/python/native/gpio.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/gpio.c\t2019-09-03 00:04:59.969368480 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/gpio.c\t2019-09-02 23:58:58.757767098 +0900\n</span><span class=\"p\">@@ -23,6 +23,7 @@</span> SOFTWARE.\n #include <stdio.h>\n #include <stdint.h>\n #include <stdlib.h>\n<span class=\"gi\">+#include <unistd.h>\n</span> #include <string.h>\n #include <fcntl.h>\n #include <sys/mman.h>\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/webiopi/utils/thread.py WebIOPi-0.7.1/python/webiopi/utils/thread.py\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/webiopi/utils/thread.py\t2019-09-03 00:04:44.520586361 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/webiopi/utils/thread.py\t2019-09-02 23:54:10.087479478 +0900\n</span><span class=\"p\">@@ -33,14 +33,14 @@</span> def stop(signum=0, frame=None):\n             task.stop()\n                 \n \n<span class=\"gd\">-def runLoop(func=None, async=False):\n</span><span class=\"gi\">+def runLoop(func=None, async_Flag=False):\n</span>     global RUNNING\n     RUNNING = True\n     signal.signal(signal.SIGINT, stop)\n     signal.signal(signal.SIGTERM, stop)\n \n     if func != None:\n<span class=\"gd\">-        if async:\n</span><span class=\"gi\">+        if async_Flag:\n</span>             TASKS.append(Task(func, True))\n         else:\n             while RUNNING:\n</code></pre></div></div>\n\n<p>これを<code class=\"language-plaintext highlighter-rouge\">webiopi-buster.patch</code>として保存し、以下のコマンドを実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch <span class=\"nt\">-p1</span> <span class=\"nt\">-i</span> webiopi-buster.patch\n</code></pre></div></div>\n\n<p>で後は<code class=\"language-plaintext highlighter-rouge\">settup.sh</code>を実行して、その後は参照ページの通り進めれば良い。</p>\n\n<h1 id=\"めでたしめでたし\">めでたしめでたし</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian Busterのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian Busterのインストール</h1>\n      <p>Raspbian Buster with desktopのインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspbian Buster with desktop」 の 「DownloadZIP」でダウンロードしてSDカードに書き込んでブート。<br />\n(「・・・ and recommended software」 の方ではない)<br />\n以下の手順は、RaspberryPi3 model B+、「Version: July 2019」 で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>は表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nframebuffer_width=1920\nframebuffer_height=1080\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B1 Desktop / CLI\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B3 Splash Screen\n            Would you like to show the splash screen at boot? \n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    5 Interfacing Options        \n        P3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>    \n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n<p>Windows側のクライアントは、<br />\n<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a> \nから VNC Viewerをダウンロード。<br />\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。<br />\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。<br />\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。<br />\n日本語化の手順はこちらを参考に。 <a href=\"http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"c\"># export PYENV_ROOT=/proj/.pyenv</span>\n<span class=\"c\"># export PATH=$PYENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(pyenv init -)\"</span>\n<span class=\"c\"># eval \"$(pyenv virtualenv-init -)\"</span>\n\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"c\"># export NODENV_ROOT=/proj/.nodenv</span>\n<span class=\"c\"># export PATH=$NODENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(nodenv init -)\"</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マウスフォーカスの変更\">マウスフォーカスの変更</h1>\n\n<p>ウィンドウをクリックしないとフォーカスが移動しないのはイライラするので x-mouse相当の設定をする。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/xdg/openbox/lxde-pi-rc.xml</code>の以下の部分をnoからyesに変更。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><followMouse>yes</followMouse>\n</code></pre></div></div>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(RaspberryPi編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(RaspberryPi編)</h1>\n      <p>過去のブログ(RaspberryPi編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"センサ接続gpio\">センサ接続/GPIO</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4f2290b79f3005f839afe798c424fadd\">BOSCH 9軸センサ bmx055 ドライバ(Node.js用) </a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/310580fc726f8b2315d2a81486cbe551\">RaspberryPi向けBOSCH 温度/湿度/気圧センサ(BME280)、9軸センサ(加速度/ジャイロ/地磁気)(BMX055)動作確認プログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/dc6f4c0987e462ca94f003b8d20ea456\">RaspberryPi向けGPIO操作テストプログラム</a></li>\n</ol>\n\n<h1 id=\"webサーバ\">WEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/e37a1d11ac25cf7e421f4d6c32d9a03c\">RaspberryPi向けWEBサーバ&センサテストプログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/18ee6da1c77671949e881eb45dda6edf\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/b23849cf9b82b83fe0c2df22836b6c27\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ/ついでに3D姿勢計算もブラウザでやるっちゃ</a></li>\n</ol>\n\n<h1 id=\"もう一つのwebサーバ\">もう一つのWEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/bcaa47ce1b04bd6b8285e553d6fb9f4f\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/11cc216ffde610e26a5b8cd4ee5b599b\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js/webサーバにExpressを使ってサッパリと</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/8179edb10867faf98e233a52965a9e53\">Raspbianのシリアルコンソールでloginするとイケてないのを改善する</a></li>\n</ol>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>nodenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>nodenvのインストール</h1>\n      <p>nodenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonのpyenvと同様にNode.jsのバージョン管理システムのnodenvを使用する。<br />\n(両方インストールするくらいならanyenvを使えという説もあるが…)</p>\n\n<p>他にもnvmやnodebrewなんてのもあるらしい。nodenvはディレクトリごとにローカルバージョンを設定できてとても便利なのでおススメ。<br />\nnodeenv(eが2つ)という超マイナーなのもあるけど、間違わないように。</p>\n\n<p>Node.jsはリポジトリにバイナリパッケージが用意されているバージョンはバイナリインストールできる。用意されていないバージョンはソースからコンパイルされるが、必要なライブラリ類のインストールなど必要。ここでは手順は割愛。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>インストールに必要なモジュールをインストールする。インストール済みならスキップして可。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>git\n</code></pre></div></div>\n\n<h2 id=\"nodenv本体のインストール\">nodenv本体のインストール</h2>\n\n<p>nodenv本体をインストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\ngit clone git://github.com/nodenv/nodenv.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/nodenv/node-build.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>nodenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"nodenvでインストールできるバージョンの一覧を表示\">nodenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install</span> <span class=\"nt\">-l</span>\n</code></pre></div></div>\n<p>バイナリインストールできるか確認したい場合は以下。<br />\nバイナリがなければソースからコンパイルされるが、時間がかかるのが嫌な場合に(大抵のバージョンはバイナリが用意されているようだ)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"nt\">-r</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/share/\n<span class=\"c\"># ただし、uname -m が x86_64 | amd64 | i686-64 のときはx64に置き換える</span>\n</code></pre></div></div>\n\n<h3 id=\"nodejsのインストール\">Node.jsのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install </span>10.15.3 \n</code></pre></div></div>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv global 10.15.3\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境について\">仮想環境について</h3>\n\n<p>pyenvと異なり、nodenvは仮想環境をサポートしていない。<br />\nNode.jsはローカルモジュールのインストールが簡単なので、仮想環境を構築しなくても個々のディレクトリでローカルモジュールをインストールすることで仮想環境相当のことが実現できる。</p>\n\n<h3 id=\"npmのバージョンアップ\">npmのバージョンアップ</h3>\n\n<p>「npmが古い~」と言われる前にバージョンアップ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> npm\n</code></pre></div></div>\n\n<h3 id=\"ローカルで使用するバージョンの設定\">ローカルで使用するバージョンの設定</h3>\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは9.11.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">local</span> <バージョン名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv shell <バージョン名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"nodenvのバージョンアップ\">nodenvのバージョンアップ</h1>\n\n<p>Node.jsの新しいバージョンがリリースされ、それをインストールしたい場合など、nodenvのバージョンアップが必要。<br />\n<strong>下記その2の方がおススメ。こっちの手順は参考までに。</strong></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/\ngit pull\n</code></pre></div></div>\n<p>実行後、ターミナルを開きなおす</p>\n\n<h1 id=\"nodenvのバージョンアップ-その2\">nodenvのバージョンアップ その2</h1>\n<p>nodenv-updateをインストールしておけば、<code class=\"language-plaintext highlighter-rouge\">nodenv update</code>を実行するだけですべてのプラグインを含めてバージョンアップしてくれるので、おススメ。インストール方法は下記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/nodenv/nodenv-update.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/nodenv-update\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのnodejsを使いたい場合\">システムのNode.jsを使いたい場合</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv version\n</code></pre></div></div>\n\n<h3 id=\"nodenvでインストールされているnodejsのバージョンを確認\">nodenvでインストールされているNode.jsのバージョンを確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"nodenv自体のバージョン確認\">nodenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"nodenvで使用できるコマンドの確認\">nodenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv commands\n</code></pre></div></div>\n\n<h3 id=\"nodenvのヘルプの表示\">nodenvのヘルプの表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">help</span>\n\n<span class=\"c\"># 各コマンドのヘルプを表示するには以下</span>\nnodenv <span class=\"nb\">help</span> <<span class=\"nb\">command</span><span class=\"o\">></span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのインストール</h1>\n      <p>pyenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>システムのpythonのバージョンを変更したり、モジュールの変更をしたりするとシステム上のスクリプトの動作に影響が出る場合があるので、pyenvで個別のpython環境を構築するのがベター。<br />\nさらに、virtualenvプラグインを使うと、同じpythonのバージョンでもそれぞれに別のモジュールをインストールできる、仮想環境を構築できる。</p>\n\n<p>なお、pyenvはpythonをバイナリインストールできなくて、ソースからコンパイルするので、インストールにはそれなりに時間がかかる(RasPi2で1~2時間くらい?)。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<h3 id=\"必要なモジュールをインストール\">必要なモジュールをインストール</h3>\n<p>インストールに必要なモジュールをインストールする。</p>\n<ul>\n  <li>Bullseye以降ではこちら<br />\n(<code class=\"language-plaintext highlighter-rouge\">python-openssl</code> →  <code class=\"language-plaintext highlighter-rouge\">python3-openssl</code>)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>Buster以前ではこちら\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"bluetoothを使用する場合\">bluetoothを使用する場合</h3>\n<p>bluetoothを使用する場合は以下も必要</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以前、 ubuntuの場合は以下と書いていたが、<code class=\"language-plaintext highlighter-rouge\">libbluetooth3-dev</code>は<code class=\"language-plaintext highlighter-rouge\">libbluetooth-dev</code>の別名定義だったので上のコマンドでOKのはず。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth3-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"pyenv本体とvirtualenvプラグインのインストール\">pyenv本体とvirtualenvプラグインのインストール</h2>\n\n<p>pyenv本体とvirtualenvプラグインをインストール。<br />\nついでにupdateプラグインも入れとく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>pyenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n<span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>Raspbianでは以下も追加<br />\nnumpyをimportしたとき、undefined symbol: PyFPE_jbuf でエラーになる対策。<br />\n参考: <a href=\"https://research.itplants.com/?p=2437\">https://research.itplants.com/?p=2437</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"--enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-fpectl\"</span>\n</code></pre></div></div>\n\n<p>Ubuntuでは以下を追加しておく(デフォルトだとShared Library のimportでエラーになる)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h2 id=\"sudoでpyenv環境を実行するように設定する\">sudoでpyenv環境を実行するように設定する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo</code>でpythonを実行すると、pyenvの設定に関係なくsystemのpythonが実行されてしまいます。<br />\nこれを防ぐためには、<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers</code>の<code class=\"language-plaintext highlighter-rouge\">Defaults secure_path</code>に以下のpathを追加します。</p>\n\n<ul>\n  <li>«pyenvインストール先»/plugins/pyenv-virtualenv/shims:</li>\n  <li>«pyenvインストール先»shims:</li>\n  <li>«pyenvインストール先»/bin:</li>\n</ul>\n\n<p>具体的には以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 変更前\nDefaults  secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n    ↓\n# 変更後\nDefaults  secure_path=\"/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n</code></pre></div></div>\n<ul>\n  <li></li>\n</ul>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"pyenvでインストールできるバージョンの一覧を表示\">pyenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span> \n</code></pre></div></div>\n\n<h3 id=\"pythonのインストール\">pythonのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.4\n</code></pre></div></div>\n\n<p>・・・ 気長に待つ。 ・・・</p>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global 3.6.4\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-V</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境の構築\">仮想環境の構築</h3>\n\n<p>色々試したあとに、インストールしたモジュールをチャラにしたいときを考えて、仮想環境を構築しておく。<br />\nここでは、python 3.6.4を使用して 仮想環境名 mypython を作成。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.6.4 mypython\n</code></pre></div></div>\n\n<p>デフォルトをmypythonに変更する場合は以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global mypython\n</code></pre></div></div>\n\n<h3 id=\"pipのバージョンアップ\">pipのバージョンアップ</h3>\n\n<p>「pipが古い~」と言われる前にバージョンアップ。ついでにsetuptoolsとwheelも。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n<blockquote>\n  <p>[!IMPORTANT]\nベース環境をバージョンアップしても、仮想環境に引き継がれないので、仮想環境毎に実行が必要。</p>\n</blockquote>\n\n<h3 id=\"ローカルバージョンの設定\">ローカルバージョンの設定</h3>\n\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは3.4.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">local</span> <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"i2cを使用する場合raspi\">I2Cを使用する場合(RasPi)</h1>\n\n<p>RaspberryPi環境で、I2Cを使うためのsmbusモジュールは、通常 <code class=\"language-plaintext highlighter-rouge\">sudo apt install python3-smbus</code> でインストールするが、これだとpyenv環境にインストールできない。<br />\nこれはsmbus2をインストールして使用することで回避できる。\nインストールは以下のように実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>smbus2\n</code></pre></div></div>\n<p>ちなみに、pyenv 環境へのモジュールのインストールには <code class=\"language-plaintext highlighter-rouge\">sudo</code> は不要。/usr 下へのインストールではないので。</p>\n\n<p>で、プログラムソース側はsmbusのインストール部分を以下のように修正。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus</span>\n<span class=\"k\">except</span> <span class=\"nb\">ImportError</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus2</span> <span class=\"k\">as</span> <span class=\"n\">smbus</span>\n</code></pre></div></div>\n\n<p>smbus2 だけにしても良いけど、smbus でも動作できるようにしておくのがベターかな。</p>\n\n<h1 id=\"pyenvのバージョンアップ\">pyenvのバージョンアップ</h1>\n<p>pythonの新しいバージョンがリリースされ、それをインストールしたい場合など、pyenvのバージョンアップが必要。<br />\npyenv-updateをインストールしておけば(上記手順でインストール済み)、以下のコマンドですべてのプラグインを含めてバージョンアップしてくれる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv update\n</code></pre></div></div>\n\n<h2 id=\"古い方法\">古い方法</h2>\n<p>pyenv-updateをインストールしていない場合は以下の手順でそれぞれのリポジトリをpullする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit pull\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのpythonを使いたい場合は以下のように実行\">システムのpythonを使いたい場合は以下のように実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv version\n</code></pre></div></div>\n\n<h3 id=\"pyenvでインストールされているpythonのバージョン仮想環境を確認\">pyenvでインストールされているpythonのバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"pyenv自体のバージョン確認\">pyenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"pyenvで使用できるコマンドの確認\">pyenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv commands\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>python の async/await</title>\n  </head>\n  <body>\n    <header>\n      <h1>python の async/await</h1>\n      <p>python の async/awaitってどう動くんだっけ?</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h2 id=\"python-の-asyncawaitってどう動くんだっけ\">python の async/awaitってどう動くんだっけ?</h2>\n\n<p>と思ったので、ちょっとテストプログラムを書いて試してみた。</p>\n\n<p>asyncioはnon-preemptiveなので、最近のpreemptiveに慣れ切った脳ミソにはややこしい。</p>\n\n<p>preemptiveなプログラムを書きたければ、threadingを使えば良い。適材適所というやつだ。</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">asyncio</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n\n<span class=\"n\">argvs</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span>  <span class=\"c1\"># コマンドライン引数を格納したリストの取得\n</span><span class=\"n\">argc</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">)</span> <span class=\"c1\"># 引数の個数\n</span>\n<span class=\"k\">if</span> <span class=\"n\">argc</span> <span class=\"o\">></span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"mi\">5</span>        <span class=\"c1\"># テストケース\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"testCase = \"</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">testCase</span><span class=\"p\">))</span>\n\n<span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>           <span class=\"c1\"># 念のため宣言だけしておく\n</span>\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">sub</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub start        \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub wakeup       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"mi\">42</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"n\">task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">sub</span><span class=\"p\">())</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"k\">await</span> <span class=\"n\">task</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">task</span>\n    \n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main wakeup      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main2</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 start      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 wakeup     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n\n<span class=\"c1\"># =============================================================================\n</span><span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>     <span class=\"c1\"># 開始時刻を記憶\n</span><span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">or</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">4</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">wait</span><span class=\"p\">([</span><span class=\"n\">main</span><span class=\"p\">(),</span> <span class=\"n\">main2</span><span class=\"p\">()]))</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">5</span> <span class=\"p\">:</span>\n    <span class=\"n\">loop</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">get_event_loop</span><span class=\"p\">()</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"unknown test case!!\"</span><span class=\"p\">)</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n\n<p>以下のようにコマンドラインからテストケース番号を指定して実行する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python test.py <testCase>\n</code></pre></div></div>\n\n<h2 id=\"実行結果\">実行結果</h2>\n<h3 id=\"testcase1\">testCase=1</h3>\n\n<p>基本的なパターン、というか、全然非同期実行になってないけど。。。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code>→ <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p>awaitが付いていると、その場でタスクに実行権を渡し、そのタスクが終了するまで待つ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 1\ntestCase <span class=\"o\">=</span>  1\nbefor create     0.00026416778564453125\nafter create     0.00034689903259277344\nbefor call       0.00040340423583984375\nsub start        0.00047469139099121094\nsub wakeup       2.0033931732177734\nafter call       2.0035252571105957\nmain wakeup      3.004753351211548\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase2\">testCase=2</h3>\n\n<p>基本的なパターン、こっちが非同期実行として本命。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code>を実行するときに<code class=\"language-plaintext highlighter-rouge\">await</code>を付けない。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">await</code>が付いていないと、その場でタスクに実行権を渡さず、自分の実行を中断する部分か終了するまでそのまま実行する。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> 呼び出し箇所では即時実行されず、sleep(2)で <code class=\"language-plaintext highlighter-rouge\">main</code> の実行が中断されたところで <code class=\"language-plaintext highlighter-rouge\">sub</code> へ切り替わる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> で <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> が実行されると実行されるタスクがなくなるので、イベントループは実行可能タスク待ちになる。</p>\n\n<p>1秒後、<code class=\"language-plaintext highlighter-rouge\">main</code> が起床するので、そのままmainが終了される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> で イベントループは <code class=\"language-plaintext highlighter-rouge\">main</code> の終了を待っているので、<code class=\"language-plaintext highlighter-rouge\">sub</code> が実行中でも無関係にイベントループを終了してしまい、\n <code class=\"language-plaintext highlighter-rouge\">sub</code> の残りは実行されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 2\ntestCase <span class=\"o\">=</span>  2\nbefor create     0.0002646446228027344\nafter create     0.00034308433532714844\nbefor call       0.00039768218994140625\nafter call       0.0004489421844482422\nsub start        0.0005385875701904297\nmain wakeup      1.0014407634735107\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase3\">testCase=3</h3>\n\n<p>testCase=2 でsubの残りも実行するには?と思って試したパターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で、即座に <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main2())</code> を実行してみた。</p>\n\n<p>見事失敗。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→ <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p>どうやら、 <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で イベントループは一旦 <code class=\"language-plaintext highlighter-rouge\">close</code> されてしまうらしい。</p>\n\n<p>単にtestCase=2の後ろにmain2の実行を付け加えただけになってしまった。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 3\ntestCase <span class=\"o\">=</span>  3\nbefor create     0.00029540061950683594\nafter create     0.0003790855407714844\nbefor call       0.0004353523254394531\nafter call       0.00048828125\nsub start        0.0005817413330078125\nmain wakeup      1.0015552043914795\nmain2 start      1.0021519660949707\nmain2 wakeup     4.0038042068481445\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase4\">testCase=4</h3>\n\n<p>testCase=3 の失敗挽回パターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でmainとmain2をまとめてみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でまとめたタスクがすべて終了するまでイベントループは<code class=\"language-plaintext highlighter-rouge\">close</code> されないので、<code class=\"language-plaintext highlighter-rouge\">sub</code>は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> と <code class=\"language-plaintext highlighter-rouge\">main2</code> のどちらが先に実行されるかは規定されていない様子。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 4\ntestCase <span class=\"o\">=</span>  4\nmain2 start      0.0003325939178466797\nbefor create     0.0004305839538574219\nafter create     0.0005018711090087891\nbefor call       0.0005679130554199219\nafter call       0.0006389617919921875\nsub start        0.0007307529449462891\nmain wakeup      1.002068042755127\nsub wakeup       2.002253293991089\nmain2 wakeup     3.003903388977051\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase5\">testCase=5</h3>\n\n<p>testCase=3 の失敗挽回パターン その2。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.get_event_loop()</code> でイベントループを取得し、<code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> でそれぞれのタスクを実行してみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> → イベントループ終了\nとなっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> ではタスクが終了してもイベントループはcloseされないので、同じイベントループで<code class=\"language-plaintext highlighter-rouge\">main2</code>が実行される。\n結果、<code class=\"language-plaintext highlighter-rouge\">sub</code> は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> が終了するまで <code class=\"language-plaintext highlighter-rouge\">main2</code> は実行(起動)されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 5\ntestCase <span class=\"o\">=</span>  5\nbefor create     0.0002574920654296875\nafter create     0.0003345012664794922\nbefor call       0.00038933753967285156\nafter call       0.0004410743713378906\nsub start        0.0005307197570800781\nmain wakeup      1.0010528564453125\nmain2 start      1.0011804103851318\nsub wakeup       2.002350330352783\nmain2 wakeup     4.002865314483643\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Windows": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MSYS2とgccのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>MSYS2とgccのインストール</h1>\n      <p>WindowsにMSYS2とgccをインストールした時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows環境でLinuxライクな環境を使用できる<a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2</a><br />\ngcc は単体で配布されている <a href=\"https://github.com/niXman/mingw-builds-binaries/releases\" target=\"_blank\">MinGW-W64-binaries</a>を使っていたが、\nMSYS2で管理されているものに切り替えてみた。</p>\n\n<h1 id=\"msys2のインストール\">MSYS2のインストール</h1>\n<p>大体以下の感じでインストールできる。</p>\n<ul>\n  <li><a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2のページ</a> を開く</li>\n  <li>Installation セクションの Download the installer: に書かれているリンクからダウンロード(バージョンアップで更新されるのでここにはリンクを貼らないでおく)</li>\n  <li>ダウンロードしたファイルを実行</li>\n  <li>デフォルトのままNextをクリックして行き、Installをクリック</li>\n  <li>終わったらFinishをクリック</li>\n</ul>\n\n<h1 id=\"msys2の設定\">MSYS2の設定</h1>\n<p>後でWindowsTerminalから使えるようにするからやらなくても良いけど、ま、気持ちの問題なので。</p>\n<ul>\n  <li>msys2を起動(スタート→すべて→MSYS2→MSYS2 UCRT64)し、タイトルバーを右クリックし 「Options…」 を選択\n    <ul>\n      <li>Text の Font の Select.. をクリックしてフォントとサイズを変更</li>\n      <li>Text の Local で ja_JP と UTF8 を選択</li>\n      <li>Window の Default size で ウィンドウサイズが変更できる</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"最新版にアップデート\">最新版にアップデート</h1>\n<p>MSYS2を起動して以下を実行(ubuntuの<code class=\"language-plaintext highlighter-rouge\">apt update && apt upgrade</code>に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -Syuu\n</code></pre></div></div>\n\n<p>何か聞かれたらYを入力<br />\nウィンドウが閉じられたら再度MSYS2を起動<br />\n再度MSYS2を起動したらもう一回 <code class=\"language-plaintext highlighter-rouge\">pacman -Syuu</code> を実行</p>\n\n<h1 id=\"開発ツールのインストール\">開発ツールのインストール</h1>\n<p>MSYS2を起動して以下を実行<br />\n(make、gcc、gdbなどのインストール)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -S base-devel\npacman -S mingw-w64-ucrt-x86_64-gcc\npacman -S mingw-w64-ucrt-x86_64-gdb\n</code></pre></div></div>\n\n<h1 id=\"pathの変更\">PATHの変更</h1>\n<p>MSYS2のbashで実行する際はpathは設定済みだが、\nコマンドプロンプト等で実行するためにWindows側のPATHを変更する。</p>\n\n<ul>\n  <li>設定 → システム → バージョン情報</li>\n  <li>関連リンクの「システムの詳細設定」をクリック</li>\n  <li>開いたウィンドウの下のほうにある「環境変数(N)…」をクリック</li>\n  <li>上側のユーザ環境変数で「Path」を選択して「編集」をクリック</li>\n  <li>「新規」をクリックして以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>c:\\msys64\\ucrt64\\bin\nC:\\msys64\\usr\\bin\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\nc:\\msys64\\ucrt64\\bin にはpythonが入っているので、Windowsでインストールしたpythonを使用したい場合は\nそのPATHより後(下)に設定すること</p>\n    </blockquote>\n  </li>\n</ul>\n\n<p>念のためここでPCを再起動する。<br />\n(PATHの変更が有効にならない場合がある)</p>\n\n<h1 id=\"windowsterminal-にmsys2を登録\">WindowsTerminal にMSYS2を登録</h1>\n<p>MSY2のデフォルトのターミナルはminttyだが、いつも使っているWindowsTerminalで使えるようにする。</p>\n<ul>\n  <li>WindowsTerminalを起動</li>\n  <li>「新しいプロファイルを追加」を選択</li>\n  <li>「新しい空のプロファイル」をクリック\n    <ul>\n      <li>コマンドラインに以下を設定(ucrt64の場合。それ以外は最後のオプションを変更する)\n        <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>C:/msys64/msys2_shell.cmd -defterm -here -no-start -ucrt64\"  \n</code></pre></div>        </div>\n      </li>\n      <li>開始ディレクトリに MSYS2のhomeディレクトリ(<code class=\"language-plaintext highlighter-rouge\">cygpath.exe -w ~</code> で取得可能) を指定</li>\n      <li>アイコンは何でもいいけど、<code class=\"language-plaintext highlighter-rouge\">C:\\\\msys64\\\\ucrt64.ico</code>とかが良いかな</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"vs-codeのターミナルでmsys2のbashを使用する方法\">VS CodeのターミナルでMSYS2のBashを使用する方法</h1>\n<p>VS CodeのターミナルでもMSYS2を使えるようにしておく。<br />\n(別ウィンドウでWindowsTerminalから実行すればいいんだけど)</p>\n\n<ul>\n  <li>VSCodeを起動</li>\n  <li>設定(ファイル→ユーザ設定→設定)を開く</li>\n  <li>機能→ターミナルを選ぶ\n-「integrated > profiles:windows」 を探す(検索すれば良いんだけど)\n    <ul>\n      <li>「setting,jsonで編集」 をクリック\n        <ul>\n          <li>ひな型作って開いてくれる。</li>\n          <li>そこに 以下を追加\n            <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>          \"MSYS2 Bash\": {\n              \"path\": [\n                  \"C:\\\\msys64\\\\msys2_shell.cmd\"\n              ],\n              \"args\": [\n                  \"-defterm\",\n                  \"-here\",\n                  \"-no-start\",\n                  \"-ucrt64\"\n              ]\n          }\n</code></pre></div>            </div>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nファイルは ユーザだと、<code class=\"language-plaintext highlighter-rouge\">%APPDATA%\\code\\User\\settings.json</code><br />\nワークスペースだとワークスペース下の<code class=\"language-plaintext highlighter-rouge\">.vscode\\settings.json</code></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nデフォルトのプロファイルをBashにすると悲しい結果が待ち受けているのでやらない方が良さそう</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINO 2022.1のbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1はRaspberry Pi OS(64bit)向けのバイナリがリリースされていないので、自力でbuildしてみます。</p>\n\n<p>今回もUbuntu上のDockerコンテナを使用しましたが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思います。</p>\n\n<p>前回はPythonを諦めてクロスコンパイルする方法とbuild時間を諦めてセルフコンパイル(エミュレーション)する方法を使いましたが、<br />\n今回はPython以外をクロスコンパイル、Python関連部をセルフコンパイル(エミュレーション)して生成物をマージする方法をとってみます。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_2022.1_pi64 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_2022.1_pi64\n</code></pre></div></div>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>workディレクトリを作成し、openvino と openvino_contrib のリポジトリをcloneします。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 2022.1.1 <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib checkout 1a28b530ab40d2ad79ab29021dfddfbbc7d2db0b\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の2022.1だと一部のノードが未対応とエラーになるため、対応済みのcommitを使用します。<br />\ntagが振られていないので、commit IDを指定してcheckoutします。<br />\nこれ以降のcommitではopenvinoのバージョン2022.2が必要になります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ntagやbranchが設定されていない場合はcloneでcheckoutするバージョンを指定できないため、\n一旦cloneしてからcommit IDを指定してcheckoutします。<br />\nsubmoluleのcheckoutは対象のバージョンをcheckoutしてから行います。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の最新commit(試した時点ではcommit ID <code class=\"language-plaintext highlighter-rouge\">fd2ac364435757d23a9b3e91d67235b5e6555bf9</code>)を使用する場合は\nopenvinoのバージョン2022.2を使用する必要がありますが、試した時点で <code class=\"language-plaintext highlighter-rouge\">2022.2.0.dev20220829</code> がリリースされているので\nこれを使用します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0.dev20220829  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit -C ./work/openvino_contrib checkout fd2ac364435757d23a9b3e91d67235b5e6555bf9\ngit -C ./work/openvino_contrib submodule update --init --recursive --depth 1\n</code></pre></div>  </div>\n  <blockquote>\n    <p>2022.2.0正式リリース後はこんな感じになるのかな?</p>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  -b 2022.2    --recursive --depth 1 https://github.com/openvinotoolkit/openvino_contrib.git\n</code></pre></div>    </div>\n  </blockquote>\n\n  <p>この場合、NVIDIA GPUのpluginのbuildでエラーになるため、以下のcmakeのオプションに以下のオプションを追加します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      -D BUILD_nvidia_plugin=OFF\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h1 id=\"openvinoのbuildクロスコンパイル\">openVINOのBuild(クロスコンパイル)</h1>\n\n<p>クロスコンパイルでpython関連以外の部分をbuildします。</p>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir cross</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">cross/Dockerfile</code>を作成します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cross/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates:arm64 <span class=\"se\">\\\n</span>    libboost-regex-dev:arm64 <span class=\"se\">\\\n</span>    libgtk2.0-dev:arm64 <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev:arm64 <span class=\"se\">\\\n</span>    libcairo2-dev:arm64 <span class=\"se\">\\\n</span>    libpango1.0-dev:arm64 <span class=\"se\">\\\n</span>    libglib2.0-dev:arm64 <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev:arm64 <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗します</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeは新しめのをインストールしておきたいので、3.23.2をbuildして使用しています。<br />\nもしかすると、<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたものをそのまま使っても大丈夫かもしれませんが。</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_cross cross\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\ncacheを使わずimage buildしたい場合は<code class=\"language-plaintext highlighter-rouge\">--no-cache</code>オプションを追加します。<br />\n以前に作ったイメージのキャッシュを使って<code class=\"language-plaintext highlighter-rouge\">apt install</code>がエラーになったことがあったので。<br />\n(デフォルトのリポジトリに変更があったらしい)</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_cross_2 ov_2022.1_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_cross_2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_2022.1_pi64_cross_2 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/cmake/arm64.toolchain.cmake <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_BEH_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLDNN</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_FUNCTIONAL_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">THREADING</span><span class=\"o\">=</span>SEQ <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">CONTRIB_TOP</span><span class=\"k\">}</span>/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span> 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=${WORK_DIR}/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"クロスコンパイル終了\">クロスコンパイル終了</h3>\n<p>クロスコンパイルはここまでなので、コンテナから抜ける。</p>\n\n<h1 id=\"openvinoのbuildセルフコンパイル\">openVINOのBuild(セルフコンパイル)</h1>\n\n<p>セルフコンパイルでpython関連部分をbuildします。<br />\ncythonを使うときにクロスコンパイルする方法が分からないので、セルフコンパイルで。</p>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir emu</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">emu/Dockerfile</code>を作成します。</p>\n\n<p>python部だけなので、こんなにライブラリとか要らない気もしますが、全部セルフコンパイルするときのことも考えて\n全部入りのイメージを作っておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  emu/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates <span class=\"se\">\\\n</span>    libboost-regex-dev <span class=\"se\">\\\n</span>    libgtk2.0-dev <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev <span class=\"se\">\\\n</span>    libcairo2-dev <span class=\"se\">\\\n</span>    libpango1.0-dev <span class=\"se\">\\\n</span>    libglib2.0-dev <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_emu emu\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_emu_2 ov_2022.1_pi64_emu /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_emu_2\n</code></pre></div></div>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成-1\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build_python <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build_python\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">InferenceEngineDeveloperPackage_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/build <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/src/bindings/python 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">CMAKE_INSTALL_PREFIX</code>の設定はクロスコンパイルのときと同じ設定にしてください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npyenvでインストールしたpythonなど、デフォルトでないpythonを使用する場合に指定します。<br />\n(以下の設定値はubuntu 22.04の標準インストールの場合のパスなのであまり参考にならないかも)</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  -D PYTHON_EXECUTABLE=/usr/bin/python3.8 \\\n  -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.8.so \\\n  -D PYTHON_INCLUDE_DIR=/usr/include/python3.8 \\\n  -D PYTHON_MODULE_EXTENSION=\".so\" \\\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"make-1\">make</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。</p>\n\n<h3 id=\"セルフコンパイル終了\">セルフコンパイル終了</h3>\n<p>セルフコンパイルはここまでなので、コンテナから抜けます。</p>\n\n<h1 id=\"インストール媒体の作成\">インストール媒体の作成</h1>\n\n<p>ホスト側の<code class=\"language-plaintext highlighter-rouge\">work</code>ディレクトリ内を見ると、<code class=\"language-plaintext highlighter-rouge\">intel</code>ディレクトリが出来ているので、ここをtarなどで固めておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>work\n<span class=\"nb\">tar </span>czvf ov1.tar.gz intel/\n</code></pre></div></div>\n\n<p>この<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiにコピーして展開します。</p>\n\n<h1 id=\"raspberrypiへのインストール\">RaspberryPiへのインストール</h1>\n\n<h2 id=\"インストール\">インストール</h2>\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiの適当なディレクトリに展開します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/proj</code>ディレクトリに展開しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /proj/\n<span class=\"nb\">tar </span>xzvf ov1.tar.gz \n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<p>これで<code class=\"language-plaintext highlighter-rouge\">/proj/intel/openvino</code>ディレクトリにインストールされました。</p>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n<p>環境変数の設定のため、以下を実行します。<br />\nshell起動の度に実行が必要なので<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>などに書いておくと良いです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/intel/openvino/setupvars.sh \n</code></pre></div></div>\n\n<h2 id=\"udevルールの設定\">udevルールの設定</h2>\n<p>以下のスクリプトを実行すればNCS2を挿せば認識されるようになります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/proj/intel/openvino/install_dependencies/install_NCS_udev_rules.sh \n</code></pre></div></div>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n<p>openCVの必要になるので、インストールしておきます。<br />\n今回はお手軽にpipでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認用のプログラムは<a href=\"https://github.com/ippei8jp/ov_trial_2022.1\" target=\"_blank\">https://github.com/ippei8jp/ov_trial_2022.1</a> とかにあります。<br />\nでもモデルのダウンロード/コンバートはRaspberryPiではできないので、UbuntuやWondowsで実行したものをコピーして使用してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Pythonのasyncioでnon-blockingなコンソール入力</title>\n  </head>\n  <body>\n    <header>\n      <h1>Pythonのasyncioでnon-blockingなコンソール入力</h1>\n      <p>Pythonのasyncioでnon-blockingなコンソール入力を行うためのクラス</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでasyncioを使ったときにnon-blockingなコンソール入力(キーボード入力)ができなくて困ったので、実現するためのクラスを作ってみた。</p>\n\n<p>もともと Linux用に作ったら、Windowsだとうまく動かない。<br />\nちょっと汚い方法だけど、とりあえず動くようにしてお茶を濁しておく。<br />\n(あんまりテストしてないから動かなかったらごめん)</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/5033eec9b9b774ede4f87604a51fb162.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>お試しならこのソースをそのまま実行すると実行できます。<br />\n<code class=\"language-plaintext highlighter-rouge\">char_mode = False</code> の部分を変更すると、1行入力モードと1文字入力モードを切り替えられます。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout_mode = True</code> の部分を変更すると、タイムアウトなしとタイムアウトありを切り替えられます。</p>\n\n<p>実際に使用するには、このソースをimportして使ってください。</p>\n\n<h1 id=\"注意\">注意</h1>\n\n<p>Linuxで1文字入力モードを使っている場合は、終了時(例外で死んだ場合も含めて)<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行しないと悲しいことになります。<br />\n(ターミナルの入力モードが変更されてしまうので、うまく入力できなくなる)<br />\nそのために、<code class=\"language-plaintext highlighter-rouge\">atexit.retister()</code>で終了処理ルーチンを登録し、その中で<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行するようにしています。</p>\n\n<h1 id=\"ひとりごと\">ひとりごと</h1>\n\n<p>asyncioのサンプルって、タスク1個で動かしてることが多いからあんまり ありがたみが分からんのかな…<br />\nあと、タスクとコルーチンが同じように語られていて分かり難いのもあると思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINOのクロスコンパイル</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINOのクロスコンパイル</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild(クロスコンパイル環境)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi OS(64bit)向けにopenVINOをクロスコンパイルする方法についてまとめた。<br />\nセルフコンパイル(Docker使用)については『<a href=\"/memoBlog/2022/03/07/openVINO_build_2.html\" target=\"_blank\">openVINO(Raspberry Pi OS(64bit)向け)のbuild</a>』を参照。<br />\nただ、クロスコンパイルだとセルフコンパイルの10倍くらい速い(環境によるけど)ので、クロスコンパイルがおススメ。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_cross <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_cross\n</code></pre></div></div>\n\n<h2 id=\"ソースの取得\">ソースの取得</h2>\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h3>\n<p>以下の1つのpatchファイルを作成する。<br />\nサンプル(テスト?)プログラムのBuildを抑制してコンパイル時間の短縮を計っている。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"opencv-の-gitリポジトリを-clone\">openCV の gitリポジトリを clone</h3>\n<p>opencv のリポジトリをcloneする(opencvのBuildを行わない場合は不要)。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libgtk-3-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_cross <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_cross_1 ov_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_cross_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_cross_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n<p>ここからコンテナ内</p>\n\n<h2 id=\"buildディレクトリの作成\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openvino/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/openvino/build\n</code></pre></div></div>\n\n<h2 id=\"cmake実行\">cmake実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm64.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_SAMPLES</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLANG_FORMAT</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_OPENCV</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n    .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>サンプルはBuildしないので、ENABLE_SAMPLES=OFF を設定</li>\n    <li>ソースをいじるわけではないので、ENABLE_CLANG_FORMAT=OFF を設定</li>\n    <li>openCVインストールされていないので、ENABLE_OPENCV=OFF を設定<br />\n(サンプルのBuildしないのでopenCVなくても大丈夫)</li>\n  </ul>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nログには いくつかWarningがあるが、とくに問題はなさそう</p>\n</blockquote>\n\n<h2 id=\"make\">make</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h2 id=\"その他細々したところ\">その他細々したところ</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"c\"># クロスコンパイルを反映したファイル名になっていないので修正</span>\n<span class=\"nb\">mv</span> /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-x86_64-linux-gnu.so /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-aarch64-linux-gnu.so\n\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>CPU Extentionは<code class=\"language-plaintext highlighter-rouge\">make install</code>でコピーされないので手動でインストールする。</li>\n    <li>バイナリリリースに<code class=\"language-plaintext highlighter-rouge\">inference_engine</code>のシンボリックリンクがあるので同様に作成しておく。</li>\n    <li>ngraphのライブラリファイルのファイル名がx86_64(ホスト環境の名前)になっているので、aarch64に修正。<br />\nバイナリ自体はaarch64になっているので、ファイル名のリネームだけでOK。<br />\n本来はファイル名決めてるところで対処するのが良いのだろうけど、とりあえず力技で。</li>\n  </ul>\n</blockquote>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<p>openCVのBuild方法についてもメモっておく。<br />\npythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。<br />\nその場合は、ここはスキップしても大丈夫。<br />\nopenVINOをBuildしたDockerコンテナで引き続き作業を行う</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk-3-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libjpeg-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libpng-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev:arm64\n</code></pre></div></div>\n<h2 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n</code></pre></div></div>\n<h2 id=\"cmakeの実行\">cmakeの実行</h2>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PKG_CONFIG_LIBDIR</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_ENABLE_PKG_CONFIG</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_FIND_ROOT_PATH</span><span class=\"o\">=</span>/ <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span>/work/opencv/platforms/linux/aarch64-gnu.toolchain.cmake <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_NUMPY_INCLUDE_DIRS</span><span class=\"o\">=</span>/usr/lib/python3/dist-packages/numpy/core/include <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n       .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあらかじめ環境変数<code class=\"language-plaintext highlighter-rouge\">PKG_CONFIG_LIBDIR</code>を設定して<code class=\"language-plaintext highlighter-rouge\">pkg-config</code>でaarch64のライブラリとNativeのツール類を参照するように設定しておく。<br />\nこれをやらないと、libjpegとかをインストールしてあることを検出できない</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeのオプションに <code class=\"language-plaintext highlighter-rouge\">-D CMAKE_FIND_DEBUG_MODE=1</code>を追加すると\ncmake中の<code class=\"language-plaintext highlighter-rouge\">find_xxx</code>の動作のログが出力されるので、パッケージのサーチなどの検索パスの確認などが容易になる。</p>\n</blockquote>\n\n<h2 id=\"make-1\">make</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install-1\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino/opencv</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/opencv</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-D CMAKE_INSTALL_PREFIX=/work/opt/intel/openvino/opencv</code>の部分を変更すれば良いけど、ここはopenVINOのインストール先と合わせておかないとうまく動かない。</p>\n\n<h1 id=\"実機へのインストール\">実機へのインストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">opt</code>ディレクトリ以下を丸ごとアーカイブする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<p>作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>をRaspberryPiの適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"コンテナから出る\">コンテナから出る</h1>\n<p>Dockerコンテナは作業終了したら終了しておく。<br />\nCTRL-D でshell終了</p>\n\n<h1 id=\"補足\">補足</h1>\n<p>コンテナにインストールされているパッケージは以下の通り。<br />\nバージョン違いで動かなくなることもあるかもしれんので、念のため。</p>\n\n<p>こんな感じで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span> | <span class=\"nb\">grep</span> <span class=\"nt\">-v</span> automatic\n</code></pre></div></div>\n\n<p>で、こんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>build-essential/stable,now 12.9 amd64 [installed]\ncmake/stable,now 3.18.4-2+deb11u1 amd64 [installed]\ncrossbuild-essential-arm64/stable,stable,now 12.9 all [installed]\ncython3/stable,now 0.29.21-3+b1 amd64 [installed]\ngit/stable,now 1:2.30.2-1 amd64 [installed]\nlibavcodec-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibavformat-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibgstreamer-plugins-base1.0-dev/stable,now 1.18.4-2 arm64 [installed]\nlibgstreamer1.0-dev/stable,now 1.18.4-2.1 arm64 [installed]\nlibgtk-3-dev/stable,now 3.24.24-4 arm64 [installed]\nlibjpeg-dev/stable,now 1:2.0.6-4 arm64 [installed]\nlibpng-dev/stable,now 1.6.37-3 arm64 [installed]\nlibprotobuf-dev/stable,now 3.12.4-1 arm64 [installed]\nlibprotoc-dev/stable,now 3.12.4-1 arm64 [installed]\nlibpython3-dev/stable,now 3.9.2-3 arm64 [installed]\nlibswscale-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibtiff-dev/stable,now 4.2.0-1 arm64 [installed]\nlibusb-1.0-0-dev/stable,now 2:1.0.24-3 arm64 [installed]\nlibwebp-dev/stable,now 0.6.1-2.1 arm64 [installed]\nprotobuf-compiler/stable,now 3.12.4-1 amd64 [installed]\npython3-minimal/stable,now 3.9.2-3 amd64 [installed]\npython3-numpy/stable,now 1:1.19.5-1 amd64 [installed]\npython3-pip/stable,stable,now 20.3.4-4 all [installed]\nscons/stable,stable,now 4.0.1+dfsg-2 all [installed]\nwget/stable,now 1.21-1+deb11u1 amd64 [installed]\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>aspberry Pi OS(64bit)がリリースされたが、openVINOのBuild済みモジュールはまだこれに対応していない。<br />\nそのうち対応されると思うけど、とりあえず自前でBuildする方法を調べてみた。<br />\nついでにCPU Extensionも作成しておく。<br />\nなお、Raspberry Pi OS(32bit Buster)向けのBuild手順については、\n『<a href=\"/memoBlog/2021/10/28/openVINO_build.html\" target=\"_blank\">openVINO(Raspberry Pi向け)のbuild</a>』を参照。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<p>今回もARM版Dockerコンテナを使用してセルフコンパイルする方法で行う。<br />\n手順そのものは特殊なことはないので、Raspberry Pi上のNative環境でもBuildできそうだけど、\nディスク容量とかスワップ領域とか気にしないといけないかもしれないので試してない。<br />\n(今回はクロスコンパイル環境はなし。cythonの出力モジュールも使いたかったので)</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_emu\n</code></pre></div></div>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h2 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h2>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n32bit版との差分はこんな感じ。<br />\nあれ?32bit版の<code class=\"language-plaintext highlighter-rouge\">python-minimal</code>って間違ってる?<br />\n<code class=\"language-plaintext highlighter-rouge\">python3-numpy</code>で依存モジュールとしてインストールされて事なきを得たのか?<br />\n実質、ベースイメージを変更してるだけだな。</p>\n\n  <div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- Dockerfile.old\t2022-03-01 07:26:28.774187231 +0900\n</span><span class=\"gi\">+++ Dockerfile\t2022-03-01 07:19:45.668393598 +0900\n</span><span class=\"p\">@@ -1,4 +1,4 @@</span>\n<span class=\"gd\">-FROM arm32v7/debian:buster\n</span><span class=\"gi\">+FROM arm64v8/debian:bullseye\n</span> \n USER root\n \n<span class=\"p\">@@ -18,7 +18,7 @@</span>\n     libprotobuf-dev libprotoc-dev protobuf-compiler \\\n     cmake \\\n     python3-pip \\\n<span class=\"gd\">-    python-minimal \\\n</span><span class=\"gi\">+    python3-minimal \\\n</span>     python3-numpy cython3 scons\n \n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_emu_1 ov_pi64_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<p>数時間レベルでかかるので、のんびり待ちましょう。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"その他細々したところ\">その他細々したところ</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コメント\">コメント</h3>\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール\">実機へのインストール</h2>\n\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>を適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>ついでにopenCVのBuild方法についてもメモっておく。</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>openCVのリポジトリをcloneしておく。<br />\n指定するタグは適宜変更してください。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n<p>新しいDockerコンテナ作っても良いけど、別にその必要もないので上記のコンテナをそのまま使用する。</p>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n  <h2 id=\"本番-1\">本番</h2>\n</blockquote>\n\n<h3 id=\"準備-2\">準備</h3>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk2.0-dev  libjpeg-dev libpng-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev\n</code></pre></div></div>\n\n<h3 id=\"build\">Build</h3>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n\n<span class=\"c\"># インストール</span>\nmake <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf opencv.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コンテナから出る-1\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール-1\">実機へのインストール</h2>\n<p>openVINOをBuildしたコンテナで続けてBuildした場合は<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>にopenVINO、openCVがインストールされている。<br />\nこれを適当なディレクトリに展開して環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば良い。</p>\n\n<p>別のコンテナを使用したり、openVINOのBuild結果を削除していた場合は、<br />\n最終的に作成した<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>をopenVINOをインストールしたディレクトリに展開する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi向け)のbuild</h1>\n      <p>Raspberry Pi向けopenVINOのbuild(特にCPU extension)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi用 openVINO は デフォルト状態ではCPUで実行できない(NCS2必須)。<br />\nそこで、オープンソース版openVINOを使用してCPU extensionを作成してみる。<br />\nとはいえ、CPU extension だけサクっと作成できなくて、openVINO全体を作成するハメに…</p>\n\n<p>Raspberry Pi 実機でbuildすると、ディスク容量がバカにならないし、<br />\nあまり実環境を弄りたくなかったので、<br />\nUbuntuマシン上のDockerコンテナで実行する方法を試してみる(Docker Desktop for Windowsでもできると思う)</p>\n\n<h1 id=\"arm版dockerコンテナを使用したセルフコンパイル\">ARM版Dockerコンテナを使用したセルフコンパイル</h1>\n\n<p>Dockerコンテナ全体をQEMU上でARMエミュレーションしてくれるので、特に難しいことを考えずに<br />\nネイティブ環境と変わりなくあつかえる。<br />\nでも、かなり遅い(実機よりちょっと速い?同じくらい?)。<br />\n試した環境では、x86_64な環境でクロスコンパイルした場合の15倍くらいかかった。  <br />\n(M1 Mac上でACVMを使うとかなり早いという噂も…M1 Mac持ってない😢  <a href=\"https://qiita.com/kose3/items/af9edc9c40c9ae8fc5c3\" target=\"_blank\">参考</a>  )</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h3 id=\"qemuのインストール\">qemuのインストール</h3>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_emu\n</code></pre></div></div>\n\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm32v7/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成\">patchファイルを作成</h3>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_emu_1 ov_pi_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n以下のオプションを追加すると少しは速くなるかと思ったが、あまり変わらない。</p>\n  <ul>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_OPENCV=OFF</code></li>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_SAMPLES=OFF</code></li>\n  </ul>\n</blockquote>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。</p>\n\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./inference_engine</code> がない\n    <ul>\n      <li>実体は <code class=\"language-plaintext highlighter-rouge\">deployment_tools/inference_engine</code> なので、シンボリックリンクを作れば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/opencv/</code>からコピーすれば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>opencvのpythonモジュールがない\n        <ul>\n          <li>どこから持ってくれば良いんだろう?</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h3 id=\"実機へのインストール\">実機へのインストール</h3>\n<p>CPU extensionだけなら<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l/</code><br />\nへコピーするだけで良い。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれはmake install してもこれはコピーされないらしい。</p>\n</blockquote>\n\n<p>openVINO全体のインストールなら<code class=\"language-plaintext highlighter-rouge\">work/opt/intel/openvino</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/</code>にコピーすれば良いのだけど、opencvのpythonインタフェースがないので注意。<br />\nということで、実際に試していない…</p>\n\n<blockquote>\n  <p>[!NOTE]\n※※※※ メモ ※※※※ <br />\nopenCVはここでbuildするのではなく、<br />\n<a href=\"https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/\" target=\"_blank\">https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/</a> \nからbuild済みモジュールをダウンロードして<br />\n<code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/</code><br />\nに展開している。</p>\n</blockquote>\n\n<h1 id=\"i386版32bit-x86dockerコンテナを使用したクロスコンパイル\">i386版(32bit x86)Dockerコンテナを使用したクロスコンパイル</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>セルフコンパイルは時間がかかりすぎるので、クロスコンパイルで試してみた。<br />\nかなり早くなったが、一部使えないモジュールが…<br />\n当初の目的のCPU extensionは使えるので、掲載しとく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n当初、64bit版debianをベースに作業しようとしたが、\npybind11のbuildで以下のように怒られる。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Make Error at build/_deps/pybind11-src/tools/FindPythonLibsNew.cmake:127 (message):\n  Python config failure: Python is 64-bit, chosen compiler is 32-bit\nCall Stack (most recent call first):\n  build/_deps/pybind11-src/tools/pybind11Tools.cmake:16 (find_package)\n  build/_deps/pybind11-src/CMakeLists.txt:33 (include)\n</code></pre></div>  </div>\n  <p>以下のような対策が考えられる。</p>\n  <ul>\n    <li>FindPythonLibsNew.cmakeにbit数チェックをしないようにパッチを当てる\n      <ul>\n        <li>やり方がよう分からん…</li>\n      </ul>\n    </li>\n    <li>amd64なdebianに32bitのpythonをインストールする\n      <ul>\n        <li>イマイチうまくインストールできなかった</li>\n      </ul>\n    </li>\n  </ul>\n\n  <p>しかたないので、32bit版debianで作ることにした</p>\n</blockquote>\n\n<h2 id=\"準備-1\">準備</h2>\n\n<h3 id=\"作業用ディレクトリの準備-1\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_buster_32 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_buster_32\n</code></pre></div></div>\n<h3 id=\"openvino-の-gitリポジトリを-clone-1\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> i386/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> armhf <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-armhf <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:armhf <span class=\"se\">\\\n</span>    libgtk-3-dev:armhf <span class=\"se\">\\\n</span>    libavcodec-dev:armhf <span class=\"se\">\\\n</span>    libavformat-dev:armhf <span class=\"se\">\\\n</span>    libswscale-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:armhf <span class=\"se\">\\\n</span>    libpython3-dev:armhf <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python-argparse <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"c\"># aptでインストールするので削除</span>\n<span class=\"c\"># RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.3/cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     tar xzvf cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     (cd cmake-3.21.3 && ./bootstrap --parallel=$(nproc --all) -- -DCMAKE_USE_OPENSSL=OFF && make --jobs=$(nproc --all) && make install) && \\</span>\n<span class=\"c\">#     rm -rf cmake-3.21.3 cmake-3.21.3.tar.gz</span>\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"patchファイルを作成-1\">patchファイルを作成</h3>\n\n<p>以下の2つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch1.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake\nindex 6cb15a0..66a1ef6 100644\n</span><span class=\"gd\">--- a/cmake/dependencies.cmake\n</span><span class=\"gi\">+++ b/cmake/dependencies.cmake\n</span><span class=\"p\">@@ -19,8 +19,9 @@</span> if(CMAKE_CROSSCOMPILING AND CMAKE_HOST_SYSTEM_NAME MATCHES Linux AND CMAKE_HOST_\n     find_program(\n         SYSTEM_PROTOC\n         NAMES protoc\n<span class=\"gd\">-        PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n-        NO_DEFAULT_PATH)\n</span><span class=\"gi\">+        # PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n+        # NO_DEFAULT_PATH)\n+        )\n</span>     if(NOT SYSTEM_PROTOC)\n         message(FATAL_ERROR \"[ONNX IMPORTER] Missing host protoc binary\")\n     endif()\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる-1\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../patch1.patch<span class=\"o\">)</span>\n<span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino apply ../../patch1.patch\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_buster_32 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32_1</code> を使用。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_buster_32_1 ov_pi_buster_32 /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/386) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_buster_32_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_buster_32_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make-1\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n\n<p>コンテナから出て、<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の \n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l</code>/<br />\nへコピーする</p>\n\n<blockquote>\n  <p>[!WARNING]\ncythonの出力がx86のコードを吐くので、pythonモジュールの一部に正常に動作しないものがある。<br />\npythonモジュールを使いたいときはセルフコンパイルするしかないかな?</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerでopenVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerでopenVINO</h1>\n      <p>DockerでopenVINOプログラムの開発</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>DockerコンテナでopenVINOのプログラム開発を行う手順。<br />\n↓ここを参考にUbuntu 20.04/openVINO 2021.3に変更してみる。ついでによく使う機能の準備もやっておく。<br />\n<a href=\"https://kuttsun.blogspot.com/2021/06/openvino-docker.html\">https://kuttsun.blogspot.com/2021/06/openvino-docker.html</a></p>\n\n<h1 id=\"dockerイメージの作成\">Dockerイメージの作成</h1>\n\n<p>上の参照先を参考に公式イメージに必要な処理を加えておく。<br />\nDockerfile は以下。<br />\n参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>ベースをopenVINO/ubuntu20に変更</li>\n  <li>sudoとvimとless入れとく。sudoはパスワードなしで動作するようにしとく。</li>\n  <li>開発マシンなのでbaskhの補完機能を有効にしておく</li>\n  <li>キーバインド変更 ( <code class=\"language-plaintext highlighter-rouge\">^p</code> / <code class=\"language-plaintext highlighter-rouge\">^n</code> )</li>\n  <li>日本語文字化け対策</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code> がキー入力待ちになってbuildエラーになるので<code class=\"language-plaintext highlighter-rouge\">-y</code>オプションを追加</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-docker highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースイメージ</span>\n<span class=\"k\">FROM</span><span class=\"s\"> openvino/ubuntu20_dev:2021.3</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">ENV</span><span class=\"s\"> DEBIAN_FRONTEND=noninteractive</span>\n\n<span class=\"c\"># sudo と vim と less のインストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install sudo </span>vim less <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo </span>openvino <span class=\"nv\">ALL</span><span class=\"o\">=</span><span class=\"se\">\\(</span>root<span class=\"se\">\\)</span> NOPASSWD:ALL <span class=\"o\">></span> /etc/sudoers.d/openvino <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">chmod </span>0440 /etc/sudoers.d/openvino\n\n<span class=\"c\"># bashの補完機能 & キーバインドの設定 & 日本語文字化け対策</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nb\">install </span>bash-completion <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"s2\">\". /usr/share/bash-completion/bash_completion\"</span> <span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-n</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-forward' </span><span class=\"se\">\\n\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-p</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-backward'</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">export LANG=C.UTF-8</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">export LANGUAGE=en_US:</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc\n\n<span class=\"c\"># 依存パッケージのインストール(-yオプションで Yes自動選択)</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies <span class=\"o\">&&</span> ./install_openvino_dependencies.sh <span class=\"nt\">-y</span>\n\n<span class=\"c\"># サンプル、デモアプリのビルド</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/samples/cpp <span class=\"o\">&&</span> ./build_samples.sh\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/demos <span class=\"o\">&&</span> ./build_demos.sh\n<span class=\"c\"># /opt/intel/openvino_2021/deployment_tools/demo にデモアプリがある</span>\n\n<span class=\"c\"># 他に必要なものを適宜インストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>wget git python3-pip\n<span class=\"k\">RUN </span>pip3 <span class=\"nb\">install </span>onnxruntime flask\n\n<span class=\"c\"># aptのクリア</span>\n<span class=\"k\">RUN </span>apt clean <span class=\"o\">&&</span> <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> /var/lib/apt/lists/<span class=\"k\">*</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> openvino</span>\n\n<span class=\"c\"># bash起動</span>\n<span class=\"k\">CMD</span><span class=\"s\"> [ \"/bin/bash\" ]</span>\n</code></pre></div></div>\n\n<h1 id=\"ビルド\">ビルド</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker build <span class=\"nt\">-t</span> myopenvino/ubuntu20_dev:2021.3 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h1 id=\"コンテナの生成\">コンテナの生成</h1>\n<p>参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>カレントディレクトリ下のworkを/workに割り当てるように追加</li>\n  <li>GPU関連の設定を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ./work\ndocker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"se\">\\</span>\n       <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"se\">\\</span>\n       myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nX-Windowの表示先(<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code> 変数) は ここで固定されるので、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を変更したい場合は<br />\nコンテナをスタートした後、コンテナ内で手打ちで設定するか、<br />\n変更後の<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を設定したターミナルから以下を実行。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> openvino_2021.3 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<p>Windows の場合は以下な感じ。<br />\nDISPLAY変数は環境に合わせて変更してちょ。<br />\nNCS周りの設定は削除してある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.204:0.0 <span class=\"nt\">-v</span> %CD%<span class=\"se\">\\w</span>ork:/work myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ndocker をWSL上のコマンドラインから起動しているときは<code class=\"language-plaintext highlighter-rouge\">%CD%</code>でなく<code class=\"language-plaintext highlighter-rouge\">$PWD</code><br />\nPowerShellでコマンドを複数行に分割する場合は、行末記号は<code class=\"language-plaintext highlighter-rouge\">\\</code> ではなく <code class=\"language-plaintext highlighter-rouge\">`</code><br />\nコマンドプロンプトでは<code class=\"language-plaintext highlighter-rouge\">^</code> NYAGOSは分からん😢<br />\nそれぞれ違ってびみょーにストレス…</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> openvino_2021.3\n</code></pre></div></div>\n\n<p>コンテナ内でデモを動かしてみる<br />\n(デモの実行で必要なライブラリ類がインストールされたりするので、実行しましょう)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ~/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/demo1.log\n\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/dem2.log\n</code></pre></div></div>\n\n<p>前に作ったプログラムを試してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\ngit clone https://github.com/ippei8jp/ov_trial.git\n<span class=\"c\"># 入力画像の準備</span>\n<span class=\"nb\">cd </span>ov_trial/images/\nbash download.sh\n<span class=\"c\"># モデルファイルの準備(mobilenet-ssdのダウンロードがエラーになるけど大勢に影響ない) </span>\n<span class=\"nb\">cd</span> ../convert_model_ssd/\nbash convert_model_ssd.sh \n\n<span class=\"c\"># 認識してみる</span>\n<span class=\"nb\">cd</span> ../ssd/\nbash test.sh list\nbash test.sh 6\n</code></pre></div></div>\n\n<h1 id=\"ncs2の使用ubuntuのみ\">NCS2の使用(ubuntuのみ)</h1>\n<p>ubuntuではホストに接続したNCS2を使用することもできる。<br />\nただし、DockerコンテナからNCS2を使用するにはDokerホスト側にドライバをインストールしておく必要がある。<br />\n(udevルールだけ?イマイチ自信ないのでフルパッケージでインストールしておいた)<br />\n以下の部分がNCS2を使用するために必要な設定。(上記コマンド例では設定済み)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</h1>\n      <p>ローカル(Windows)のVSCodeからリモートホスト(ubuntu)上のDockerコンテナ内のプログラムをデバッグする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからUbuntu上のDockerコンテナに接続してデバッグする方法。</p>\n\n<p>UbuntuへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>\nsudo なしで Docker動かせるようにしとく必要あり</p>\n\n<h1 id=\"リモートホストへの接続\">リモートホストへの接続</h1>\n<p>UbuntuへのSSH接続の準備については<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">こちら</a></p>\n\n<h2 id=\"手順\">手順</h2>\n<ul>\n  <li>WindowsマシンでVScode 起動する</li>\n  <li>拡張機能「Remote Development」をインストールしておく。</li>\n  <li>左下にある「><」ボタンをクリック</li>\n  <li>上にメニューが出るので、「Connect to host…」 または「Connect Current Window to Host…」を選択</li>\n  <li>続いて「Select configured SSH host~」で接続するホストを選択。\n    <ul>\n      <li>新規接続の場合は「Add New SSH Host…」を選択</li>\n      <li>「ssh «user»@«IPアドレス or マシン名»」</li>\n      <li>設定を保存するファイルを選択。特に理由がなければ c:\\Users\\«ユーザ».config でいいかな。</li>\n      <li>右下に「Host added!」ウィンドウが出るので「Connect」をクリック</li>\n      <li>初めて接続するホストの場合、上にSelect the platform of remote host “~” と聞かれるのでOS種別を選択</li>\n      <li>「あんた«OS»を選らんだでー。~に保存したから変えたかったら ここ変更しぃや~」みたいなことを言ってるウィンドウが出るので「Don’t Show Again」をクリック</li>\n    </ul>\n  </li>\n  <li>接続された。右下の「><」ボタンが「>< SSH:«マシン名»」に変わっている。</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n一度接続すればリモートエクスプローラ(SSH TARGETS)に表示されるのでそこから接続しても良い。</p>\n</blockquote>\n\n<p>リモートホスト上のプログラムをデバッグしたい場合はここでフォルダを開いてごちょごちょやればよい。</p>\n\n<h1 id=\"dockerコンテナへの接続\">Dockerコンテナへの接続</h1>\n<h2 id=\"準備\">準備</h2>\n<p>WindowsマシンにDocker desktop for windows が必要になるので、インストールしておく。<br />\nWindowsへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\">こちら</a><br />\nCLIだけでよさそうなんだけど、CLIだけってのがどこかにあるのか分からんかったのでとりあえず全部入れた。<br />\nDocker Desktopは動いてなくて良いので、Exitして可。<br />\n普段から使わないならDocker Dashboardの設定のGeneralから「Start Docker Desktop when you log in」のチェックを はずしておけばOK。</p>\n\n<h2 id=\"dockerexeで疎通確認\">docker.exeで疎通確認</h2>\n<p>コマンドプロンプト等で以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">set </span><span class=\"nv\">DOCKER_HOST</span><span class=\"o\">=</span>ssh://«ユーザ名»@«ホスト»\ndocker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<p>リモートホスト上のコンテナの状態が返ってくるか確認。</p>\n\n<h2 id=\"docker-hostの設定\">DOCKER HOSTの設定</h2>\n<p>VScodeの<code class=\"language-plaintext highlighter-rouge\">settings.json</code> に以下の一文を追加する。もちろん上で確認した内容で。</p>\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\">    </span><span class=\"nl\">\"docker.host\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"ssh://«ユーザ名»@«ホスト»\"</span><span class=\"err\">,</span><span class=\"w\">\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルにつなぎたいときはこの行をコメントアウト(<code class=\"language-plaintext highlighter-rouge\">//</code>をつける)すればOK。<br />\n<code class=\"language-plaintext highlighter-rouge\">setting.json</code>はJSONファイルだけど、 <code class=\"language-plaintext highlighter-rouge\">//</code>でコメントアウトできる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nVScode settings.json の開き方</p>\n  <ul>\n    <li>メニュー ファイル→ユーザ設定→ 設定</li>\n    <li>設定画面の右上のボタン「設定(JSON)を開く」をクリック</li>\n  </ul>\n\n  <p>または</p>\n  <ul>\n    <li>メニュー表示→コマンドパレット</li>\n    <li>Preference:  Open Settings(JSON) を選択</li>\n  </ul>\n</blockquote>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その1\">VScodeでリモート エクスプローラからリモートホストに接続(その1)</h2>\n<p>リモートホストに拡張機能 Docker と Docker Explorer をインストールしておき、\nDockerペインを開くとリモートホスト上のコンテナとかが見える</p>\n\n<p>ここでは既にリモートホスト上でコンテナ作成済みとする。<br />\n(イメージからコンテナ作ったりDockerfileからBuildしたりできると思うけど、今はおいとく)</p>\n\n<ul>\n  <li>接続するコンテナが起動していない場合はDockerペインで使用するコンテナを右クリック→Start でコンテナを起動</li>\n  <li>起動したら対象コンテナのアイコンが三角マークになる</li>\n  <li>同じくDockerペインで使用するコンテナを右クリック→Attach Visual Studio Code を選択</li>\n  <li>select the container to attach VS Code と聞かれるのでアタッチするコンテナを選択(コンテナ選択してAttachしたはずだけど、なぜかここで再度選択が必要)</li>\n  <li>初めて接続した場合は「Attaching to a container may execute arbitrary code」<br />\nと言われるので、変なコードが実行されないことが分かっていれば Got it をクリック</li>\n  <li>接続された。右下の「><」ボタンが「>< Conteiner «コンテナ名»」に変わっている。</li>\n</ul>\n\n<p>あとはリモート SSH や ローカルのDockerでのデバッグと同じ。</p>\n\n<h2 id=\"接続の終了\">接続の終了</h2>\n<p>接続を終了する場合は</p>\n<ul>\n  <li>メニュー表示→コマンドパレット</li>\n  <li>Remote:  Close Remote Connection を選択</li>\n</ul>\n\n<p>このとき、コンテナからだけでなく、リモートホストからも切断される。</p>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その2\">VScodeでリモート エクスプローラからリモートホストに接続(その2)</h2>\n<p>リモートエクスプローラ(Containers)で接続するコンテナを右クリックし、「Attach to Container」または「Attach in New Window」を選択<br />\n(コンテナが起動されていなければ起動して)コンテナに接続される。</p>\n\n<p>あんまりごちょごちょしなくて済むのでこっちの方がおススメかな。</p>\n\n<h1 id=\"ネットワークポート\">ネットワークポート</h1>\n<p>通常Cockerコンテナ内のネットワークポートをホストや外部コンピュータからアクセスするには、<br />\nコンテナ作成時に-p (–publish) オプションで接続を受け入れるポート番号を指定する必要があるが、<br />\nVScodeから接続している場合は、Docker内のネットワークポートにVScodeが実行されているマシンからlocalhost:«ポート番号»で接続できる。<br />\n(アクセス遅いけど、ちょっと別のポート開けて試したい なんて時には便利)</p>\n\n<p>ただし、これはDockerが動作しているホストコンピュータや他のコンピュータからはアクセスできない。<br />\nこれらからアクセスするには-pオプションを指定する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n<p><a href=\"https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0\">https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0</a><br />\n↑ここにある、「Remote-Containers: Open Folder in Container…」での手順はリモートホストに接続した状態では実行できないらしい。<br />\nどうしてもこのコンテナでデバッグしたい場合は、<br />\n一旦リモートホスト上でVSCodeを起動してコンテナを作成しておき、<br />\nその後ローカルPCからこのコンテナにアタッチするような手順をふめばデバッグできる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ubuntuにSSHサーバをセットアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ubuntuにSSHサーバをセットアップする</h1>\n      <p>ubuntuにSSHサーバをセットアップするし、公開鍵認証を設定する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuにsshサーバをセットアップする\">UbuntuにSSHサーバをセットアップする</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n\n<p>この状態でWindowsなどから以下のコマンドで接続するとパスワード認証でlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«ユーザ名»@«IPアドレス»<span class=\"s1\">'s password: «パスワードを入力»  \n</span></code></pre></div></div>\n\n<p>リモート接続でshellを使うだけならこれでも良いが、\nVScodeでリモートデバッグをしたりするときなどはパスワード入力を何回も行う必要があったりして面倒。<br />\nそこで、公開鍵認証を設定してパスワード入力を不要にする。</p>\n\n<h1 id=\"秘密鍵と公開鍵の生成と公開鍵ファイルの設置\">秘密鍵と公開鍵の生成と公開鍵ファイルの設置</h1>\n<p>Windowsマシンで以下のコマンドを実行して秘密鍵ファイルと公開鍵ファイルを生成する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh-keygen.exe <span class=\"nt\">-t</span> rsa\n<span class=\"o\">(</span>リターン3回<span class=\"o\">)</span>\n※ 本当はpassphase入れないといけないけど、ローカルお試し環境なので省略\n</code></pre></div></div>\n<p>実行すると以下のファイルが出来る</p>\n<ul>\n  <li>%USERPROFILE%/.ssh/id_rsa</li>\n  <li>%USERPROFILE%/.ssh/id_rsa.pub</li>\n</ul>\n\n<p>このうち、<code class=\"language-plaintext highlighter-rouge\">id_rsa.pub</code>をUbuntuマシンの <code class=\"language-plaintext highlighter-rouge\">~/.ssh</code>へ<code class=\"language-plaintext highlighter-rouge\">authorized_keys</code>というファイル名でコピー(既に存在する場合は追記)する。</p>\n<blockquote>\n  <p>[!NOTE]\nやり方検索すると<code class=\"language-plaintext highlighter-rouge\">scp</code>コマンドでコピーする方法が紹介されているが、\n家の中だけなのでネットワークドライブ経由でのコピーや\nファイル自体はテキストファイルなので、SSH接続したshellからエディタを起動して\nコピペするのでも良い。</p>\n</blockquote>\n\n<p>コピーが完了したらファイルのパーミッションを変更する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod </span>600 ~/.ssh/authorized_keys\n</code></pre></div></div>\n\n<h1 id=\"接続テスト\">接続テスト</h1>\n<p>この状態でWindowsマシンから以下のコマンドで接続するとパスワード認証なしでlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«パスワード入力なしで接続»\n</code></pre></div></div>\n\n<p>Windows側のユーザディレクトリ/.ssh/config の設定もやっておくと便利<br />\n参考: <a href=\"https://qiita.com/passol78/items/2ad123e39efeb1a5286b\">https://qiita.com/passol78/items/2ad123e39efeb1a5286b</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerコンテナからGUIを起動する</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerコンテナからGUIを起動する</h1>\n      <p>Windos/Ubuntu の DockerコンテナからGUIを起動する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuでローカルのデスクトップに表示する場合\">Ubuntuでローカルのデスクトップに表示する場合</h1>\n<p>Docker(ubuntu)のみ。<br />\nコンテナ生成時に以下のように<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数の設定と<code class=\"language-plaintext highlighter-rouge\">/tmp/.X11-unix/</code>のマウントを行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test3 <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n<p>この場合、表示する前にホスト側で以下を実行しておく必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>xhost +local:\n</code></pre></div></div>\n<p>実行していない場合、GUI起動コマンド実行で以下のエラーが出る。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>No protocol specified\nError: Can't open display: XXX\n</code></pre></div></div>\n\n<p>Ubuntuを再起動したときに設定は忘れられてしまうので、起動の度に実行必要。</p>\n\n<blockquote>\n  <p>[!NOTE]\nxhostはセキュリティ上問題があるとのことだが、家の中だけだし、localだけなら許可してもいいかな…\nrc.localあたりに書いとこうかと思ったけど、使用するときだけ実行するのが無難かな。</p>\n</blockquote>\n\n<h1 id=\"windows上のvcxsrvに表示する場合\">Windows上のVcXsrvに表示する場合</h1>\n<p>Docker(windows)だとコレ一択。<br />\nDocker(ubuntu)でも大丈夫。<br />\nなので、Docker(ubuntu)にリモート接続で使用することがある場合はこっちを使っておくのが良いと思う。<br />\nWindowsマシンのIPアドレスが192.168.XXX.XXX(マシン名指定不可)だとして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test4 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XXX.XXX:0.0 <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>VSCodeでDocker内のpythonプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>VSCodeでDocker内のpythonプログラムをデバッグする</h1>\n      <p>VSCodeでDocker内のpythonプログラムをデバッグする(Windos/Ubuntu)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからWindows上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nubuntu上のVSCodeからubuntu上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nどちらもほぼ同じ手順でデバッグできる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>VScodeに拡張機能Python、Docker、Remote Containers をインストールしておく</p>\n\n<h1 id=\"コンテナ起動\">コンテナ起動</h1>\n<p>ターミナルからコンテナ起動する<br />\nソースの編集をしやすいように、ホストのフォルダを<code class=\"language-plaintext highlighter-rouge\">/work</code>に割り当てている。<br />\nいや、VSCodeで編集すれば問題ないんだけどさ…<br />\nいつも編集は別のエディタ使ってたりするとコンテナ内のファイルいじるのが面倒なので…</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Windows\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> /m/work/zzz:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ubuntu\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> <span class=\"sb\">`</span><span class=\"nb\">realpath</span> .<span class=\"sb\">`</span>:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンテナを一度作成してあれば起動していなくても大丈夫らしい。</p>\n</blockquote>\n\n<h1 id=\"コンテナに接続\">コンテナに接続</h1>\n<p>VScodeのリモートエクスプローラにコンテナが見える</p>\n<blockquote>\n  <p>[!NOTE]\nRemote SSHやRemote WSLがインストールされている場合はリモートエクスプローラ上部のドロップダウンリストからContainersを選択</p>\n</blockquote>\n\n<p>対象のコンテナを右クリックして<code class=\"language-plaintext highlighter-rouge\">Attach to Container</code> または<code class=\"language-plaintext highlighter-rouge\">Attach in New Window</code>をクリック<br />\n<code class=\"language-plaintext highlighter-rouge\">Attaching to a container may execute arbitrary code</code><br />\nと言われるたら、変なコードが実行されないことが分かっていれば <code class=\"language-plaintext highlighter-rouge\">Got it</code> をクリック</p>\n<blockquote>\n  <p>[!NOTE]\n一度開いたフォルダはその下にショートカットが表示されているので、そこから開けば手っ取り早い。</p>\n</blockquote>\n\n<p>コンテナが開く</p>\n\n<p>コンテナ内には拡張機能が入ってないので、必要な拡張機能をインストールする</p>\n\n<h1 id=\"デバッグ\">デバッグ</h1>\n<p>エクスプローラでデバッグしたいフォルダを開いてソースを開く(VSCodeの設定によっては前回開いていたフォルダが開かれる)<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Python: Select Interpreter</code> で 使用するpythonを選択する。<br />\nこのとき、必ずしも使用するpythonのpathが表示されているとは限らないので、<br />\n(逆にコンテナ内にないホスト側のものが表示されたりする😢)<br />\n表示されていない場合は<code class=\"language-plaintext highlighter-rouge\">+ Enter Interpreter path...</code>から使用するpythonを選択する。<br />\n上記イメージの場合、<code class=\"language-plaintext highlighter-rouge\">/usr/local/bin/python3</code> なので、これを設定。</p>\n<blockquote>\n  <p>[!NOTE]\nあらかじめコンソールで which python3 して調べておく</p>\n</blockquote>\n\n<p>あとはローカルと同じようにデバッグできる。</p>\n\n<h1 id=\"コンテナとの接続終了\">コンテナとの接続終了</h1>\n\n<p>コンテナとの接続を終了するときは<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Remote: Close Remote Connection</code> で終了する。</p>\n\n<p>接続終了してもコンテナを停止しないので、別途停止処理を行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker stop py_test2\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>こういうのもある。<br />\n(参照しているのはmicrosoft純正のサンプルらしい)<br />\n普通にDocker使うのと異なるファイル<code class=\"language-plaintext highlighter-rouge\">devcontainer.json</code>を使うので、\n便利なんだか不便なんだか…<br />\nDocker拡張機能なくても動かせた気がする。<br />\n<a href=\"https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html\">https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Dockerをインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Dockerをインストールする</h1>\n      <p>Windos/Ubuntu に Dockerをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows10-home-に-dockerをインストールする\">Windows10 Home に Dockerをインストールする</h1>\n<p>HomeだとWSL2必須なので、WSL2はあらかじめインストールして使用できるようにしておく。<br />\n<a href=\"/memoBlog/2021/03/03/WSL_memo.html\" target=\"_blank\">WSL2 メモ</a></p>\n\n<p><a href=\"https://docs.docker.jp/docker-for-windows/install-windows-home.html\" target=\"_blank\">https://docs.docker.jp/docker-for-windows/install-windows-home.html</a> を参考にインストールする。 <br />\nとはいっても、<a href=\"https://hub.docker.com/editions/community/docker-ce-desktop-windows/\" target=\"_blank\">https://hub.docker.com/editions/community/docker-ce-desktop-windows/</a>からダウンロードして実行するだけ。</p>\n\n<p>コンテナを一杯作るとデータ領域がどんどん肥大していくので、Cドライブから変更しておいた方が良いかも。<br />\n<a href=\"https://nosubject.io/windowsdocker-desktop-move-disk-image/\" target=\"_blank\">Docker Desktop の ディスク領域 を Cドライブから別のドライブへ移動する方法</a><br />\nを参考に作業すればOK。<br />\nVHDをエクスポート、元の仮想マシンのレジストリを削除、他の場所へ同名でインポート、とやってる。</p>\n\n<h1 id=\"ubuntu-に-dockerをインストールする\">Ubuntu に Dockerをインストールする</h1>\n<p><a href=\"https://docs.docker.jp/linux/step_one.html\" target=\"_blank\">https://docs.docker.jp/linux/step_one.html</a> を参考にインストールする。 <br />\n実際は以下を実行するだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>curl <span class=\"nt\">-fsSL</span> https://get.docker.com/ | sh\n</code></pre></div></div>\n\n<p>docker実行に逐一<code class=\"language-plaintext highlighter-rouge\">sudo</code>をつけるのは面倒なので、以下の設定をしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> docker\n</code></pre></div></div>\n<p>設定後は念のためリブートしておく(logoutだけで可らしいけど)。</p>\n\n<h1 id=\"インストール後のお試し実行\">インストール後のお試し実行</h1>\n<p>正常に動いていることを確認するためになんか動かしてみる。<br />\n以下はWindows版で書かれているが、基本的にUbuntuでも同じ。<br />\n<a href=\"https://qiita.com/nanaki11/items/97e5685ed84547526be2\" target=\"_blank\">https://qiita.com/nanaki11/items/97e5685ed84547526be2</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">docker pull</code>はしなくても<code class=\"language-plaintext highlighter-rouge\">docker run</code>したときにローカルにimegeがなければ自動でダウンロードしてくれるらしい。</p>\n\n<h1 id=\"コマンド例\">コマンド例</h1>\n<p>ちょろっと試したコマンド群</p>\n<h2 id=\"コンテナの生成\">コンテナの生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの起動\">コンテナの起動</h2>\n<p>終了したコンテナの再開も同じ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> py_test\n</code></pre></div></div>\n\n<h2 id=\"コンテナに新たなコンソール接続\">コンテナに新たなコンソール接続</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> py_test /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの生成と起動を同時に行う\">コンテナの生成と起動を同時に行う</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">create</code>を<code class=\"language-plaintext highlighter-rouge\">run</code>に変えるだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"nwork-を-work-にマウントする場合windows\">n:\\work を /work にマウントする場合(Windows)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /n/work:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"カレントディレクトリを-work-にマウントする場合ubuntu\">カレントディレクトリを /work にマウントする場合(ubuntu)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナ一覧起動中のもののみ\">コンテナ一覧(起動中のもののみ)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<h2 id=\"コンテナ一覧終了したものを含む\">コンテナ一覧(終了したものを含む)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n\n<h2 id=\"pull済みイメージ一覧\">pull済みイメージ一覧</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<h2 id=\"コンテナの情報を確認する\">コンテナの情報を確認する</h2>\n<p>下記コマンドでJSONデータが出力される。<br />\n直近で興味ありそうなのは<code class=\"language-plaintext highlighter-rouge\">HostConfig</code>、<code class=\"language-plaintext highlighter-rouge\">Mounts</code>、<code class=\"language-plaintext highlighter-rouge\">NetworkSettings</code>あたりかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker inspect py_test2\n</code></pre></div></div>\n\n<h1 id=\"どんなイメージがあるのか\">どんなイメージがあるのか?</h1>\n<p><a href=\"https://hub.docker.com/search?type=image\" target=\"_blank\">dockerhub</a>でサーチしてちょ。</p>\n\n<h1 id=\"dockerはwsl2でどんな感じで動いているのか\">DockerはWSL2でどんな感じで動いているのか?</h1>\n<p>あんまり意味ないけど。<br />\n<a href=\"https://www.docker.com/blog/new-docker-desktop-wsl2-backend/\" target=\"_blank\">https://www.docker.com/blog/new-docker-desktop-wsl2-backend/</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要--背景\">概要 & 背景</h1>\n\n<p>WiresharkでUSBパケットをキャプチャしたとき、実際に転送されてるデータの中身が見たいというニッチな要求があった。<br />\n(送ったデータがちゃんとUSBバスに出てるよね~、という確認がしたいなどの用途)</p>\n\n<p>Wiresharkのセーブデータ渡して「Wiresharkで見てね~」と言ったら「見方が分からん!」と…<br />\nで、Excelで一覧表にしてあげようと思い、エクスポートできんかな~と探してみるも、適当な機能が見つからず…<br />\nしかたなく、変換スクリプトかましてCSVに出力してExcelで読み込んでみよう、と試した時のメモ。</p>\n\n<p>今回はisochronous転送のデータの中身をダンプしている。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<ol>\n  <li>最初に解析したいパケットをキャプチャしておく(これをやらなきゃ始まらん…)。</li>\n  <li>必要なら表示フィルタで解析したいパケットだけ選び出す。</li>\n  <li>それらのパケットの一部だけ(最初の1秒だけ など)解析したい場合はそのパケット群を選択する。<br />\n   RaspberryPiでのやり方が分からん…Windows版なら他のアプリ同様、先頭で左クリック→最後でshift押しながら左クリックでOK。<br />\n   どうしても出来なかったら、RaspberryPiでキャプチャしたのを保存して、そのファイル(pcapngファイル)をWindowsにコピーして、\n   Windows上のWiresharkで読み込んでくだされ…😅</li>\n  <li>メニューの「ファイル」→「パケット解析をエクスポート」→「JSONとして」を選択</li>\n  <li>ファイル操作ダイアログが表示される\n    <ul>\n      <li>真ん中の「ファイル名」を入力</li>\n      <li>左下の「パケットの範囲」で\n        <ul>\n          <li>「表示されたパケット」を選択</li>\n          <li>「すべてのパケット」または「選択されたパケットのみ」を選択<br />\n (ここで「範囲」を選んで入力すれば選択しなくてもいいのかな?試してないので不明)</li>\n        </ul>\n      </li>\n      <li>「保存」をクリック</li>\n    </ul>\n  </li>\n</ol>\n\n<p>これでJSONファイルが保存される。</p>\n\n<h1 id=\"csvファイルに変換\">CSVファイルに変換</h1>\n\n<p>さぁ、このJSONファイルを読み込んで必要な部分を取り出すスクリプトを書けばOKじゃん?と思ったが、<br />\nそうは問屋がおろしてくれない😢<br />\nじつはWiresharkがエクスポートするJSONファイルはJSONファイルの文法からはずれた部分があるのだ…<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">/_source/layers/usb</code> の配下に複数のキー<code class=\"language-plaintext highlighter-rouge\">usb</code>があって、すべてのUSBデータを読み込めない。<br />\n(JSONの仕様では同一階層に複数の同じキーの存在を許さない。pythonのJSONモジュールでは複数あるデータのうち、一つだけが読み込まれる)<br />\nここが配列になってればOKだと気が付いて、チカラワザで変換する処理を追加してみた。</p>\n\n<p>で、pyshonで書いたスクリプトがこちら。<br />\nWindows/RaspberryPi どっちでも大丈夫と思うけど、Windowsでしか試してない。<br />\npythonは3.6以降が必要。3.7.7で動作確認。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  json_read.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"c1\"># テンポラリファイル名\n</span><span class=\"n\">tmp_file</span> <span class=\"o\">=</span> <span class=\"s\">'tmp.json'</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'==== USAGE ========================='</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'    </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> <JSON file> <CSV file>'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'===================================='</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">json_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">csv_file</span>  <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'Error: JSON file not exist!!'</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># \"usb\" キーが複数あるので、これをリストに変換したJSONファイルを作成する\n# かなり力技...\n</span><span class=\"k\">def</span> <span class=\"nf\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_json</span><span class=\"p\">,</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_tmp</span><span class=\"p\">:</span>\n        <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        \n        <span class=\"k\">while</span> <span class=\"n\">line</span><span class=\"p\">:</span>\n            <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"n\">line_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>           <span class=\"c1\"># 行番号\n</span>            <span class=\"c1\"># line = line.rstrip('\\r\\n')              # CRLFを削除\n</span>            <span class=\"k\">if</span> <span class=\"n\">find_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">'\"usb\": '</span><span class=\"p\">,</span> <span class=\"s\">''</span><span class=\"p\">)</span>      <span class=\"c1\"># key名称 \"usb\"を削除\n</span>                <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'START: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          \"usb_data\": [</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">+</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'{'</span><span class=\"p\">)</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">-</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'}'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">brackets</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'END: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          ]</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb.iso.numdesc\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">f_pos</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">tell</span><span class=\"p\">()</span>\n                    <span class=\"n\">next_line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>        <span class=\"c1\"># 次の行を読み込んで\n</span>                    <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"n\">f_pos</span><span class=\"p\">)</span>                   <span class=\"c1\"># ファイル位置を戻す\n</span>                    <span class=\"k\">if</span> <span class=\"n\">next_line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                    <span class=\"c1\"># 括弧の数\n</span>            <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">line</span><span class=\"p\">)</span>\n            <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># JSONファイルの修正\n</span><span class=\"n\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># パケット解析用変数\n</span><span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n<span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># JSONファイルの読み込み\n</span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n    <span class=\"n\">json_load</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(json_load)\n</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">csv_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_csv</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ヘッダの出力\n</span>    <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">'PacketNo,Date,Relative_time,Delta_time,Packet Size,Video Stream Size,Video Stream offset,Frame No,Stream No,Stream Data</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">json_data</span> <span class=\"ow\">in</span> <span class=\"n\">json_load</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フレームデータ\n</span>        <span class=\"n\">frame_data</span>          <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"frame\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_index</span>         <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.number\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_epoc</span>     <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_epoch\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_delta</span>    <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_delta_displayed\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_relative</span> <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_relative\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_dt</span>       <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">fromtimestamp</span><span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">frame_time_epoc</span><span class=\"p\">))</span>\n        <span class=\"n\">frame_time</span>          <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_time_dt</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_len</span>           <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.len\"</span><span class=\"p\">]</span>\n        <span class=\"c1\"># print(f'{frame_index},\"\\'{frame_time}\",{frame_len},', end='')\n</span>        <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_index</span><span class=\"si\">}</span><span class=\"s\">,\"</span><span class=\"se\">\\'</span><span class=\"si\">{</span><span class=\"n\">frame_time</span><span class=\"si\">}</span><span class=\"s\">\",</span><span class=\"si\">{</span><span class=\"n\">frame_time_relative</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_time_delta</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_len</span><span class=\"si\">}</span><span class=\"s\">,'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># USBデータ\n</span>        <span class=\"n\">usb_datas</span>  <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"usb\"</span><span class=\"p\">][</span><span class=\"s\">\"usb_data\"</span><span class=\"p\">]</span>\n        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"k\">for</span> <span class=\"n\">usb_data</span> <span class=\"ow\">in</span> <span class=\"n\">usb_datas</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f',,,,,', end='')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">',,,,,'</span><span class=\"p\">)</span>\n            <span class=\"n\">iso_len</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_len'</span><span class=\"p\">])</span>\n            <span class=\"n\">iso_off</span>  <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_off'</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">iso_len</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">\"usb.iso.data\"</span><span class=\"p\">]</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"s\">'0x'</span><span class=\"o\">+</span><span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">':'</span><span class=\"p\">,</span> <span class=\"s\">',0x'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">stream_number</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_number</span><span class=\"p\">)</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"s\">''</span>\n                \n                <span class=\"c1\"># print(f'{iso_len},{iso_off},{stream_number},{iso_data}')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_number_str</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">stream_number</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_data</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x02'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x03'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"n\">stream_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f'{iso_len},{iso_off},,')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,,</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># テンポラリファイルの削除\n</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。(RaspberryPiだと<code class=\"language-plaintext highlighter-rouge\">python3</code>にしてちょ)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python json_read.py «入力JSONファイル» «出力CSVファイル»\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>やっつけスクリプトなので、エラーチェックはかなりいい加減…</p>\n\n<p>関数<code class=\"language-plaintext highlighter-rouge\">modify_json()</code> が 前述のJSONファイルの不具合をチカラワザで修正する処理。</p>\n\n<p>テンポラリファイルとしてカレントディレクトリに<code class=\"language-plaintext highlighter-rouge\">tmp.json</code>を作成するので、注意。\nファイル名を変更したければ、8行目の<code class=\"language-plaintext highlighter-rouge\">tmp_file</code>を変更。<br />\nこのファイルはスクリプトの最後で削除している。<br />\n作成したテンポラリファイルを残しておきたければ最後の<code class=\"language-plaintext highlighter-rouge\">os.remove(tmp_file)</code>をコメントアウト。</p>\n\n<p>71~72行目で修正したJSONファイルを読み込み。</p>\n\n<p>75行目で書き出すCSVファイルをオープン。</p>\n\n<p>78行目~のforループで各JSONレコードを読み込みながら処理。</p>\n\n<p>82,85~86行目でframe.time_epochから時刻文字列を作成。<br />\n時刻は<code class=\"language-plaintext highlighter-rouge\">frame.time</code>を使用する手もあるが、ここはプラットフォームによって変化するらしいので同じ表示にするためにエポックタイムから生成している。<br />\nその他時刻関連データでは、<code class=\"language-plaintext highlighter-rouge\">frame.time_delta_displayed</code>で「前のパケットからの相対時間」、\n<code class=\"language-plaintext highlighter-rouge\">frame.time_relative</code>で「最初のパケットからの相対時間」を取得している。</p>\n\n<p>94行目~のforループがデータを取り出す部分。<br />\nisochronous転送のデータではないデータを取り出したい場合は、所望のデータのキーに置き換えて取り出せば良い。<br />\n<code class=\"language-plaintext highlighter-rouge\">frame_number</code>と<code class=\"language-plaintext highlighter-rouge\">stream_number</code>は私の解析用の補助データなので気にしないでネ。</p>\n\n<p>あとは、エクスポートされたJSONファイルとスクリプトを見比べてちゃぶだい。(^^ゞ</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>あとは、csvファイルをExcelで読み込むなり、pandasとかを使った別のスクリプトで加工するなりしてちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git の差分比較ツールにWinMergeを使用する</title>\n  </head>\n  <body>\n    <header>\n      <h1>git の差分比較ツールにWinMergeを使用する</h1>\n      <p>git の差分比較ツールに WinMerge を使用する方法</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows上のgit-の差分比較ツールに-winmerge-を使用する方法\">Windows上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows限定だが、git の差分比較ツールに WinMerge を使用する方法のメモ<br />\n参考: <a href=\"https://qiita.com/kobake@github/items/fb317b4fdacad718a4b2?fbclid=IwAR1eO6ENMKDeeY3PmGJWrKLf_n1rgC8NVPBF60xKMiG02yAFgCFS6ceC7IE\">git の差分比較・マージを WinMerge で行う</a><br />\n↑参考というよりパクリだが(^^ゞ</p>\n\n<p>git の差分比較の <code class=\"language-plaintext highlighter-rouge\">git diff</code> で見ると見難いので、WinmMergeを使えるようにしてみた。<br />\n普段はVS Code 使ってるけど…</p>\n\n<p>手順は、 <code class=\"language-plaintext highlighter-rouge\">C:\\Users\\〇〇\\.gitconfig</code> に以下を追記するだけ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n[difftool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -f \\\"*.*\\\" -e -u -r \\\"$LOCAL\\\" \\\"$REMOTE\\\"\n[merge]\n    tool = WinMerge\n[mergetool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -e -u \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$MERGED\\\"\n[alias]\n    windiff = difftool -y -d -t WinMerge\n    winmerge = mergetool -y -t WinMerge\n</code></pre></div></div>\n\n<p>差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力すれば良い。</p>\n\n<p>差分はファイル書き換えても自動的にアップデートされなので、都度<code class=\"language-plaintext highlighter-rouge\">git windiff</code> する必要がある。<br />\n(あくまでスナップショットでの比較を表示してるだけ)</p>\n\n<p>比較対象の指定とか、マージとかもできるみたいだけど、使ってないので、詳しくは↑の参考先を見てね。(^^ゞ</p>\n\n<h1 id=\"wsl上のgit-の差分比較ツールに-winmerge-を使用する方法\">WSL上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows上の場合とほぼ同じ。<code class=\"language-plaintext highlighter-rouge\">~/.gitconfig</code>に以下を追加しておき、差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力する。<br />\nマージは使わないので、diffだけ設定。<br />\n(上の方法をwslpathでLinux上のpath→Windows上のpath 変換してるだけ、かな?)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n\n[difftool]\n    prompt = false\n\n[difftool \"WinMerge\"]\n    cmd = '/mnt/c/Program Files/WinMerge/WinMergeU.exe' -e -r -u -wl -dl Local -wr -dr Remote \\\"`wslpath -wa $LOCAL`\\\" \\\"`wslpath -wa $REMOTE`\\\"\n    trustExitCode = false\n\n[alias]\n    windiff = difftool -y -d --no-symlinks -t WinMerge\n</code></pre></div></div>\n<p>参考:<a href=\"https://qiita.com/forest1/items/334b5d756b5696c63331\">WSL(Ubuntu 18.04)環境のgitでWinMergeを使う方法</a></p>\n\n<p>参考先ではUbuntu18.04となっているが、20.04でも問題なし。<br />\nまた、<code class=\"language-plaintext highlighter-rouge\">/mnt/c/Users/username</code>以下で作業と書いてあるが、どこで作業しても大丈夫。テンポラリパスの変更も不要。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WindowsでX-serve</title>\n  </head>\n  <body>\n    <header>\n      <h1>WindowsでX-serve</h1>\n      <p>WindowsでX-serveを使用するためにVcXsrvを使う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>SSH ログインしたLinuxマシンからX-Windowプログラムを実行したときに、ウィンドウをWindoesマシンに表示する方法。<br />\nUbuntu、RaspberryPiともにOK。</p>\n\n<h1 id=\"vcxsrvのインストール\">VcXsrvのインストール</h1>\n\n<p>このあたりを参考に(といっても、ダウンロードしてインストーラ実行するだけだけど)。<br />\n<a href=\"https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html\">https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html</a></p>\n\n<h1 id=\"設定のメモ\">設定のメモ</h1>\n\n<h2 id=\"リモートマシンからの要求を受け付ける\">リモートマシンからの要求を受け付ける</h2>\n\n<p>リモートマシンからの要求を受け付けるには、起動時に3ページ目で”Disable access control” にチェックを入れる。</p>\n\n<blockquote>\n  <p>[!NOTE]\nC:\\Program Files\\VcXsrv\\X0.hosts にクライアント(Linuxマシン)のIPアドレスを書いておくと、”Disable access control”にチェックを入れなくても良いらしい。<br />\nしかし、サブネット全体を指定するために「192.168.1.」とやってもうまく動かない。。。<br />\n個別に「192.168.1.5」と書いておくとOK</p>\n</blockquote>\n\n<h2 id=\"逐一設定するのがめんどい\">逐一設定するのがめんどい</h2>\n\n<p>4ページ目で”Save configuration”\tをクリックして保存した設定ファイル(拡張子は”.xlaunch”)を実行すれば設定済みの状態で起動できる。</p>\n\n<h2 id=\"linux側の設定\">Linux側の設定</h2>\n\n<p>Linux側では~/.bashrcに以下を追加しておくと、SSHでlog inしたときに自動でDISPLAY変数を設定してくれる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n\t</span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XXX.XXX:0.0\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h2 id=\"その他注意事項\">その他注意事項</h2>\n\n<p>VcXsrvを起動するとキーボードが勝手に変わることがあるらしい。<br />\n日本語入力できなくなったらWindows+SPACEで確認すること。</p>\n\n<h2 id=\"愚痴\">愚痴</h2>\n\n<p>コマンドラインオプションで設定できないか調べてみたが、見つからない。<br />\n「Addituinal parameters」という設定項目があるので、何かしら設定できるはずなんだけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>モバイル ホットスポットでRaspberryPiをネットに接続</title>\n  </head>\n  <body>\n    <header>\n      <h1>モバイル ホットスポットでRaspberryPiをネットに接続</h1>\n      <p>Windows10のモバイル ホットスポットでRaspberryPiをネットに接続する手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>お出かけ先でも RaspberryPi を、常に同じWi-Fi AP で接続できるような方法を考える。</p>\n\n<p>一つの案として、Windows10のモバイル ホットスポットを経由して RaspberryPi をネットワークにつなげる。\nこの場合、PCと RaspberryPi はセットで持ち歩くものと考えれば、 \nRaspberryPi は常にPCのモバイル ホットスポットのAPに接続すれば良いことになる。</p>\n\n<p>一つのWi-Fiアダプタを通常接続用とモバイル ホットスポット用でシェアすることはできないので、<br />\nUSBドングルを追加して使用する。</p>\n\n<ul>\n  <li>内蔵Wi-Fi → 通常接続用</li>\n  <li>USBドングル → モバイル ホットスポット用</li>\n</ul>\n\n<p>USBドングルは BUFFALO WLI-UC-GNM2S で確認\nWindowsはWindows10 ver.1903 で確認</p>\n\n<h1 id=\"windows側の事前準備\">Windows側の事前準備</h1>\n\n<p>内蔵Wi-Fi は 通常通り ルータに接続しておく。<br />\nこのとき、どのルータに繋いでいるかは考慮しなくて良いはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPCのルータ接続ダウン時、モバイル ホットスポットは使えない</p>\n</blockquote>\n\n<p>USBドングル BUFFALO WLI-UC-GNM2S はあらかじめドライバをインストールしてWindowsに認識させておく。<br />\n接続先は設定しなくて大丈夫。</p>\n\n<ul>\n  <li>Windowsで「設定」→「ネットワークとインターネット」→「モバイル ホットスポット」を開く\n    <ul>\n      <li>「インターネット接続を共有する」で、ルータに接続しているアダプタを選択</li>\n      <li>「Wi-Fi」を選択</li>\n      <li>「ネットワーク名」と「ネットワーク パスワード」をメモっておく</li>\n      <li>この状態で一番上のスイッチを「オン」にする\n        <ul>\n          <li>スイッチがアクティブカラーになったら準備完了</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"raspberrypi側の事前準備\">RaspberryPi側の事前準備</h1>\n\n<h2 id=\"etcwpa_supplicantwpa_supplicantconf-の修正\">/etc/wpa_supplicant/wpa_supplicant.conf の修正</h2>\n\n<p>モバイル ホットスポットか通常のルータか、どちらか生きてる方に接続にいくように設定する。<br />\n(いつもの環境ならモバイル ホットスポット使わなくて良いように)</p>\n\n<p>以下の「モバイルホットスポットのSSID名」「パスワード」は<br />\n上記でメモった「ネットワーク名」と「ネットワーク パスワード」を記入する。<br />\nダブルクォーテーションで囲むのを忘れないこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">ctrl_interface</span><span class=\"o\">=</span><span class=\"nv\">DIR</span><span class=\"o\">=</span>/var/run/wpa_supplicant <span class=\"nv\">GROUP</span><span class=\"o\">=</span>netdev\n<span class=\"nv\">update_config</span><span class=\"o\">=</span>1\n<span class=\"nv\">country</span><span class=\"o\">=</span>JP\n\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"デフォルトのSSID名\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span><span class=\"s2\">\"パスワード\"</span>\n        <span class=\"nv\">priority</span><span class=\"o\">=</span>3\n<span class=\"o\">}</span>\n\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"モバイルホットスポットのSSID名\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span><span class=\"s2\">\"パスワード\"</span>\n        <span class=\"nv\">priority</span><span class=\"o\">=</span>5\n<span class=\"o\">}</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npriority設定値は大きい方が優先される。<br />\n上記の場合、モバイルホットスポットが生きていればそちらが優先される</p>\n</blockquote>\n\n<h2 id=\"ap再接続用スクリプト\">AP再接続用スクリプト</h2>\n\n<p>モバイル ホットスポット の Enable/Disable を切り替えたとき、<br />\n(RaspberryPiを起動してからモバイルホットスポットを有効にするのを忘れていたことに気がついたなど)\nRaspberryPiのネットワーク設定は自動的に新しい環境に切り替わらない。<br />\nコマンドをチマチマ入力するのも面倒なので、コマンド イッパツで再接続処理するようにしておく。</p>\n\n<p>まず、 ~/wifi_reconnect.sh を以下の内容で作成する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo </span>wlan0 down..\n<span class=\"nb\">sudo </span>ifconfig wlan0 down\n<span class=\"nb\">sleep </span>1\n\n<span class=\"nb\">echo </span>wlan0 up..\n<span class=\"nb\">sudo </span>ifconfig wlan0 up\n<span class=\"nb\">sleep </span>3\n\n<span class=\"nb\">echo </span>re-get IP address...\n<span class=\"nb\">sudo </span>dhcpcd <span class=\"nt\">-k</span>\n<span class=\"nb\">sleep </span>3\n<span class=\"nb\">sudo </span>dhcpcd <span class=\"nt\">-n</span>\n<span class=\"nb\">sleep </span>15\n\n<span class=\"nb\">echo </span>DONE!!\n</code></pre></div></div>\n\n<p>スクリプトファイルに実行属性をつける。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod</span> +x ~/wifi_reconnect.sh\n</code></pre></div></div>\n\n<p>再接続したいタイミングで <code class=\"language-plaintext highlighter-rouge\">~/wifi_reconnect.sh</code>を実行する。<br />\nDHCPのアドレス確定時間分を待っているので、コマンド実行には20秒強かかる。</p>\n\n<h1 id=\"raspberrypiの起動\">RaspberryPiの起動</h1>\n\n<p>上記の準備が整ったら、RaspberryPiを起動する。<br />\n起動後、<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>(他のコマンドでも良いけど)でIPアドレスを確認する。</p>\n\n<ul>\n  <li>192.168.137.XXX になっていればOK</li>\n</ul>\n\n<p>また、PC側で「設定」→「ネットワークとインターネット」→「モバイル ホットスポット」の<br />\n「接続されているデバイス」にRaspberryPiが表示されているハズ。</p>\n\n<h1 id=\"問題点\">問題点</h1>\n\n<h2 id=\"windows10-pcがルータにつながっていないと使えない\">Windows10 PCがルータにつながっていないと使えない</h2>\n\n<p>ルータにつながっていないと、そもそもモバイル ホットスポット がオンできない。<br />\nこれは、ネットワーク環境がまったくない場合(つまりPCとRaspberryPiだけで箱庭環境だけ作りたいとき)は使えない。<br />\n回避策としては、スマホのテザリングでネットワークにつなぐ?\n間違って外部にアクセスしちゃったら、パケ死しそう。。。</p>\n\n<h2 id=\"pcの外側ルータのサブネット内からraspberrypiにアクセスできない\">PCの外側(ルータのサブネット内)からRaspberryPiにアクセスできない</h2>\n\n<p>モバイル ホットスポットのサブネットとルータのサブネットは別なので、<br />\nモバイル ホットスポットのサブネットの外側から内側へのアクセスはできない。<br />\nもちろん、ルータの外側からもアクセスできない。<br />\nRaspberryPiにアクセスできるのはモバイル ホットスポットを提供しているPCのみ。</p>\n\n<h2 id=\"mdnsが使えない\">mDNSが使えない</h2>\n\n<p>モバイル ホットスポットのサブネットとルータのサブネットは別なので、\nルータを超えられないmDNSは名前を取得できない。<br />\n回避策としては、/etc/hosts を名前エラーが出るたびに名前追加するか?</p>\n\n<p>なお、WindowsPCからRaspberryPiへのmDNS参照はできるが、RaspberryPiからWindowsPCへのmDNS参照はできない。</p>\n\n<h1 id=\"結論\">結論</h1>\n\n<p>とりあえず、RaspberryPiにアクセスするのはWindowsPC 1台のみで、<br />\nRaspberryPiからアクセスするはルータの外側のみ、という条件なら使えそう。</p>\n\n<p>う~ん、良いところまで行くんだけど、微妙に不満の残る結果に。。。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(Windows編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(Windows編)</h1>\n      <p>過去のブログ(Windows編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"リモートデバッグ\">リモートデバッグ</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4784a559cb0e78d060fe01d69a3c829d\">windowsのVisualStudioCodeでRasPiのNode.jsをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/aed3ddde84d76cca5c5be62df1120f81\">windowsのVisualStudioCodeでRasPiのPythonをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/46e92ee968b99174c1e1fa3199465877\">VisualStudioCodeのリモート開発が使えるようになったらしいので試してみる</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/c9bf43575d8fce47233bf191b21fbaad\">NW.jsによるWebアプリのデスクトップアプリ化</a></li>\n</ol>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのWindows環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのWindows環境での実行</h1>\n      <p>github pagesをWindows環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行できるようにした(<a href=\"/memoBlog/2019/07/17/githubpages.html\">参照</a>)が、\nわざわざUbuntu立ち上げるのが面倒になってきたので、Windows上で実行できるようにしてみた。</p>\n\n<h1 id=\"何はともあれrubyのインストール\">何はともあれRubyのインストール</h1>\n<p>Windows版Rubyをインストールしないとはじまらないので、\n<a href=\"https://www.ruby-lang.org/ja/\">Rubyの総本山</a> から(RubyInstaller のダウンロード](https://rubyinstaller.org/downloads/)\nへ行ってダウンロード。<br />\nWITH DEVKIT を選んでおく方が良いらしい。<br />\nバージョンは最新で良いでしょう(私は Ruby+Devkit 2.6.3-1 (x64) を選びました)。</p>\n\n<p>ダウンロードしたらなんとなーくインストーラ実行して案内にしたがってなんとな~く進んでちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\ngccも要るのかな?Rubyインストール時にMSYS64環境がインストールされるみたいなので、大丈夫かな?<br />\nちなみに、うちの環境はmingw-w64が入ってる。</p>\n</blockquote>\n\n<p>とりあえずbundlerはグローバルに入れとく。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem install bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。<br />\n一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをローカルにインストールする。<br />\nUbuntuみたいにrdenv環境じゃないので、グローバル環境はなるべく汚染したくないので、<code class=\"language-plaintext highlighter-rouge\">--path</code>指定してローカルにインストールする。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div></div>\n\n<p>あるいは、<code class=\"language-plaintext highlighter-rouge\">install.cmd</code>に登録してあるので、そっちを実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRubyのバージョンを変更したり、ディレクトリを移動した場合はgemsディレクトリを削除してから</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div>  </div>\n  <p>を実行する</p>\n</blockquote>\n\n<p>windows対応にあたって、リポジトリの _config.yml と .gitignore は対処済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>サーバ起動</p>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\\server.cmd\n</code></pre></div></div>\n\n<p>もちろん、エクスプローラなどから <code class=\"language-plaintext highlighter-rouge\">server.cmd</code> をダブルクリックして実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこのときのキモ、jekyll実行前に以下を実行してRubyのエンコードをUTF-8に設定している。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>set RUBYOPT=--encoding=UTF-8`  \n</code></pre></div>  </div>\n  <p>これがないとエンコードエラーが発生する。<br />\n環境変数で設定しておけば逐一設定しなくても良いが、どうせcmdファイル書いてあるので、ついでに設定している。</p>\n</blockquote>\n\n<p>firewallが警告を表示するので、許可してちょ。<br />\nまごまごしてるとjekyllがエラー終了しちゃうけど、その後でも許可してしまえば次回からは大丈夫。</p>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>以降は<a href=\"/memoBlog/2019/07/17/githubpages.html\">こっち</a>を見てちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>python の async/await</title>\n  </head>\n  <body>\n    <header>\n      <h1>python の async/await</h1>\n      <p>python の async/awaitってどう動くんだっけ?</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h2 id=\"python-の-asyncawaitってどう動くんだっけ\">python の async/awaitってどう動くんだっけ?</h2>\n\n<p>と思ったので、ちょっとテストプログラムを書いて試してみた。</p>\n\n<p>asyncioはnon-preemptiveなので、最近のpreemptiveに慣れ切った脳ミソにはややこしい。</p>\n\n<p>preemptiveなプログラムを書きたければ、threadingを使えば良い。適材適所というやつだ。</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">asyncio</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n\n<span class=\"n\">argvs</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span>  <span class=\"c1\"># コマンドライン引数を格納したリストの取得\n</span><span class=\"n\">argc</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">)</span> <span class=\"c1\"># 引数の個数\n</span>\n<span class=\"k\">if</span> <span class=\"n\">argc</span> <span class=\"o\">></span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"mi\">5</span>        <span class=\"c1\"># テストケース\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"testCase = \"</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">testCase</span><span class=\"p\">))</span>\n\n<span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>           <span class=\"c1\"># 念のため宣言だけしておく\n</span>\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">sub</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub start        \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub wakeup       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"mi\">42</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"n\">task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">sub</span><span class=\"p\">())</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"k\">await</span> <span class=\"n\">task</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">task</span>\n    \n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main wakeup      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main2</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 start      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 wakeup     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n\n<span class=\"c1\"># =============================================================================\n</span><span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>     <span class=\"c1\"># 開始時刻を記憶\n</span><span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">or</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">4</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">wait</span><span class=\"p\">([</span><span class=\"n\">main</span><span class=\"p\">(),</span> <span class=\"n\">main2</span><span class=\"p\">()]))</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">5</span> <span class=\"p\">:</span>\n    <span class=\"n\">loop</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">get_event_loop</span><span class=\"p\">()</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"unknown test case!!\"</span><span class=\"p\">)</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n\n<p>以下のようにコマンドラインからテストケース番号を指定して実行する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python test.py <testCase>\n</code></pre></div></div>\n\n<h2 id=\"実行結果\">実行結果</h2>\n<h3 id=\"testcase1\">testCase=1</h3>\n\n<p>基本的なパターン、というか、全然非同期実行になってないけど。。。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code>→ <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p>awaitが付いていると、その場でタスクに実行権を渡し、そのタスクが終了するまで待つ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 1\ntestCase <span class=\"o\">=</span>  1\nbefor create     0.00026416778564453125\nafter create     0.00034689903259277344\nbefor call       0.00040340423583984375\nsub start        0.00047469139099121094\nsub wakeup       2.0033931732177734\nafter call       2.0035252571105957\nmain wakeup      3.004753351211548\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase2\">testCase=2</h3>\n\n<p>基本的なパターン、こっちが非同期実行として本命。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code>を実行するときに<code class=\"language-plaintext highlighter-rouge\">await</code>を付けない。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">await</code>が付いていないと、その場でタスクに実行権を渡さず、自分の実行を中断する部分か終了するまでそのまま実行する。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> 呼び出し箇所では即時実行されず、sleep(2)で <code class=\"language-plaintext highlighter-rouge\">main</code> の実行が中断されたところで <code class=\"language-plaintext highlighter-rouge\">sub</code> へ切り替わる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> で <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> が実行されると実行されるタスクがなくなるので、イベントループは実行可能タスク待ちになる。</p>\n\n<p>1秒後、<code class=\"language-plaintext highlighter-rouge\">main</code> が起床するので、そのままmainが終了される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> で イベントループは <code class=\"language-plaintext highlighter-rouge\">main</code> の終了を待っているので、<code class=\"language-plaintext highlighter-rouge\">sub</code> が実行中でも無関係にイベントループを終了してしまい、\n <code class=\"language-plaintext highlighter-rouge\">sub</code> の残りは実行されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 2\ntestCase <span class=\"o\">=</span>  2\nbefor create     0.0002646446228027344\nafter create     0.00034308433532714844\nbefor call       0.00039768218994140625\nafter call       0.0004489421844482422\nsub start        0.0005385875701904297\nmain wakeup      1.0014407634735107\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase3\">testCase=3</h3>\n\n<p>testCase=2 でsubの残りも実行するには?と思って試したパターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で、即座に <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main2())</code> を実行してみた。</p>\n\n<p>見事失敗。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→ <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p>どうやら、 <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で イベントループは一旦 <code class=\"language-plaintext highlighter-rouge\">close</code> されてしまうらしい。</p>\n\n<p>単にtestCase=2の後ろにmain2の実行を付け加えただけになってしまった。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 3\ntestCase <span class=\"o\">=</span>  3\nbefor create     0.00029540061950683594\nafter create     0.0003790855407714844\nbefor call       0.0004353523254394531\nafter call       0.00048828125\nsub start        0.0005817413330078125\nmain wakeup      1.0015552043914795\nmain2 start      1.0021519660949707\nmain2 wakeup     4.0038042068481445\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase4\">testCase=4</h3>\n\n<p>testCase=3 の失敗挽回パターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でmainとmain2をまとめてみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でまとめたタスクがすべて終了するまでイベントループは<code class=\"language-plaintext highlighter-rouge\">close</code> されないので、<code class=\"language-plaintext highlighter-rouge\">sub</code>は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> と <code class=\"language-plaintext highlighter-rouge\">main2</code> のどちらが先に実行されるかは規定されていない様子。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 4\ntestCase <span class=\"o\">=</span>  4\nmain2 start      0.0003325939178466797\nbefor create     0.0004305839538574219\nafter create     0.0005018711090087891\nbefor call       0.0005679130554199219\nafter call       0.0006389617919921875\nsub start        0.0007307529449462891\nmain wakeup      1.002068042755127\nsub wakeup       2.002253293991089\nmain2 wakeup     3.003903388977051\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase5\">testCase=5</h3>\n\n<p>testCase=3 の失敗挽回パターン その2。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.get_event_loop()</code> でイベントループを取得し、<code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> でそれぞれのタスクを実行してみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> → イベントループ終了\nとなっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> ではタスクが終了してもイベントループはcloseされないので、同じイベントループで<code class=\"language-plaintext highlighter-rouge\">main2</code>が実行される。\n結果、<code class=\"language-plaintext highlighter-rouge\">sub</code> は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> が終了するまで <code class=\"language-plaintext highlighter-rouge\">main2</code> は実行(起動)されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 5\ntestCase <span class=\"o\">=</span>  5\nbefor create     0.0002574920654296875\nafter create     0.0003345012664794922\nbefor call       0.00038933753967285156\nafter call       0.0004410743713378906\nsub start        0.0005307197570800781\nmain wakeup      1.0010528564453125\nmain2 start      1.0011804103851318\nsub wakeup       2.002350330352783\nmain2 wakeup     4.002865314483643\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "python": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyでドラッグで並べ替えできるリスト</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyでドラッグで並べ替えできるリスト</h1>\n      <p>kivyでドラッグで並べ替えできるリストを作った時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nドラッグで並べ替えできるリスト(AndroidでよくあるUI、<code class=\"language-plaintext highlighter-rouge\">RecycleView</code>と<code class=\"language-plaintext highlighter-rouge\">ItemTouchHelper</code>で作るんだったかな?)\nを作ってみた時のメモ。<br />\n<a href=\"https://maausa.marurm.com/wp-content/uploads/RecyclerView.gif\" target=\"_blank\">ちょっと違うけど、大体こんな感じ</a></p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nreorderablelist.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=reorderablelist.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>ソースは、表示する項目を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>と\nリスト全体を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>で構成される。<br />\n(あと、単体実行で動作するテストプログラム)<br />\n動作としては、</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>に<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を追加していきリスト化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code> をドラッグすることで並べ替え</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を左右にスワイプすることでハンドラ実行(デフォルトでは右スワイプで項目削除)\nといった感じ。</li>\n</ul>\n\n<p>テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>を<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>で囲んでスクロール可能にしています。\nスクロール不要ならそのまま配置しても可(テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">with_scroll</code>を<code class=\"language-plaintext highlighter-rouge\">False</code>に設定)。</p>\n\n<h2 id=\"reorderablelist\">ReorderableList</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>はリスト全体を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承したクラス。</p>\n\n<h3 id=\"追加したプロパティ\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>item_bg</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>item_fg</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>list_bg</td>\n      <td>リストの背景色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\n(<code class=\"language-plaintext highlighter-rouge\">orientation</code>は<code class=\"language-plaintext highlighter-rouge\">\"vertical\"</code>固定(項目を縦方向に並べるため)、\n<code class=\"language-plaintext highlighter-rouge\">size_hint_y</code>は<code class=\"language-plaintext highlighter-rouge\">None</code>固定(ScrollViewに包むため))\nのほか、<br />\n背景色の設定と、スクロール可能にするためminimum_height変更時の処理のbindを行っている。</p>\n\n<h3 id=\"項目追加処理\">項目追加処理</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">add_item</code>が項目追加処理。<br />\nパラメータは<code class=\"language-plaintext highlighter-rouge\">cls</code>で項目表示に使用するクラス(デフォルトは<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>)と、項目表示クラスの初期化パラメータを受け取る。<br />\nこれは項目に表示する内容を柔軟に切り替えられるよう、項目表示クラスを<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を継承したクラスに切り替えられるようにするため。</p>\n\n<h3 id=\"レイアウト処理\">レイアウト処理</h3>\n<p>kivyでは、レイアウトの変更命令と実際に変更が行われるまでにディレイがある。<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">add_widget(wid)</code> して直後にwid.posを読み出すと実際に追加されたあとの位置が読み出せない。<br />\nこれは、<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>では処理の予約だけ行い、実際に描画が行われるのは別のところ(<code class=\"language-plaintext highlighter-rouge\">mainloop</code>?)で\n他のウィジェットのレイアウト結果を五月雨式に反映していくため、\n描画結果がposに反映されるまでタイムラグが発生するためと思われる。</p>\n\n<p>そこで、<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>のレイアウトが変更され、処理が終了したタイミングで子ウィジェットに\nレイアウト完了を通知できるよう<code class=\"language-plaintext highlighter-rouge\">do_layout()</code>をオーバライドし、基底クラスの処理が完了した後\n各子ウィジェットの<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>をコールしている。</p>\n\n<h2 id=\"reorderableitem\">ReorderableItem</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>はリストに表示する項目を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスと<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承している。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスはドラッグ処理を実現するクラス。<br />\nもう一つの基底クラスを<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>とすることで、派生クラスのレイアウトを柔軟に設定できるようにしている。</p>\n\n<h3 id=\"追加したプロパティ-1\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>text</td>\n      <td>項目に表示する文字列</td>\n    </tr>\n    <tr>\n      <td>bg_color</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>fg_color</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ-1\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\nのほか、<br />\n項目内部の構築(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)、\n背景色の設定と、pos/size変更時にドラッグ範囲を変更する処理のbind、\nインスタンス変数の設定を行っている</p>\n\n<h3 id=\"内部ウィジェットの追加処理add_inner_widget\">内部ウィジェットの追加処理(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)</h3>\n<p>項目の内部の表示を構築する処理。<br />\nデフォルトではLabelを1個追加している。<br />\n項目の表示内容を変更したい場合は、派生クラスでこの処理をオーバライドし、\n必要な内容を追加していく。</p>\n\n<h3 id=\"ドラッグ開始処理on_touch_down\">ドラッグ開始処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_down()</code>)</h3>\n<p>まず、基底クラスのドラッグ開始処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ対象としての処理(インスタンス変数の設定)を行い、<br />\n自身の描画Canvasを親ウィジェット(<code class=\"language-plaintext highlighter-rouge\">self.parent</code>)のcanvasからcanvas.afterに繋ぎかえる。\nこれはドラッグ中の表示が前面に表示されるようにするためである。</p>\n\n<blockquote>\n  <p>[!NOTE]\n通常、add_widget()すると追加されたウィジェットの描画Canvasは親ウィジェットのCanvasに繋がれる。<br />\nこの親ウィジェットのCanvasに繋がれた描画ウィジェットは後から繋がれたものが前面に表示される。<br />\n(縦方向のBoxLayoutの場合下に表示されているウィジェットが前に表示される)<br />\n重ならない表示であれば問題ないが、ドラッグを行うとドラッグ中のウィジェットが背面に表示されることがある。<br />\nそこで、ドラッグ中のウィジェット他のウィジェットより前面に表示するため、CanvasからCanvas.afterに繋ぎかえ、前面に表示されるようにする。<br />\n仕様を読む限り、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index, canvas='after')</code>でadd_widget時にcanvas.afterに接続できるようなのだが、\n実際にはバグ(仕様制限?)により、indexが0のときのみcanvasパラメータが有効になるらしい。<br />\nこれを回避するため、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index)</code>で通常通りウィジェットを追加した後、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">after</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>として描画Canvasを繋ぎかえている。\ncanvas.afterに繋いだ描画Canvasをcanvasに戻す場合は、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">cur_index</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">children</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>    <span class=\"c1\"># canvas.after から canvasへ繋ぎかえるため\n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">remove_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>                 <span class=\"c1\"># 一旦削除して(canvasかcanvas.afterは自動的に判別してくれる) \n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"o\">=</span><span class=\"n\">cur_index</span><span class=\"p\">)</span>   <span class=\"c1\"># 再度同じ場所に挿入\n</span></code></pre></div>  </div>\n  <p>と実行する。  <code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>は描画Canvasがどこに繋がっていても探して削除してくれるので、\nそのまま実行して問題ない。</p>\n</blockquote>\n\n<h3 id=\"ドラッグ中処理on_touch_move\">ドラッグ中処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_move()</code>)</h3>\n<p>まず、基底クラスのドラッグ中処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ中の処理を行う。<br />\n親ウィジェットに繋がっている子ウィジェットをサーチして、自分以外で自分の中心がウィジェットの表示範囲内に入っているウィジェットを探す\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>)<br />\n自分の上端が対象ウィジェットの上端を超えたか、自分の下端が対象ウィジェットの下端を超えた場合は自分と対象ウィジェットを入れ替える。<br />\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>だけで判断すると、自分より高さが高いウィジェットと入れ替えるときに不都合が起こる)<br />\n位置を交換するには、自分を一旦削除(<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>)して、対象ウィジェットの位置(<code class=\"language-plaintext highlighter-rouge\">i</code>)に繋ぐ(<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>)。<br />\nその後、ドラッグを継続するので、ドラッグ開始時と同様に描画Canvasをcanvas.afterに繋ぎかえる。</p>\n\n<h3 id=\"ドラッグ終了処理on_touch_up\">ドラッグ終了処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_up()</code>)</h3>\n\n<p>まず、基底クラスのドラッグ終了処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ終了の処理を行う。<br />\nドラッグ開始/ドラッグ中処理でcanvas.afterに繋ぎかえた描画Canvasをcanvasに戻すために一旦<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>してから\n<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>する(これによりドラッグにより表示が移動していた対象ウィジェットが通常位置に戻る)。<br />\nその後、対象ウィジェットの表示位置がドラッグ開始時と変わっていなく、ドラッグした距離が設定値を超えている場合は\nスワイプ処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>または<code class=\"language-plaintext highlighter-rouge\">do_swipe_left()</code>)を実行する。</p>\n\n<h3 id=\"右へswipeしたときの処理do_swipe_right\">右へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、対象ウィジェットを削除する。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"左へswipeしたときの処理do_swipe_right\">左へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、デバッグ用にログ出力のみ。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"親ウィジェットのレイアウト完了時処理done_parent_layout\">親ウィジェットのレイアウト完了時処理(<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>)</h3>\n<p>親ウィジェットのレイアウト完了時に子ウィジェットすべてのこのメソッドがコールされる。<br />\nドラッグ中であれば必要な処理(現在位置の記憶とドラッグ中位置への移動)を行う。</p>\n\n<h1 id=\"サンプルプルグラム\">サンプルプルグラム</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nサンプルプルグラム</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=test1.py\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyで画面遷移</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyで画面遷移</h1>\n      <p>kivyで画面遷移する方法について</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\n実行時に画面を切り替えて使用する方法について試した時のメモ。<br />\nついでにAndroidアプリ化もしてみた。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\n(multi_screenって名前はなんか違う気もするけど、複数画面を制御するってことでヨシとしとこう)</p>\n\n<h2 id=\"メイン処理スクリーンマネージャのソース\">メイン処理/スクリーンマネージャのソース</h2>\n<p>multi_screen.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=multi_screen.py\"></script>\n</dev>\n\n<h2 id=\"第1画面のソース\">第1画面のソース</h2>\n<p>screen1.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen1.py\"></script>\n</dev>\n\n<h2 id=\"第2画面のソース\">第2画面のソース</h2>\n<p>screen2.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen2.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyで画面を切り替えて使用するには、<code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承したクラスを使用し、ここに各画面を登録し、\n<code class=\"language-plaintext highlighter-rouge\">self.current</code>に表示する画面の名前(<code class=\"language-plaintext highlighter-rouge\">name</code>)を設定することで切り替えるらしい。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>今回は日本語を使ってみようと思うので、日本語フォントをインストール。<br />\n有名どころではNotoSansCJKとかTAKAOとか。<br />\nubuntuだと以下でインストールできる。<br />\nNotoSansCJK は Androidでもインストールされていることが多いのかな?(手元のちょっと古いAndroidには入ってた)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n<span class=\"c\"># または</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n<p>あと、テキスト入力も試してみるので、クリップボード操作のためのライブラリをインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>xclip\n</code></pre></div></div>\n\n<h2 id=\"multi_screenpy\">multi_screen.py</h2>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">multi_screen.py</code>の内容について。</p>\n\n<p>今回は日本語を使ってみるので、フォントディレクトリの登録と日本語対応フォントをデフォルトフォントに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">get_system_fonts_dir</span><span class=\"p\">()</span>                                        <span class=\"c1\"># フォントディレクトリにシステムフォントディレクトリを登録\n</span><span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'NotoSansCJK-Regular.ttc'</span><span class=\"p\">)</span>  <span class=\"c1\"># デフォルトフォントを設定\n</span></code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承した<code class=\"language-plaintext highlighter-rouge\">ControlScreenManager</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ControlScreenManager</span><span class=\"p\">(</span><span class=\"n\">ScreenManager</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">ControlScreenManager</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># 画面間で共有する変数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n</code></pre></div></div>\n<p>ネットで検索すると画面間で共有する変数を画面間で直接やりとりする例があったが、\nソースの再利用性などを考えてスクリーンマネージャで管理することにした。<br />\nそのための設定/取得メソッド</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ターゲット文字列の設定\n</span>    <span class=\"k\">def</span> <span class=\"nf\">set_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"n\">text</span>\n    \n    <span class=\"c1\"># ターゲット文字列の取得\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span>\n</code></pre></div></div>\n\n<p>画面切り替え処理<br />\nこれも画面から他の画面に直接遷移している例があるけど、\n一旦スクリーンマネージャでうけとってから\n遷移した方が分かりやすいと思う。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># screen1への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">SlideTransition</span><span class=\"p\">(</span><span class=\"n\">direction</span><span class=\"o\">=</span><span class=\"s\">'left'</span><span class=\"p\">,</span> <span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen1'</span>\n        \n    <span class=\"c1\"># screen2への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen2</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">FadeTransition</span><span class=\"p\">(</span><span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen2'</span>\n</code></pre></div></div>\n\n<p>アプリケーションクラス</p>\n\n<p>アプリケーションクラスのbuildメソッドでは上で定義したスクリーンマネージャのインスタンスに\n各画面のインスタンスを登録し、そのインスタンスをリターンする。</p>\n\n<p>KV言語で書く方法もあるけど、画面切り替えのときに使用する名前をここで定義できるので\nソースの見通しが良くなって好み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ScreenManager1</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># スクリーンマネージャの生成\n</span>        <span class=\"n\">sm</span> <span class=\"o\">=</span> <span class=\"n\">ControlScreenManager</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 画面1を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen1</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen1'</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 画面2を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen2</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen2'</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">sm</span>\n</code></pre></div></div>\n\n<h2 id=\"screen1py\">screen1.py</h2>\n\n<p>レイアウトの定義</p>\n\n<p>kvファイルにレイアウトを書く例が多いけど、こう書くとレイアウトと処理をまとめて書けるので好み。</p>\n\n<blockquote>\n  <p>[!NOTE]\n最近知ったけど、色指定は(rr, gg, bb, aa)(各値は0~1)と書かれている例が多いけど、\n色名(“black”とか”red”とか。指定できる色名は kivyインストールディレクトリの<code class=\"language-plaintext highlighter-rouge\">util.py</code>で定義されている<code class=\"language-plaintext highlighter-rouge\">hex_colormap</code>を参照)\nの他、”#RRGGBBAA”でも指定可能(AAは省略可能)。\nどちらも文字列指定なのでダブルクォーテーションまたはシングルクォーテーションで囲む必要あり。</p>\n\n  <p>また、サイズ類は<code class=\"language-plaintext highlighter-rouge\">dp(36)</code>みたいな書き方もできるけど、文字列で<code class=\"language-plaintext highlighter-rouge\">\"36dp\"</code>と書くこともできる。\nサイズ類は数値で指定すると単位は<code class=\"language-plaintext highlighter-rouge\">px</code>になる。</p>\n</blockquote>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen1>:\n    ・・・・\n            bg_color_normal : \"#585858ff\"       # \"coloe_name\" or \"#RRGGBB\" or \"#RRGGBAA\" or (rr, gg, bb, aa) で指定\n    ・・・・\n            item_height          : '36dp'   # 数値で指定したときの単位はpx\n    ・・・・\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nAndroidアプリ化する場合、テキスト入力が下の方にあるとソフトキーボードが出てきたときに見えなくなるので\n上の方に配置しておく方が無難。<br />\nなんかうまくやる方法があるのかもしれんけど、現状分かってない。</p>\n</blockquote>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>class Screen1(Screen):\n</code></pre></div></div>\n\n<p>あとは<code class=\"language-plaintext highlighter-rouge\">Screen1</code>クラス内で動作を定義していけば良い。<br />\n画面切り替え処理はkv言語で直接スクリーンマネージャの処理をコールすると訳わかめになるので\n一旦このクラス内で受け取ってスクリーンマネージャの処理をコールするようにしている。<br />\nこの辺は好みの問題なので、お好きにどうぞ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'switch_to_screen1'</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">switch_to_screen1</span><span class=\"p\">()</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nスクリーンマネージャはScreen派生クラスの<code class=\"language-plaintext highlighter-rouge\">self.manager</code>で取得できる。</p>\n</blockquote>\n\n<h2 id=\"screen2py\">screen2.py</h2>\n\n<p>こちらも同様にレイアウトを定義しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen2>:\n    ・・・・\n</span></code></pre></div></div>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">Screen2</span><span class=\"p\">(</span><span class=\"n\">Screen</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>画面が切り替わる前にScreen1で設定した文字列を取得したいので、<code class=\"language-plaintext highlighter-rouge\">on_pre_enter()</code>をオーバーライドする。<br />\n文字列をScreen1から直接取ると画面構成変えた時に困るので、スクリーンマネージャ経由で取得するようにしている。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">on_pre_enter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"c1\"># 表示用ラベルを書き換え\n</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">get_target_string</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"NONE\"</span>       <span class=\"c1\"># 空文字が来たらNONEに書き換え\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">text</span><span class=\"si\">}</span><span class=\"s\"> が選択されました'</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">python multi_screen.py</code>で実行。<br />\n一番上のドロップダウンリストで項目を選択し、2番目の「Go to Screen 2」ボタンを押すとScreen2に切り替わる。<br />\nScreen2では画面下側の領域にScreen1のドロップダウンリストで選択した文字列が表示される。\n「Go to Screen 1」ボタンでScreen1に戻る。<br />\nScreen1のテキスト入力欄に文字列を入力し、「ADD」ボタンをクリックするとドロップダウンリストに入力した文字列が追加される。<br />\nもちろん、その文字列を選択してScreen2に切り替えればその文字列が表示される。</p>\n\n<blockquote>\n  <p>[!NOTE]\nLunuxでは日本語入力できないみたい。ただしコピペは可能なので他のところで入力してコピペすればOK。<br />\nAndroidではそのまま日本語も入力できる。</p>\n</blockquote>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>の手順でAndroidアプリ化もできる。<br />\nここの準備が終わっていれば以下のコマンドでOK。</p>\n\n<h2 id=\"multi_screenpyをリネーム\">multi_screen.pyをリネーム</h2>\n<p>python for androidはエントリーポイントがmain.pyに固定らしいので、リネーム</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mv </span>multi_screen.py main.py\n</code></pre></div></div>\n\n<h2 id=\"buildozerspec-の生成\">buildozer.spec の生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>今回は特に編集の必要なし。\n<code class=\"language-plaintext highlighter-rouge\">title</code>、<code class=\"language-plaintext highlighter-rouge\">package.name</code>、<code class=\"language-plaintext highlighter-rouge\">package.domain</code>なんかは必要なら変更してちょ。</p>\n\n<h2 id=\"build実行\">build実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動する)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪SDK Platform-Tools <span class=\"k\">for </span>Windowsを展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>で、実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、Android上で動作した。メデタシメデタシ。<br />\n文字入力もちゃんと動いてるし、改造したボタンやスピナーも動いてる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのSpinnerをカスタマイズ</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのSpinnerをカスタマイズ</h1>\n      <p>kivyのSpinner(ドロップダウンリスト)をカスタマイズする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nSpinner(ドロップダウンリスト)の項目の表示がすべて同じ色で現在選択されている項目がどれか一目で分からなかったので\n選択されている項目の色が変わるようにカスタマイズしてみた。</p>\n\n<p><a href=\"/memoBlog/2025/04/26/kivy_2.html\">kivyのButtonの色を変更する</a>ではButtonをカスタマイズして\n簡単に背景色を変更できるようにしたので、それを使えばわりとお手軽にできそうな感じ。</p>\n\n<h1 id=\"カスタマイズ内容\">カスタマイズ内容</h1>\n<ul>\n  <li>ドロップダウンの項目の表示色を選択中のものとそれ以外のもので分ける</li>\n  <li>それらの色(背景/文字)はプロパティで指定する</li>\n  <li>ドロップダウンの項目の表示高さをプロパティで指定する</li>\n</ul>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7.js\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyではドロップダウンリスト(クリックすると選択項目がぺろっと出てくるやつ)を表示するのにSpinnerウィジェットを使う。<br />\nで、クリックすると設定された項目が表示されるのだけれど、すべて同じ色(通常時、クリックした時、無効化した時の色はそれぞれ画像で指定できる)\nで表示され、現在どれを選択しているのかが分かり難い。<br />\nそこで、現在選択されている項目の色(画像でなく)を変更できるようにカスタマイズする。</p>\n\n<p>色指定に関して、<code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと項目を表示するための<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスはどちらも<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスを継承しているので、\n<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを同時に継承することで<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスに関連する処理を置き換えられる。</p>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスを作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスは特に追加する処理などはない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinnerOption</span><span class=\"p\">(</span><span class=\"n\">SpinnerOption</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n    <span class=\"k\">pass</span>\n</code></pre></div></div>\n\n<p>次に <code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinner</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinner</span><span class=\"p\">(</span><span class=\"n\">Spinner</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>追加するプロパティ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">item_selected_bg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の背景色\n</span>    <span class=\"n\">item_selected_fg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_unselected_bg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 非選択項目の背景色\n</span>    <span class=\"n\">item_unselected_fg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_height</span>          <span class=\"o\">=</span> <span class=\"n\">NumericProperty</span><span class=\"p\">(</span><span class=\"s\">'48dp'</span><span class=\"p\">)</span>               <span class=\"c1\"># 項目の高さ(デフォルトは48dp)\n</span></code></pre></div></div>\n\n<p>コンストラクタでは<code class=\"language-plaintext highlighter-rouge\">option_cls</code>のデフォルト値を<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>に設定し、基底クラスのコンストラクタを実行。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"s\">'option_cls'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">kwargs</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 項目表示用クラスが指定されていなければCustomSpinnerOptionを指定\n</span>            <span class=\"n\">kwargs</span><span class=\"p\">[</span><span class=\"s\">'option_cls'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">CustomSpinnerOption</span>\n        \n        <span class=\"c1\"># 基底クラスの初期化\n</span>        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">CustomSpinner</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>その後、追加した各プロパティと<code class=\"language-plaintext highlighter-rouge\">text</code>プロパティの変更時の処理をバインドする。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span>\n                    <span class=\"n\">text</span>                <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_bg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_bg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_fg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_fg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_height</span>         <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 項目高さ\n</span>                <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの項目の色などを変更する処理を追加。<br />\nこの処理が各プロパティの変更時の処理としてバインドされる。</p>\n\n<p>項目の一覧は<code class=\"language-plaintext highlighter-rouge\">self._dropdown.container.children</code>か<code class=\"language-plaintext highlighter-rouge\">self._dropdown.children</code>にあるので判断して取得。</p>\n\n<p>選択されている項目か否かは各項目の<code class=\"language-plaintext highlighter-rouge\">text</code>と<code class=\"language-plaintext highlighter-rouge\">self.text</code>が一致しているかどうかで判断できるので、\nこの条件で設定する色を変更。<br />\nまた、項目すべてをループするので、ついでに項目高さ(<code class=\"language-plaintext highlighter-rouge\">height</code>)も変更しておく。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ドロップダウン内の項目の高さ/背景色/文字色を更新\n</span>    <span class=\"k\">def</span> <span class=\"nf\">update_dropdown_background</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">text</span>\n        <span class=\"c1\"># 項目のリストを取得\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        \n        <span class=\"c1\"># 各項目の背景色/文字色を変更\n</span>        <span class=\"k\">for</span> <span class=\"n\">item</span> <span class=\"ow\">in</span> <span class=\"n\">items</span><span class=\"p\">:</span>\n            <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_height</span>                      <span class=\"c1\"># 項目高さ\n</span>            <span class=\"k\">if</span> <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">==</span> <span class=\"n\">text</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_bg</span>    <span class=\"c1\"># 選択中の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_fg</span>    <span class=\"c1\"># 選択中の文字色\n</span>            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_bg</span>  <span class=\"c1\"># 非選択の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_fg</span>  <span class=\"c1\"># 非選択中の文字色\n</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの更新処理をオーバーライド。<br />\nこの処理はドロップダウンの新規作成時や項目追加時にコールされる。<br />\nここに上のドロップダウンの項目の色などを変更する処理のコールを追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">_update_dropdown</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">_update_dropdown</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 項目の背景色等を更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>ついでに項目の追加処理を追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># 項目の追加\n</span>    <span class=\"k\">def</span> <span class=\"nf\">add_item</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">values</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>以上でカスタマイズは終了。</p>\n\n<h1 id=\"動作確認プログラム\">動作確認プログラム</h1>\n<p>このファイルを単体で実行すれば動作確認プログラムが動作する。<br />\n動作確認ではAddボタンをクリックする度にドロップダウンリストの項目が追加されるようになっている。<br />\nSpinnerのボタンをクリックするとドロップダウンリストが表示され、現在選択されている項目が他の色で表示されている。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのButtonの色を変更する</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのButtonの色を変更する</h1>\n      <p>kivyのButtonの色を変更する方法あれこれ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nボタン<code class=\"language-plaintext highlighter-rouge\">Button</code>の色を変更しようとすると、なかなか大変なので色々試してみたメモ。</p>\n\n<h1 id=\"画像ファイルを使用して変更する\">画像ファイルを使用して変更する</h1>\n\n<p>これが通常の方法。<br />\nプロパティ<code class=\"language-plaintext highlighter-rouge\">background_normal</code>、<code class=\"language-plaintext highlighter-rouge\">background_down</code>、<code class=\"language-plaintext highlighter-rouge\">background_disabled_normal</code>、<code class=\"language-plaintext highlighter-rouge\">background_disabled_down</code>に\nそれぞれに表示する画像ファイルを指定する。<br />\n単色で表示するなら1✕1pixelの画像ファイルでかまわない。</p>\n\n<h2 id=\"ソース\">ソース</h2>\n<p>ソースはこんな感じ。<br />\n別途画像ファイル<code class=\"language-plaintext highlighter-rouge\">lightgray.png'</code>、<code class=\"language-plaintext highlighter-rouge\">red.png</code>、<code class=\"language-plaintext highlighter-rouge\">gray.png</code>をカレントディレクトリに用意しておく。</p>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。</p>\n<dev class=\"accordion_head_close\"></dev>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.app</span> <span class=\"kn\">import</span> <span class=\"n\">App</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.button</span> <span class=\"kn\">import</span> <span class=\"n\">Button</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.lang</span> <span class=\"kn\">import</span> <span class=\"n\">Builder</span>\n\n    <span class=\"c1\"># GUIlレイアウト\n</span>    <span class=\"n\">Layout</span> <span class=\"o\">=</span> <span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">'''\n# この中はインデントに意味があるので余計なインデントを入れてはいけない\nBoxLayout:\n    orientation:'horizontal'\n    \n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n    Button:\n        id              : button_test\n        text            : \"TEST\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_test()\n        background_normal: 'lightgray.png'\n        background_down: 'red.png'\n        background_disabled_normal: 'gray.png'\n        background_disabled_down: 'gray.png'\n\n    Button:\n        id              : button_ctrl\n        text            : \"Ena/Dis\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_ctrl()\n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n'''</span>\n    <span class=\"p\">)</span>\n\n    <span class=\"k\">class</span> <span class=\"nc\">MyApp</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n        <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n            <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">__init__</span><span class=\"p\">()</span>\n            \n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span> <span class=\"o\">=</span> <span class=\"n\">Layout</span><span class=\"p\">.</span><span class=\"n\">ids</span><span class=\"p\">.</span><span class=\"n\">button_test</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_ctrl</span> <span class=\"o\">=</span> <span class=\"n\">Layout</span><span class=\"p\">.</span><span class=\"n\">ids</span><span class=\"p\">.</span><span class=\"n\">button_ctrl</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"n\">Layout</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">on_test</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'pressed'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">on_ctrl</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span><span class=\"p\">.</span><span class=\"n\">disabled</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span><span class=\"p\">.</span><span class=\"n\">disabled</span>\n            \n    <span class=\"n\">MyApp</span><span class=\"p\">().</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"動作\">動作</h2>\n\n<p>実行すると、Buttonが2つ表示され、TESTボタンが指定されたファイルのイメージで表示される。<br />\nEna/DisボタンをクリックするとTESTボタンのDisable/Enableが切り替えらる。</p>\n\n<h1 id=\"base64エンコードデータで指定\">Base64エンコードデータで指定</h1>\n\n<p>画像ファイルを使用すると、使用する色の分だけ画像ファイルを用意し、処理を流用する度に\n忘れずにすべてのファイルをコピーしないといけない。<br />\nそこで、画像ファイルをbase64エンコードした文字列をpyファイル(またはkvファイル)に保存する方法を試してみる。</p>\n\n<p>まず、上で用意したpngファイルを以下のコマンドでbase64エンコード(前に特定の文字列を付加)する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"data:image/png;base64,</span><span class=\"sb\">`</span><span class=\"nb\">base64</span> <span class=\"nt\">-w</span> 0 ≪pngファイル≫<span class=\"sb\">`</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n<p>付加されている<code class=\"language-plaintext highlighter-rouge\">data:image/png;base64,</code>は続くデータがpngイメージであることを示している。</p>\n\n<p>出力された文字列を以下のようにファイル名の代わりに記載する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        background_normal           : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2M4fPjwfwAH3wNJzT7giwAAAABJRU5ErkJggg=='\n        background_down             : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAANSURBVBhXY3gro/IfAAVUAi3GPZKdAAAAAElFTkSuQmCC'\n        background_disabled_normal  : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2Oor6//DwAFewJ9z0FqqgAAAABJRU5ErkJggg=='\n        background_disabled_down    : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2Oor6//DwAFewJ9z0FqqgAAAABJRU5ErkJggg=='\n</code></pre></div></div>\n\n<p>これにより、pngファイルを削除しても動作するようになる。</p>\n\n<p>ただし、pyファイル(またはkvファイル)が大きくなってしまうことと、一目で指定されている色が把握できないというデメリットがある。</p>\n\n<h1 id=\"canvasbefor-で指定する\">canvas.befor で指定する</h1>\n\n<p>画像ファイルを用意すること自体面倒なので、RGBA値で指定する方法はないかと考えてみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">Label</code>と同様に<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>で背景色を指定してみることを試してみたが、うまくいかなかった。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    Button:\n        ・・・\n        canvas.before:\n            Color:\n                rgba    : (1,0,0,1)\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n</code></pre></div></div>\n<p>これは<code class=\"language-plaintext highlighter-rouge\">Button</code>が<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>をサポートしていないわけではなく、\nちゃんと指定通りに描画しているが、\nその前面に<code class=\"language-plaintext highlighter-rouge\">Button</code>のBackground_XXXが表示されているためらしい。</p>\n\n<p>それならば、Buttonの表示を透明にしてやれば<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>の表示が見えるはずである。<br />\n以下のように変更して試してみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">background_color : (0, 0, 0, 0)</code>が透明色にしている部分で、<br />\n<code class=\"language-plaintext highlighter-rouge\">background_XXX</code>をヌル文字列にしているのはすべてのピクセルを(255,255,255,255)にするためであるが、\n透明になるのであまり関係ないかもしれない。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    Button:\n        ・・・\n        background_normal           : ''\n        background_down             : ''\n        background_disabled_normal  : ''\n        background_disabled_down    : ''\n        background_color            : (0, 0, 0, 0) # 透明\n        canvas.before:\n            Color:\n                rgba    : (1,0,0,1)\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n</code></pre></div></div>\n<p>これでボタンが赤色になった。<br />\nしかし、これでばボタンを押下した時やDisableにした時に色が変化しない。</p>\n\n<p>そこで、さらに以下のようにして押下した時やDisableにした時に色が変わるようにしてみた。<br />\n<code class=\"language-plaintext highlighter-rouge\">canvas.before.Color.rgba</code>を <code class=\"language-plaintext highlighter-rouge\">self.disabled</code>と<code class=\"language-plaintext highlighter-rouge\">self.state</code>によって変更している。<br />\n下にGUIリソース定義部分全体を記載しておく。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 分かりやすいようにグローバル変数で定義しておく\n#:set BG_COLOR_NORMAL   (0.75, 0.75, 0.75, 1.0)\n#:set BG_COLOR_DOWN     (1.00, 0.00, 0.00, 1.0)\n#:set BG_COLOR_DISABLED (0.50, 0.50, 0.50, 1.0)\n\nBoxLayout:\n    orientation:'horizontal'\n    \n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n    Button:\n        id              : button_test\n        text            : \"TEST\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_test()\n        background_normal           : ''\n        background_down             : ''\n        background_disabled_normal  : ''\n        background_disabled_down    : ''\n        background_color            : (0, 0, 0, 0) # 透明\n        canvas.before:\n            Color:\n                rgba    : BG_COLOR_DISABLED if self.disabled else BG_COLOR_NORMAL if self.state == 'normal' else BG_COLOR_DOWN\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n    Button:\n        id              : button_ctrl\n        text            : \"Ena/Dis\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_ctrl()\n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n</code></pre></div></div>\n\n<h1 id=\"カスタムボタンウィジェットを作成する\">カスタムボタンウィジェットを作成する</h1>\n\n<p>上でとりあえず目的は達成されたが、ボタンを配置する度に上記のような設定を書くのは面倒なので、\nカスタムボタンウィジェットを作成してみる。</p>\n\n<h2 id=\"ソース-1\">ソース</h2>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/98907d88de7106b1c30a0be4b39aa77f\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/98907d88de7106b1c30a0be4b39aa77f.js\"></script>\n</dev>\n\n<h2 id=\"解説\">解説</h2>\n<p>上の「canvas.befor で指定する」の方法をkv言語を使用せずpythonで定義している。<br />\nそれぞれの色を自由に変更できるようにプロパティを用意した。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_normal</code>   通常時の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_down</code>     押下時の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_disabled</code> 無効時の色</li>\n</ul>\n\n<p>また、そのままだとボタンを並べて表示したときに境界が分からなくなるので、枠線を描画するため、以下のプロパティを用意した。<br />\nデフォルトは黒で幅1。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">border_color</code>    枠線の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">border_width</code>    枠線の幅</li>\n</ul>\n\n<p>初期化時にボタン本体の背景を透明にし、<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>に描画命令を追加して背景の描画(背景色と枠線)することと、\n状態、位置、プロパティが変化したときに描画パラメータを再設定する処理をbindしている。<br />\nbindした処理では状態や位置に合わせて<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>の処理のパラメータを変更している。</p>\n\n<p>枠線を描画するための<code class=\"language-plaintext highlighter-rouge\">Line</code>はwidth×2の幅で描画されるようなので、本来の矩形のwidthの半分だけ内側に描画されるようにしている。</p>\n\n<p>GUIレイアウトを定義するときは、通常のButtonと同様のプロパティ設定で配置できる。<br />\nもちろん、上の通常時の色、押下時の色、無効時の色を変更したい場合は追加で指定すれば良い。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>AndroidでpythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>AndroidでpythonでBLE</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerでBLE通信アプリを作ってみたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2025/04/04/Buildozer_2.html\">Buildozerでブロック崩しを作る</a>ではゲームを作ってみたが、次はペリフェラルを使ってみたくなるのが人情というもの。<br />\n<a href=\"https://bleak.readthedocs.io/en/latest/\" target=\"_blank\">Bleak</a>というモジュールがクロスプラットフォームでAndroidでも使えるらしい。<br />\nということで、Bleakを使ってBLEを使用するアプリを作って、それをBuildozerでAndroidアプリ化してみる。</p>\n\n<p>以下、<a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>での環境構築が終わっているものとして進める。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>これまで使用してきたWSL環境だとBluetoothが使用できないので、開発にはRaspberryPi5を使用することにした(Pi3以降なら大丈夫だと思う)。<br />\npyenvで仮想環境作ってkivyとbleakをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<h1 id=\"通信相手の準備\">通信相手の準備</h1>\n<p>通信相手は前に作ったランダム値を送るペリフェラルを使った。<br />\n<a href=\"https://github.com/ippei8jp/MultiBLE/tree/main/micropython\" target=\"_blank\">ここ</a>のble_RandomSensor3.py を\nRascberryPi PICO や ESP32 の micropython で動かしておく。</p>\n\n<p>micropythoの使い方は以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは下の「開く」をクリックすると表示されます。<br />\nダウンロードする場合は<a href=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1\" target=\"_blank\">こちら</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nimportしている<code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>は\n<a href=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7\" target=\"_blank\">ここ</a>\nにあります。</p>\n</blockquote>\n\n<p>用意するファイルはこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── kivy_ble.py\n└── scrolllabel.py\n</code></pre></div></div>\n\n<p>↓をクリックするとソースが開きます。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1.js\"></script>\n</dev>\n\n<h1 id=\"raspberrypiで実行\">RaspberryPiで実行</h1>\n<p>まずはPythonスクリプトが動くことを確認するために、RaspBerryPiで動かしてみる。<br />\n通信相手がいないと動かないので、事前に上の通信相手を実行しておく。</p>\n\n<p>RaspberyPi上でkivy_ble.pyを実行するとウィンドウが開くので、connectボタンをクリックする。<br />\nペリフェラルをスキャンが開始され、最初に見つかったデバイスに接続される。<br />\nさらにDATA1とDATA2のNotifyハンドラが登録され、受信データがウィンドウ右上の表示領域に表示される。<br />\ndisconnectボタンをクリックすると切断される。<br />\nQUITボタンをクリックするとプログラム終了。<br />\nウィンドウ下半分のログ表示領域には情報が表示される。この領域はスクロール可能。</p>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>と同様の手順でAndroidアプリ化していく。</p>\n\n<h2 id=\"ファイルの準備\">ファイルの準備</h2>\n\n<ul>\n  <li>BuidozerがインストールされたWSLの仮想マシンに作業ディレクトリを作成</li>\n  <li>作業ディレクトリに 上で作成した<code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code> <code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>をコピー</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code>を <code class=\"language-plaintext highlighter-rouge\">main.py</code> にリネーム</li>\n  <li>RaspberryPiの≪Bleakインストール先≫>/bleak/backends/p4android/recipes を 作業ディレクトリにコピー(ディレクトリまるごと)\n    <blockquote>\n      <p>[!NOTE]\nBleakのインストール先ディレクトリは以下のコマンドで確認できます</p>\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"bleak \"</span>\n</code></pre></div>      </div>\n    </blockquote>\n  </li>\n</ul>\n\n<p>-または以下でもOK</p>\n<blockquote>\n  <p>[!NOTE]</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> recipes/bleak\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/__init__.py\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/fix_setup.py\n</code></pre></div>  </div>\n</blockquote>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer init</code> を実行して<code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>を生成する</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>に以下の修正を加える</li>\n</ul>\n\n<dev class=\"accordion_head\"></dev>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- buildozer.spec.org  2025-04-09 07:58:44.836709400 +0900\n</span><span class=\"gi\">+++ buildozer.spec      2025-04-17 08:12:06.676451390 +0900\n</span><span class=\"p\">@@ -1,10 +1,10 @@</span>\n [app]\n\n # (str) Title of your application\n<span class=\"gd\">-title = My Application\n</span><span class=\"gi\">+title = BLE Demo\n</span>\n # (str) Package name\n<span class=\"gd\">-package.name = myapp\n</span><span class=\"gi\">+package.name = bledemo\n</span>\n # (str) Package domain (needed for android/ios packaging)\n package.domain = org.test\n<span class=\"p\">@@ -22,7 +22,7 @@</span>\n #source.exclude_exts = spec\n\n # (list) List of directory to exclude (let empty to not exclude anything)\n<span class=\"gd\">-#source.exclude_dirs = tests, bin, venv\n</span><span class=\"gi\">+source.exclude_dirs = tests, bin, venv, recipes\n</span>\n # (list) List of exclusions using pattern matching\n # Do not prefix with './'\n<span class=\"p\">@@ -37,7 +37,13 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements =\n+    python3,\n+    kivy,\n+    bleak,\n+    typing_extensions,\n+    async_to_sync,\n+    async-timeout\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n<span class=\"p\">@@ -95,7 +101,14 @@</span>\n\n # (list) Permissions\n # (See https://python-for-android.readthedocs.io/en/latest/buildoptions/#build-options-1 for all the supported syntaxes and properties)\n<span class=\"gd\">-#android.permissions = android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)\n</span><span class=\"gi\">+android.permissions =\n+    BLUETOOTH,\n+    BLUETOOTH_SCAN,\n+    BLUETOOTH_CONNECT,\n+    BLUETOOTH_ADMIN,\n+    ACCESS_FINE_LOCATION,\n+    ACCESS_COARSE_LOCATION,\n+    ACCESS_BACKGROUND_LOCATION\n</span>\n # (list) features (adds uses-feature -tags to manifest)\n #android.features = android.hardware.usb.host\n<span class=\"p\">@@ -330,7 +343,7 @@</span>\n #p4a.source_dir =\n\n # (str) The directory in which python-for-android should look for your own build recipes (if any)\n<span class=\"gd\">-#p4a.local_recipes =\n</span><span class=\"gi\">+p4a.local_recipes = ./recipes\n</span>\n # (str) Filename to the hook for p4a\n #p4a.hook =\n</code></pre></div></div>\n\n<ul>\n  <li>最終的に作業ディレクトリは以下のようになる\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>≪作業ディレクトリ≫\n├── buildozer.spec\n├── main.py\n├── scrolllabel.py\n└── recipes\n     └── bleak\n         ├── __init__.py\n         └── fix_setup.py\n</code></pre></div>    </div>\n    <h2 id=\"build\">build</h2>\n    <p>以下のコマンドでbuidする</p>\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"インストール実行\">インストール&実行</h2>\n<p>Windows側でadbサーバを起動しておき、以下を実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>connectボタンを最初にクリックした時、「この端末の位置情報へのアクセスをBLE Demoに許可しますか?」と聞かれたら「許可」をクリック\n(Androidのバージョンによって違うかもしれん。ターゲットAPIレベルで決まるんだっけ?)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのスクロール可能なラベルのカスタムウィジェット</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのスクロール可能なラベルのカスタムウィジェット</h1>\n      <p>PythonプログラムでGUIを作成するkivyでスクロール可能なラベルのカスタムウィジェットを作ったメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>でお試しプログラムを作っていた時、\nログ出力をスクロール可能にしたい(TeraTermみたいなターミナル表示のイメージ)と思い作ってみたけれど、\n汎用的に使えそうな気がしたのでカスタムウィジェットとしてまとめてみた。</p>\n\n<h1 id=\"解説\">解説</h1>\n<p>解説するほど理解してないけど…<br />\nkivyでは文字列を表示するのにLabelウィジェットを使うらしい(AndroidStudioでいうことろのTextView?)。<br />\nで、表示をスクロールするにはScrollViewウィジェットを使う(AndroidStudioでもScrollView)。<br />\n文字列をスクロールするには、ScrollViewの中にLabelを配置してやれば良いのだけれど、「配置しておしまい」という訳でもなく、\n色々と細々と下処理が必要になる。</p>\n\n<p>まずは、表示をどの程度残すか。TeraTermやWindowsTerminalでもスクロールバッファ行数や履歴のサイズとして指定する項目。<br />\nこれを設定できないと際限なく表示が増えてしまうので。<br />\nこれを実現するため、表示内容をdequeに保存し、新規行を追加した際にあふれた分を自動的に破棄するようにしている。</p>\n\n<p>また、テキストが表示領域からあふれた際に自動的にスクロールするようにするため、ラベルの<code class=\"language-plaintext highlighter-rouge\">texture_size</code>プロパティが変更された際に\nイベントハンドラ<code class=\"language-plaintext highlighter-rouge\">update_label_size</code>がコールされるように設定。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"n\">texture_size</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_label_size</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>ここでラベルのサイズをテクスチャサイズに合わせて変更している。<br />\nまた、このときラベルサイズがスクロールビューのサイズを超えた時、<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>に設定することで\n最下行を表示できるようにしている。<br />\nなお、ラベルサイズがスクロールビューのサイズ以下の時に<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>にしてしまうと下付き表示になってしまうため、\nこの条件では<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">1,0</code>にしている。<br />\nラベルサイズがスクロールビューのサイズ以上の時に常に<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>にすると\n以前の内容を確認するためにスクロールしている状態で新しい行が表示されると最下行までスクロールしてしまうので、\n<code class=\"language-plaintext highlighter-rouge\">0.0</code>に設定するのはスクロールビューのサイズを超えた時だけにしている。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">ScrollLabel</code>クラスをインポートして使ってください。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">scrolllabel</span> <span class=\"kn\">import</span> <span class=\"n\">ScrollLabel</span>\n</code></pre></div></div>\n\n<p>設定できるプロパティは<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>のプロパティに<code class=\"language-plaintext highlighter-rouge\">rows</code>(バッファ行数)を追加しています。<br />\nプロパティに<code class=\"language-plaintext highlighter-rouge\">rows</code>は初期化時にのみ変更可能です。\n初期化後(実際は最初のテキスト出力後)は変更してもバッファ行数に反映されません。</p>\n\n<p>テキストを追加するには<code class=\"language-plaintext highlighter-rouge\">add_text(text)</code>を使用します。\n引数<code class=\"language-plaintext highlighter-rouge\">end</code>を指定することで行末文字を変更できます(デフォルトは<code class=\"language-plaintext highlighter-rouge\">\\n</code>)。  <br />\nテキストを消去するには<code class=\"language-plaintext highlighter-rouge\">clear_text()</code>を使用します。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7.js?file=scrolllabel.py\"></script>\n</dev>\n\n<p>また、gistには実際に使用する際の例(レイアウトに Kv language使用/python使用)も載せてあるのでよろしかったら見てください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Buildozerでブロック崩しを作る</title>\n  </head>\n  <body>\n    <header>\n      <h1>Buildozerでブロック崩しを作る</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerでブロック崩しを作ってみたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>では訳も分からずとりあえずbuildして実行してみたが、\n少し何がどうなっているか調べてみたところ、\n実行の実体は<a href=\"https://github.com/kivy/python-for-android\" target=\"_blank\">python for android</a>\nというもので、Buildozerはこのプロジェクトをbuildするためのヘルパーらしい。</p>\n\n<p>で、githubのリポジトリを眺めていると<code class=\"language-plaintext highlighter-rouge\">pythonforandroid/recipes</code>にモジュールをbuildするためのレシピが置いてあるようだ。<br />\nそこに、<code class=\"language-plaintext highlighter-rouge\">pygame</code>というディレクトリがあったので、たぶんゲームを作るためのモジュールなんだろうとあたりをつけて\nぐぐってみた。</p>\n\n<p>で、<a href=\"https://python.joho.info/pygame/pygame-blockout/\" target=\"_blank\">【Pygame】ブロック崩しの作り方とサンプルコード(効果音付き)</a>\nにブロック崩しのプログラムの例があったので拝借してAndroidアプリ化してみることにした。</p>\n\n<p>今回は趣向を変えて、失敗事例も含めて書いてみる。</p>\n\n<p>以下、<a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>での環境構築が終わっているものとして進める。</p>\n\n<h1 id=\"使用したソース\">使用したソース</h1>\n<p><a href=\"https://python.joho.info/pygame/pygame-blockout/\" target=\"_blank\">【Pygame】ブロック崩しの作り方とサンプルコード(効果音付き)</a>\nのソースそのままでは動かなかったので、色々試行錯誤した結果のソースが以下。</p>\n\n<p>画像ファイルとオーディオファイルをプロジェクトフォルダに移動して\nアクセスするためのベースディレクトリを環境変数<code class=\"language-plaintext highlighter-rouge\">ANDROID_APP_PATH</code>から取得するようにした。<br />\n(相対パスだとうまく動かない。実行時のディレクトリがmain.pyがあるディレクトリと異なるため)</p>\n\n<p>あと、全画面表示にするため<code class=\"language-plaintext highlighter-rouge\">pygame.display.set_mode</code>に第2パラメータ<code class=\"language-plaintext highlighter-rouge\">(SCALED | FULLSCREEN)</code>を追加している。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pygame</span>\n<span class=\"kn\">from</span> <span class=\"nn\">pygame.locals</span> <span class=\"kn\">import</span> <span class=\"o\">*</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pygame.mixer</span>\n\n<span class=\"c1\"># ベースディレクトリの設定\n# Androidだとchdirされて相対パスでアクセスできなくなるので\n</span>\n<span class=\"n\">BASE_DIR</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getenv</span><span class=\"p\">(</span><span class=\"s\">'ANDROID_APP_PATH'</span><span class=\"p\">)</span>    <span class=\"c1\"># アプリケーションの格納されているパスを環境変数から取得\n</span><span class=\"k\">if</span> <span class=\"n\">BASE_DIR</span> <span class=\"ow\">is</span> <span class=\"bp\">None</span><span class=\"p\">:</span>\n    <span class=\"n\">BASE_DIR</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getcwd</span><span class=\"p\">()</span>                  <span class=\"c1\"># 設定されていない(Androidでない)→ カレントディレクトリを設定\n</span>\n<span class=\"c1\"># 画面サイズ\n</span><span class=\"n\">WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">400</span>\n<span class=\"n\">HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">400</span>\n<span class=\"n\">SCREEN</span> <span class=\"o\">=</span> <span class=\"n\">Rect</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">WIDTH</span><span class=\"p\">,</span> <span class=\"n\">HEIGHT</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像ファイルのパス\n</span><span class=\"n\">PADDLE_IMG_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'paddle.png'</span><span class=\"p\">)</span>\n<span class=\"n\">BLOCK_IMG_PATH</span>  <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'block.png'</span><span class=\"p\">)</span>\n<span class=\"n\">BALL_IMG_PATH</span>   <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'ball.png'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># オーディオファイルのパス\n</span><span class=\"n\">PADDLE_SOUND_PATH</span>   <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'paddle_sound.mp3'</span><span class=\"p\">)</span>\n<span class=\"n\">BLOCK_SOUND_PATH</span>    <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'block_sound.mp3'</span><span class=\"p\">)</span>\n<span class=\"n\">GAMEOVER_SOUND_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'gameover_sound.mp3'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># バドルのスプライトクラス\n</span><span class=\"k\">class</span> <span class=\"nc\">Paddle</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"c1\"># コンストラクタ\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">-</span> <span class=\"mi\">20</span>          <span class=\"c1\"># パドルのy座標\n</span>\n    <span class=\"k\">def</span> <span class=\"nf\">update</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mouse</span><span class=\"p\">.</span><span class=\"n\">get_pos</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span>  <span class=\"c1\"># マウスのx座標をパドルのx座標に\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">clamp_ip</span><span class=\"p\">(</span><span class=\"n\">SCREEN</span><span class=\"p\">)</span>                     <span class=\"c1\"># ゲーム画面内のみで移動\n</span>\n<span class=\"c1\"># ボールのスプライトクラス\n</span><span class=\"k\">class</span> <span class=\"nc\">Ball</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"c1\"># コンストラクタ\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">paddle</span><span class=\"p\">,</span> <span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">,</span> <span class=\"n\">speed</span><span class=\"p\">,</span> <span class=\"n\">angle_left</span><span class=\"p\">,</span> <span class=\"n\">angle_right</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>  <span class=\"c1\"># ボールの速度\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span> <span class=\"o\">=</span> <span class=\"n\">paddle</span>  <span class=\"c1\"># パドルへの参照\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">blocks</span> <span class=\"o\">=</span> <span class=\"n\">blocks</span>  <span class=\"c1\"># ブロックグループへの参照\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">start</span> <span class=\"c1\"># ゲーム開始状態に更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">score</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 連続でブロックを壊した回数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">=</span> <span class=\"n\">speed</span> <span class=\"c1\"># ボールの初期速度\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_left</span> <span class=\"o\">=</span> <span class=\"n\">angle_left</span> <span class=\"c1\"># パドルの反射方向(左端:135度)\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_right</span> <span class=\"o\">=</span> <span class=\"n\">angle_right</span> <span class=\"c1\"># パドルの反射方向(右端:45度)\n</span>\n    <span class=\"c1\"># ゲーム開始状態(マウスを左クリック時するとボール射出)\n</span>    <span class=\"k\">def</span> <span class=\"nf\">start</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># ボールの初期位置(パドルの上)\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span>\n\n        <span class=\"c1\"># 左クリックでボール射出\n</span>        <span class=\"k\">if</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mouse</span><span class=\"p\">.</span><span class=\"n\">get_pressed</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">move</span>\n\n    <span class=\"c1\"># ボールの挙動\n</span>    <span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">+=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centery</span> <span class=\"o\">+=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n        <span class=\"c1\"># 壁との反射\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span><span class=\"p\">:</span>    <span class=\"c1\"># 左側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>              <span class=\"c1\"># 速度を反転\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">></span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>  <span class=\"c1\"># 右側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">right</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span><span class=\"p\">:</span>      <span class=\"c1\"># 上側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n        <span class=\"c1\"># パドルとの反射(左端:135度方向, 右端:45度方向, それ以外:線形補間)\n</span>        <span class=\"c1\"># 2つのspriteが接触しているかどうかの判定\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">colliderect</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                                <span class=\"c1\"># 連続ヒットを0に戻す\n</span>            <span class=\"p\">(</span><span class=\"n\">x1</span><span class=\"p\">,</span> <span class=\"n\">y1</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">-</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">width</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_left</span><span class=\"p\">)</span>\n            <span class=\"p\">(</span><span class=\"n\">x2</span><span class=\"p\">,</span> <span class=\"n\">y2</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_right</span><span class=\"p\">)</span>\n            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span>                          <span class=\"c1\"># ボールが当たった位置\n</span>            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">y2</span><span class=\"o\">-</span><span class=\"n\">y1</span><span class=\"p\">)</span><span class=\"o\">/</span><span class=\"p\">(</span><span class=\"n\">x2</span><span class=\"o\">-</span><span class=\"n\">x1</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">x1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">y1</span>  <span class=\"c1\"># 線形補間\n</span>            <span class=\"n\">angle</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">radians</span><span class=\"p\">(</span><span class=\"n\">y</span><span class=\"p\">)</span>                     <span class=\"c1\"># 反射角度\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">*</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">cos</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">*</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">sin</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>                    <span class=\"c1\"># 反射音\n</span>\n        <span class=\"c1\"># ボールを落とした場合\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">></span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">start</span>                    <span class=\"c1\"># ボールを初期状態に\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">gameover_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">set_score</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>                               <span class=\"c1\"># スコアを0点にする\n</span>            <span class=\"c1\">#self.score.add_score(-100)                  # スコア減点-100点\n</span>\n        <span class=\"c1\"># ボールと衝突したブロックリストを取得(Groupが格納しているSprite中から、指定したSpriteと接触しているものを探索)\n</span>        <span class=\"n\">blocks_collided</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">spritecollide</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">blocks_collided</span><span class=\"p\">:</span>  <span class=\"c1\"># 衝突ブロックがある場合\n</span>            <span class=\"n\">oldrect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span>\n            <span class=\"k\">for</span> <span class=\"n\">block</span> <span class=\"ow\">in</span> <span class=\"n\">blocks_collided</span><span class=\"p\">:</span>\n                <span class=\"c1\"># ボールが左からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"ow\">and</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n                    \n                <span class=\"c1\"># ボールが右からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"ow\">and</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n\n                <span class=\"c1\"># ボールが上からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"ow\">and</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n                <span class=\"c1\"># ボールが下からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"ow\">and</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">block_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>     <span class=\"c1\"># 効果音を鳴らす\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>               <span class=\"c1\"># 衝突回数をカウント\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">add_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">*</span> <span class=\"mi\">10</span><span class=\"p\">)</span>   <span class=\"c1\"># 衝突回数に応じてスコア加点\n</span>\n<span class=\"c1\"># ブロック\n</span><span class=\"k\">class</span> <span class=\"nc\">Block</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"c1\"># ブロックの左上座標\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">+</span> <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">width</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">+</span> <span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">height</span>\n\n<span class=\"c1\"># スコア\n</span><span class=\"k\">class</span> <span class=\"nc\">Score</span><span class=\"p\">():</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">sysfont</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">font</span><span class=\"p\">.</span><span class=\"n\">SysFont</span><span class=\"p\">(</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"mi\">20</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">draw</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">screen</span><span class=\"p\">):</span>\n        <span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">sysfont</span><span class=\"p\">.</span><span class=\"n\">render</span><span class=\"p\">(</span><span class=\"s\">\"SCORE:\"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">),</span> <span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span><span class=\"mi\">255</span><span class=\"p\">,</span><span class=\"mi\">250</span><span class=\"p\">))</span>\n        <span class=\"n\">screen</span><span class=\"p\">.</span><span class=\"n\">blit</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">))</span>\n    <span class=\"k\">def</span> <span class=\"nf\">add_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">+=</span> <span class=\"n\">x</span>\n    <span class=\"k\">def</span> <span class=\"nf\">set_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">score</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"c1\"># 初期化\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># スクリーンの設定\n</span>    <span class=\"c1\"># screen = pygame.display.set_mode(SCREEN.size)\n</span>    <span class=\"n\">screen</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">display</span><span class=\"p\">.</span><span class=\"n\">set_mode</span><span class=\"p\">(</span><span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">SCALED</span> <span class=\"o\">|</span> <span class=\"n\">FULLSCREEN</span><span class=\"p\">))</span>    <span class=\"c1\"># (SCALED | FULLSCREEN) で前画面に拡大表示できる\n</span>\n    <span class=\"c1\"># オーディオ初期化\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># 各種効果音の設定\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">paddle_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">PADDLE_SOUND_PATH</span><span class=\"p\">)</span>               <span class=\"c1\"># パドルにボールが衝突した時の効果音取得\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">block_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">BLOCK_SOUND_PATH</span><span class=\"p\">)</span>                 <span class=\"c1\"># ブロックにボールが衝突した時の効果音取得\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">gameover_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">GAMEOVER_SOUND_PATH</span><span class=\"p\">)</span>           <span class=\"c1\"># ゲームオーバー時の効果音取得\n</span>    \n    <span class=\"c1\"># 描画用のスプライトグループ\n</span>    <span class=\"n\">group</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">RenderUpdates</span><span class=\"p\">()</span>  \n\n    <span class=\"c1\"># 衝突判定用のスプライトグループ\n</span>    <span class=\"n\">blocks</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Group</span><span class=\"p\">()</span>   \n\n    <span class=\"c1\"># スプライトグループに追加    \n</span>    <span class=\"n\">Paddle</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span>\n    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span>\n    <span class=\"n\">Block</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span><span class=\"p\">,</span> <span class=\"n\">blocks</span>\n\n    <span class=\"c1\"># パドルの作成\n</span>    <span class=\"n\">paddle</span> <span class=\"o\">=</span> <span class=\"n\">Paddle</span><span class=\"p\">(</span><span class=\"n\">PADDLE_IMG_PATH</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ブロックの作成(14*10)\n</span>    <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">15</span><span class=\"p\">):</span>\n        <span class=\"k\">for</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">11</span><span class=\"p\">):</span>\n            <span class=\"n\">Block</span><span class=\"p\">(</span><span class=\"n\">BLOCK_IMG_PATH</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># スコアを画面(10, 10)に表示\n</span>    <span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">Score</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>    \n\n    <span class=\"c1\"># ボールを作成\n</span>    <span class=\"n\">Ball</span><span class=\"p\">(</span><span class=\"n\">BALL_IMG_PATH</span><span class=\"p\">,</span> <span class=\"n\">paddle</span><span class=\"p\">,</span> <span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">135</span><span class=\"p\">,</span> <span class=\"mi\">45</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">clock</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">Clock</span><span class=\"p\">()</span>\n\n    <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>  <span class=\"c1\"># ループ処理の実行を継続するフラグ\n</span>\n    <span class=\"k\">while</span> <span class=\"n\">running</span><span class=\"p\">:</span>\n        <span class=\"n\">clock</span><span class=\"p\">.</span><span class=\"n\">tick</span><span class=\"p\">(</span><span class=\"mi\">60</span><span class=\"p\">)</span>      <span class=\"c1\"># フレームレート(60fps)\n</span>        <span class=\"n\">screen</span><span class=\"p\">.</span><span class=\"n\">fill</span><span class=\"p\">((</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">20</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 全てのスプライトグループを更新\n</span>        <span class=\"n\">group</span><span class=\"p\">.</span><span class=\"n\">update</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 全てのスプライトグループを描画       \n</span>        <span class=\"n\">group</span><span class=\"p\">.</span><span class=\"n\">draw</span><span class=\"p\">(</span><span class=\"n\">screen</span><span class=\"p\">)</span>\n        <span class=\"c1\"># スコアを描画  \n</span>        <span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">draw</span><span class=\"p\">(</span><span class=\"n\">screen</span><span class=\"p\">)</span> \n        <span class=\"c1\"># 画面更新 \n</span>        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">display</span><span class=\"p\">.</span><span class=\"n\">update</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># イベント処理\n</span>        <span class=\"k\">for</span> <span class=\"n\">event</span> <span class=\"ow\">in</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">event</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">():</span>\n            <span class=\"c1\"># 閉じるボタンが押されたら終了\n</span>            <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"nb\">type</span> <span class=\"o\">==</span> <span class=\"n\">QUIT</span><span class=\"p\">:</span> \n                <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"c1\"># キーイベント\n</span>            <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"nb\">type</span> <span class=\"o\">==</span> <span class=\"n\">KEYDOWN</span><span class=\"p\">:</span>\n                <span class=\"c1\"># Escキーが押されたら終了\n</span>                <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"n\">K_ESCAPE</span><span class=\"p\">:</span>   \n                    <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># 終了処理\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">quit</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">main</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>画像ファイルとオーディオファイルは参照元のページにあるリンクからダウンロードして以下のように配置する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── main.py\n├── images\n│   ├── ball.png\n│   ├── block.png\n│   └── paddle.png\n└── sound\n    ├── block_sound.mp3\n    ├── gameover_sound.mp3\n    └── paddle_sound.mp3\n</code></pre></div></div>\n\n<p>とりあえずホスト上で動作するか確認してみる。<br />\n(Android上のpython/pygameとバージョンが違うので厳密な動作確認にはならないけど、大体OKを確認したいだけなのでこれでいく)</p>\n\n<p>pygameのインストールは以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>pygame\n</code></pre></div></div>\n\n<p>WSLではデフォルトでオーディオ再生するためのライブラリ類がインストールされていないので、以下でインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>pulseaudio\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWSLってオーディオ再生できるんだ。<br />\n初めて知った…</p>\n</blockquote>\n\n<p>で実行してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python main.py\n</code></pre></div></div>\n\n<p>全画面表示になるので、終了はESCキー押下で。</p>\n\n<h1 id=\"まずは何も考えずにbuildしてみる失敗\">まずは何も考えずにbuildしてみる(失敗)</h1>\n\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>とりあえず最低限必要な修正だけで試してみる。<br />\nbuildozer.spec を以下の内容で修正。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- block0/buildozer.spec       2025-04-04 07:08:53.520218478 +0900\n</span><span class=\"gi\">+++ block1/buildozer.spec       2025-04-04 06:25:27.858934801 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n</code></pre></div></div>\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<p>しばらくするとエラーで止まる。<br />\nmk.logを確認してみると、以下のようなエラーメッセージがあった。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/Buildozer/biock1/.buildozer/android/platform/build-arm64-v8a_armeabi-v7a/build/other_builds/pygame/arm64-v8a__ndk_target_21/pygame/setup.py:70: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives\n・・・\nsrc_c/_sdl2/sdl2.c:211:12: fatal error: 'longintrepr.h' file not found\n</code></pre></div></div>\n\n<p>どうやらpygameのbuuild中に<code class=\"language-plaintext highlighter-rouge\">longintrepr.h</code>が見つからなくてエラーになっているらしい。<br />\n「longintrepr.h」でぐぐってみると、python 3.10 → 3.11 の変更で削除されたファイルらしい。</p>\n\n<h1 id=\"それならばpygameのバージョンを新しくしてbuildしてみる失敗\">それならばpygameのバージョンを新しくしてbuildしてみる(失敗)</h1>\n\n<p>pygameをpython 3.11に対応しているバージョンに変更して試してみる。<br />\n調べてみると、2.1.3からpython 3.11 に対応しているようである。</p>\n\n<p>作成済みのファイルを削除<br />\n<code class=\"language-plaintext highlighter-rouge\">buildozer android clean</code>でも良さそうだけど、念のため全部消して最初からやってみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> .buildozer bin buildozer.spec mk.log\n</code></pre></div></div>\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>buildozer.spec を以下の内容で修正。<br />\npygameのバージョンを2.1.3指定している。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- block0/buildozer.spec       2025-04-04 07:08:53.520218478 +0900\n</span><span class=\"gi\">+++ block2/buildozer.spec       2025-04-04 09:32:40.050228726 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame==2.1.3\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n</code></pre></div></div>\n\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n<p>しばらく待つと、以下のように表示されたので、buildは成功したようである。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Android packaging done!\n# APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<p>なので、実行してみる。<br />\nWindows側でadbサーバを起動しておき、以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>起動はするが、すぐに落ちてしまう。<br />\nなにやらエラーが発生している模様。ログで何が起こっているか確認する。<br />\n無関係なログも多く含まれているので、python関連のログだけ抜き出してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"nt\">-i</span> python run.log <span class=\"o\">></span> run_python.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code> に以下を追加するとlogcatのフィルタが有効になるので、設定しておくと良いかもしれない。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>android.logcat_filters = *:S python:V pythonutil:V PythonActivity:V\n</code></pre></div>  </div>\n  <p>コマンドラインで指定できると良いのがだが…\nadbを直接起動すればコマンドラインで設定できるけど。</p>\n\n  <p>タグ<code class=\"language-plaintext highlighter-rouge\">python</code>がpythonプログラム内のログ、その他は実行時の制御を行っている部分らしい。<br />\nまた、プログラム内のprintによるメッセージ出力もここに表示される。</p>\n</blockquote>\n\n<p>ログファイルの最後の部分には以下のように出力されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> I python  : Traceback (most recent call last):\n I python  :   File \"/work/Buildozer/block2/.buildozer/android/app/main.py\", line 34, in <module>\n I python  :   File \"/work/Buildozer/block2/.buildozer/android/platform/build-arm64-v8a_armeabi-v7a/build/python-installs/myapp/arm64-v8a/pygame/__init__.py\", line 70, in __getattr__\n I python  : NotImplementedError: sprite module not available (ImportError: dlopen failed: cannot locate symbol \"alphablit_alpha_sse2_argb_surf_alpha\" referenced by \"/data/data/org.test.myapp/files/app/_python_bundle/site-packages/pygame/surface.so\"...)\n I python  : Python for android ended.\n</code></pre></div></div>\n\n<p>どうやらpygameの初期化時に<code class=\"language-plaintext highlighter-rouge\">alphablit_alpha_sse2_argb_surf_alpha</code>が見つからないということらしい。<br />\n単にバージョン変えるだけではダメで、ちゃんとレシピも修正しないといけないらしい。</p>\n\n<h1 id=\"python-for-androidのバージョンを下げてみる成功\">python for androidのバージョンを下げてみる(成功)</h1>\n\n<p>python 3.10以下にして試してみることも考えたが、同様にレシピの変更なしで動くとは思えないので\npython for androidのバージョンを下げて試してみることにする。</p>\n\n<p>作成済みのファイルを削除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> .buildozer bin buildozer.spec mk.log\n</code></pre></div></div>\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>buildozer.spec を以下の内容で修正。<br />\n<code class=\"language-plaintext highlighter-rouge\">p4a.branch = release-2022.12.20</code> と指定してrelease-2022.12.20を使用するように設定している。<br />\nこのバージョンは python 3.9.9 を使用している。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gi\">+++ block3/buildozer.spec       2025-04-04 12:28:23.302885362 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n<span class=\"p\">@@ -321,7 +321,7 @@</span>\n #p4a.fork = kivy\n\n # (str) python-for-android branch to use, defaults to master\n<span class=\"gd\">-#p4a.branch = master\n</span><span class=\"gi\">+p4a.branch = release-2022.12.20\n</span>\n # (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch\n #p4a.commit = HEAD\n</code></pre></div></div>\n\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n<p>しばらく待つと、以下のように表示されたので、buildは成功したようである。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Android packaging done!\n# APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<p>なので、実行してみる。<br />\nWindows側でadbサーバを起動しておき(前のセクションで起動してれば再度実行する必要なし)、以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、動いた。<br />\nメデタシメデタシ。<br />\nログがファイルに格納され続けてしまうので、早めにCTRL+Cで止めておきましょう。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Buildozerをお試し</title>\n  </head>\n  <body>\n    <header>\n      <h1>Buildozerをお試し</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerをお試ししたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonプログラムをAndroid アプリ化できる Buildozer を試してみた時のメモ<br />\n(iOSもできるみたいだけど試してないのでわからん)<br />\n参考:<br />\n<a href=\"https://buildozer.readthedocs.io/en/latest/installation.html\" target=\"_blank\">公式サイト</a><br />\n<a href=\"https://qiita.com/kouzimiso/items/1332ab62791ca5d81c5f\" target=\"_blank\">BuildozerでAndroidアプリを作る 2024 WSL2</a><br />\n<a href=\"https://paloma69.hatenablog.com/entry/2022/07/05/195915\" target=\"_blank\">pythonでAndroidの野良アプリを作りたい2 buildozerでコンパイル編</a></p>\n\n<h1 id=\"準備\">準備</h1>\n<p>環境はWSL で Ubuntu 24.04を使用した。<br />\n(公式では20.04 or 22.04 となってるけど、24.04でも動いた)<br />\n以下ディストリビューション情報</p>\n\n<p>Andoridはちょっと古いけど ZenFone Max Pro (M2) Android9<br />\n新しいAndroidでも動くかどうかわからん。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>~<span class=\"nv\">$ </span>lsb_release <span class=\"nt\">-a</span>\nNo LSB modules are available.\nDistributor ID: Ubuntu\nDescription:    Ubuntu 24.04.2 LTS\nRelease:        24.04\nCodename:       noble\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n\n<p><a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a>参照</p>\n\n<h2 id=\"pyenvでpythonインストール\">pyenvでpythonインストール</h2>\n<p>公式では python は 3.8 以降となっているので、3.12を使うこととした。</p>\n\n<blockquote>\n  <p>[!NOTE]\n3.12では<code class=\"language-plaintext highlighter-rouge\">distutils</code>が廃止されているので、<code class=\"language-plaintext highlighter-rouge\">setuptools</code>のインストールが必須。<br />\n参考:<a href=\"https://openillumi.com/python-3-12-distutils-error-fix-guide/\" target=\"_blank\">Python 3.12での「ModuleNotFoundError: distutilsが見つかりません」を解決する方法</a></p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.12.9 \npyenv shell 3.12.9 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\npyenv shell <span class=\"nt\">--unset</span> \n</code></pre></div></div>\n\n<h2 id=\"pyenvで仮想環境構築\">pyenvで仮想環境構築</h2>\n<p>お約束で仮想環境を作っておく。<br />\n(そのまま3.12.xにインストールしてもいいけど)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Buildozer <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Buildozer\npyenv virtualenv 3.12.9 Buildozer\npyenv <span class=\"nb\">local </span>Buildozer \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"必要なツール類のインストール\">必要なツール類のインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>zip unzip openjdk-17-jdk autoconf libtool pkg-config zlib1g-dev cmake libffi-dev libssl-dev\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n公式サイトで指定されているライブラリのうち以下は24.04では存在しない。<br />\n<code class=\"language-plaintext highlighter-rouge\">libncurses5-dev libncursesw5-dev libtinfo5</code><br />\nWSL2のUbuntu24.04ではデフォルトで後継のlibncurses-dev、libtinfo6が入ってるので気にしなくても大丈夫</p>\n</blockquote>\n\n<h2 id=\"buildozer関連のモジュールのインストール\">Buildozer関連のモジュールのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> buildozer\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">Cython</span><span class=\"o\">==</span>0.29.33 virtualenv\n</code></pre></div></div>\n\n<h2 id=\"使用するフォントのインストール\">使用するフォントのインストール</h2>\n<p>どっかからダウンロードしてきてもいいけど、お手軽にaptでインストール<br />\n(あとで作業ディレクトリにコピーする)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n\n<h2 id=\"ubuntu上でアプリ実行するとき必要なライブラリのインストール\">Ubuntu上でアプリ実行するとき必要なライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libmtdev-dev\n</code></pre></div></div>\n\n<h2 id=\"アプリで使うモジュールのインストール\">アプリで使うモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>kivy\n</code></pre></div></div>\n\n<h1 id=\"アプリの作成\">アプリの作成</h1>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n\n<p>どこでも良いけど、先に作ったpyenvの仮想環境<code class=\"language-plaintext highlighter-rouge\">Buildozer</code>が使えるh場所で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /work/Buildozer/app <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Buildozer/app\n</code></pre></div></div>\n\n<h2 id=\"フォントのコピー\">フォントのコピー</h2>\n<p>先ほどインストールしたフォントを作業ディレクトリにコピー</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir assets\ncp /usr/share/fonts/truetype/fonts-japanese-gothic.ttf assets/\n</code></pre></div></div>\n\n<h2 id=\"mainpyを作成\">main.pyを作成</h2>\n\n<p><a href=\"https://qiita.com/kouzimiso/items/1332ab62791ca5d81c5f\" target=\"_blank\">参考にしたサイト</a>\nにあったプログラムを使わせてもらった(ちょっち変更あり)。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  main.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.app</span> <span class=\"kn\">import</span> <span class=\"n\">App</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.button</span> <span class=\"kn\">import</span> <span class=\"n\">Button</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.label</span> <span class=\"kn\">import</span> <span class=\"n\">Label</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.boxlayout</span> <span class=\"kn\">import</span> <span class=\"n\">BoxLayout</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.utils</span> <span class=\"kn\">import</span> <span class=\"n\">platform</span>\n\n<span class=\"c1\"># フォントのパスを指定してフォントを設定する\n</span><span class=\"k\">if</span> <span class=\"n\">platform</span> <span class=\"o\">==</span> <span class=\"s\">'win'</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Windowsの場合はシステムフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">\"C:/Windows/Fonts/YuGothR.ttc\"</span><span class=\"p\">)</span>\n<span class=\"k\">elif</span> <span class=\"n\">platform</span> <span class=\"o\">==</span> <span class=\"s\">'android'</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Androidの場合はassetsフォルダ内のフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'assets/fonts-japanese-gothic.ttf'</span><span class=\"p\">)</span>\n<span class=\"k\">else</span><span class=\"p\">:</span>\n    <span class=\"c1\"># その他のプラットフォームではデフォルトフォントを使用\n</span>    <span class=\"c1\"># LabelBase.register(DEFAULT_FONT, fn_regular='DejaVuSans.ttf')\n</span>    <span class=\"c1\"># その他の場合もassetsフォルダ内のフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'assets/fonts-japanese-gothic.ttf'</span><span class=\"p\">)</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MyApp</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># レイアウトの生成\n</span>        <span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"n\">BoxLayout</span><span class=\"p\">(</span><span class=\"n\">orientation</span><span class=\"o\">=</span><span class=\"s\">'vertical'</span><span class=\"p\">,</span> <span class=\"n\">spacing</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ボタンの生成\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span> <span class=\"o\">=</span> <span class=\"n\">Button</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"o\">=</span><span class=\"s\">'クリックしてください'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ボタンにコールバックを設定\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"n\">on_press</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">on_button_press</span><span class=\"p\">,</span> <span class=\"n\">on_release</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">on_button_release</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ラベルの生成\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">Label</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"o\">=</span><span class=\"s\">'ボタンがクリックされるとここに表示されます'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># layoutにボタンとラベルを配置\n</span>        <span class=\"n\">layout</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span><span class=\"p\">)</span>\n        <span class=\"n\">layout</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">layout</span>\n\n    <span class=\"c1\"># ボタンが押されたたときのコールバック処理\n</span>    <span class=\"k\">def</span> <span class=\"nf\">on_button_press</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">instance</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">'ボタンが押されました!'</span>\n    \n    <span class=\"c1\"># ボタンが離されたたときのコールバック処理\n</span>    <span class=\"k\">def</span> <span class=\"nf\">on_button_release</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">instance</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">'ボタンが離されました!'</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">MyApp</span><span class=\"p\">().</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"とりあえずununtu上で試してみる\">とりあえずUnuntu上で試してみる</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python main.py\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n上半分がボタン、下半分がラベル<br />\nボタンを押す/離すとラベルの表示が変わる<br />\nXボタンで終了</p>\n</blockquote>\n\n<h2 id=\"buildozer初期化\">Buildozer初期化</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n<p>buildozer.spec が生成される</p>\n\n<h2 id=\"buildozerspecファイルの修正\">buildozer.specファイルの修正</h2>\n<p>以下の修正を行う</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- buildozer.spec.org  2025-03-28 11:44:32.382972664 +0900\n</span><span class=\"gi\">+++ buildozer.spec      2025-03-28 11:52:18.977717226 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,ttf\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*.ttf\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n</code></pre></div></div>\n\n<h2 id=\"clean--build\">clean & build</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer android clean     <span class=\"c\"># 初回はやらなくてOK(FileNotFoundErrorになる)</span>\nbuildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee</span> <span class=\"nt\">-a</span> buildozer.log\n</code></pre></div></div>\n\n<p>正常にbuildが終了したら以下のように表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n初回は途中ライセンスに同意を求められるので同意するならyを入力(同意しないと終わっちゃうけど)<br />\n終了まで15分ほどかかった(環境依存なのであまりあてにしないで)<br />\n初回はダウンロードが入るのでもうちょっとかかる</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n<h2 id=\"android側の準備\">Android側の準備</h2>\n<p>adbが接続できるようになんか準備が必要(デバッグモードを有効にするとか?)だった気がするけど\n忘れちゃったので良きに計らってちょ\n(<a href=\"https://developer.android.com/studio/debug/dev-options?hl=ja\" target=\"_blank\">このへん?</a>)</p>\n\n<p>で、PCとUSBで接続しておく。</p>\n\n<h2 id=\"windows用-adbのダウンロード\">Windows用 adbのダウンロード</h2>\n<p><a href=\"https://developer.android.com/tools/releases/platform-tools?hl=ja\" target=\"_blank\">SDK Platform-Tools リリースノート</a><br />\n「ダウンロード」セクションの「SDK Platform-Tools for Windowsをダウンロード」からダウンロードし、適当なディレクトリに展開\n(例:C:\\Android_tools )</p>\n\n<blockquote>\n  <p>[!NOTE]\nPATHを通してもいいけど、AndroidStudio使うときに不安なので通さないでcdしてから実行するようにした</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nAndroidStudioが入っているのであれば、そっちを使っても可。<br />\n その場合、adb.exeは<code class=\"language-plaintext highlighter-rouge\">%LOCALAPPDATA%\\Android\\Sdk\\platform-tools</code>にある。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n公式の情報ではWindowsのadbとUbuntuのadbのバージョンが同じでないとダメと書いてあるが、多少違っても大丈夫っぽい。<br />\n(てか、古いバージョンダウンロードできるんだろか?と思ったら、\n<a href=\"https://qiita.com/azumagoro/items/3a44fad53d88b3b2817b\" target=\"_blank\">Android SDK platform-tools 旧バージョン インストール</a>\nに手順書いてあった。メンドクサイけど…)</p>\n</blockquote>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動するためだと思う)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪上で展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!IMPORTANT]\n最初のadbの実行はWindows側。コマンドプロンプトやpowershellで実行する。</p>\n</blockquote>\n\n<p>以下のように表示されるはず</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>* daemon not running; starting now at tcp:XXXX\n* daemon started successfully\nList of devices attached\n== 接続されているデバイスが表示される ==\n</code></pre></div></div>\n\n<p>ちなみにサーバを停止するには以下</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>adb kill-server\n</code></pre></div></div>\n\n<h2 id=\"ダウンロードと実行\">ダウンロードと実行</h2>\n\n<p>WSL側のターミナルに戻って以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run \n</code></pre></div></div>\n\n<p>これでプログラムがAndroidにダウンロードされて実行される。</p>\n\n<p>logcatを表示したいときは以下</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n上記のコマンドを実行すると内部でadbが実行されるようだ。</p>\n</blockquote>\n\n<h2 id=\"usb接続せずに実行したい場合\">USB接続せずに実行したい場合</h2>\n<p>USB接続せずに実行したい場合は以下のように実行してWebサーバを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer serve\n</code></pre></div></div>\n<p>WEBサーバが立ち上がったら、Androidのchrome等からアクセスし、apkファイルをダウンロードしてインストール<br />\n…できるんだけど、通常firewallが動いていてアクセスが弾かれるのでfirewallの設定変更しないといけない。<br />\n変更方法は<a href=\"https://www.fmworld.net/cs/azbyclub/qanavi/jsp/qacontents.jsp?PID=0111-2966\" target=\"_blank\">このへん</a><br />\n(試してないけど)</p>\n\n<h2 id=\"その他の方法\">その他の方法</h2>\n<p>quickshreを使うとか、USBのファイル転送モードを使えばapkファイルを転送できるので、\nあとはFiles等で表示してapkファイルとタップすればインストールできる。<br />\n(なんか野良アプリのインストール許可とか色々許可しないといけなかった気がする)</p>\n\n<h1 id=\"まとめ\">まとめ</h1>\n<p>とりあえずなんか実行できるものができたけど、実用に堪えるかはビミョー。<br />\nファイルアクセスとかネットワークアクセスとか出来るのかな?<br />\nBluetoothはどうなんだろ?<br />\nアクセス権限とかいろいろメンドクサイ処理が必要だったけど、そこまで対応してるんだろか?<br />\n気が向いたらもうちょっと調べてみるかも…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openpyxlのバグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>openpyxlのバグ</h1>\n      <p>openpyxl(3.1.5)のバグ(ではないけど、あえてそう書いておく)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"内容\">内容</h1>\n<p>openpyxl(3.1.2)でExcelのグラフを作成するスクリプトを使っていたが、\nopenpyxlを現時点での最新版(3.1.5)にアップデートしたところ、表示されるグラフの見た目が変わってしまった。</p>\n\n<h1 id=\"原因\">原因</h1>\n<p>検索してみたところ、teratailに\n『<a href=\"https://teratail.com/questions/5q9cujzlc2307x\" target=\"_blank\">python openpyxl グラフ作成 グラフ書式が変わったのを治せない</a>』\nというエントリを見つけた。</p>\n\n<p>どうやら、Excelの仕様に厳密に従ったらExcelのバグに引っかかった ということらしい。<br />\n(バグが他のバグ回避になってた、みたいな感じ)</p>\n\n<h1 id=\"対策\">対策</h1>\n<p>Excelのバグの修正を待っててもしかたないので、なんとか出来る方法を探してみた。<br />\nこの部分は openpyxl の 3.1.4 で仕様変更されたようなので、3.1.3以前を使うというのも手なのだけど、<br />\n最新版を使いたい場合はExcelのバグに引っかかってる部分だけ元にもどしてやれば良い。</p>\n\n<p>ということで、上のページにあった変更点を出力している部分を探して修正してみた。</p>\n\n<p>結論から言うと、以下のパッチをインストールしたライブラリにあててやれば良い。</p>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -urpN openpyxl.org/packaging/extended.py openpyxl/packaging/extended.py\n</span><span class=\"gd\">--- openpyxl.org/packaging/extended.py  2025-01-07 07:23:30.159676700 +0900\n</span><span class=\"gi\">+++ openpyxl/packaging/extended.py      2025-01-07 07:41:28.823592900 +0900\n</span><span class=\"p\">@@ -126,7 +126,8 @@</span> class ExtendedProperties(Serialisable):\n         self.HLinks = None\n         self.HyperlinksChanged = HyperlinksChanged\n         self.DigSig = None\n<span class=\"gd\">-        self.Application = f\"Microsoft Excel Compatible / Openpyxl {__version__}\"\n</span><span class=\"gi\">+        # self.Application = f\"Microsoft Excel Compatible / Openpyxl {__version__}\"\n+        self.Application = f\"Microsoft Excel\"\n</span>         self.AppVersion = \".\".join(__version__.split(\".\")[:-1])\n         self.DocSecurity = DocSecurity\n</code></pre></div></div>\n\n<p>で、試してみたところ うまくグラフが表示されるようになった。<br />\nメデタシメデタシ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>TkEasyGUIを使ってみる</title>\n  </head>\n  <body>\n    <header>\n      <h1>TkEasyGUIを使ってみる</h1>\n      <p>pythonでGUIを簡単に作れる TkEasyGUI を使ってみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでGUIを作るにはtkinterを使うが、とっても分かり難い。<br />\nそこで、簡単にGUIが作れるとウワサの TkEasyGUI を使ってみた。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/TkEasyGUI/0.1.4/\" target=\"_blank\">PyPI</a></li>\n  <li><a href=\"https://github.com/kujirahand/tkeasygui-python\" target=\"_blank\">GitHub</a></li>\n  <li><a href=\"https://note.com/sirodon_256/n/na73d3fdac68d?fbclid=IwY2xjawHpgzhleHRuA2FlbQIxMQABHWBZ650bkpcT7-r0B3xAXpeUoIWsjSZJjZ4lqPUtBrxxQp3mlsCzFtM7tA_aem_lSSEVGhwq5SisJRckTFZcw\" target=\"_blank\">TkEasyGUIライブラリの基本とサンプルコード解説</a></li>\n</ul>\n\n<h1 id=\"使ってみる\">使ってみる</h1>\n<p>使ってみようと思ってはみたものの 何を作れば良いか思いつかなかったので、\n以前にtkinterで作ったプログラムを TkEasyGUI を使って書き直して見ることにした。</p>\n\n<p>元にしたのは、\n<a href=\"https://gist.github.com/ippei8jp/b8af596718e357dce185b5279b3533b8\" target=\"_blank\">ketsuatsu_GUI.py</a><br />\nこれの <code class=\"language-plaintext highlighter-rouge\">ketsuatsu_GUI.py</code>だけを書き換えてみる。<br />\n(<code class=\"language-plaintext highlighter-rouge\">ketsuatsu_csv2xls.py</code>はそのまま使用)</p>\n\n<h1 id=\"作ってみた\">作ってみた</h1>\n<p>ということで、書き直してみた。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>TkEasyGUI のインストールは以下を実行するだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>TkEasyGUI\n</code></pre></div></div>\n<p>TkEasyGUI と pyperclip がインストールされる。</p>\n\n<p>全体を実行するには、上の元ソースのREADMEを参照。</p>\n\n<h2 id=\"ソース\">ソース</h2>\n<p>ということで、作ってみたソースがこちら。<br />\n元のソースと比べても行数で半分以下になった。<br />\nまた、イベントによる実行がイベントハンドラで登録するのから\nイベントループでイベントを監視するように変更されたので、プログラムの見通しがよくなった。</p>\n\n<p>これを</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ketsuatsu_easyGUI.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">dont_write_bytecode</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>      <span class=\"c1\"># pycacheを作成しない\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">TkEasyGUI</span> <span class=\"k\">as</span> <span class=\"n\">eg</span>\n\n<span class=\"c1\"># CSV→エクセル変換処理\n</span><span class=\"kn\">from</span> <span class=\"nn\">ketsuatsu_csv2xls</span> <span class=\"kn\">import</span> <span class=\"n\">ketsuatsu_csv2xls</span>\n\n<span class=\"c1\"># フォント\n# FONT_NAME1 = \"MS ゴシック\"\n</span><span class=\"n\">FONT_NAME1</span> <span class=\"o\">=</span> <span class=\"s\">\"BIZ UDゴシック\"</span>\n<span class=\"n\">FONT_NAME2</span> <span class=\"o\">=</span> <span class=\"s\">\"Noto Sans CJK JP\"</span>\n\n<span class=\"n\">FONT_SIZE</span> <span class=\"o\">=</span> <span class=\"mi\">12</span>\n\n\n<span class=\"c1\"># レイアウト\n</span><span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Text</span><span class=\"p\">(</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"CSV file  \"</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Input</span><span class=\"p\">(</span>       <span class=\"s\">\"\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"s\">\"-csvfilepath-\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span> \n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">FileBrowse</span><span class=\"p\">(</span>  <span class=\"n\">button_text</span> <span class=\"o\">=</span> <span class=\"s\">\"Browse...\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"CSV file\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">file_types</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"s\">'CSV file'</span><span class=\"p\">,</span> <span class=\"s\">'*.csv'</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"s\">'all'</span><span class=\"p\">,</span> <span class=\"s\">'*.*'</span><span class=\"p\">)),</span>\n                     <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Text</span><span class=\"p\">(</span>        <span class=\"s\">\"Excel file\"</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Input</span><span class=\"p\">(</span>       <span class=\"s\">\"\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"s\">\"-excelfilepath-\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span> \n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">FileBrowse</span><span class=\"p\">(</span>  <span class=\"n\">button_text</span> <span class=\"o\">=</span> <span class=\"s\">\"Browse...\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">title</span> <span class=\"o\">=</span> <span class=\"s\">\"Excel file\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">file_types</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"s\">'Excel file'</span><span class=\"p\">,</span> <span class=\"s\">'*.xlsx'</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"s\">'all'</span><span class=\"p\">,</span> <span class=\"s\">'*.*'</span><span class=\"p\">)),</span>\n                        <span class=\"n\">save_as</span> <span class=\"o\">=</span> <span class=\"bp\">True</span><span class=\"p\">,</span>\n                     <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Column</span><span class=\"p\">(</span>\n            <span class=\"n\">layout</span><span class=\"o\">=</span><span class=\"p\">[</span>\n                      <span class=\"p\">[</span>\n                        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Button</span><span class=\"p\">(</span>  <span class=\"s\">\"Convert\"</span><span class=\"p\">,</span>\n                                    <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">),</span>\n                                 <span class=\"p\">),</span> \n                        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Button</span><span class=\"p\">(</span>  <span class=\"s\">\"Exit\"</span><span class=\"p\">,</span>\n                                    <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">),</span>\n                                 <span class=\"p\">),</span>\n                      <span class=\"p\">]</span>\n                    <span class=\"p\">],</span>\n            <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n            <span class=\"n\">expand_y</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n            <span class=\"n\">text_align</span><span class=\"o\">=</span><span class=\"s\">\"right\"</span><span class=\"p\">,</span>\n            <span class=\"n\">vertical_alignment</span><span class=\"o\">=</span><span class=\"s\">\"bottom\"</span><span class=\"p\">,</span>\n        <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n<span class=\"p\">]</span>\n\n\n<span class=\"c1\"># CSVファイルからexcelファイルへの変換処理をコールする\n</span><span class=\"k\">def</span> <span class=\"nf\">convert_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">):</span>\n    <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n\n    <span class=\"c1\"># パラメータエラーチェック\n</span>    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ファイルが指定されていない\n</span>        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"入力ファイルを指定してください\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># filedialog.askopenfilename()は存在するファイルしか選択できないが\n</span>    <span class=\"c1\"># エディットボックスを直接編集した場合のためにチェック\n</span>    <span class=\"k\">elif</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"入力ファイルを指定してください\"</span><span class=\"p\">,</span>  <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">output_filename</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ファイルが指定されていない\n</span>        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"出力ファイルを指定してください\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># この判定はfiledialog.asksaveasfilename()内で行うが\n</span>    <span class=\"c1\"># エディットボックスを直接編集した場合のためにチェック\n</span>    <span class=\"k\">elif</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">output_filename</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">ret</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup_ok_cancel</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"出力ファイルが存在します</span><span class=\"se\">\\n</span><span class=\"s\">上書きしますか?\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"確認\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span> <span class=\"k\">if</span> <span class=\"n\">ret</span> <span class=\"o\">==</span> <span class=\"s\">'OK'</span> <span class=\"k\">else</span> <span class=\"bp\">False</span>\n    <span class=\"k\">if</span> <span class=\"n\">execute_flag</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 変換処理\n</span>        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"c1\"># CSVファイルからエクセルファイルを作成\n</span>            <span class=\"n\">ketsuatsu_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">)</span>\n            <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"変換終了\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"終了\"</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"nb\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">e</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n\n    <span class=\"c1\"># 使用するフォントの設定\n</span>    <span class=\"n\">fonts</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">get_font_list</span><span class=\"p\">()</span>\n    <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n    <span class=\"n\">target_font_size</span> <span class=\"o\">=</span> <span class=\"n\">FONT_SIZE</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">FONT_NAME1</span> <span class=\"ow\">in</span> <span class=\"n\">fonts</span> <span class=\"p\">:</span>\n        <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"n\">FONT_NAME1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">FONT_NAME2</span> <span class=\"ow\">in</span> <span class=\"n\">fonts</span> <span class=\"p\">:</span>\n        <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"n\">FONT_NAME2</span>\n\n\n    <span class=\"c1\"># window create\n</span>    <span class=\"n\">window</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Window</span><span class=\"p\">(</span><span class=\"s\">'血圧 CSV->excel'</span><span class=\"p\">,</span> \n                        <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">600</span><span class=\"p\">,</span> <span class=\"mi\">150</span><span class=\"p\">),</span>\n                        <span class=\"n\">font</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">target_font_name</span><span class=\"p\">,</span> <span class=\"n\">target_font_size</span><span class=\"p\">),</span>\n                        <span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"n\">layout</span>\n                    <span class=\"p\">)</span>\n\n    <span class=\"c1\"># event loop\n</span>    <span class=\"k\">while</span> <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">is_alive</span><span class=\"p\">():</span>\n        <span class=\"n\">event</span><span class=\"p\">,</span> <span class=\"n\">values</span> <span class=\"o\">=</span> <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#\"</span><span class=\"p\">,</span> <span class=\"n\">event</span><span class=\"p\">,</span> <span class=\"n\">values</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">event</span> <span class=\"o\">==</span> <span class=\"s\">\"Exit\"</span> <span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">event</span> <span class=\"o\">==</span> <span class=\"s\">\"Convert\"</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># print(values)\n</span>            <span class=\"n\">input_filename</span>  <span class=\"o\">=</span> <span class=\"n\">values</span><span class=\"p\">[</span><span class=\"s\">'-csvfilepath-'</span><span class=\"p\">]</span>\n            <span class=\"n\">output_filename</span> <span class=\"o\">=</span> <span class=\"n\">values</span><span class=\"p\">[</span><span class=\"s\">'-excelfilepath-'</span><span class=\"p\">]</span>\n            <span class=\"n\">convert_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 終了\n</span>    <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n\n\n<span class=\"c1\"># ======================================================\n</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">main</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"未対応項目\">未対応項目</h1>\n<h2 id=\"ドラッグアンドドロップ\">ドラッグアンドドロップ</h2>\n<p>TkEasyGUI は ドラッグアンドドロップに対応していないので、作成したプログラムも未対応。<br />\nissueはあがっていて、作者さんも「It seems we could easily support」と言っているので、近いうちにサポートされるかも。</p>\n<ul>\n  <li><a href=\"https://github.com/kujirahand/tkeasygui-python/issues/7\" target=\"_blank\">Drag & Drop files #7</a></li>\n</ul>\n\n<h2 id=\"テーマの使用\">テーマの使用</h2>\n<p>TkEasyGUI は ttkの使用に対応しているが、使い方によってはうまく動かない。<br />\n(今回は <code class=\"language-plaintext highlighter-rouge\">eg.Column</code> の中の <code class=\"language-plaintext highlighter-rouge\">eg.Button</code> で  <code class=\"language-plaintext highlighter-rouge\">use_ttk_buttons=True</code>を指定したらエラーになった。<br />\nなにか条件があるのかもしれんが。)<br />\nとりあえず「お手軽にGUI」が目的なので、テーマで見た目に凝らなくてもいいか、と対応はあきらめた。</p>\n\n<h1 id=\"まとめ\">まとめ</h1>\n<p>さらっと触っただけだけど、tkinterをそのまま使うよりかなり分かりやすい。<br />\nが、ちょっと凝ったことをやろうとすると、できなかったりすることも。<br />\nその辺は必須かどうか見極めて、あきらめるか、tkinterで泥沼にハマってでも実現するかを決めるしかないか。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tkinter で スクロール可能なcanvasを作る</title>\n  </head>\n  <body>\n    <header>\n      <h1>tkinter で スクロール可能なcanvasを作る</h1>\n      <p>tkinter で スクロール可能なcanvasを作る</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>tkinterでスクロール可能なcanvasのクラス<code class=\"language-plaintext highlighter-rouge\">ScrollableCanvas</code>を作ってみました。<br />\nぶっちゃけ、あちこちにその手の記事はあるのですが、なんか自分のコーディングスタイルとあってないの気がしたので\n微妙に書き換えてみました。</p>\n\n<h1 id=\"サンプルプログラム\">サンプルプログラム</h1>\n\n<p>さっそくサンプルプログラムを貼りつけておきます。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/0ccd48b5cec72ad363d7eaa452972b1f.js\"></script>\n</dev>\n\n<h2 id=\"解説のようなもの\">解説のようなもの</h2>\n\n<h3 id=\"canvas-を継承した-scrollablecanvas-クラス\">canvas を継承した ScrollableCanvas クラス</h3>\n<p>ネット上にある例では、Frameクラスを継承してその下にcanvasを貼り付けているものが多いですが、\nなんとなく余分なウィジェットを作りたくない気分だったのでCanvasクラスを継承するようにしてみました。<br />\nまた、コンストラクタ中でpackしている例が多かったですが、配置の自由度を上げるため上位側に任せるようにしました。</p>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>今回は縦スクロールのみ対応なので、canvasの幅はあらかじめ指定しておくようにしてあります。<br />\nまた、表示するウィジェットを配置するためのフレーム(<code class=\"language-plaintext highlighter-rouge\">child_frame</code>)は幅を自由に設定できるようにすると\n親ウィジェットであるcanvasの幅まで大きくなりますが、これだとスクロールバーが見えなくなります。<br />\nそこで、<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の幅はcanvasの幅からスクロールバーの幅を差し引いたサイズを設定しています。</p>\n\n<blockquote>\n  <p>[!NOTE]\n縦横スクロール可能にした場合は このあたり見直さないといけないかもしれない。</p>\n</blockquote>\n\n<p>また、マウスドラッグによるスクロールをスムーズにするため、スクロール量(<code class=\"language-plaintext highlighter-rouge\">yscrollincrement</code>)のデフォルトを1に設定しています。\nこれはScrollableCanvasクラスのインスタンスを生成する際に変更することができます。</p>\n\n<h3 id=\"ウィンドウイベント\">ウィンドウイベント</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">\"<Configure>\"</code> イベントをbindすることで、ウィンドウが移動されたり、リサイズされたりしたときに実行する処理を割り当てています。<br />\n<code class=\"language-plaintext highlighter-rouge\">\"<Configure>\"</code> イベントはウィンドウのリサイズ等だけでなく、pack()等でFrameのサイズが変更されたときも通知されます。</p>\n\n<p>ここではスクロール範囲の再設定を行っています。</p>\n\n<h3 id=\"マウスイベント\">マウスイベント</h3>\n\n<p>マウスイベントのbindは\n<a href=\"/memoBlog/2024/09/14/tkinter_event_1.html\" target=\"_blank\">tkinter で 低層のウィジェットでイベントを検出する</a>\nの方法を使用しています。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>操作</th>\n      <th>処理</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>左クリック</td>\n      <td>ドラッグ開始位置の設定</td>\n    </tr>\n    <tr>\n      <td>左クリック→マウス移動</td>\n      <td>縦方向の移動量に応じたスクロール</td>\n    </tr>\n    <tr>\n      <td>左ダブルクリック</td>\n      <td>子ウィジェットの追加</td>\n    </tr>\n    <tr>\n      <td>ホイール</td>\n      <td>縦方向スクロール</td>\n    </tr>\n    <tr>\n      <td>右クリック</td>\n      <td>子ウィジェットの全削除</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"実は\">実は…</h3>\n\n<p>右クリックで子ウィジェットを全削除した際、<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の高さは削除前の高さのままになっています。<br />\nつまり、なにもないフレームをスクロールできる状態になっています。<br />\n次に左ダブルクリックでウィジェットを追加したときに1ジェット1個分の高さに変更されます。<br />\nこの仕様が気持ち悪くて色々試したのですが、うまくいきませんでした。<br />\nそこで、「cleard」と表示して<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の高さを変更して誤魔化しています。<br />\n子ウィジェットの差し替えしかしないのであれば特に気にしなくても良い部分だと思います。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tkinter で 低層のウィジェットでイベントを検出する</title>\n  </head>\n  <body>\n    <header>\n      <h1>tkinter で 低層のウィジェットでイベントを検出する</h1>\n      <p>tkinter で 低層のウィジェットでイベントを検出する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>tkinterでイベントを検出する際、対象のウィジェットの手前に別のウィジェットがあるとイベントを検出できません。<br />\nそれを回避し、手前にウィジェットが存在してもイベントが検出できるサンプルプログラムを書いてみました。</p>\n\n<h1 id=\"サンプルプログラム\">サンプルプログラム</h1>\n\n<p>さっそくサンプルプログラムを貼りつけておきます。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/59faf9f974e22d34a8e988954a32518b.js\"></script>\n</dev>\n\n<h2 id=\"解説のようなもの\">解説のようなもの</h2>\n\n<h3 id=\"canvasにバインドしたイベントハンドラ\">canvasにバインドしたイベントハンドラ</h3>\n\n<p>以下の部分が普通にcanvasにマウスクリックイベントをバインドしている部分です。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">test_canvas</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"s\">'<ButtonPress-1>'</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_on_click_canvas</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>canvas上(水色の部分)でクリックすると<code class=\"language-plaintext highlighter-rouge\">_on_click_canvas</code>が実行され、\n<code class=\"language-plaintext highlighter-rouge\">_on_click_canvas : click on canvas</code>と表示されます。<br />\nしかし、その上に配置されたラベル(labex_1x)上でクリックしたときは表示されません。</p>\n\n<p>labelもcanvasの一部なので、ここでもクリック処理が動いてほしいことはよくあると思います。</p>\n\n<h3 id=\"rootにバインドしたイベントハンドラ\">rootにバインドしたイベントハンドラ</h3>\n\n<p>そこで、以下の部分でrootにマウスクリックイベントをバインドします。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">winfo_toplevel</span><span class=\"p\">().</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"s\">'<ButtonPress-1>'</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_on_click</span><span class=\"p\">,</span> <span class=\"s\">\"+\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>これはrootにバインドされたイベントですから、当然canvas以外の部分でも処理が動きます。<br />\nそこで、イベントハンドラでマウス座標を取得し、canvasの範囲内かを確認し、\nそうであればクリック処理(ここでは<code class=\"language-plaintext highlighter-rouge\">_on_click : click on canvas</code>を表示)を実行します。<br />\nパラメータの最後の<code class=\"language-plaintext highlighter-rouge\">\"+\"</code>は、既にバインドされているハンドラがあった時、上書きせずに追加することを指定しています。<br />\n(つまり、以前にバインドしたハンドラと今回のハンドラ両方が実行されます)</p>\n\n<p>こちらの処理はcanvas上(水色の部分)でクリックしたときも\nその上に配置されたラベル(labex_1x)上でクリックしたときもクリック処理が実行されます。</p>\n\n<p>なお、イベントハンドラに渡されるパラメータ<code class=\"language-plaintext highlighter-rouge\">event</code>の<code class=\"language-plaintext highlighter-rouge\">event.x</code>、<code class=\"language-plaintext highlighter-rouge\">event.y</code>はウィジェット内の相対座標なので\n比較には<code class=\"language-plaintext highlighter-rouge\">event.x_root</code>、<code class=\"language-plaintext highlighter-rouge\">event.y_root</code>を使用して画面上の座標を使用します。<br />\n当然比較するcanvasの座標も<code class=\"language-plaintext highlighter-rouge\">widget.winfo_rootx()</code>、<code class=\"language-plaintext highlighter-rouge\">widget.winfo_rooty()</code>で画面上の座標を使用しなければなりません。</p>\n\n<h3 id=\"おまけ\">おまけ</h3>\n\n<p>おまけとして、ダブルクリックした位置に存在するウィジェットの一覧を表示する処理を入れておきました(<code class=\"language-plaintext highlighter-rouge\">_on_doubleclick</code>) 。<br />\nダブルクリックに意味はなく、クリックは既に使っていたのでダブルクリックにしただけです。</p>\n\n<blockquote>\n  <p>おーちゃくせずに別のプログラム書けよ > 自分</p>\n</blockquote>\n\n<h3 id=\"ふと思ったこと\">ふと思ったこと</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">event.widget</code> から 順に <code class=\"language-plaintext highlighter-rouge\">master</code> をたどって行き、対象のウィジェットが見つかるかで判断する方法もあるなぁ…<br />\nrootの <code class=\"language-plaintext highlighter-rouge\">master</code> は <code class=\"language-plaintext highlighter-rouge\">None</code> なのでそこでサーチ終了。<br />\nどっちが簡単かな…</p>\n\n<h3 id=\"ふと思ったこと-その2\">ふと思ったこと その2</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">bind</code>するときに、.winfo_children() を再帰的にサーチしてすべての子ウィジェットにbindしていく、という手もあるなぁ。<br />\nいっぱいウィジェット配置してるとえらいことになるかもしれんけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi で Text To Speech(音声合成)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi で Text To Speech(音声合成)</h1>\n      <p>Raspberry Pi でpythonを使用してText To Speech(音声合成)を試す</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi でText To Speech(音声合成)をofflineで実行することを試してみます。<br />\n(初回実行時は辞書データをダウンロードするのでインターネットにつながっている必要があります)</p>\n\n<blockquote>\n  <p>[!NOTE]\n環境変数 DISPLAY が設定されている場合、変数が示すマシンでXサーバが実行されている必要があります。<br />\n実行されていない場合は、オーディオ再生の際、コマンドがハングアップします、<br />\nその際は対象マシンでXサーバを実行するか、<code class=\"language-plaintext highlighter-rouge\">unset DISPLAY</code>で環境変数を削除してください。</p>\n</blockquote>\n\n<h1 id=\"スピーカの準備\">スピーカの準備</h1>\n<p>Raspberry Pi5ではオーディオジャックがなくなったので、\n将来のことを考えてUSBスピーカ(USBヘッドセット)を使用することにします。</p>\n\n<h2 id=\"スピーカの接続\">スピーカの接続</h2>\n\n<p>まず、USBスピーカをUSBポートに接続し、スピーカが認識されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>lsusb\nBus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub\nBus 001 Device 003: ID 0c76:161f JMTek, LLC. USB PnP Audio Device   ← これ\nBus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub\nBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub\n</code></pre></div></div>\n\n<h2 id=\"カード番号とデバイス番号の確認\">カード番号とデバイス番号の確認</h2>\n<p>使用するカード番号/デバイス番号を確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay <span class=\"nt\">-l</span>\n<span class=\"k\">****</span> ハードウェアデバイス PLAYBACK のリスト <span class=\"k\">****</span>\nカード 0: vc4hdmi0 <span class=\"o\">[</span>vc4-hdmi-0], デバイス 0: MAI PCM i2s-hifi-0 <span class=\"o\">[</span>MAI PCM i2s-hifi-0]\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\nカード 1: vc4hdmi1 <span class=\"o\">[</span>vc4-hdmi-1], デバイス 0: MAI PCM i2s-hifi-0 <span class=\"o\">[</span>MAI PCM i2s-hifi-0]\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\nカード 2: Headphones <span class=\"o\">[</span>bcm2835 Headphones], デバイス 0: bcm2835 Headphones <span class=\"o\">[</span>bcm2835 Headphones]\n  サブデバイス: 8/8\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\n  サブデバイス <span class=\"c\">#1: subdevice #1</span>\n  サブデバイス <span class=\"c\">#2: subdevice #2</span>\n  サブデバイス <span class=\"c\">#3: subdevice #3</span>\n  サブデバイス <span class=\"c\">#4: subdevice #4</span>\n  サブデバイス <span class=\"c\">#5: subdevice #5</span>\n  サブデバイス <span class=\"c\">#6: subdevice #6</span>\n  サブデバイス <span class=\"c\">#7: subdevice #7</span>\nカード 3: Device <span class=\"o\">[</span>USB PnP Audio Device], デバイス 0: USB Audio <span class=\"o\">[</span>USB Audio]         ← これ\n  サブデバイス: 1/1\n  サブデバイス <span class=\"c\">#0: subdevice #0</span>\n</code></pre></div></div>\n\n<p>カード番号が 3 または ‘Device’、デバイス番号が0であることが分かります</p>\n\n<h2 id=\"テスト再生\">テスト再生</h2>\n<p>テスト再生してみます。<br />\n-D オプションのパラメータは、<code class=\"language-plaintext highlighter-rouge\">plughw:</code>に続けて上で調べたカード番号、<code class=\"language-plaintext highlighter-rouge\">,</code>を挟んでデバイス番号を指定します。<br />\nwavファイルは何でもかまいません。下記はデフォルトでインストール済みのファイルなのでそれを使いました。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay <span class=\"nt\">-D</span> plughw:Device,0 /usr/share/sounds/alsa/Front_Center.wav\n再生中 WAVE <span class=\"s1\">'/usr/share/sounds/alsa/Front_Center.wav'</span> : Signed 16 bit Little Endian, レート 48000 Hz, モノラル\n</code></pre></div></div>\n\n<h2 id=\"デフォルトのオーディオデバイスの設定\">デフォルトのオーディオデバイスの設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">sudo raspi-config</code> を実行し、以下の順で選択します。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">1 System Options</code>\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">S2 Audio</code>\n        <ul>\n          <li>使用するオーディオデバイス( <code class=\"language-plaintext highlighter-rouge\">71 USB PnP Audio Device</code>など )</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">Finish</code>で終了</li>\n</ul>\n\n<p>デフォルト設定が変更されたことを確認するため、上記テスト再生のコマンドから-Dオプションを削除して再生されることを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>aplay /usr/share/sounds/alsa/Front_Center.wav\n再生中 WAVE <span class=\"s1\">'/usr/share/sounds/alsa/Front_Center.wav'</span> : Signed 16 bit Little Endian, レート 48000 Hz, モノラル\n</code></pre></div></div>\n\n<h1 id=\"python仮想環境の作成とモジュールのインストール\">python仮想環境の作成とモジュールのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openjtalk\n<span class=\"nb\">cd</span> /work/openjtalk\n\npyenv virtualenv 3.11.9 openjtalk\npyenv <span class=\"nb\">local </span>openjtalk \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># pyopenjtalkのインストールに必要なのでcmakeをインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n\n<span class=\"c\"># pyopenjtalkのインストールbuildが実行されるので時間がかかる</span>\npip <span class=\"nb\">install </span>pyopenjtalk\n\n<span class=\"c\"># wavファイルの保存に使用するのでscipyもインストール</span>\npip <span class=\"nb\">install </span>scipy\n\n<span class=\"c\"># marineを使う場合は以下も実行</span>\npip <span class=\"nb\">install </span>pyopenjtalk[marine]\n</code></pre></div></div>\n\n<h1 id=\"pyopenjtalk-を実行してみる\">pyopenjtalk を実行してみる</h1>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  talk_test1.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">pyopenjtalk</span>\n<span class=\"kn\">from</span> <span class=\"nn\">scipy.io</span> <span class=\"kn\">import</span> <span class=\"n\">wavfile</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"c1\"># marineを使用する場合はrun_marineをTrueにする\n</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">sr</span> <span class=\"o\">=</span> <span class=\"n\">pyopenjtalk</span><span class=\"p\">.</span><span class=\"n\">tts</span><span class=\"p\">(</span><span class=\"s\">\"おめでとうございます\"</span><span class=\"p\">,</span> <span class=\"n\">run_marine</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n<span class=\"n\">wavfile</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">\"test1.wav\"</span><span class=\"p\">,</span> <span class=\"n\">sr</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">int16</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python talk_test1.py\n</code></pre></div></div>\n\n<p>再生します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>aplay test1.wav\n</code></pre></div></div>\n\n<p>スピーカーから「おめでとうございます」と聞こえたら成功です。おめでとうございます。</p>\n\n<h1 id=\"pythonからオーディオ再生する\">pythonからオーディオ再生する</h1>\n\n<p>オーディオ再生のためのモジュールは色々ありますが、\n下の直接再生に使用するにはnumpyデータを入力できることが必須となるので\nsimpleaudioを使用してみます。</p>\n\n<p>モジュールをインストールします。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># simpleaudioのインストールに必要なパッケージのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libasound2-dev\n\n<span class=\"c\"># インストール</span>\npip <span class=\"nb\">install </span>simpleaudio\n</code></pre></div></div>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  play_test1.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">simpleaudio</span>\n\n<span class=\"n\">wav_obj</span> <span class=\"o\">=</span> <span class=\"n\">simpleaudio</span><span class=\"p\">.</span><span class=\"n\">WaveObject</span><span class=\"p\">.</span><span class=\"n\">from_wave_file</span><span class=\"p\">(</span><span class=\"s\">\"test1.wav\"</span><span class=\"p\">)</span>\n<span class=\"n\">play_obj</span> <span class=\"o\">=</span> <span class=\"n\">wav_obj</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n<span class=\"n\">play_obj</span><span class=\"p\">.</span><span class=\"n\">wait_done</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python play_test1.py\n</code></pre></div></div>\n<h1 id=\"pyopenjtalkで作成した音声を直接再生する\">pyopenjtalkで作成した音声を直接再生する</h1>\n\n<p>逐一wavファイルを作成するのは面倒なので、合成したらすぐ再生するようにしてみます。</p>\n\n<p>以下のプログラムを作成します。</p>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  talk_test2.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">pyopenjtalk</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">simpleaudio</span>\n\n<span class=\"c1\"># marineを使用する場合はrun_marineをTrueにする\n</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">sr</span> <span class=\"o\">=</span> <span class=\"n\">pyopenjtalk</span><span class=\"p\">.</span><span class=\"n\">tts</span><span class=\"p\">(</span><span class=\"s\">\"直接再生します\"</span><span class=\"p\">,</span> <span class=\"n\">run_marine</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n<span class=\"c1\"># x : waveform\n# sr: sampling rate\n</span>\n<span class=\"n\">wav_obj</span> <span class=\"o\">=</span> <span class=\"n\">simpleaudio</span><span class=\"p\">.</span><span class=\"n\">WaveObject</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">int16</span><span class=\"p\">),</span> <span class=\"n\">num_channels</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">bytes_per_sample</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">sample_rate</span><span class=\"o\">=</span><span class=\"n\">sr</span><span class=\"p\">)</span>\n<span class=\"n\">play_obj</span> <span class=\"o\">=</span> <span class=\"n\">wav_obj</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n<span class=\"n\">play_obj</span><span class=\"p\">.</span><span class=\"n\">wait_done</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python talk_test2.py\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>キーボードコマンダーのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>キーボードコマンダーのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用キーボードコマンダーのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/18/key_commander_1.html\" target=\"_blank\">キーボードコマンダーのひな型(C言語版)</a>\nのpython版も作/memoBlog定して使うだけなんだけど、<br />\nstdinの設定を元に戻すのを忘れないように、クラス化してデストラクタで設定を戻すようにしてみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれまでatexitモジュール使って終了処理ルーチン登録して<br />\nそこで元に戻してたけど、処理追加忘れて悲しいことになったことが数知れず…</p>\n</blockquote>\n\n<h1 id=\"ちょっと解説\">ちょっと解説</h1>\n<p>このクラスは、複数の箇所からインスタンスを作成してしまうとstdinの設定変更が複数箇所で行われてしまい、<br />\nデストラクタの実行順序によっては正常に元に戻せなくなる可能性がある。<br />\nそれを回避するため、Singletonパターンを適用し、インスタンスが一つだけ保持するようにした。</p>\n\n<p>しかし、これだけでは不十分で、コンストラクタ(<code class=\"language-plaintext highlighter-rouge\">__init__()</code>)が<code class=\"language-plaintext highlighter-rouge\">KeyReader()</code>実行の度に実行されてしまう。(下のNOTE参照) <br />\nそこで、インスタンス変数にコンストラクタ実行済みフラグ(<code class=\"language-plaintext highlighter-rouge\">_inited</code>)を用意し、\nこれが存在しないときのみコンストラクタ処理を実行するようにしている。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">__new__</code>、<code class=\"language-plaintext highlighter-rouge\">__init__</code>、<code class=\"language-plaintext highlighter-rouge\">__del__</code>の実行タイミングは以下のプログラムで確認できる。</p>\n\n  <pre><code class=\"language-pythn\">class Hoge:\n    def __new__(cls, *args, **kargs):\n        print(\"__new__\")\n        if not hasattr(cls, \"_instance\"):\n            print(\"create\")\n            cls._instance = super().__new__(cls)\n        return cls._instance\n    \n    # コンストラクタ\n    def __init__(self):\n        print(\"__init__\")\n        if not hasattr(self, \"_inited\"):\n            print(\"init\")\n            self._inited = True\n    \n    # デストラクタ\n    def __del__(self):\n        print(\"__del__\")\n    \n    def __call__(self):\n        print(\"__call__\")\n\ndef func2() :\n    h2 = Hoge()\n    print(\"h2 before\")\n    h2()\n    print(\"h2 after\")\n\ndef func1() :\n    h1 = Hoge()\n    print(\"h1 before\")\n    h1()\n    print(\"h1 after\")\n\nprint(\"func1 before\")\nfunc1()\nprint(\"func1 after\")\n\nprint(\"func2 before\")\nfunc2()\nprint(\"func2 after\")\n\nprint(\"end\")\n\n</code></pre>\n  <p>実行結果は以下。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>func1 before\n__new__\ncreate                  ← 1回だけ表示されている\n__init__\ninit                    ← 1回だけ表示されている\nh1 before\n__call__\nh1 after\nfunc1 after\nfunc2 before\n__new__\n__init__\nh2 before\n__call__\nh2 after\nfunc2 after\nend\n__del__\n</code></pre></div>  </div>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">Hoge()</code>が実行されると、<code class=\"language-plaintext highlighter-rouge\">__new__()</code>が実行されるが、\n2回目以降は新たにインスタンスを作成せずクラス変数<code class=\"language-plaintext highlighter-rouge\">_instance</code>に格納されたインスタンスを返す。<br />\n(2回目は「create」が表示されていない)</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__init__()</code>が<code class=\"language-plaintext highlighter-rouge\">Hoge()</code>実行の度に実行されているのが分かる。<br />\n(つまりインスタンス生成時に実行されるわけではない)<br />\n<code class=\"language-plaintext highlighter-rouge\">__init__()</code>内でインスタンス変数<code class=\"language-plaintext highlighter-rouge\">_inited</code>の存在をチェックしているので<br />\n「init」は1回しか表示されていないのが分かる。</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__del__()</code> はインスタンス破棄時に実行されるので、1回しか実行されない。</p>\n\n</blockquote>\n\n<p>その他のプログラムの動作についてはソース読んでちょ。<br />\nって、ほとんど何もしてないけど。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>test shellのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>test shellのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用コマンド入力処理のサンプルのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/15/test_shell_1.html\" target=\"_blank\">test shellのひな型</a>\nでC言語版を作ったので、python版も作っておこうかと作ってみた。</p>\n\n<p>pythonには『行指向のコマンドインタープリタのサポート』というcmdモジュールが標準で用意されている。<br />\nこれを使用すれば、そんなに手間もかからず実装できる。<br />\n補完処理やヘルプ表示も簡単。<br />\nコマンドの大文字/小文字同一視はできなかったけど…</p>\n\n<p>コマンド補完だけでなく、パラメータ補完も可能。<br />\nもちろん、補完のための処理は書かないといけないけど。</p>\n\n<p>標準モジュールしか使ってないので、モジュールをインストールする必要なし。</p>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n大体コメントに書いたつもり。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Pythonのasyncioでnon-blockingなコンソール入力</title>\n  </head>\n  <body>\n    <header>\n      <h1>Pythonのasyncioでnon-blockingなコンソール入力</h1>\n      <p>Pythonのasyncioでnon-blockingなコンソール入力を行うためのクラス</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでasyncioを使ったときにnon-blockingなコンソール入力(キーボード入力)ができなくて困ったので、実現するためのクラスを作ってみた。</p>\n\n<p>もともと Linux用に作ったら、Windowsだとうまく動かない。<br />\nちょっと汚い方法だけど、とりあえず動くようにしてお茶を濁しておく。<br />\n(あんまりテストしてないから動かなかったらごめん)</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/5033eec9b9b774ede4f87604a51fb162.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>お試しならこのソースをそのまま実行すると実行できます。<br />\n<code class=\"language-plaintext highlighter-rouge\">char_mode = False</code> の部分を変更すると、1行入力モードと1文字入力モードを切り替えられます。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout_mode = True</code> の部分を変更すると、タイムアウトなしとタイムアウトありを切り替えられます。</p>\n\n<p>実際に使用するには、このソースをimportして使ってください。</p>\n\n<h1 id=\"注意\">注意</h1>\n\n<p>Linuxで1文字入力モードを使っている場合は、終了時(例外で死んだ場合も含めて)<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行しないと悲しいことになります。<br />\n(ターミナルの入力モードが変更されてしまうので、うまく入力できなくなる)<br />\nそのために、<code class=\"language-plaintext highlighter-rouge\">atexit.retister()</code>で終了処理ルーチンを登録し、その中で<code class=\"language-plaintext highlighter-rouge\">prompt.terminate()</code>を実行するようにしています。</p>\n\n<h1 id=\"ひとりごと\">ひとりごと</h1>\n\n<p>asyncioのサンプルって、タスク1個で動かしてることが多いからあんまり ありがたみが分からんのかな…<br />\nあと、タスクとコルーチンが同じように語られていて分かり難いのもあると思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi で python で PWM</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi で python で PWM</h1>\n      <p>Raspberry Pi 上で python で PWMの制御を行うブログラムの雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Piでロボットアームを制御するのに、PWMのテストを行ったときのプログラムソースを貼っておく。<br />\n使ったロボットアーム: <a href=\"https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1\" target=\"_blank\">https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1</a></p>\n\n<p>ソフトウェアPWMだと他の処理の負荷によってジッタが発生し、ガタガタいうのでこの使い方はあまり実用的ではない。<br />\nハードウェアPWMを使う(pigpio か wiringpi が必要)、PWM制御を担うMCUを用意してコマンド通信(TCP/IPやBluetoothなど経由)で制御するのが現実的かも。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>PRi.GPIOを使うので、インストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>RPi.GPIO\n</code></pre></div></div>\n\n<p>プログラムの設定にあわせてGPIOとサーボモータを接続しておく(または接続に合わせてプログラム修正)。<br />\nスイッチで調整できるようにしてあるけど、キーボードから調整できるのでスイッチの接続は必須ではない。</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/0e8eeedb37d59c85b6ae6085da2a2cb4.js\"></script>\n</dev>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">GPIO.add_event_detect()</code>には<code class=\"language-plaintext highlighter-rouge\">bouncetime=«チャタリング除去時間(msec)»</code>を追加しておくのが良いかも。<br />\n参考: <a href=\"https://tomosoft.jp/design/?p=8685\" target=\"_blank\">GPIOエッジ検出コールバック関数 | TomoSoft</a></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n公式マニュアルは存在しないらしい。<br />\n唯一以下のページがそれっぽい情報を掲載している。<br />\n<a href=\"https://sourceforge.net/p/raspberry-gpio-python/wiki/Examples/\" target=\"_blank\">raspberry-gpio-python / Wiki / Examples</a><br />\nあとはソース読むしかないんだけど、python - C インタフェースを理解してないと苦しい…<br />\nソース全体を<code class=\"language-plaintext highlighter-rouge\">python function</code>で検索すると出てくるけど全部じゃない…<br />\nソースはここ: <a href=\"https://pypi.org/project/RPi.GPIO/#files\" target=\"_blank\">RPi.GPIO · PyPI</a></p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>プログラム実行して、スイッチかキーボードで出力値変えてみる。<br />\n設定値の範囲は個体差があるので、適当に変更必要。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MediaPipeの手の認識でお絵かき</title>\n  </head>\n  <body>\n    <header>\n      <h1>MediaPipeの手の認識でお絵かき</h1>\n      <p>MediaPipe Handsでの手の認識結果と使ってお絵かきしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>MediaPipeで手の認識</p>\n\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』の手の認識子処理を使って空間にお絵かきしてみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』を参照。</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<h2 id=\"共通ルーチン\">共通ルーチン</h2>\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』を参照。</p>\n\n<h2 id=\"お絵かきプログラム\">お絵かきプログラム</h2>\n\n<p>お絵かきプログラム本体。<br />\n人差し指先端に点を打っていくことでお絵かきしている。<br />\n人差し指だけ立てた状態(ジェスチャ ONE)だと赤、人差し指と中指を立てた状態(ジェスチャ PEACE)だと緑で描画するようにしてあるが、この組み合わせにあまり意味はない。なんとなく色を切り替えてみたかったので。<br />\nコマンドラインオプションと表示中操作についてはソース見てちょ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  oekaki.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n<span class=\"n\">HandLandmark</span> <span class=\"o\">=</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span>  <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span>         <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n<span class=\"c1\">#     parser.add_argument(\"-nh\", \"--num_hand\",         default=2,   type=int,     help=\"(optional) Max number of hands\")\n</span>    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n# max_num_hands            = args.num_hand            # 検出する手の個数\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"mi\">1</span>                        <span class=\"c1\"># 検出する手の個数 今回は1固定\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">verbose2</span>                 <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>\n\n<span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">True</span>                    <span class=\"c1\"># 鏡像使用\n</span><span class=\"n\">fg_only</span>                  <span class=\"o\">=</span> <span class=\"bp\">False</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"n\">COLOR_WHITE</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_BLUE</span>  <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_GREEN</span> <span class=\"o\">=</span> <span class=\"p\">(</span>  <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_RED</span>   <span class=\"o\">=</span> <span class=\"p\">(</span>  <span class=\"mi\">0</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># カメラ\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像サイズ\n</span><span class=\"n\">image_width</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n<span class=\"n\">image_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n<span class=\"n\">fps</span>          <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'image size : </span><span class=\"si\">{</span><span class=\"n\">image_width</span><span class=\"si\">}</span><span class=\"s\"> x </span><span class=\"si\">{</span><span class=\"n\">image_height</span><span class=\"si\">}</span><span class=\"s\"> @ </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">Hz'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前景イメージを作成\n</span><span class=\"n\">image_fg</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">full</span><span class=\"p\">((</span><span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span>   <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">,</span>            <span class=\"c1\"># 動画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>        <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 前のフレーム処理完了時刻を初期化\n</span>    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># キャプチャ\n</span>        <span class=\"n\">success</span><span class=\"p\">,</span> <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">success</span><span class=\"p\">:</span>\n            <span class=\"c1\"># エラーになったら再度キャプチャ\n</span>            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Ignoring empty camera frame.\"</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>        <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n            <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        \n        <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>        <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>        <span class=\"c1\"># 検出できたか?\n</span>            <span class=\"c1\"># ポーズの認識\n</span>            <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 人差し指先の位置\n</span>            <span class=\"n\">finger_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n            <span class=\"n\">finger_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'(</span><span class=\"si\">{</span><span class=\"n\">finger_x</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">finger_y</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">)  </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ポーズによって色を変更\n</span>            <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"o\">==</span> <span class=\"s\">'ONE'</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"n\">COLOR_RED</span>           <span class=\"c1\"># 赤\n</span>            <span class=\"k\">elif</span> <span class=\"n\">gesture</span> <span class=\"o\">==</span> <span class=\"s\">'PEACE'</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"n\">COLOR_GREEN</span>         <span class=\"c1\"># 緑\n</span>            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n            <span class=\"k\">if</span> <span class=\"n\">color</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># 前景イメージに点を打つ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">circle</span><span class=\"p\">(</span><span class=\"n\">image_fg</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">finger_x</span><span class=\"p\">,</span> <span class=\"n\">finger_y</span><span class=\"p\">)</span> <span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span><span class=\"o\">=-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># フレーム処理時間\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 現在のフレーム処理完了時刻\n</span>        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>                   <span class=\"c1\"># このフレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        \n        <span class=\"c1\"># FPS表示\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                <span class=\"sa\">f</span><span class=\"s\">'FPS:</span><span class=\"si\">{</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>  <span class=\"c1\"># 文字列\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">50</span><span class=\"p\">),</span>                    <span class=\"c1\"># 座標\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                <span class=\"n\">COLOR_RED</span><span class=\"p\">,</span>                  <span class=\"c1\"># 色\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>            <span class=\"p\">)</span>\n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"n\">fg_only</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 前景イメージだけ表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image_fg</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 画像を重ね合わせ(COLOR_WHITEを透過色として指定)て表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">where</span><span class=\"p\">(</span><span class=\"n\">image_fg</span> <span class=\"o\">==</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">image_fg</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># 表示終了待ち\n</span>        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'c'</span><span class=\"p\">):</span>\n            <span class=\"c1\"># 前景イメージを初期化\n</span>            <span class=\"n\">image_fg</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">full</span><span class=\"p\">((</span><span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'d'</span><span class=\"p\">):</span>\n            <span class=\"n\">fg_only</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">fg_only</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'v'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'b'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose2</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose2</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'p'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imwrite</span><span class=\"p\">(</span>\n                    <span class=\"sa\">f</span><span class=\"s\">'z_oekaki_</span><span class=\"si\">{</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">now</span><span class=\"p\">().</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s\">\"%d_%H%M%S\"</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">.jpg'</span><span class=\"p\">,</span> \n                    <span class=\"n\">image_fg</span>\n                <span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"c1\"># ウィンドウをすべて閉じる\n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># カメラリリース\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: oekaki.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD]\n                 <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h1 id=\"感想\">感想</h1>\n\n<p>それなりにお絵かきできるけど…</p>\n<ul>\n  <li>認識処理が遅いと手をゆっくり動かさないと線にならない</li>\n  <li>ポーズの認識の精度がイマイチで描画結果が微妙な感じになる</li>\n</ul>\n\n<p>実際にユーザインタフェースとして使うには色々と工夫が必要かな。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MediaPipeで手の認識</title>\n  </head>\n  <body>\n    <header>\n      <h1>MediaPipeで手の認識</h1>\n      <p>MediaPipe Handsで手の認識処理をやってみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>MediaPipe Handsを使って手の認識処理を行ってみる。<br />\nMediaPipeを使用するとかなり簡単に手の特徴点を取得できる。<br />\nまた、各特徴点の位置がわかるので、それらの位置関係からポーズを取得することもできる。</p>\n\n<p>参考: <a href=\"https://google.github.io/mediapipe/solutions/hands.html\" target=\"_blank\">https://google.github.io/mediapipe/solutions/hands.html</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/mediapipe\n<span class=\"nb\">cd</span> /work/ble/mediapipe\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 mediapipe\npyenv <span class=\"nb\">local </span>mediapipe\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>mediapipe\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<h2 id=\"共通ルーチン\">共通ルーチン</h2>\n\n<p>各指の関節と指先の位置関係から指が伸びているのか、曲がっているのかを判別し(親指だけは各関節の角度から判別)、<br />\nその組み合わせからどのようなポーズなのかを判別している。<br />\nアルゴリズムは <a href=\"https://github.com/geaxgx/openvino_hand_tracker\">https://github.com/geaxgx/openvino_hand_tracker</a> から拝借した。<br />\n元のプログラムは各関節の位置を検出された手の画像を回転して角度調整した画像のY座標から取得しているが、<br />\n今回は手の角度が分からないので、手首から各関節位置までの距離を比較するように変更した。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  hand_gesture.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">HandLandmark</span> <span class=\"o\">=</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">distance</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">):</span>\n    <span class=\"c1\"># a, b: 2 points in 3D (x,y,z)\n</span>    <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">a</span> <span class=\"o\">-</span> <span class=\"n\">b</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">angle</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">,</span> <span class=\"n\">c</span><span class=\"p\">):</span>\n    <span class=\"c1\"># a, b and c : points as np.array([x, y, z]) \n</span>    <span class=\"n\">ba</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">-</span> <span class=\"n\">b</span>\n    <span class=\"n\">bc</span> <span class=\"o\">=</span> <span class=\"n\">c</span> <span class=\"o\">-</span> <span class=\"n\">b</span>\n    <span class=\"n\">cosine_angle</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">dot</span><span class=\"p\">(</span><span class=\"n\">ba</span><span class=\"p\">,</span> <span class=\"n\">bc</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">ba</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">bc</span><span class=\"p\">))</span>\n    <span class=\"n\">angle</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arccos</span><span class=\"p\">(</span><span class=\"n\">cosine_angle</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">degrees</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ジェスチャの認識\n# 参考: https://github.com/geaxgx/openvino_hand_tracker\n</span><span class=\"k\">def</span> <span class=\"nf\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">debug</span> <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">):</span>\n    <span class=\"c1\"># 各landmarkの手首からの距離を求める\n</span>    <span class=\"n\">lm_pos</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([[</span><span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">z</span><span class=\"p\">]</span> <span class=\"k\">for</span> <span class=\"n\">lm</span> <span class=\"ow\">in</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">])</span>    <span class=\"c1\"># 計算のためndarray化\n</span>    <span class=\"c1\"># lm_pos = np.array([[lm.x, lm.y] for lm in landmarks.landmark])          # 計算のためndarray化(zは無視)\n</span>    <span class=\"n\">r_</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span> <span class=\"o\">-</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">WRIST</span><span class=\"p\">],</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>        <span class=\"c1\"># numpyなので一括計算\n</span>    \n    <span class=\"c1\"># 親指の角度で状態判別\n</span>    <span class=\"n\">distance0</span> <span class=\"o\">=</span> <span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">],</span>     <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指の第二関節と人差し指の付け根の距離\n</span>    <span class=\"n\">distance1</span> <span class=\"o\">=</span> <span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span>    <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">]</span>        <span class=\"p\">)</span>     <span class=\"c1\"># 親指の付け根と親指の第二関節の距離\n</span>    <span class=\"n\">angle0</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">WRIST</span><span class=\"p\">],</span>      <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_CMC</span><span class=\"p\">],</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指付け根の角度\n</span>    <span class=\"n\">angle1</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_CMC</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">]</span> <span class=\"p\">)</span>     <span class=\"c1\"># 親指第二関節の角度\n</span>    <span class=\"n\">angle2</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_TIP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指第一関節の角度\n</span>    <span class=\"n\">thumb_angle</span> <span class=\"o\">=</span> <span class=\"n\">angle0</span> <span class=\"o\">+</span> <span class=\"n\">angle1</span> <span class=\"o\">+</span> <span class=\"n\">angle2</span>\n    <span class=\"k\">if</span> <span class=\"n\">thumb_angle</span> <span class=\"o\">></span> <span class=\"mi\">460</span> <span class=\"ow\">and</span> <span class=\"n\">distance0</span> <span class=\"o\">/</span> <span class=\"n\">distance1</span> <span class=\"o\">></span> <span class=\"mf\">1.2</span><span class=\"p\">:</span> \n        <span class=\"n\">thumb_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">thumb_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># 人差し指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 中指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 薬指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 小指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># Gesture\n</span>    <span class=\"k\">if</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FIST\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"OK\"</span> \n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"PEACE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"ONE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"TWO\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"THREE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>      <span class=\"c1\"># 日本型の3\n</span>        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"THREE_J\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FOUR\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FIVE\"</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># for debug\n</span>    <span class=\"c1\"># print(f'{r_[HandLandmark.INDEX_FINGER_MCP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_PIP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_DIP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_TIP]:6.3f}    {index_state}')\n</span>\n    <span class=\"k\">if</span> <span class=\"n\">debug</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">21</span><span class=\"p\">):</span>\n            <span class=\"n\">lm_x</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"c1\"># * image_width\n</span>            <span class=\"n\">lm_y</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"c1\"># * image_height\n</span>            <span class=\"n\">lm_z</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">z</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">HandLandmark</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">))</span><span class=\"si\">:</span><span class=\"mi\">32</span><span class=\"n\">s</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">:</span><span class=\"mi\">2</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">):   </span><span class=\"si\">{</span><span class=\"n\">lm_x</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">lm_y</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">lm_z</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">:</span><span class=\"mf\">6.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">gesture</span>\n</code></pre></div></div>\n\n<h2 id=\"カメラ画像から認識\">カメラ画像から認識</h2>\n<p>カメラ画像から認識してみる。<br />\nこっちの方が用途は多いかな。<br />\nコマンドラインオプションについてはソース見てちょ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  test_camera.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span>  <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span>         <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-nh\"</span><span class=\"p\">,</span> <span class=\"s\">\"--num_hand\"</span><span class=\"p\">,</span>         <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span>   <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Max number of hands\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num_hand</span>            <span class=\"c1\"># 検出する手の個数\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">verbose2</span>                 <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>\n<span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">True</span>                    <span class=\"c1\"># 鏡像使用\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># カメラ\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span>   <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">,</span>            <span class=\"c1\"># 動画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>        <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 前のフレーム処理完了時刻を初期化\n</span>    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># キャプチャ\n</span>        <span class=\"n\">success</span><span class=\"p\">,</span> <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">success</span><span class=\"p\">:</span>\n            <span class=\"c1\"># エラーになったら再度キャプチャ\n</span>            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Ignoring empty camera frame.\"</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>        <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n            <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像サイズ\n</span>        <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n        \n        <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>        <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># 検出結果の処理\n</span>        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">handedness</span> <span class=\"ow\">in</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_handedness</span><span class=\"p\">):</span>\n                <span class=\"k\">if</span> <span class=\"n\">verbose</span> <span class=\"ow\">or</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'--------------------------------------------------------------------------'</span><span class=\"p\">)</span>\n                \n                <span class=\"c1\"># データは鏡像として判別されているので、鏡像でなければラベルを入れ替え\n</span>                <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span> <span class=\"o\">==</span> <span class=\"s\">\"Left\"</span> <span class=\"p\">:</span>\n                        <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Right\"</span>\n                    <span class=\"k\">else</span> <span class=\"p\">:</span>\n                        <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Left\"</span>\n                \n                <span class=\"c1\"># ジェスチャの認識\n</span>                <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n                \n                <span class=\"k\">if</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'==== sore ======================='</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">index</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'score   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">score</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'label   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>            <span class=\"c1\"># あんまりあてにならないな...\n</span>                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'gesture : </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'================================='</span><span class=\"p\">)</span>\n                \n                <span class=\"c1\"># landmarkの描画\n</span>                <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">draw_landmarks</span><span class=\"p\">(</span>\n                    <span class=\"n\">image</span><span class=\"p\">,</span>                              <span class=\"c1\"># 画像\n</span>                    <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span>                     <span class=\"c1\"># ランドマーク\n</span>                    <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span>          <span class=\"c1\"># ランドマーク接続リスト\n</span>                    <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_landmarks_style</span><span class=\"p\">(),</span>       <span class=\"c1\"># ランドマーク描画スタイル\n</span>                    <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_connections_style</span><span class=\"p\">()</span>      <span class=\"c1\"># 接続描画スタイル\n</span>                <span class=\"p\">)</span>\n                <span class=\"c1\"># ジェスチャ表示\n</span>                <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># 人差し指の付け根あたりに表示\n</span>                    <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n                    <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                        <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                        <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>     <span class=\"c1\"># 文字列\n</span>                        <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">),</span>                     <span class=\"c1\"># 座標\n</span>                        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                        <span class=\"mi\">1</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                        <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                        <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>                    <span class=\"p\">)</span>\n        \n        <span class=\"c1\"># フレーム処理時間\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 現在のフレーム処理完了時刻\n</span>        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>                   <span class=\"c1\"># このフレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        \n        <span class=\"c1\"># FPS表示\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                <span class=\"sa\">f</span><span class=\"s\">'FPS:</span><span class=\"si\">{</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>  <span class=\"c1\"># 文字列\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">50</span><span class=\"p\">),</span>                    <span class=\"c1\"># 座標\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>            <span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示終了待ち\n</span>        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'v'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'b'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose2</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose2</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"c1\"># ウィンドウをすべて閉じる\n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># カメラリリース\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"静止画像から認識\">静止画像から認識</h2>\n\n<p>デバッグ用途など、静止画から認識する場合はこちら。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  test_photo.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'input'</span><span class=\"p\">,</span> <span class=\"n\">metavar</span><span class=\"o\">=</span><span class=\"s\">\"INPUT_FILE\"</span><span class=\"p\">,</span>                          <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Path to the input picture \"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                 <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--world'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                         <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp world landmark map\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-nh\"</span><span class=\"p\">,</span> <span class=\"s\">\"--num_hand\"</span><span class=\"p\">,</span>         <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span>   <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Max number of hands\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># 入力ファイル名\n</span><span class=\"nb\">file</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num_hand</span>            <span class=\"c1\"># 検出する手の個数\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">False</span>                    <span class=\"c1\"># 鏡像使用しない\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span> <span class=\"o\">=</span> <span class=\"bp\">True</span><span class=\"p\">,</span>               <span class=\"c1\"># 静止画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>                    <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"c1\"># 画像読み込み\n</span>    <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'file name : </span><span class=\"si\">{</span><span class=\"nb\">file</span><span class=\"si\">}</span><span class=\"s\">   image size : </span><span class=\"si\">{</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>    <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n        <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    \n    <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>    <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># 検出結果の処理\n</span>    <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">handedness</span> <span class=\"ow\">in</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_handedness</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">verbose</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'--------------------------------------------------------------------------'</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># データは鏡像として判別されているので、鏡像でなければラベルを入れ替え\n</span>            <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n                <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span> <span class=\"o\">==</span> <span class=\"s\">\"Left\"</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Right\"</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Left\"</span>\n            \n            <span class=\"c1\"># ジェスチャの認識\n</span>            <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n            \n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'==== sore ======================='</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">index</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'score   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">score</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'label   : </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'gesture : </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'================================='</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># landmarkの描画\n</span>            <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">draw_landmarks</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                              <span class=\"c1\"># 画像\n</span>                <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span>                     <span class=\"c1\"># ランドマーク\n</span>                <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span>          <span class=\"c1\"># ランドマーク接続リスト\n</span>                <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_landmarks_style</span><span class=\"p\">(),</span>       <span class=\"c1\"># ランドマーク描画スタイル\n</span>                <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_connections_style</span><span class=\"p\">()</span>      <span class=\"c1\"># 接続描画スタイル\n</span>            <span class=\"p\">)</span>\n            <span class=\"c1\"># ジェスチャ表示\n</span>            <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># 人差し指の付け根あたりに表示\n</span>                <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n                <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                    <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                    <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>     <span class=\"c1\"># 文字列\n</span>                    <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">),</span>                     <span class=\"c1\"># 座標\n</span>                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                    <span class=\"mi\">1</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                    <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                    <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>                <span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"** NO HANDS **\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 表示終了待ち\n</span>    <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'p'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imwrite</span><span class=\"p\">(</span>\n                    <span class=\"s\">'output_'</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">),</span> \n                    <span class=\"n\">image</span>\n                <span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"ow\">not</span> <span class=\"n\">k</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n          <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># ウィンドウをすべて閉じる\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">world</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># hand world landmarks の 3D座標の表示\n</span>        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_world_landmarks</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">hand_world_landmarks</span> <span class=\"ow\">in</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_world_landmarks</span><span class=\"p\">:</span>\n                <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">plot_landmarks</span><span class=\"p\">(</span>\n                                <span class=\"n\">hand_world_landmarks</span><span class=\"p\">,</span> \n                                <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span> \n                                <span class=\"n\">azimuth</span><span class=\"o\">=</span><span class=\"mi\">5</span>\n                            <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<h2 id=\"カメラ画像から認識-1\">カメラ画像から認識</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: test_camera.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-nh</span> NUM_HAND]\n                      <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">-nh</span> NUM_HAND, <span class=\"nt\">--num_hand</span> NUM_HAND\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Max number of hands\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h2 id=\"静止画像から認識-1\">静止画像から認識</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: test_photo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--world</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-nh</span> NUM_HAND]\n                     <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n                     INPUT_FILE\n\npositional arguments:\n  INPUT_FILE            Path to the input picture\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">--world</span>               <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp world landmark map\n  <span class=\"nt\">-nh</span> NUM_HAND, <span class=\"nt\">--num_hand</span> NUM_HAND\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Max number of hands\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h1 id=\"説明\">説明</h1>\n\n<p>説明….するほどのことはないな。<br />\nほとんど出来あいの処理。</p>\n\n<p>各指の状態からポーズを取得する処理を変更すれば、ほかの認識(ジャンケン認識など)にも変更可能。<br />\nまた、人差し指の指先をトラッキングしていけば、バーチャルお絵描きなんてのもできるかも。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>BLEでアプリケーションパラメータ設定</title>\n  </head>\n  <body>\n    <header>\n      <h1>BLEでアプリケーションパラメータ設定</h1>\n      <p>ESP32 BLEを使用してアプリケーションパラメータの設定を変更する処理の雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>アプリケーションを作成したとき、マシン名のように端末毎に変更を変更したり、\nサーバ名のように設置条件によって変更したいパラメータってありますよね。<br />\nいつもは起動時に設定モードに入ったり、動作中に簡易シェルを動かしてコンソール(UART)から設定していましたが、<br />\n実装面積などの関係でUARTが接続できなかったりした場合、それ以外の方法としてBLEで設定する方法を考えました。<br />\n(ESP32の場合、Flash書き換えでUART使うので繋がない訳にはいかないのですが…)</p>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nを参考にカスタムプロファイルでアプリケーションパラメータをread/writeできるようにしてみました。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは<a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a><br />\nにあるのでcloneしてください。</p>\n\n<p>このプログラムではアプリケーションはWi-Fiに接続するだけの処理です。<br />\nうまくパラメータが設定できて、nvsに保存しておけば、2回目以降はBLEによる設定なしにWi-Fiに接続することができます。<br />\n接続できれば、外部マシンからpingを打って応答があることが確認できます。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a> のREADME.mdを参照してください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nパラメータの設定はRaspberryPiのpythonから行っていますが、その気になればAndroidのBLE接続確認ツールなどからでも設定できます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n設定パラメータにループインターバルがありますが、プログラム中では参照していません。<br />\n数値を設定する例として入れてあります。</p>\n</blockquote>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>設定したいパラメータが増えてたら、Characteristicを増やしていけばいくらでも対応できるハズ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>pythonでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に pythonスクリプトでアクセスしてみる方法についてのメモ。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<p>pythonスクリプトはRaspberryPiで動作している(実際に試したのはPi4だが、Pi3/Pi0wでも同様)。<br />\nubuntu-PCでも同様にできるはずだが、うちのマシンは内蔵Bluetoothのバージョンが古くてBLE非対応だったので試してない。<br />\nwindows-PCはよくわからん…</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/test1\n<span class=\"nb\">cd</span> /work/ble/test1\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.9.10 bluepy\npyenv <span class=\"nb\">local </span>bluepy\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>bluepy\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/9bbdfa53526411967975097cfbcc66e6.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>ESP32側はAdvertising 開始状態にしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>python ble_hr.py\n</code></pre></div></div>\n<p>デバイスのスキャンを行うので<code class=\"language-plaintext highlighter-rouge\">sudo</code>が必要。</p>\n<blockquote>\n  <p>[!NOTE]\nもし、scanせずにアドレスを指定して実行するだけの処理に書き換えれば<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要になる。</p>\n</blockquote>\n\n<h1 id=\"説明\">説明</h1>\n\n<h2 id=\"ble_hr_delegateクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR_Delegate</code>クラス</h2>\n<p>Notifyを受け取っての処理は<code class=\"language-plaintext highlighter-rouge\">bluepy.btle.DefaultDelegate</code>クラスを継承したクラスを作成して登録する必要がある。<br />\n処理自体は<code class=\"language-plaintext highlighter-rouge\">handleNotification</code>メソッドをオーバーライドして定義する。<br />\n受け取るデータ<code class=\"language-plaintext highlighter-rouge\">data</code>はbytes型なので、数値として使用する場合は<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換してやる必要があるが、<br />\nこの時のエンディアンは接続しているデバイスのFW仕様によるので、どちらを使うかはあらかじめ確認しておく必要がある。<br />\n(大抵はFWを動かしているCPUのエンディアンなのかな?)</p>\n\n<h2 id=\"ble_hrクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR</code>クラス</h2>\n<p>peripheralを操作するための処理をクラス化してある。<br />\nクラス化は必須ではないけど、処理をまとめておいた方が分かりやすいかな?と思ったので。</p>\n\n<p>コンストラクタ、接続、Characteristicのリード/ライト、Notifyの有効化/無効化/ポーリング、切断などの処理がある。</p>\n\n<h2 id=\"main関数\"><code class=\"language-plaintext highlighter-rouge\">main</code>関数</h2>\n<p>メイン処理。<br />\n処理の流れはこんな感じ。</p>\n<ul>\n  <li>デバイスのスキャン</li>\n  <li>スキャン結果から指定されたUUIDを持つデバイスを探す\n    <ul>\n      <li>UUIDやデバイス名が必ずしも同じところにあるとは限らないので色々読んでみる必要がある</li>\n    </ul>\n  </li>\n  <li>複数のデバイスを同時に操作することも可能だが、今回は最初の1個だけを決め打ちで使う</li>\n  <li>接続</li>\n  <li>Characteristicのリード\n    <ul>\n      <li>ここもリード結果はbytes型なので、<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換する</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト\n    <ul>\n      <li>ライトデータはbytes型に変換する必要があるが、この処理は、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.write()</code>で変換しているのでここではそのまま。</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト結果の確認\n    <ul>\n      <li>ライトできたか確認するために、再度リードしている</li>\n    </ul>\n  </li>\n  <li>Notifyの有効化</li>\n  <li>Notifyが通知されることを確認するために少し待つ\n    <ul>\n      <li>Notifyを待つ間、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.waitForNotifications()</code>(<code class=\"language-plaintext highlighter-rouge\">Peripheral.waitForNotifications()</code>のラッパ)をコールし続ける必要がある。<br />\nこれをコールしないとNotifyを受信できない(キューイングされるがコールバックは実行されない)。</li>\n    </ul>\n  </li>\n  <li>Notifyの無効化\n    <ul>\n      <li>Notifyが入らないことを確認するためにちょっと待つ</li>\n    </ul>\n  </li>\n  <li>切断</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano に pyenv をインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano に pyenv をインストールする</h1>\n      <p>Jetson nano に pyenvをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>systemのpythonを使うのはちょっと嫌なので、仮想環境を使えるようにしておく。<br />\n<code class=\"language-plaintext highlighter-rouge\">venv</code>でもいいけど、やっぱり使い慣れた<code class=\"language-plaintext highlighter-rouge\">pyenv</code>+<code class=\"language-plaintext highlighter-rouge\">vertualenv</code>で。<br />\n基本的に<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a>と同じだけど、<br />\nJetpackでインストール済みで、<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできないパッケージがあるなど、<br />\nJetson nano 固有の設定等があるので、メモ。</p>\n\n<h1 id=\"手順再掲を含む\">手順(再掲を含む)</h1>\n\n<h2 id=\"pyenvをインストールする\">pyenvをインストールする</h2>\n<ul>\n  <li>必要なパッケージのインストール\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>pyenvとプラグインをダウンロード\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git            <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone git://github.com/pyenv/pyenv-update.git      <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境からJetpackでインストール済みのパッケージを参照できるようにしておく。<br />\n(pipでインストールできないみたいなので、お手軽な方法で解決)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/cv2          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/graphsurgeon <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/tensorrt     <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/uff          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>\n、とやりたいけど、ARM版は非対応らしいので…</p>\n    </blockquote>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>の修正<br />\n以下を追加しておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n<span class=\"c\">#jetson専用のインストール済みパッケージをコピっておく</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHONPATH</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span><span class=\"s2\">/jetson_pythonlib:</span><span class=\"nv\">$PYTHONPATH</span><span class=\"s2\">\"</span>\n</code></pre></div>    </div>\n  </li>\n  <li>ターミナル開きなおし or <code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を再読み込み</li>\n</ul>\n\n<h2 id=\"ベースとなるpythonのインストール\">ベースとなるpythonのインストール</h2>\n<p>バージョンは3.6.xでないとダメっぽい</p>\n\n<h2 id=\"python-のインストール\">python のインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.12\npyenv global 3.6.12\n</code></pre></div></div>\n<p>pip と setuptools のアップデート</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n<h2 id=\"その他\">その他</h2>\n<p>wheelが入ってると仮想環境を変えて同じモジュールをインストールするときに早いので、<br />\nインストールしておきたいが、各仮想環境に逐一インストールするのも面倒なので<br />\n共通に参照できるディレクトリにインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>wheel <span class=\"nt\">-t</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのバグ??</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのバグ??</h1>\n      <p>pyenvのバグ??</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>バグかどうかわからんけど、思った通りの動作をしなかったので、メモ。</p>\n\n<h1 id=\"現象\">現象</h1>\n\n<p>pyenv を使う環境で、</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    python script.py <span class=\"nt\">--option</span> /path/to/file\n</code></pre></div></div>\n\n<p>と実行した場合、カレントディレクトリと<code class=\"language-plaintext highlighter-rouge\">/path/to/file</code>の存在するディレクトリで使用するpythonのバージョンが異なる場合、<br />\n(どちらか片方 or 両方で <code class=\"language-plaintext highlighter-rouge\">pyenv local</code>が指定されている)<br />\nカレントディレクトリではなく、/path/to/fileの存在するディレクトリで使用するpythonのバージョンが指定されてしまうらしい。</p>\n\n<p>問題が発生するシチュエーションは そんなに多くないと思うけど、 双方のバージョンでインストールしてるモジュールが違ったりすると困ったことになる。</p>\n\n<h1 id=\"原因\">原因</h1>\n\n<p>色々試行錯誤してみてわかったことを結論だけ。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> を見ると、<br />\nコマンドラインをサーチして最初に見つかったファイルの属する<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読むらしい。<br />\n(以下の部分)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    ・・・\n    <span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"k\">in</span>\n        <span class=\"nt\">-c</span><span class=\"k\">*</span> <span class=\"p\">|</span> <span class=\"nt\">--</span> <span class=\"p\">)</span> <span class=\"nb\">break</span> <span class=\"p\">;;</span>\n        <span class=\"k\">*</span>/<span class=\"k\">*</span> <span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-f</span> <span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n                </span><span class=\"nb\">export </span><span class=\"nv\">PYENV_FILE_ARG</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$arg</span><span class=\"s2\">\"</span>\n                <span class=\"nb\">break\n            </span><span class=\"k\">fi</span>\n            <span class=\"p\">;;</span>\n    <span class=\"k\">esac</span>\n    ・・・\n</code></pre></div></div>\n<p>本来ならスクリプトファイルのあるディレクトリの<code class=\"language-plaintext highlighter-rouge\">.python-version</code>を読んでほしいはずなのに…<br />\n<code class=\"language-plaintext highlighter-rouge\">*/* )</code> でなく、<code class=\"language-plaintext highlighter-rouge\">*)</code> じゃないのかな? なんか深い訳があるのかもしれんけど…</p>\n\n<h1 id=\"対処方法\">対処方法</h1>\n\n<p>で、以下のいずれかの方法で対処できる。</p>\n\n<ul>\n  <li>オプションの場合は、オプションとオプションパラメータの間をスペースでなく、<code class=\"language-plaintext highlighter-rouge\">=</code>にする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  python script.py <span class=\"nt\">--option</span><span class=\"o\">=</span>/path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>ただし、パーサが<code class=\"language-plaintext highlighter-rouge\">argparse.ArgumentParser</code>など、オプションとオプションパラメータの区切りに<code class=\"language-plaintext highlighter-rouge\">=</code>が使えるものでなければダメ。</li>\n      <li>しかも、そもそもオプションパラメータでなくコマンドパラメータだったらどうしようもない…orz…</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pyenv shell</code>で使用するバージョンを指定する\n    <ul>\n      <li>メンドクサイ…</li>\n    </ul>\n  </li>\n  <li>スクリプトファイルの前に<code class=\"language-plaintext highlighter-rouge\">--</code>を追加してやる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">--</span> script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">~~~/.pyenv/shims/python</code> では<code class=\"language-plaintext highlighter-rouge\">-c</code>か<code class=\"language-plaintext highlighter-rouge\">--</code>が見つかったら<code class=\"language-plaintext highlighter-rouge\">PYENV_FILE_ARG</code>を探すループを抜けてくれるので。</li>\n      <li>ちょっとめんどくさい…</li>\n    </ul>\n  </li>\n  <li>スクリプト名の前に./を追加する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ./script.py /path/to/file\n</code></pre></div>    </div>\n    <ul>\n      <li>これが一番シンプルかな?</li>\n      <li>てか、コレしかないっしょ。 常に<code class=\"language-plaintext highlighter-rouge\">./</code>付けるクセ付ければいいし。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"免責のツモリ\">免責(のツモリ)</h1>\n\n<p>あくまで自分のメモなんで、、、  ゴニョゴニョ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ガラクタ置き場</title>\n  </head>\n  <body>\n    <header>\n      <h1>ガラクタ置き場</h1>\n      <p>COCO データセットから適当にファイルを取得する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ガラクタ\">ガラクタ</h1>\n<p>SSDなどの動作確認に使えるかなぁ~?と思ってCOCO データセットから適当にいくつかの画像ファイルを取得するスクリプトを作ってみた。<br />\n結局使わなかったけど、せっかくなのでガラクタ置き場に置いておく。(^^ゞ</p>\n\n<p>今回はリポジトリ作るほどではないので、ここにソース貼っとく。<br />\n解説するほどでもないので、使い方はソース見てチョ!←   テヌキ…</p>\n\n<h2 id=\"ソース\">ソース</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"s\">'''\nCOCOデータセットから適当にファイルを取得する\n'''</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">glob</span>\n<span class=\"kn\">import</span> <span class=\"nn\">shutil</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">RawTextHelpFormatter</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">urllib.request</span>\n<span class=\"kn\">import</span> <span class=\"nn\">zipfile</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n\n<span class=\"n\">COCO_2014</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>       <span class=\"c1\"># COCO 2014のminivalデータセット を使用する場合はTrueにする\n</span>\n<span class=\"c1\"># パラメータ\n</span><span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n    <span class=\"n\">DOWNLOAD_URL</span> <span class=\"o\">=</span> <span class=\"s\">'https://dl.dropboxusercontent.com/s/o43o90bna78omob/instances_minival2014.json.zip?dl=0'</span>\n    <span class=\"n\">JSON_FILE</span>    <span class=\"o\">=</span> <span class=\"s\">'instances_minival2014.json'</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">DOWNLOAD_URL</span> <span class=\"o\">=</span> <span class=\"s\">'http://images.cocodataset.org/annotations/image_info_test2017.zip'</span>\n    <span class=\"n\">JSON_FILE</span>    <span class=\"o\">=</span> <span class=\"s\">'annotations/image_info_test2017.json'</span>\n\n<span class=\"c1\"># zipファイル展開のための一時ファイル\n</span><span class=\"n\">TEMP_ZIP</span>     <span class=\"o\">=</span> <span class=\"s\">'temp.zip'</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">formatter_class</span><span class=\"o\">=</span><span class=\"n\">RawTextHelpFormatter</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--num'</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロードするファイル数\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--margin'</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">30</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロードエラーのためのマージン数\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--clean'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"ダウンロード済みのファイルを削除して終了します</span><span class=\"se\">\\n</span><span class=\"s\">(ダウンロードは行いません)\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n\n<span class=\"c1\"># コマンドラインパーサの生成&解析\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">clean</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"==== CLEAN!! ====\"</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">):</span>\n        <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n            <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">shutil</span><span class=\"p\">.</span><span class=\"n\">rmtree</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">dirname</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">),</span> <span class=\"n\">ignore_errors</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">for</span> <span class=\"nb\">file</span> <span class=\"ow\">in</span> <span class=\"n\">glob</span><span class=\"p\">.</span><span class=\"n\">glob</span><span class=\"p\">(</span><span class=\"s\">'*.jpg'</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">):</span>\n            <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ファイル数設定\n</span><span class=\"n\">num_files</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num</span>\n<span class=\"n\">num_margin</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">margin</span>\n\n<span class=\"c1\"># JSONファイルがなければダウンロードする\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ダウンロードを実行\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">DOWNLOAD_URL</span><span class=\"si\">}</span><span class=\"s\"> をダウンロード中...'</span><span class=\"p\">)</span>\n    <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">urlretrieve</span><span class=\"p\">(</span><span class=\"n\">DOWNLOAD_URL</span><span class=\"p\">,</span> <span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 展開\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">TEMP_ZIP</span><span class=\"si\">}</span><span class=\"s\"> を展開中...'</span><span class=\"p\">)</span>\n    <span class=\"k\">with</span> <span class=\"n\">zipfile</span><span class=\"p\">.</span><span class=\"n\">ZipFile</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">zf</span><span class=\"p\">:</span>\n        <span class=\"n\">zf</span><span class=\"p\">.</span><span class=\"n\">extractall</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># テンポラリファイルの削除\n</span>    <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">TEMP_ZIP</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># JSONファイルの読み込み\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">JSON_FILE</span><span class=\"si\">}</span><span class=\"s\">の読み込み中...'</span><span class=\"p\">)</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">JSON_FILE</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_json</span> <span class=\"p\">:</span>\n    <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f_json</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ個数(5000のハズ)\n</span><span class=\"n\">data_len</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">])</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'DATA_LENGTH = </span><span class=\"si\">{</span><span class=\"n\">data_len</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 内容をダンプ\n# print(json.dumps(data[\"images\"], indent=2))\n</span>\n<span class=\"c1\"># ダウンロード数のチェック\n</span><span class=\"k\">if</span> <span class=\"n\">num_files</span> <span class=\"o\">+</span> <span class=\"n\">num_margin</span> <span class=\"o\">></span> <span class=\"n\">data_len</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'ERROR : ファイル数とマージンの合計がデータ個数を超えています'</span><span class=\"p\">)</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ダウンロードするインデックスを乱数で決定(エラー発生時のためにマージンを積んどく)\n</span><span class=\"n\">download_indexs</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">(</span><span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">data_len</span><span class=\"p\">),</span> <span class=\"n\">num_files</span> <span class=\"o\">+</span> <span class=\"n\">num_margin</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># ダウンロード完了個数\n</span><span class=\"n\">num_downloaded</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n<span class=\"n\">num_error</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># ダウンロードループ\n</span><span class=\"k\">for</span> <span class=\"nb\">id</span> <span class=\"ow\">in</span> <span class=\"n\">download_indexs</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ファイル名\n</span>    <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"file_name\"</span><span class=\"p\">]</span>\n    <span class=\"c1\"># URL\n</span>    <span class=\"k\">if</span> <span class=\"n\">COCO_2014</span> <span class=\"p\">:</span>\n        <span class=\"n\">url</span>      <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"url\"</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">url</span>      <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">[</span><span class=\"s\">\"images\"</span><span class=\"p\">][</span><span class=\"nb\">id</span><span class=\"p\">][</span><span class=\"s\">\"coco_url\"</span><span class=\"p\">]</span>\n    <span class=\"c1\"># ダウンロード\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">filename</span><span class=\"si\">}</span><span class=\"s\">をダウンロード中...'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'ID : </span><span class=\"si\">{</span><span class=\"nb\">id</span><span class=\"si\">:</span><span class=\"mi\">3</span><span class=\"si\">}</span><span class=\"se\">\\t</span><span class=\"s\">NAME : </span><span class=\"si\">{</span><span class=\"n\">filename</span><span class=\"si\">}</span><span class=\"se\">\\t</span><span class=\"s\">URL : </span><span class=\"si\">{</span><span class=\"n\">url</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">try</span> <span class=\"p\">:</span> \n        <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">urlretrieve</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">)</span>\n    <span class=\"k\">except</span> <span class=\"n\">urllib</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">.</span><span class=\"n\">HTTPError</span> <span class=\"k\">as</span> <span class=\"n\">e</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># エラー発生\n</span>        <span class=\"n\">num_error</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'**** skip!! ****  </span><span class=\"si\">{</span><span class=\"n\">e</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ダウンロード完了\n</span>        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'---- DONE!! ----'</span><span class=\"p\">)</span>\n        <span class=\"n\">num_downloaded</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"c1\"># 所望の数に達したら終了\n</span>        <span class=\"k\">if</span> <span class=\"n\">num_downloaded</span> <span class=\"o\">>=</span> <span class=\"n\">num_files</span> <span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'ダウンロード数 : </span><span class=\"si\">{</span><span class=\"n\">num_downloaded</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'エラー数       : </span><span class=\"si\">{</span><span class=\"n\">num_error</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">num_error</span> <span class=\"o\">></span> <span class=\"n\">num_margin</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'warning : エラー数がマージンを越えました'</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<p>今後、なんかに使えると良いなぁ~(笑)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>csvファイルをエクセルファイルに変換する</title>\n  </head>\n  <body>\n    <header>\n      <h1>csvファイルをエクセルファイルに変換する</h1>\n      <p>pythonでcsvファイルをエクセルファイルに変換する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonでcsvファイルをエクセルファイルに変換する方法。<br />\nぐぐったらすぐ出てくるけど、自分のとこにもメモしとく。<br />\nついでに、おまけとしてcsvファイルを読んで、各列の平均値を出力する処理も載せとく。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p>必要なモジュールをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>pandas openpyxl\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pandas</span> <span class=\"k\">as</span> <span class=\"n\">pd</span>\n\n<span class=\"c1\"># コマンドラインパラメータ\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span>\n\n<span class=\"c1\"># エラーチェックは省略\n# 入力ファイル(csv形式、拡張子は任意)の拡張子をxlsxに変更したファイルとして出力する\n</span>\n<span class=\"n\">input_file</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>                                        <span class=\"c1\"># 入力ファイル名\n</span><span class=\"n\">output_file</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">input_file</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".xlsx\"</span>     <span class=\"c1\"># 出力ファイル名\n</span> \n<span class=\"c1\"># CSVファイルの読み込み\n</span><span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">pd</span><span class=\"p\">.</span><span class=\"n\">read_csv</span><span class=\"p\">(</span><span class=\"n\">input_file</span><span class=\"p\">,</span> <span class=\"n\">index_col</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>     <span class=\"c1\"># 1行目がヘッダ、1列目がインデックスとする\n</span>\n<span class=\"c1\"># Excel形式で出力\n</span><span class=\"n\">data</span><span class=\"p\">.</span><span class=\"n\">to_excel</span><span class=\"p\">(</span><span class=\"n\">output_file</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s\">'utf-8'</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<p>csvファイルを読んで、各列の平均値を出力する処理をワンライナーで。<br />\n(前提:1行目がヘッダ、1列目がインデックス)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import sys; import pandas as pd; data = pd.read_csv(sys.argv[1], index_col=0); ave=data.mean(); print(ave)\"</span> «csvファイル»\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openCV で MPEG再生</title>\n  </head>\n  <body>\n    <header>\n      <h1>openCV で MPEG再生</h1>\n      <p>python + openCV でMPEGファイルを再生する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>python + openCV で MPEGファイルを再生するには、以下のようにread→imshowを繰り返せば良い。<br />\nしかし、これではフレームレートを考慮していないため、実際の時間とは異なる速度で再生されてしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n<span class=\"k\">while</span> <span class=\"n\">true</span><span class=\"p\">:</span>\n    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"k\">break</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>そこで、フレーム間に待ち時間を確保し、実際の時間と同じになるように再生する方法を考える。</p>\n\n<h1 id=\"フレーム間の待ち時間を決め打ちで待つパターン一番シンプルなパターン\">フレーム間の待ち時間を決め打ちで待つパターン(一番シンプルなパターン)</h1>\n\n<p>最も簡単な方法は、フレーム間に決め打ちでwait処理を挿入する方法である。<br />\nフレームレートは一定であるため、待ち時間も一定になる。<br />\n再生中にキー入力による中止を検出したいので、<code class=\"language-plaintext highlighter-rouge\">time.sleep()</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">cv2.waitKey(delay)</code>を使用している。<br />\n試した環境では、<code class=\"language-plaintext highlighter-rouge\">cv2.waitKey()</code> は 25くらいを指定すると大体30fpsに合うくらいの間隔になる(ちょっと早いかも)。<br />\n設定値はトライ&エラーで設定値を探るしかない。</p>\n\n<p>しかし、MPEG再生しか行わない場合はこれでも問題ないが、フレーム間に他の処理を行うと待ち時間が変わってきてしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./video.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 現在時刻\n</span>    <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"n\">index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># delay = 1         # 最速再生\n</span>    <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"mi\">25</span>          <span class=\"c1\"># それっぽい再生速度になるように決め打ちで\n</span>    \n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">delay</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"前回の時刻からフレーム間の待ち時間を決めるパターン\">前回の時刻からフレーム間の待ち時間を決めるパターン</h1>\n\n<p>前回の表示時刻を覚えておき、今回の表示時刻との間隔がフレームレートに一致するように待ち時間を調整する。<br />\nこれなら、フレーム間に他の処理を挿入しても(その処理時間が一定でなくても)、その処理時間を除いて待ち時間を設定できる。</p>\n\n<p>しかし、挿入した処理がフレームレートを超えてしまうと、回復する術がなく、どんどん遅れていってしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./video.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n        <span class=\"n\">tmp_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 現在時刻\n</span>    <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"n\">index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># 待ち時間計算用起点からの差分とsec/frameから待ち時間決定\n</span>    <span class=\"n\">delta_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">tmp_time</span>\n    <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">sec_per_frame</span> <span class=\"o\">-</span> <span class=\"n\">delta_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(f'delta =  {int(delta_time*1000)}    {delay}')\n</span>    <span class=\"c1\"># 待ち時間がsec/frameを超えてたら最小値に設定\n</span>    <span class=\"k\">if</span> <span class=\"n\">delay</span> <span class=\"o\"><</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n\n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">delay</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># 待ち時間計算用起点\n</span>    <span class=\"n\">tmp_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"経過時間から表示すべきフレームを求めて移動しながら表示するパターン\">経過時間から表示すべきフレームを求めて移動しながら表示するパターン</h1>\n\n<p>現在時刻と再生開始時刻の差から表示すべきフレーム番号を求め、必要であれば<code class=\"language-plaintext highlighter-rouge\">cap.set(cv2.CAP_PROP_POS_FRAMES, index)</code>で読み込みフレームを移動して現在時刻とフレームの同期をとる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">cap.set()</code>は処理に時間がかかるので、無条件で実行すると再生フレームレートが遅くなるため、フレーム飛びが発生したときのみ実行するようにする。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n# filepath = os.path.abspath(\"./video.mp4\") \n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./stopwatch.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 前回表示フレーム番号の更新\n</span>    <span class=\"n\">prev_index</span> <span class=\"o\">=</span> <span class=\"n\">index</span>\n    \n    <span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 現在時刻\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        \n        <span class=\"c1\"># 表示するフレーム位置の取得\n</span>        <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">sec_per_frame</span><span class=\"p\">)</span>\n        <span class=\"c1\"># print(f\"{prev_time}    {cur_time}    {prev_index}    {index}\")\n</span>        <span class=\"k\">if</span> <span class=\"n\">prev_index</span> <span class=\"o\">==</span> <span class=\"n\">index</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 前回と同じフレーム番号ならちょっと待つ\n</span>            <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.001</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"k\">break</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># 表示するフレーム位置が連続するフレームでなければ移動\n</span>    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">!=</span> <span class=\"n\">prev_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># 動作確認0.5秒待ってみる\n</span>    <span class=\"c1\"># time.sleep(0.5)\n</span>\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PythonでIntel NCStick2</title>\n  </head>\n  <body>\n    <header>\n      <h1>PythonでIntel NCStick2</h1>\n      <p>PythonでIntel NCStick2を操作する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"事前準備\">事前準備</h1>\n<p>何はなくともPythonが必要。<br />\n実際には3.7.4を使用して動作確認。</p>\n\n<p>Pythonはpyenvでインストールしておくのが便利。インストール方法は \n<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a> を参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\npyenvとの相性が悪いらしく、pyenvで3.7.xがインストールされていると\n(python3.7コマンド自体は存在するので;実行自体はエラーで返ってくるが)、\nsetupvars.shでPYTHONPATHにpython3.7用pathが設定されてしまう。\nプログラム中で<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>でpathを追加しても、sys.pathの末尾に追加されてしまい、\n先に設定された3.7用モジュールがインポートされてしまう。\nもし、他のバージョンのpythonで実行する場合は<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">sys.path.insert</code>で\npathの先頭に追加するようにしないといけないようだ(試してないけど)。</p>\n\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n    <span class=\"err\">↓</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>ということで、下のプログラムソースの<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>の行は不要。</p>\n</blockquote>\n\n<h2 id=\"モジュールのインストール\">モジュールのインストール</h2>\n\n<p>必要なモジュール類をインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgfortran-6-dev\npip <span class=\"nb\">install </span>numpy\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h2 id=\"ワークディレクトリ\">ワークディレクトリ</h2>\n\n<p>色々共通で使いたいサイズのでっかいファイルがあるので、ワークディレクトリを以下の構成で作成しておく。<br />\n以降のopenVINO関連の投稿もこのディレクトリ構成を使うようにする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># C++プログラム湯尾</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++\n<span class=\"c\"># pythonプログラム用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/python\n<span class=\"c\"># モデルデータ用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP16\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP32\n</code></pre></div></div>\n\n<h1 id=\"参考\">参考</h1>\n\n<p><del>パクった</del> 参考にしたのは以下のあたり<br />\n解説や実行方法などはこっちを参照してちょ(相変わらずの他力本願ぶり…))</p>\n\n<ul>\n  <li><a href=\"http://jellyware.jp/openvino/\">JELLYWARE ゼロから学ぶディープラーニング推論</a>\n    <ul>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c07_ie_emotion.html\">Inference Engineを学んで感情分類</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c08_face_detection.html\">リアルタイム顔検出</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c09_emotion_app.html\">リアルタイム感情分析アプリ</a></li>\n    </ul>\n  </li>\n</ul>\n\n<p>顔検出+感情分類の参照元はカメラキャプチャした画像を処理しているけど、手元に適当なカメラがなかったので、JPEGファイルで実行するようにしてある(こっちの方が余計な処理なくて分かりやすいかな、と思ったのもある)。</p>\n\n<h1 id=\"感情分類\">感情分類</h1>\n\n<p>感情分類のプログラムを試す。</p>\n\n<h3 id=\"準備\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/emotions-recognition-retail-0003/FP16/emotions-recognition-retail-0003\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する顔画像(顔部分のみ切り出し)をPHOTO/face.jpgとして保存しておく。</p>\n\n<h3 id=\"プログラム\">プログラム</h3>\n\n<p>試したソースはこちら。<br />\nPCのubuntuで実行するための処理も追加済み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/face.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 結果取り出し\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>\n<span class=\"c1\"># 結果の最大値を持つインデックスを取得\n</span><span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 結果表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">結果'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">index_max</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"c1\"># 結果の詳細表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">詳細'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'スコア:</span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出\">顔検出</h1>\n\n<p>顔検出のプログラムを試す。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-1\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-1\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n\n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-1\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_detect.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_detect.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_detect.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出感情分類\">顔検出+感情分類</h1>\n\n<p>上の2つを合体させ、顔検出した結果に感情分類を実行する。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-2\">準備</h3>\n\n<p>モデルデータは上の2つをそのまま使用。</p>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-2\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出 + 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n# 日本語表示にはPillow使うとかしないといけないので、英語で。\n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# バウンティングボックスとラベルを表示する関数\n</span><span class=\"k\">def</span> <span class=\"nf\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ラベル領域サイズ\n</span>    <span class=\"n\">LABEL_W</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">12</span>    <span class=\"c1\"># 等幅フォントじゃないので正確ではないけど、大体こんな感じ\n</span>    <span class=\"n\">LABEL_H</span> <span class=\"o\">=</span> <span class=\"mi\">14</span>                <span class=\"c1\"># こっちもトライアンドエラーで微調整\n</span>    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">IMAGE_W</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">IMAGE_H</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># バウンディングボックス表示 \n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ラベル表示位置(X)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">IMAGE_W</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">IMAGE_W</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_W</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">xmin</span>\n    \n    <span class=\"c1\"># ラベル表示位置(Y)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span>\n    \n    <span class=\"c1\"># 文字列背景描画(塗りつぶし)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">label_x</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 文字列描画(座標は文字の左下)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX_SMALL</span><span class=\"p\">,</span> <span class=\"mf\">0.8</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n    \n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。特にminは補正しないとエラーになる\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 顔領域のみ切り出し \n</span>    <span class=\"n\">frame_face</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">[</span> <span class=\"n\">ymin</span><span class=\"p\">:</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">:</span><span class=\"n\">xmax</span> <span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 入力データフォーマットへ変換 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame_face</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span>   <span class=\"c1\"># サイズ変更 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">img_face</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img_face</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>    \n    <span class=\"c1\"># 推論実行 \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img_face</span><span class=\"p\">})</span>\n    \n    <span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>    \n    <span class=\"c1\"># 出力値が最大のインデックスを得る \n</span>    <span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"c1\"># print(list_emotion[index_max])\n</span>    <span class=\"n\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-2\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<h1 id=\"考察\">考察</h1>\n\n<p>基本パターンはこんな感じ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># モジュールのロード\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># 初期化\n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"s\">\"MYRIAD\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み\n</span><span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"s\">'xmlファイル'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"s\">'binファイル'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 推論実行 \n# imgは入力データ、Numpy配列 ndarray型\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># outが出力データ、Numpy配列 ndarray型\n</span>\n</code></pre></div></div>\n\n<p>入出力データの並びは読み込んだモデルに依存する。<br />\n入力データのサイズやRGB並び順などを合わせる。<br />\n(モデルに入力する際にリサイズすれば、元の画像ファイルのサイズは任意で良い。)<br />\n出力データはそのままでは「何のこっちゃ?」なので、きちんと整形してやる必要がある。</p>\n\n<p>ここに学習済みデータが色々登録されているらしい。<br />\n<a href=\"https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html\">https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html</a></p>\n\n<p>TensorflowやCaffeで作成した学習済みデータを変換することもできるらしいが、やり方はこれから調査。</p>\n\n<h1 id=\"参考情報\">参考情報</h1>\n<p><a href=\"https://software.intel.com/en-us/articles/OpenVINO-RelNotes\">openVINO toolkit リリースノート</a><br />\n<a href=\"https://git.uni-paderborn.de/rnagle/dldt/tree/noctua_plugin_develop\">openVINO toolkit リポジトリ</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WebIOPiをRaspbian Busterで動かす</title>\n  </head>\n  <body>\n    <header>\n      <h1>WebIOPiをRaspbian Busterで動かす</h1>\n      <p>WebIOPiをRaspbian Busterで動かす</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"背景\">背景</h1>\n\n<p>知人がWebIOPiをRaspbian Busterで動かそうとして、Raspbian Stretch では動いたが、Raspbian Busterだと動かないと言っていたので、\n興味本位でデバッグしてみた。</p>\n\n<p>私はこれを使おうと思ってないので、「鳴かぬなら鳴かせてみせようホトトギス」なだけなので、詳しい使い方とかは調べてません。</p>\n\n<h1 id=\"参照\">参照</h1>\n\n<p>そもそものインストール手順は、<br />\n<a href=\"https://www.hiramine.com/physicalcomputing/raspberrypi3/webiopi_install.html\">WebIOPi のインストール</a><br />\n<a href=\"https://www.fabshop.jp/%E9%96%8B%E7%99%BA%E3%81%8C%E7%B5%82%E4%BA%86%E3%81%97%E3%81%9Fwebiopi%E3%82%92%E6%9C%80%E6%96%B0%E3%81%AEraspbian%E3%81%A7%E5%8B%95%E4%BD%9C%E3%81%95%E3%81%9B%E3%82%88%E3%81%86%E3%80%82/?fbclid=IwAR1u1Hq0wSqnDhPnKDeoyf1b2AmrdpO99TLSevUTZ237D5Ny97pliLjlOwU\">開発が終了したWebIOPiを最新のRaspbianで動作させよう。</a><br />\nあたりを参考にしてちょ。</p>\n\n<h1 id=\"いきなり結論\">いきなり結論</h1>\n\n<p>で、まぁ結論から言うと、根本原因は、BusterのPython3がPython3.7にバージョンアップされたこと。<br />\nちなみに、StretchのPython3はPython3.5 。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">python/webiopi/utils/thread.py</code> 内の 関数 <code class=\"language-plaintext highlighter-rouge\">runLoop()</code>の中で<code class=\"language-plaintext highlighter-rouge\">async</code>を変数に使っていたため、SyntaxErrorが発生していた模様。<br />\nPythom3.7では(正確にはPython3.6から)<code class=\"language-plaintext highlighter-rouge\">async</code>は予約語になっているため、エラーとなっていた。</p>\n\n<p>で、変数名を<code class=\"language-plaintext highlighter-rouge\">async</code>からそれ以外(例えば<code class=\"language-plaintext highlighter-rouge\">async_Flag</code>)に変更すれば良い。</p>\n\n<h1 id=\"でpatchファイル\">で、patchファイル</h1>\n\n<p>修正内容のpatchファイルがこちら。<br />\nついでにCプログラムのコンパイルの際に出るワーニングも消すようにちょこっと修正しときました。(こっちの修正は、かなりヤッツケ…)</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/cpuinfo.c WebIOPi-0.7.1/python/native/cpuinfo.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/cpuinfo.c\t2019-09-03 00:04:59.959369913 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/cpuinfo.c\t2019-09-02 23:55:16.207501342 +0900\n</span><span class=\"p\">@@ -35,7 +35,8 @@</span> char *get_cpuinfo_revision(char *revisio\n       return 0;\n \n    while(!feof(fp)) {\n<span class=\"gd\">-      fgets(buffer, sizeof(buffer) , fp);\n</span><span class=\"gi\">+      char* aaa = fgets(buffer, sizeof(buffer) , fp);\n+      aaa = aaa;\n</span>       sscanf(buffer, \"Hardware\t: %s\", hardware);\n       if (strcmp(hardware, \"BCM2708\") == 0)\n          rpi_found = 1;\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/gpio.c WebIOPi-0.7.1/python/native/gpio.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/gpio.c\t2019-09-03 00:04:59.969368480 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/gpio.c\t2019-09-02 23:58:58.757767098 +0900\n</span><span class=\"p\">@@ -23,6 +23,7 @@</span> SOFTWARE.\n #include <stdio.h>\n #include <stdint.h>\n #include <stdlib.h>\n<span class=\"gi\">+#include <unistd.h>\n</span> #include <string.h>\n #include <fcntl.h>\n #include <sys/mman.h>\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/webiopi/utils/thread.py WebIOPi-0.7.1/python/webiopi/utils/thread.py\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/webiopi/utils/thread.py\t2019-09-03 00:04:44.520586361 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/webiopi/utils/thread.py\t2019-09-02 23:54:10.087479478 +0900\n</span><span class=\"p\">@@ -33,14 +33,14 @@</span> def stop(signum=0, frame=None):\n             task.stop()\n                 \n \n<span class=\"gd\">-def runLoop(func=None, async=False):\n</span><span class=\"gi\">+def runLoop(func=None, async_Flag=False):\n</span>     global RUNNING\n     RUNNING = True\n     signal.signal(signal.SIGINT, stop)\n     signal.signal(signal.SIGTERM, stop)\n \n     if func != None:\n<span class=\"gd\">-        if async:\n</span><span class=\"gi\">+        if async_Flag:\n</span>             TASKS.append(Task(func, True))\n         else:\n             while RUNNING:\n</code></pre></div></div>\n\n<p>これを<code class=\"language-plaintext highlighter-rouge\">webiopi-buster.patch</code>として保存し、以下のコマンドを実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch <span class=\"nt\">-p1</span> <span class=\"nt\">-i</span> webiopi-buster.patch\n</code></pre></div></div>\n\n<p>で後は<code class=\"language-plaintext highlighter-rouge\">settup.sh</code>を実行して、その後は参照ページの通り進めれば良い。</p>\n\n<h1 id=\"めでたしめでたし\">めでたしめでたし</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pyenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>pyenvのインストール</h1>\n      <p>pyenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>システムのpythonのバージョンを変更したり、モジュールの変更をしたりするとシステム上のスクリプトの動作に影響が出る場合があるので、pyenvで個別のpython環境を構築するのがベター。<br />\nさらに、virtualenvプラグインを使うと、同じpythonのバージョンでもそれぞれに別のモジュールをインストールできる、仮想環境を構築できる。</p>\n\n<p>なお、pyenvはpythonをバイナリインストールできなくて、ソースからコンパイルするので、インストールにはそれなりに時間がかかる(RasPi2で1~2時間くらい?)。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<h3 id=\"必要なモジュールをインストール\">必要なモジュールをインストール</h3>\n<p>インストールに必要なモジュールをインストールする。</p>\n<ul>\n  <li>Bullseye以降ではこちら<br />\n(<code class=\"language-plaintext highlighter-rouge\">python-openssl</code> →  <code class=\"language-plaintext highlighter-rouge\">python3-openssl</code>)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>Buster以前ではこちら\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"bluetoothを使用する場合\">bluetoothを使用する場合</h3>\n<p>bluetoothを使用する場合は以下も必要</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以前、 ubuntuの場合は以下と書いていたが、<code class=\"language-plaintext highlighter-rouge\">libbluetooth3-dev</code>は<code class=\"language-plaintext highlighter-rouge\">libbluetooth-dev</code>の別名定義だったので上のコマンドでOKのはず。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth3-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"pyenv本体とvirtualenvプラグインのインストール\">pyenv本体とvirtualenvプラグインのインストール</h2>\n\n<p>pyenv本体とvirtualenvプラグインをインストール。<br />\nついでにupdateプラグインも入れとく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>pyenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n<span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>Raspbianでは以下も追加<br />\nnumpyをimportしたとき、undefined symbol: PyFPE_jbuf でエラーになる対策。<br />\n参考: <a href=\"https://research.itplants.com/?p=2437\">https://research.itplants.com/?p=2437</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"--enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n --with-fpectl\"</span>\n</code></pre></div></div>\n\n<p>Ubuntuでは以下を追加しておく(デフォルトだとShared Library のimportでエラーになる)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h2 id=\"sudoでpyenv環境を実行するように設定する\">sudoでpyenv環境を実行するように設定する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo</code>でpythonを実行すると、pyenvの設定に関係なくsystemのpythonが実行されてしまいます。<br />\nこれを防ぐためには、<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers</code>の<code class=\"language-plaintext highlighter-rouge\">Defaults secure_path</code>に以下のpathを追加します。</p>\n\n<ul>\n  <li>«pyenvインストール先»/plugins/pyenv-virtualenv/shims:</li>\n  <li>«pyenvインストール先»shims:</li>\n  <li>«pyenvインストール先»/bin:</li>\n</ul>\n\n<p>具体的には以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 変更前\nDefaults  secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n    ↓\n# 変更後\nDefaults  secure_path=\"/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n</code></pre></div></div>\n<ul>\n  <li></li>\n</ul>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"pyenvでインストールできるバージョンの一覧を表示\">pyenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span> \n</code></pre></div></div>\n\n<h3 id=\"pythonのインストール\">pythonのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.4\n</code></pre></div></div>\n\n<p>・・・ 気長に待つ。 ・・・</p>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global 3.6.4\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-V</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境の構築\">仮想環境の構築</h3>\n\n<p>色々試したあとに、インストールしたモジュールをチャラにしたいときを考えて、仮想環境を構築しておく。<br />\nここでは、python 3.6.4を使用して 仮想環境名 mypython を作成。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.6.4 mypython\n</code></pre></div></div>\n\n<p>デフォルトをmypythonに変更する場合は以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv global mypython\n</code></pre></div></div>\n\n<h3 id=\"pipのバージョンアップ\">pipのバージョンアップ</h3>\n\n<p>「pipが古い~」と言われる前にバージョンアップ。ついでにsetuptoolsとwheelも。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n<blockquote>\n  <p>[!IMPORTANT]\nベース環境をバージョンアップしても、仮想環境に引き継がれないので、仮想環境毎に実行が必要。</p>\n</blockquote>\n\n<h3 id=\"ローカルバージョンの設定\">ローカルバージョンの設定</h3>\n\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは3.4.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">local</span> <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell <バージョン名 or 仮想環境名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"i2cを使用する場合raspi\">I2Cを使用する場合(RasPi)</h1>\n\n<p>RaspberryPi環境で、I2Cを使うためのsmbusモジュールは、通常 <code class=\"language-plaintext highlighter-rouge\">sudo apt install python3-smbus</code> でインストールするが、これだとpyenv環境にインストールできない。<br />\nこれはsmbus2をインストールして使用することで回避できる。\nインストールは以下のように実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>smbus2\n</code></pre></div></div>\n<p>ちなみに、pyenv 環境へのモジュールのインストールには <code class=\"language-plaintext highlighter-rouge\">sudo</code> は不要。/usr 下へのインストールではないので。</p>\n\n<p>で、プログラムソース側はsmbusのインストール部分を以下のように修正。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus</span>\n<span class=\"k\">except</span> <span class=\"nb\">ImportError</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">smbus2</span> <span class=\"k\">as</span> <span class=\"n\">smbus</span>\n</code></pre></div></div>\n\n<p>smbus2 だけにしても良いけど、smbus でも動作できるようにしておくのがベターかな。</p>\n\n<h1 id=\"pyenvのバージョンアップ\">pyenvのバージョンアップ</h1>\n<p>pythonの新しいバージョンがリリースされ、それをインストールしたい場合など、pyenvのバージョンアップが必要。<br />\npyenv-updateをインストールしておけば(上記手順でインストール済み)、以下のコマンドですべてのプラグインを含めてバージョンアップしてくれる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv update\n</code></pre></div></div>\n\n<h2 id=\"古い方法\">古い方法</h2>\n<p>pyenv-updateをインストールしていない場合は以下の手順でそれぞれのリポジトリをpullする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit pull\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのpythonを使いたい場合は以下のように実行\">システムのpythonを使いたい場合は以下のように実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv version\n</code></pre></div></div>\n\n<h3 id=\"pyenvでインストールされているpythonのバージョン仮想環境を確認\">pyenvでインストールされているpythonのバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"pyenv自体のバージョン確認\">pyenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"pyenvで使用できるコマンドの確認\">pyenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv commands\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>python の async/await</title>\n  </head>\n  <body>\n    <header>\n      <h1>python の async/await</h1>\n      <p>python の async/awaitってどう動くんだっけ?</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h2 id=\"python-の-asyncawaitってどう動くんだっけ\">python の async/awaitってどう動くんだっけ?</h2>\n\n<p>と思ったので、ちょっとテストプログラムを書いて試してみた。</p>\n\n<p>asyncioはnon-preemptiveなので、最近のpreemptiveに慣れ切った脳ミソにはややこしい。</p>\n\n<p>preemptiveなプログラムを書きたければ、threadingを使えば良い。適材適所というやつだ。</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">asyncio</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n\n<span class=\"n\">argvs</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span>  <span class=\"c1\"># コマンドライン引数を格納したリストの取得\n</span><span class=\"n\">argc</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">)</span> <span class=\"c1\"># 引数の個数\n</span>\n<span class=\"k\">if</span> <span class=\"n\">argc</span> <span class=\"o\">></span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">argvs</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">testCase</span> <span class=\"o\">=</span> <span class=\"mi\">5</span>        <span class=\"c1\"># テストケース\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"testCase = \"</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">testCase</span><span class=\"p\">))</span>\n\n<span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>           <span class=\"c1\"># 念のため宣言だけしておく\n</span>\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">sub</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub start        \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"sub wakeup       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"mi\">42</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"n\">task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">sub</span><span class=\"p\">())</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after create     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"befor call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"k\">await</span> <span class=\"n\">task</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">task</span>\n    \n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"after call       \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main wakeup      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n<span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">main2</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 start      \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"main2 wakeup     \"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">tbase</span><span class=\"p\">))</span>\n\n\n<span class=\"c1\"># =============================================================================\n</span><span class=\"n\">tbase</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>     <span class=\"c1\"># 開始時刻を記憶\n</span><span class=\"k\">if</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">or</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">4</span> <span class=\"p\">:</span>\n    <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">wait</span><span class=\"p\">([</span><span class=\"n\">main</span><span class=\"p\">(),</span> <span class=\"n\">main2</span><span class=\"p\">()]))</span>\n<span class=\"k\">elif</span> <span class=\"n\">testCase</span> <span class=\"o\">==</span> <span class=\"mi\">5</span> <span class=\"p\">:</span>\n    <span class=\"n\">loop</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"p\">.</span><span class=\"n\">get_event_loop</span><span class=\"p\">()</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">run_until_complete</span><span class=\"p\">(</span><span class=\"n\">main2</span><span class=\"p\">())</span>\n    <span class=\"n\">loop</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"unknown test case!!\"</span><span class=\"p\">)</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n\n<p>以下のようにコマンドラインからテストケース番号を指定して実行する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python test.py <testCase>\n</code></pre></div></div>\n\n<h2 id=\"実行結果\">実行結果</h2>\n<h3 id=\"testcase1\">testCase=1</h3>\n\n<p>基本的なパターン、というか、全然非同期実行になってないけど。。。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code>→ <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p>awaitが付いていると、その場でタスクに実行権を渡し、そのタスクが終了するまで待つ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 1\ntestCase <span class=\"o\">=</span>  1\nbefor create     0.00026416778564453125\nafter create     0.00034689903259277344\nbefor call       0.00040340423583984375\nsub start        0.00047469139099121094\nsub wakeup       2.0033931732177734\nafter call       2.0035252571105957\nmain wakeup      3.004753351211548\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase2\">testCase=2</h3>\n\n<p>基本的なパターン、こっちが非同期実行として本命。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code>を実行するときに<code class=\"language-plaintext highlighter-rouge\">await</code>を付けない。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">await</code>が付いていないと、その場でタスクに実行権を渡さず、自分の実行を中断する部分か終了するまでそのまま実行する。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> 呼び出し箇所では即時実行されず、sleep(2)で <code class=\"language-plaintext highlighter-rouge\">main</code> の実行が中断されたところで <code class=\"language-plaintext highlighter-rouge\">sub</code> へ切り替わる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sub</code> で <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> が実行されると実行されるタスクがなくなるので、イベントループは実行可能タスク待ちになる。</p>\n\n<p>1秒後、<code class=\"language-plaintext highlighter-rouge\">main</code> が起床するので、そのままmainが終了される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> で イベントループは <code class=\"language-plaintext highlighter-rouge\">main</code> の終了を待っているので、<code class=\"language-plaintext highlighter-rouge\">sub</code> が実行中でも無関係にイベントループを終了してしまい、\n <code class=\"language-plaintext highlighter-rouge\">sub</code> の残りは実行されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 2\ntestCase <span class=\"o\">=</span>  2\nbefor create     0.0002646446228027344\nafter create     0.00034308433532714844\nbefor call       0.00039768218994140625\nafter call       0.0004489421844482422\nsub start        0.0005385875701904297\nmain wakeup      1.0014407634735107\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase3\">testCase=3</h3>\n\n<p>testCase=2 でsubの残りも実行するには?と思って試したパターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で、即座に <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main2())</code> を実行してみた。</p>\n\n<p>見事失敗。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→ <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p>どうやら、 <code class=\"language-plaintext highlighter-rouge\">asyncio.run(main())</code> が終了した時点で イベントループは一旦 <code class=\"language-plaintext highlighter-rouge\">close</code> されてしまうらしい。</p>\n\n<p>単にtestCase=2の後ろにmain2の実行を付け加えただけになってしまった。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 3\ntestCase <span class=\"o\">=</span>  3\nbefor create     0.00029540061950683594\nafter create     0.0003790855407714844\nbefor call       0.0004353523254394531\nafter call       0.00048828125\nsub start        0.0005817413330078125\nmain wakeup      1.0015552043914795\nmain2 start      1.0021519660949707\nmain2 wakeup     4.0038042068481445\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase4\">testCase=4</h3>\n\n<p>testCase=3 の失敗挽回パターン。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でmainとmain2をまとめてみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> となっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.wait()</code> でまとめたタスクがすべて終了するまでイベントループは<code class=\"language-plaintext highlighter-rouge\">close</code> されないので、<code class=\"language-plaintext highlighter-rouge\">sub</code>は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> と <code class=\"language-plaintext highlighter-rouge\">main2</code> のどちらが先に実行されるかは規定されていない様子。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 4\ntestCase <span class=\"o\">=</span>  4\nmain2 start      0.0003325939178466797\nbefor create     0.0004305839538574219\nafter create     0.0005018711090087891\nbefor call       0.0005679130554199219\nafter call       0.0006389617919921875\nsub start        0.0007307529449462891\nmain wakeup      1.002068042755127\nsub wakeup       2.002253293991089\nmain2 wakeup     3.003903388977051\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n<h3 id=\"testcase5\">testCase=5</h3>\n\n<p>testCase=3 の失敗挽回パターン その2。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">asyncio.get_event_loop()</code> でイベントループを取得し、<code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> でそれぞれのタスクを実行してみた。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">main</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(1)</code> → <code class=\"language-plaintext highlighter-rouge\">sub</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(2)</code> → <code class=\"language-plaintext highlighter-rouge\">main起床</code> → <code class=\"language-plaintext highlighter-rouge\">main終了</code> \n→  <code class=\"language-plaintext highlighter-rouge\">main2</code> → <code class=\"language-plaintext highlighter-rouge\">sleep(3)</code> → <code class=\"language-plaintext highlighter-rouge\">sub起床</code> → <code class=\"language-plaintext highlighter-rouge\">sub終了</code> → <code class=\"language-plaintext highlighter-rouge\">main2起床</code> → <code class=\"language-plaintext highlighter-rouge\">main2終了</code> → イベントループ終了\nとなっている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">loop.run_until_complete()</code> ではタスクが終了してもイベントループはcloseされないので、同じイベントループで<code class=\"language-plaintext highlighter-rouge\">main2</code>が実行される。\n結果、<code class=\"language-plaintext highlighter-rouge\">sub</code> は最後まで実行される。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">mainn</code> が終了するまで <code class=\"language-plaintext highlighter-rouge\">main2</code> は実行(起動)されない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>python test.py 5\ntestCase <span class=\"o\">=</span>  5\nbefor create     0.0002574920654296875\nafter create     0.0003345012664794922\nbefor call       0.00038933753967285156\nafter call       0.0004410743713378906\nsub start        0.0005307197570800781\nmain wakeup      1.0010528564453125\nmain2 start      1.0011804103851318\nsub wakeup       2.002350330352783\nmain2 wakeup     4.002865314483643\n<span class=\"k\">done</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "setup": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 24.04のVirtualBoxへのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 24.04のVirtualBoxへのインストール</h1>\n      <p>Ubuntu 24.04のVirtualBoxへのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 24.04のVirtualBoxへのインストール手順をまとめてみた。<br />\n今回は 極力コマンドコピペで実行できるように書いてみた。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2404-インストール媒体の入手\">Ubuntu 24.04 インストール媒体の入手</h2>\n<p>24.04は日本語Remixがリリースされないので(<a href=\"https://www.ubuntulinux.jp/News/ubuntu2404-ja-remix\" target=\"_blank\">ニュース</a>)、\n<a href=\"https://jp.ubuntu.com/download\" target=\"_blank\">本家</a>\nからダウンロードする必要がありますが、海外にあるサーバなのでとっても遅いです。<br />\n国内のミラーサーバの一覧が<a href=\"https://www.ubuntulinux.jp/ubuntu/mirrors#imagemirror\" target=\"_blank\">ここ</a>\nにあるので、お好きなところからダウンロードしてください。<br />\n(私がダウンロードしたときはKDDI研究所が速かった)</p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、CPU数2個以上、メインメモリーを4096MB以上に設定しておくこと</strong></p>\n<blockquote>\n  <p>[!NOTE]\n推奨環境が2 GHzデュアルコアプロセッサ以上、4GBシステムメモリなので。</p>\n</blockquote>\n\n<p>普通にインストール媒体からインストール。<br />\n以下の説明が図付きで分かりやすい:<br />\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a></p>\n\n<blockquote>\n  <p>[!TIP]\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a>では、「仮想マシンの作成」の「ハードウェア」で「EFIを有効化・・・チェックを入れます。」となっているが、\n入れなくて可(入れて試してないので入れて動くのか未確認。図でもチェック入ってないし)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nインストーラにアップデートがある場合は「今すぐアップデート」をクリックしてアップデートし、\n完了したら一旦インストーラを閉じる。<br />\nデスクトップにインストーラアイコンが出来ているので、そこから再度インストーラを起動し、\n最初から設定を行う(これまでの入力は覚えているっぽい)<br />\n参照:<a href=\"https://pc.watch.impress.co.jp/docs/column/ubuntu/1590461.html\" target=\"_blank\">Ubuntu24.04 LTSの新インストーラを徹底解説</a>\nの「インストーラにアップデートがあった場合」</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n<a href=\"https://www.infra-linux.com/menu-linux1/ubuntu24-install/\" target=\"_blank\">Ubuntu 24.04 LTSのインストール</a>では、「アプリケーション」での「拡張選択」を選択とあるが、\n余計なアプリを入れたくないので「既定の選択」のままにしておく。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n</blockquote>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<blockquote>\n  <p>[!NOTE]\n設定アプリ等のGUIで設定を変更した内容をスクリプト化したいとき、どのパスを変更すれば良いか調べるには、ターミナルで</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf watch /\n</code></pre></div>  </div>\n  <p>と実行しておくと、変更される度にパスと設定値が表示される。<br />\nこれを <code class=\"language-plaintext highlighter-rouge\">dconf write</code> で書き込めばGUIで設定した内容をコマンドラインで再現できる。<br />\n参考:<a href=\"https://qiita.com/liqsuq/items/2c7aa741caa94508050b\" target=\"_blank\">デスクトップで変えた設定をCUIでやりたい!(gnome限定)</a><br />\nその関係で前回まで<code class=\"language-plaintext highlighter-rouge\">gsettings</code>コマンドでの設定手順を載せていたが、今回は<code class=\"language-plaintext highlighter-rouge\">dconf</code>コマンドに変更した。</p>\n\n</blockquote>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<p>まだGuestAdditionをインストールしてないからコピペできないけど、BashのTab補完が効くので、\nちょろっと入力してあとは補完に頼れば大丈夫。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">dconf</code>だと変更済みのパスしか補完対象にならないらしく入力が面倒なので、\nここは補完が効く<code class=\"language-plaintext highlighter-rouge\">gsettings</code>コマンドで。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">dconf</code>だとこんな感じ。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ndconf write /org/gnome/desktop/session/idle-delay 0\n\n<span class=\"c\"># 自動画面ロック OFF</span>\ndconf write /org/gnome/desktop/screensaver/lock-enabled <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\n設定 → Privacy & Security → Screen Lock → 自動画面ロックを off に</p>\n\n  <p>==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\n設定 → Privacy & Security → Screen Lock → Blank Screen Delay を「しない」に</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>裏でソフトウェアの更新が動いていると、ロックファイルがロックされてしばらく適用できないので、<br />\nそうなっちゃったらお茶でも飲んでしばらくお待ちください。<br />\nソフトウェアの更新による自動更新を止める方法は後ほど。</p>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">upgrade</code> や <code class=\"language-plaintext highlighter-rouge\">install</code> 時にオプション <code class=\"language-plaintext highlighter-rouge\">-U</code> (<code class=\"language-plaintext highlighter-rouge\">--update</code>)をつけると\n<code class=\"language-plaintext highlighter-rouge\">update</code>も一緒に実行してくれるので命令ひとつで済む。<br />\n(ubuntu 24.04に搭載された2.7.14以降)</p>\n</blockquote>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools dconf-editor gnome-tweaks \n</code></pre></div></div>\n\n<h3 id=\"一旦リブート\">一旦リブート</h3>\n<p>念のため一旦リブートしておく。</p>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>以前にマウントしたものが残ってたらアンマウントしておくこと(インストール後初めてなのでマウントされてることはないけれど)。<br />\nVirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<blockquote>\n  <p>[!TIPS]\nプログラムが自動で始まらない場合は、CDROMのマウント先(たぶん、<code class=\"language-plaintext highlighter-rouge\">/media/${USER}/VBox_GAs_x.x.xx/</code>)に移動して<code class=\"language-plaintext highlighter-rouge\">sudo ./VBoxLinuxAdditions.run</code>を実行すれば良い。</p>\n</blockquote>\n\n<h3 id=\"再度リブート\">再度リブート</h3>\n<p>GuestAdditionによる更新適用のため、もう一度リブート。<br />\n(再ログインだけでもよさそうな感じではあるが、念のため)</p>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから<br />\n「デバイス」→「クリップボードの共有」→「双方向」 を選択。<br />\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<p>また、デスクトップサイズの変更(仮想マシンのウィンドウのサイズ変更)にも対応できる。</p>\n\n<h3 id=\"使わないアプリのアンインストール\">使わないアプリのアンインストール</h3>\n<p>「アプリケーション」で「既定の選択」を選んでいれば要らないアプリは入っていないハズ。</p>\n\n<h2 id=\"お好みで\">お好みで</h2>\n\n<h3 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h3>\n\n<p>bashでクリップボードからペーストするとペーストした文字が反転表示になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n以前の動作が良い場合は<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>に設定を追加するため、以下を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/inputrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n# disable bracked-paste mode\nset enable-bracketed-paste off\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<blockquote>\n  <p>[!NOTE]\nteraterm使ってるときはteratermが確認ダイアログ出すので邪魔なんだけど、<br />\ngnome-terminalだと誤ペースト防止にそのままが良いかも。</p>\n</blockquote>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>以下のコマンドで~/.bashrcに設定を追加。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.bashrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n# プロンプトの設定\nPS1=\"</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\n\n# キーバインドの設定\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-n\": history-search-forward'\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-p\": history-search-backward'\n\n# ディレクトリスタックの表示改善\nfunction pushd() {\n    command pushd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction popd() {\n    command popd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction dirs() {\n    command dirs -v\n}\n\n# 表示色変更\nexport LS_COLORS='di=01;32:ln=01;36:ex=01;31:'\nexport GREP_COLORS='mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'\n\n# lessのオプション\nexport LESS=\"-iMR\"\n\n# grepのオプション指定(GREP_OPTIONS)は廃止されたのでaliasで設定\n# export GREP_OPTIONS=\"--exclude-dir .git\"\nalias grep='grep --exclude-dir .git'\n\n# for pyenv\nexport PYENV_ROOT=/proj/.pyenv    #環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    # 仮想環境名をプロンプトに表示しない場合は以下を有効化\n    # export VIRTUAL_ENV_DISABLE_PROMPT=1\n    eval \"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"sh\">\"          # pyenv 2.0以降で必要\n    eval \"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"sh\">\"\n    eval \"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"sh\">\"\n    export PYTHON_CONFIGURE_OPTS=\"</span><span class=\"se\">\\</span><span class=\"sh\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"sh\">\n    \"\nfi\n\n# for nodenv\nexport NODENV_ROOT=/proj/.nodenv    # 環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    eval \"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"sh\">\"\nfi\n\n# x11からのログイン以外ならDISPLAYを設定する\n# Ubuntu22.04/24.04だとwaylandになるらしい\nif [ \"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"sh\">\" != \"x11\" ] && [ \"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"sh\">\" != \"wayland\" ]; then\n    export DISPLAY=192.168.78.200:0.0\nfi\necho DISPLAY=\"</span><span class=\"nv\">$DISPLAY</span><span class=\"sh\">\"\n\n# direnv 設定\nif type direnv > /dev/null 2>&1; then\n    export EDITOR=vi\n    eval \"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"sh\">\"\n    \n    # # venvの仮想環境名を表示するための設定\n    # show_virtual_env() {\n    #   if [ -n \"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"sh\">\" ]; then\n    #     echo \"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"sh\">)\"\n    #   fi\n    # }\n    # PS1='</span><span class=\"si\">$(</span>show_virtual_env<span class=\"si\">)</span><span class=\"sh\">'</span><span class=\"nv\">$PS1</span><span class=\"sh\">\nfi\n\n# __pycache__ディレクトリの生成を抑制する\nexport PYTHONDONTWRITEBYTECODE=1\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nヒアドキュメント内での変数展開やコマンド置換を抑止するには、\nヒアドキュメント開始文字列(上記では__EOF__)をシングルクォートで囲む。<br />\n参考:<a href=\"https://qiita.com/take4s5i/items/e207cee4fb04385a9952#%E5%A4%89%E6%95%B0%E5%B1%95%E9%96%8B%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E7%BD%AE%E6%8F%9B\" target=\"_blank\">bashのヒアドキュメントを活用する/変数展開・コマンド置換</a></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npython でimportする度に<code class=\"language-plaintext highlighter-rouge\">__pycache__</code>ディレクトリ<code class=\"language-plaintext highlighter-rouge\">*.pyc</code>ファイルが作成されるのが\n鬱陶しかったので、<code class=\"language-plaintext highlighter-rouge\">PYTHONDONTWRITEBYTECODE</code>に1を設定している。<br />\n2回目以降、若干実行時間が延びるかもしれないが、気にするほどでもないので。<br />\n通常の動作がよければ削除してください。</p>\n</blockquote>\n\n<h3 id=\"ubuntu-japanese-teamのパッケージリポジトリを追加\">Ubuntu Japanese Teamのパッケージリポジトリを追加</h3>\n\n<p>日本語特有のパッケージをインストールするため、Ubuntu Japanese Teamのパッケージリポジトリを追加します。<br />\n参考:<a href=\"https://www.ubuntulinux.jp/News/ubuntu2404-ja-remix\" target=\"_blank\">Ubuntu 24.04 LTSの日本語Remixについて</a>\nの最後の部分</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>wget https://www.ubuntulinux.jp/sources.list.d/noble.sources <span class=\"nt\">-O</span> /etc/apt/sources.list.d/ubuntu-ja.sources <span class=\"o\">&&</span><span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade <span class=\"o\">&&</span><span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ubuntu-defaults-ja\n</code></pre></div></div>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">/usr/share/fonts</code>の下(自分専用なら<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>の下)にコピるだけ。<br />\n下では全部コピってる(移動だけど)けど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp/ <span class=\"o\">&&</span> <span class=\"se\">\\</span>\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.3.1/UDEVGothic_v1.3.1.zip <span class=\"o\">&&</span> <span class=\"se\">\\</span>\nunzip UDEVGothic_v1.3.1.zip <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo mv </span>UDEVGothic_v1.3.1 /usr/share/fonts/truetype/ <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<p>設定を反映するため、開いている端末をすべて閉じで、再度起動します。<br />\n開いたままだと設定が中途半端に反映されてしまいます。<br />\nまた、一つでも端末が残っていると新しく開いた端末にも正常な反映がされません。</p>\n\n<blockquote>\n  <p>[!NOTE]\nCLIで設定するならこちら….なんだけど、UUIDが同じとは限らないので参考まで。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/use-system-font    <span class=\"nb\">false\n</span>dconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/font               <span class=\"s2\">\"'UDEV Gothic JPDOC 12'\"</span>\ndconf write /org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/default-size-rows  40\n</code></pre></div>  </div>\n\n  <p>すべてのプロファイルに適用するならこんな感じでもできるかな。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">for </span>prof <span class=\"k\">in</span> <span class=\"si\">$(</span>dconf list /org/gnome/terminal/legacy/profiles:/<span class=\"si\">)</span> <span class=\"p\">;</span> <span class=\"k\">do\n    </span>dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>use-system-font    <span class=\"nb\">false</span>                       <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n    dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>font               <span class=\"s2\">\"'UDEV Gothic JPDOC 12'\"</span>    <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n    dconf write /org/gnome/terminal/legacy/profiles:/<span class=\"k\">${</span><span class=\"nv\">prof</span><span class=\"k\">}</span>default-size-rows  40\n<span class=\"k\">done</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h3>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /NFSROOT <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span> /proj /work /NFSROOT\n</code></pre></div></div>\n\n<h3 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h3>\n\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく<br />\n(CLIでも「どこにインストールする?」と聞かれて「どこだっけ?」となるのでその予防)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<p>設定が正常に行われたか確認するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<p>正常に設定されていれば、以下のような結果が出力される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>0 /dev/sda\n</code></pre></div></div>\n<h3 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h3>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gnome-extensions disable tiling-assistant@ubuntu.com <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/mutter/edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/desktop/wm/preferences/focus-mode        <span class=\"s2\">\"'sloppy'\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/desktop/wm/preferences/auto-raise        <span class=\"nb\">false</span>      <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/desktop/wm/preferences/raise-on-click    <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。<br />\nと書いてあったけど、同じ動き(フォーカスがはずれる)に見える….</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/ding/show-home  <span class=\"nb\">false</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ndconf write /org/gnome/shell/extensions/ding/show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/desktop/interface/cursor-size 48\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nGUIで設定する場合は「設定」→「アクセシビリティ」→「Seeing」→「Cursor Size」で選択<br />\n(数値ではなく画像で選択)</p>\n</blockquote>\n\n<h3 id=\"ファイルnautilusの設定変更\">ファイル(nautilus)の設定変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<h4 id=\"ロケーションバーをデフォルトにする\">ロケーションバーをデフォルトにする</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/nautilus/preferences/always-use-location-entry <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h4 id=\"詳細表示をデフォルトに\">詳細表示をデフォルトに</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/nautilus/preferences/default-folder-viewer <span class=\"s2\">\"'list-view'\"</span> \n</code></pre></div></div>\n\n<h4 id=\"隠しファイルを表示する\">隠しファイルを表示する</h4>\n<p>隠しファイルの表示はちょっと場所が違う</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gtk/gtk4/settings/file-chooser/show-hidden <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n\n<h4 id=\"ゴミ箱削除\">ゴミ箱削除</h4>\n\n<p>私はゴミ箱使わないので消しときます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n<h4 id=\"dockバーを画面下に表示\">Dockバーを画面下に表示</h4>\n\n<p>Windows7っぽく下に移動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/dock-position <span class=\"s2\">\"'BOTTOM'\"</span>\n</code></pre></div></div>\n\n<h4 id=\"アプリケーションをdockバーの上または左に表示\">アプリケーションをDockバーの上(または左)に表示</h4>\n\n<p>Windows7のスタートボタンっぽく左に移動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/show-apps-at-top <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h4 id=\"アイコンサイズの変更\">アイコンサイズの変更</h4>\n\n<p>最後の数字が大きさなので、お好みの大きさにしてください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dconf write /org/gnome/shell/extensions/dash-to-dock/dash-max-icon-size 20\n</code></pre></div></div>\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアとアップデート(software-properties-gtk)を起動\n    <ul>\n      <li>アップデートタブを選択</li>\n      <li>アップデートの自動確認を「なし」に変更</li>\n      <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n      <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n      <li>閉じるをクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a></p>\n\n<p>tewaksを使用する<br />\n<a href=\"https://yassan.hatenablog.jp/entry/2024/05/01/Ubuntu_Bdgie%E3%83%A1%E3%83%A2%EF%BC%9A_Tweeks%E3%81%A7Caps%E3%81%A8Ctrl%E3%81%AESwap\" target=\"_blank\">Ubuntu Bdgieメモ: TweeksでCapsとCtrlのSwap</a><br />\nというのもある。 お好きな方で。</p>\n\n<p>Native環境にインストールしてないので未確認だけど…</p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下のように「quiet splash」を削除。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h2 id=\"ネットワークアダプタの追加\">ネットワークアダプタの追加</h2>\n<p>ホストのWindowsや外部マシンからアクセスできるようにデフォルトのNAT以外にネットワークアダプタを追加します。<br />\n仮想マシンの設定を変更する必要があるので、一旦仮想マシンをシャットダウンしてください。</p>\n\n<h3 id=\"ネットワークアダプタ追加設定\">ネットワークアダプタ追加設定</h3>\n<ul>\n  <li>Virtualboxマネージャ で対象の仮想マシンを選択し、設定ボタンをクリック。</li>\n  <li>開いたウィンドウの左側で「ネットワーク」を選択</li>\n  <li>右側のウィンドウで「アダプタ2」をクリック\n    <ul>\n      <li>「ネットワークアダプタを有効化」にチェックを入れる</li>\n      <li>「割り当て」で「ホストオンリーアダプター」を選択</li>\n    </ul>\n  </li>\n  <li>右側のウィンドウで「アダプタ3」をクリック\n    <ul>\n      <li>「ネットワークアダプタを有効化」にチェックを入れる</li>\n      <li>「割り当て」で「ブリッジアダプター」を選択</li>\n      <li>「名前」で割り当てる物理的なネットワークアダプタを選択</li>\n    </ul>\n  </li>\n  <li>OKをクリック</li>\n</ul>\n\n<p>設定が終わったら仮想マシンを起動します。</p>\n\n<blockquote>\n  <p>[!NOTE]\nNATも削除してブリッジアダプターだけでも大丈夫な気もするが、ネットワーク不調になっても\nホストOS(Windows)からアクセスできるようにホストオンリーアダプターも追加しておく。<br />\nまた、ホストオンリーアダプターも不調になったときでも\nWebアクセスなど最低限のアクセスができるようNATも残しておく。<br />\n要らないと思ったら上記の設定の「ネットワークアダプタを有効化」のチェックをはずせば良い。</p>\n</blockquote>\n\n<h3 id=\"ネットワークのコネクション名の変更\">ネットワークのコネクション名の変更</h3>\n\n<p>ネットワークコントローラを追加したので、ネットワークマネージャのコネクション一覧を見てみます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection \n</code></pre></div></div>\n\n<p>結果はこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>NAME            UUID                                  TYPE      DEVICE \nnetplan-enp0s3  1eef7e45-3b9d-3043-bee3-fc5925c90273  ethernet  enp0s3 \n有線接続 1      eef7ccb4-2a33-336f-bb48-701058d5e6ce  ethernet  enp0s8 \n有線接続 2      eff49436-1aac-36eb-b1f6-2a32cc246b83  ethernet  enp0s9 \nlo              d30bde24-f5dd-458d-86b0-b5c8870f4485  loopback  lo     \n</code></pre></div></div>\n<p>「有線接続 1」と「有線接続 2」がさきほど追加したホストオンリーアダプターとブリッジアダプターなのですが、\nどっちがどっちか判別できません。<br />\nそこで判別できるような名前に変更しておきます。<br />\n(192.168.xx.xxのものだけ変更。NATとloはそのまま)<br />\n変更後のコネクション名はネットワークとの対応が分かりやすくなるよう、\n≪IPアドレスの3桁目≫_LINE としています。<br />\nお好みの名前に変更してください。<br />\n(現在、日本語だと文字化けするバグがあるようです。そのうち直ると思いますが)</p>\n\n<p>手動で設定するのは面倒なので、以下のスクリプトファイルを作成して実行してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># すべてのコネクション名を改行区切りで配列に取得</span>\n<span class=\"nv\">ORG_IFS</span><span class=\"o\">=</span><span class=\"nv\">$IFS</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"s1\">$'</span><span class=\"se\">\\n</span><span class=\"s1\">'</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span>nmcli  <span class=\"nt\">-t</span> <span class=\"nt\">-f</span> NAME connection<span class=\"si\">)</span><span class=\"o\">)</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"nv\">$ORG_IFS</span>        <span class=\"c\"># 元に戻す</span>\n\n<span class=\"k\">for </span>i <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"p\">!connections[@]</span><span class=\"k\">}</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各コネクションについて</span>\n    <span class=\"c\"># 直接取り出すとうまくいかないのでインデックス取り出して内容取得</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[</span><span class=\"nv\">$i</span><span class=\"p\">]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n\n    <span class=\"c\"># 現在設定されているIPv4アドレスを取得</span>\n    <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.ADDRESS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n    <span class=\"c\"># 結果⇒ 「IP4.ADDRESS[1]: 192.168.78.215/24」</span>\n    \n    <span class=\"c\"># IPアドスの各桁とサブネットマスクを空白区切りで取得し、配列に代入</span>\n    <span class=\"c\"># 1個目のsed ⇒ 192.168.78.215/24</span>\n    <span class=\"c\"># 2個目のsed ⇒ 192 168 78 215 24</span>\n    <span class=\"nv\">ipv4octet</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/[</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]/ /g\"</span><span class=\"si\">)</span><span class=\"o\">)</span>\n\n    <span class=\"c\"># echo ${str}</span>\n    <span class=\"c\"># echo ${ipv4octet[0]}  ${ipv4octet[1]}  ${ipv4octet[2]}  ${ipv4octet[3]}  ${ipv4octet[4]}</span>\n    \n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 192 <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 168 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n        <span class=\"c\"># 192.168.XX.XX のコネクション</span>\n        <span class=\"c\"># echo \"**** ${str} ****\"</span>\n\n        <span class=\"c\"># コネクション名を\"≪IPアドレスの3桁目≫_LINE\"変更する</span>\n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> connection.id </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[2]</span><span class=\"k\">}</span><span class=\"s2\">_LINE</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone\n\n</span><span class=\"nb\">echo</span> <span class=\"o\">==</span><span class=\"nv\">RESULT</span><span class=\"o\">==</span>\nnmcli  connection\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)→<br />\n左側のネットワークを選択し、対象のNICの設定ボタン(歯車アイコン)をクリック→<br />\n開いたウィンドウで「identity」タブをクリック→<br />\n「名前」に設定する名前を設定→<br />\n「適用」をクリック</p>\n</blockquote>\n\n<h3 id=\"sambaのインストール\">sambaのインストール</h3>\n\n<h4 id=\"ツール本体のインストール\">ツール本体のインストール</h4>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<h4 id=\"etcsambasmbconf-の設定を変更\">/etc/samba/smb.conf の設定を変更</h4>\n\n<p>以下のコマンドを実行します。<br />\n変更内容は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code>をバックアップ</li>\n  <li>[homes]セクションを有効化</li>\n  <li>[homes]セクションの「read only」を「no」に設定</li>\n  <li>[global]セクションに「map archive = no」を追加</li>\n  <li>ファイル末尾に[proj][work][NFSROOT]セクションを追加<br />\n他にも追加したいセクション(ディレクトリの設定)があったら追加してください。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /etc/samba/smb.conf /etc/samba/smb.conf.org     <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'/\\[homes\\]/s/;//g'</span> /etc/samba/smb.conf     <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'/\\[homes\\]/,/\\[/ {s/^;[^\\[]//g}'</span> /etc/samba/smb.conf   <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"/</span><span class=\"se\">\\[</span><span class=\"s2\">homes</span><span class=\"se\">\\]</span><span class=\"s2\">/,/^</span><span class=\"se\">\\[\\|</span><span class=\"s2\">^;</span><span class=\"se\">\\s</span><span class=\"s2\">*</span><span class=\"se\">\\[</span><span class=\"s2\">/ s/read only = .*/read only = no/1\"</span> /etc/samba/smb.conf <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s1\">'s/\\(^\\[global\\].*\\)/\\1\\n\\n    map archive = no/'</span> /etc/samba/smb.conf   <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/samba/smb.conf <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = </span><span class=\"nv\">$USER</span><span class=\"sh\">\nforce create mode = 0664\nforce directory mode = 0665\n</span><span class=\"no\">\n__EOF__\n</span></code></pre></div></div>\n\n<h4 id=\"ユーザの追加\">ユーザの追加</h4>\n\n<p>sambaのためのユーザを追加します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>pdbedit <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n</code></pre></div></div>\n\n<p>新しいパスワードを聞かれるので入力</p>\n\n<blockquote>\n  <p>[!NOTE]\n以前は<code class=\"language-plaintext highlighter-rouge\">sudo smbpasswd -a $USER</code> だったけど、最近は上のコマンドが正式らしい。<br />\n(まだ <code class=\"language-plaintext highlighter-rouge\">smbpasswd</code>も使えるけど)</p>\n</blockquote>\n\n<h4 id=\"sambaの再起動\">sambaの再起動</h4>\n\n<p>設定を反映するため、sambaを再起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl reload  smbd.service <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>systemctl restart smbd.service\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">Warning: The unit file, source configuration file or drop-ins of smbd.service changed on disk. Run 'systemctl daemon-reload' to reload units.</code>\nと言われたときは、<code class=\"language-plaintext highlighter-rouge\">sudo systemctl daemon-reload</code>を実行</p>\n</blockquote>\n\n<h3 id=\"nfsのインストール\">NFSのインストール</h3>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<h4 id=\"インストール-1\">インストール</h4>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<h4 id=\"設定ファイルの変更\">設定ファイルの変更</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">/NFSROOT</code>をエクスポートするため、<code class=\"language-plaintext highlighter-rouge\">/etc/exports</code>を修正。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span> /etc/exports <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<h4 id=\"再起動\">再起動</h4>\n\n<p>変更した設定を反映するため、NFSを再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl restart nfs-server.service \n</code></pre></div></div>\n\n<h4 id=\"確認\">確認</h4>\n\n<h5 id=\"exportできているか確認\">exportできているか確認</h5>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>こんな感じで表示されればOK</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT      \t192.168.0.0/255.255.0.0\n</code></pre></div></div>\n\n<h5 id=\"別のマシンからマウントしてみる\">別のマシンからマウントしてみる</h5>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n\n<p>別のマシンから以下のコマンドを実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">abc</code>の下に今インストールしているPCの<code class=\"language-plaintext highlighter-rouge\">/NFSROOT</code>ディレクトリのファイルが見えたらOK</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<p>マスタイメージを残しておいて、色々な環境をお試しするには仮想マシンをクローンして使うのがおススメ。</p>\n<ul>\n  <li>VirtualBoxのメインウィンドウでマスタイメージの仮想マシンを右クリック→クローンを選択。</li>\n  <li>名前とパスを設定し、MACアドレスのポリシーは「すべてのネットワークアダプタでMACアドレスを生成」を選択。</li>\n  <li>「次へ」をクリック</li>\n  <li>すべてをクローンにチェックが入っていることを確認し、「完了」をクリック\nクローンが終了するまで待つ。</li>\n</ul>\n\n<p>クローンした仮想マシンを起動し、必要な変更を加える。</p>\n\n<h2 id=\"ネットワーク設定の変更\">ネットワーク設定の変更</h2>\n\n<p>マシン名とか同じ名前だと色々不都合があるので、変更しておく。<br />\n他のクローン仮想環境と同時に使わないならそのままでも良いけど。<br />\nIPアドレスも固定で割り振っておくと名前が引けない時にさくっと分かってなにかと便利…\nなんだけど、最近はWindowsもUbuntuもRaspberryPiもmDNSがサポートされてるから自動割り当てのままでもそんなに不便はないかも。</p>\n\n<p>ポリシー</p>\n<ul>\n  <li>IPアドレスの最終桁を決める(numberとする)。</li>\n  <li>ホスト名をskull≪number≫とする</li>\n  <li>ホストオンリーアダプタ/ブリッジアダプタの設定変更\n    <ul>\n      <li>IPv4アドレスを手動設定にする</li>\n      <li>IPv4アドレスの1桁目~3桁目、サブネットマスクを現在のIPアドレスと同じにする</li>\n      <li>IPv4アドレスの最終桁をnumberにする</li>\n      <li>GW、DNSが設定されていれば同じアドレスを設定する</li>\n    </ul>\n  </li>\n</ul>\n\n<p>以下の内容でスクリプトファイルを作成し、実行する。<br />\nホスト名などは適宜変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/usr/bin/env bash</span>\n\n<span class=\"c\"># 設定する数値の入力</span>\n<span class=\"nb\">read</span> <span class=\"nt\">-p</span> <span class=\"s2\">\"数値を入力してください: \"</span> number \n\n<span class=\"c\"># echo ${number}</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[[</span> <span class=\"o\">!</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">=</span>~ ^[0-9]+<span class=\"nv\">$ </span><span class=\"o\">]]</span><span class=\"p\">;</span> <span class=\"k\">then\n  </span><span class=\"nb\">echo</span> <span class=\"s1\">'数値ではありません'</span>\n  <span class=\"nb\">exit </span>1\n<span class=\"k\">fi\n\nif</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"nt\">-lt</span> 2 <span class=\"o\">]</span> <span class=\"o\">||</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"nt\">-gt</span> 254 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n  </span><span class=\"nb\">echo</span> <span class=\"s1\">'数値は2~254でなければなりません'</span>\n  <span class=\"nb\">exit </span>1\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># ホスト名の変更</span>\n<span class=\"nv\">old_name</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">hostname</span><span class=\"si\">)</span>\n<span class=\"nv\">new_name</span><span class=\"o\">=</span><span class=\"s2\">\"skull</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo nmcli general hostname </span><span class=\"k\">${</span><span class=\"nv\">new_name</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n<span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo sed -i -e \"</span>s/<span class=\"k\">${</span><span class=\"nv\">old_name</span><span class=\"k\">}</span>/<span class=\"k\">${</span><span class=\"nv\">new_name</span><span class=\"k\">}</span>/<span class=\"s2\">\" /etc/hosts\"</span>\n<span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n<span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n\n<span class=\"c\"># すべてのコネクション名を改行区切りで配列に取得</span>\n<span class=\"nv\">ORG_IFS</span><span class=\"o\">=</span><span class=\"nv\">$IFS</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"s1\">$'</span><span class=\"se\">\\n</span><span class=\"s1\">'</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span>nmcli  <span class=\"nt\">-t</span> <span class=\"nt\">-f</span> NAME connection<span class=\"si\">)</span><span class=\"o\">)</span>\n<span class=\"nv\">IFS</span><span class=\"o\">=</span><span class=\"nv\">$ORG_IFS</span>        <span class=\"c\"># 元に戻す</span>\n\n<span class=\"k\">for </span>i <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"p\">!connections[@]</span><span class=\"k\">}</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各コネクションについて</span>\n    <span class=\"c\"># 直接取り出すとうまくいかないのでインデックス取り出して内容取得</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[</span><span class=\"nv\">$i</span><span class=\"p\">]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># 現在設定されているIPv4アドレスを取得</span>\n    <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.ADDRESS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n    <span class=\"c\"># 結果⇒ 「IP4.ADDRESS[1]: 192.168.78.215/24」</span>\n    \n    <span class=\"c\"># IPアドスの各桁とサブネットマスクを空白区切りで取得し、配列に代入</span>\n    <span class=\"c\"># 1個目のsed ⇒ 192.168.78.215/24</span>\n    <span class=\"c\"># 2個目のsed ⇒ 192 168 78 215 24</span>\n    <span class=\"nv\">ipv4octet</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/[</span><span class=\"se\">\\.\\/</span><span class=\"s2\">]/ /g\"</span><span class=\"si\">)</span><span class=\"o\">)</span>\n    \n    <span class=\"c\"># echo ${str}</span>\n    <span class=\"c\"># echo ${ipv4octet[0]}  ${ipv4octet[1]}  ${ipv4octet[2]}  ${ipv4octet[3]}  ${ipv4octet[4]}</span>\n    \n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 192 <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span> <span class=\"nt\">-eq</span> 168 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n        <span class=\"c\"># 192.168.XX.XX のコネクション</span>\n        <span class=\"c\"># echo \"**** ${str} ****\"</span>\n        \n        <span class=\"c\"># 現在設定されているIPv4GWアドレスを取得</span>\n        <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.GATEWAY\"</span> <span class=\"si\">)</span>\n        <span class=\"c\"># 結果⇒ 「IP4.GATEWAY: 192.168.78.1」</span>\n        \n        <span class=\"c\"># IPv4GWアドレスを抽出(未定義では--なので-も抽出対象)</span>\n        <span class=\"nv\">gwaddr</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.</span><span class=\"s2\">-]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span><span class=\"si\">)</span>\n        <span class=\"c\"># \"--\" だったら空文字にする</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">=</span> <span class=\"s2\">\"--\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then </span><span class=\"nv\">gwaddr</span><span class=\"o\">=</span><span class=\"s2\">\"\"</span><span class=\"p\">;</span> <span class=\"k\">fi</span>\n        \n        <span class=\"c\"># 現在設定されているIPv4DNSアドレスを取得(未定義ならこのエントリがない)</span>\n        <span class=\"nv\">str</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli connection show <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"s2\">\"</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"IP4.DNS</span><span class=\"se\">\\[</span><span class=\"s2\">1</span><span class=\"se\">\\]</span><span class=\"s2\">\"</span> <span class=\"si\">)</span>\n        <span class=\"c\"># 結果⇒ 「IP4.DNS[1]: 192.168.78.1」</span>\n        \n        <span class=\"c\"># IPv4DNSアドレスを抽出</span>\n        <span class=\"nv\">dnsaddr</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$str</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/.*:[ </span><span class=\"se\">\\t</span><span class=\"s2\">]</span><span class=\"se\">\\+\\(</span><span class=\"s2\">[0-9</span><span class=\"se\">\\.</span><span class=\"s2\">]</span><span class=\"se\">\\+\\)</span><span class=\"s2\">.*</span><span class=\"nv\">$/</span><span class=\"se\">\\1</span><span class=\"s2\">/g\"</span><span class=\"si\">)</span>\n        \n        <span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"ipv4.method manual ipv4.addresses </span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[0]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[1]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[2]</span><span class=\"k\">}</span><span class=\"s2\">.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/</span><span class=\"k\">${</span><span class=\"nv\">ipv4octet</span><span class=\"p\">[4]</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n            </span><span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\"> ipv4.gateway </span><span class=\"k\">${</span><span class=\"nv\">gwaddr</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">fi\n        if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$gwaddr</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n            </span><span class=\"nv\">set_str</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\"> ipv4.dns </span><span class=\"k\">${</span><span class=\"nv\">dnsaddr</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"k\">fi</span>\n        \n        <span class=\"c\"># echo ipv4.method manual ${set_str}</span>\n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">set_str</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n        \n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection down   </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n        \n        <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"nmcli connection up     </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n        <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n        <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone\n\n</span><span class=\"nb\">echo</span> <span class=\"o\">==</span><span class=\"nv\">DONE</span><span class=\"o\">==</span>\n</code></pre></div></div>\n\n<p>実行後、<br />\n<code class=\"language-plaintext highlighter-rouge\">ip address</code>や<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPアドレスが変更されていること、<br />\n<code class=\"language-plaintext highlighter-rouge\">hostname</code>でホスト名が変更されていること、<br />\n<code class=\"language-plaintext highlighter-rouge\">cat /etc/hosts</code>でhostsが変更されていること、\nをそれぞれ確認する。</p>\n\n<blockquote>\n  <p>[!TIP]\nIPアドレスの変更をGUIで行うには以下。<br />\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nこのスクリプトをマスタイメージのどこか(例えば<code class=\"language-plaintext highlighter-rouge\">~/bin</code>とか)に保存しておけば、\nクローンする度にスクリプトを実行すればIPアドレスとホスト名の変更をイッパツで完了できる。</p>\n</blockquote>\n\n<h2 id=\"あとはお約束\">あとはお約束</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-U</span> upgrade\n</code></pre></div></div>\n\n<p>VirtalBoxのバージョンが変更されているときは、GuestAdditionのバージョンアップも忘れずに。<br />\nまた、マスタイメージは定期的に<code class=\"language-plaintext highlighter-rouge\">sudo apt -U upgrade</code>しておくと\nクローン時のアップデート時間が短くて済む。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(Bookworm)のインストール(Raspberry Pi Imager)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(Bookworm)のインストール(Raspberry Pi Imager)</h1>\n      <p>Raspberry Pi OS(bookworm)のRaspberry Pi Imagerを使用したインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>RaspberrypiOSがBookwormになったので、インストール方法のメモ。<br />\n基本的にBullseyeのときと変わらないけど、ちょっと変わったところもあるので。<br />\n<a href=\"/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Bullseyeのときの手順メモ</a>も参照してください。</p>\n\n<h1 id=\"sdカードへの書き込み\">SDカードへの書き込み</h1>\n<p>Raspberry Pi Imager で書き込み。<br />\n使い方はあちこちに書いてあるけど、例えばこちら。</p>\n<ul>\n  <li><a href=\"https://qiita.com/mmake/items/576a2f60dffcd9291da3/\" target=\"_blank\">Raspberry Pi Imager のインストールと使い方</a></li>\n</ul>\n\n<p>バージョン変わると微妙に手順が変わったりするので、最新情報はぐぐってちょ。</p>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n<blockquote>\n  <p>[!NOTE]\n下記の変更をイッパツで行うスクリプトは以下。<br />\nWindowsのコマンドプロンプトで実行すると想定。  Windows版python必要。<br />\nそれぞれの<code class=\"language-plaintext highlighter-rouge\">F=</code>の部分を対象のドライブレターに変更する。</p>\n\n  <ul>\n    <li>UARTにUARTコネクタを使用する場合はこちら\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import re;F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">onfig.txt';a=open(F).read();a=re.sub(r'</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">(?!.*</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">)', '[pi5]</span><span class=\"se\">\\n</span><span class=\"s2\">dtparam=uart0</span><span class=\"se\">\\n\\n</span><span class=\"s2\">[all]</span><span class=\"se\">\\n</span><span class=\"s2\">enable_uart=1</span><span class=\"se\">\\n</span><span class=\"s2\">', a, flags=re.DOTALL);open(F, 'w').write(a)\"</span>\npython <span class=\"nt\">-c</span> <span class=\"s2\">\"F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">mdline.txt';a=open(F).read();a=a.replace(' quiet', '').replace(' splash', '').replace(' plymouth.ignore-serial-consoles', '')+' ipv6.disable=1';open(F, 'w').write(a)\"</span>\n</code></pre></div>      </div>\n    </li>\n    <li>UARTに40pinヘッダのpin8/10(GPIOs 14 & 15)を使用する場合はこちら\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python <span class=\"nt\">-c</span> <span class=\"s2\">\"import re;F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">onfig.txt';a=open(F).read();a=re.sub(r'</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">(?!.*</span><span class=\"se\">\\[</span><span class=\"s2\">all</span><span class=\"se\">\\]</span><span class=\"s2\">)', '[pi5]</span><span class=\"se\">\\n</span><span class=\"s2\">dtparam=uart0_console</span><span class=\"se\">\\n\\n</span><span class=\"s2\">[all]</span><span class=\"se\">\\n</span><span class=\"s2\">enable_uart=1</span><span class=\"se\">\\n</span><span class=\"s2\">', a, flags=re.DOTALL);open(F, 'w').write(a)\"</span>\npython <span class=\"nt\">-c</span> <span class=\"s2\">\"F=r'G:</span><span class=\"se\">\\c</span><span class=\"s2\">mdline.txt';a=open(F).read();a=a.replace(' quiet', '').replace(' splash', '').replace(' plymouth.ignore-serial-consoles', '')+' ipv6.disable=1';open(F, 'w').write(a)\"</span>\n</code></pre></div>      </div>\n    </li>\n  </ul>\n</blockquote>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行を以下に変更</p>\n\n<ul>\n  <li>UARTにUARTコネクタを使用する場合はこちら</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[pi5]\ndtparam=uart0\n\n[all]\nenable_uart=1\n</code></pre></div></div>\n\n<ul>\n  <li>UARTに40pinヘッダのpin8/10(GPIOs 14 & 15)を使用する場合はこちら</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[pi5]\ndtparam=uart0_console\n\n[all]\nenable_uart=1\n</code></pre></div></div>\n\n<h2 id=\"ipv6の無効化\">IPv6の無効化</h2>\n<p>IPv6を無効化しておきたいときは、\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する。<br />\nこのファイルは1行で書かないといけないので、改行してはいけない。</p>\n\n<h2 id=\"ブートログの表示\">ブートログの表示</h2>\n\n<p>ブートログが見えないと不安な人は、<br />\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> から <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code>\nを削除しておくとよい。</p>\n<blockquote>\n  <p>[!NOTE]\nLITE版では<code class=\"language-plaintext highlighter-rouge\">quiet</code>を削除(それ以外は指定されていないので)</p>\n</blockquote>\n\n<h1 id=\"最初の起動\">最初の起動</h1>\n<p>書き込んだSDカードをRaspberry Piに挿入して電源ON。<br />\nごちょごちょと設定したあと、起動する(途中2回ほどrebootしてるらしい)</p>\n\n<h1 id=\"お約束\">お約束</h1>\n\n<p>ソフト類を最新版にする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n<span class=\"nb\">sudo </span>reboot \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <h4 id=\"ウィンドウマネージャをopenboxに変更したい場合\">ウィンドウマネージャをOpenboxに変更したい場合</h4>\n  <p>VNCに不具合がるなどの理由で以前のバージョンと同じX11ベースのOpenboxに変更したい場合は以下の手順で変更する。<br />\nちなみにOpenboxに変更したい場合は以下のコマンドで変更できる。<br />\nVNCを有効化した後にウィンドウマネージャを変更すると動作が不安定になることがあるので、VNCを有効化する前に変更するのがベター。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config nonint do_wayland W1\n<span class=\"nb\">sudo </span>reboot \n</code></pre></div>  </div>\n\n  <p>VNC有効化後、以下のコマンドでデフォルトのウィンドウマネージャ(wayfire)が無効になっていることを確認する。<br />\nなにも表示されなければOK</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pgrep wayfire\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"お好みで\">お好みで</h1>\n\n<p>その他お好み設定は\n<a href=\"/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</a>\nと同じ。<br />\nめんどくさいのでスクリプトを実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.githubusercontent.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c/raw/pi_setup1.sh\nbash pi_setup1.sh \n<span class=\"c\"># 途中sambaのパスワード設定がある  </span>\n<span class=\"nb\">sudo </span>reboot \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nIpV6無効の環境でwayfireでVNCを有効にする場合、VNCを有効化する前に\n以下のコマンドでwayfireでIPv4を使用するように設定する必要がある。<br />\nこの処理は上の<code class=\"language-plaintext highlighter-rouge\">pi_setup1.sh</code>の処理に含まれている。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /etc/wayvnc/config /etc/wayvnc/config.org\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s/</span><span class=\"se\">\\:\\:</span><span class=\"s2\">/0</span><span class=\"se\">\\.</span><span class=\"s2\">0</span><span class=\"se\">\\.</span><span class=\"s2\">0</span><span class=\"se\">\\.</span><span class=\"s2\">0/g\"</span> /etc/wayvnc/config\n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">/etc/wayvnc/config</code>の2行目の<code class=\"language-plaintext highlighter-rouge\">address=::</code>を<code class=\"language-plaintext highlighter-rouge\">address=0.0.0.0</code>に変更している。</p>\n</blockquote>\n\n<h1 id=\"pyenvのインストール\">pyenvのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<p>ここで一旦ログアウト&再ログイン</p>\n\n<h1 id=\"pythonのインストール\">pythonのインストール</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.11.9\npyenv shell 3.11.9 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\npyenv shell <span class=\"nt\">--unset</span> \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 22.04をNative環境にインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 22.04をNative環境にインストール</h1>\n      <p>Ubuntu 22.04をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuのダウンロード\">Ubuntuのダウンロード</h1>\n<p><a href=\"https://www.ubuntulinux.jp/download\" target=\"_blank\">Ubuntuの入手</a>からダウンロード<br />\nSecure Boot環境で日本語RemixのISOファイルを使うと<code class=\"language-plaintext highlighter-rouge\">Verification failed: (0x1A) Security Violation</code>\nと怒らたので、jp.ubuntu.comのダウンロードページからUbuntu Desktopをダウンロードした。<br />\nブータブルUSBを作るには、Rufus等を使う(ググってちょ)。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<p>以下の参考ページを参照して起動するとこまでやってちょ。</p>\n\n<ul>\n  <li><a href=\"https://ippei8jp.github.io/memoBlog/2021/07/15/install2004_native.html\" target=\"_blank\">UbuntuをNative環境にインストールする(20.04)</a></li>\n  <li><a href=\"https://ippei8jp.github.io/memoBlog/2022/07/24/install2204.html\" target=\"_blank\">Ubuntu 22.04のVirtualBoxへのインストール</a></li>\n  <li>Ubuntu 22.04 デュアルブートのインストール方法は以下を参考\n    <ul>\n      <li><a href=\"https://dailylife.pman-bros.com/ubuntu22_install/\" target=\"_blank\">Ubuntu 22.04 LTS をインストールする -【マルチブート編】</a></li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"お好みで\">お好みで</h1>\n<p>作業中に画面が消えると鬱陶しいのでパワマネ無効化。<br />\nTAB補完使えばコピペするほどでもないので、最初にやっとく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h1 id=\"最新版にupdate\">最新版にupdate</h1>\n\n<p>とりあえず最新版に</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ついでにsshもインストールしておく。<br />\nwebで調べたコマンドをコピペしたいので。<br />\n参考:<a href=\"https://ippei8jp.github.io/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">ubuntuにSSHサーバをセットアップする</a></p>\n\n<ul>\n  <li>パッケージをインストール\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\n</code></pre></div>    </div>\n    <ul>\n      <li>これだけでパスワード認証は繋がるはず。</li>\n    </ul>\n  </li>\n  <li>公開鍵認証を使用する場合は、公開鍵を<code class=\"language-plaintext highlighter-rouge\">~/.ssh/authorized_keys</code>に追記し、attribute変更。<br />\n(コピペで追記したいのでsshで接続したターミナルから作業するのがベター)</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/.ssh\nvi ~/.ssh/authorized_keys\n<span class=\"c\">### 公開鍵を追記 ###</span>\n<span class=\"nb\">chmod </span>600 ~/.ssh/authorized_keys\n</code></pre></div></div>\n\n<p>念のためここでリブート。</p>\n\n<h1 id=\"chromeとリモートデスクトップのインストール\">chromeとリモートデスクトップのインストール</h1>\n<p>参考: <a href=\"https://qiita.com/grgrjnjn/items/a5c4da336031b63f09a6\" target=\"_blank\">UbuntuにChromeをインストールする手順</a><br />\n参考: <a href=\"https://zenn.dev/karaage0703/articles/cfde5e6a4f43c3\" target=\"_blank\">Linux(Ubuntu)のリモートデスクトップ設定(Google Chrome リモートデスクトップ/xrdp)</a></p>\n\n<h2 id=\"おまじない\">おまじない</h2>\n<p>chrome リモートデスクトップをインストールすると、ローカル端末でのログインができなくなるので、\n以下の処理を行う。</p>\n\n<p>新しく使用する<code class=\"language-plaintext highlighter-rouge\">.desktop</code>ファイルを作成(ubuntuをベースに使用)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /usr/share/xsessions/\n<span class=\"nb\">sudo cp </span>ubuntu.desktop ubuntu-local.desktop\n</code></pre></div></div>\n\n<p>以下のパッチをあてる。</p>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">Name</code>の変更と<code class=\"language-plaintext highlighter-rouge\">Exec</code>に<code class=\"language-plaintext highlighter-rouge\">DISPLAY=\":0\"</code>を追加</p>\n</blockquote>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ubuntu.desktop      2022-04-08 04:07:53.000000000 +0900\n</span><span class=\"gi\">+++ ubuntu-local.desktop        2023-11-11 07:25:37.223280734 +0900\n</span><span class=\"p\">@@ -1,7 +1,7 @@</span>\n [Desktop Entry]\n<span class=\"gd\">-Name=Ubuntu\n</span><span class=\"gi\">+Name=Ubuntu on local\n</span> Comment=This session logs you into Ubuntu\n<span class=\"gd\">-Exec=env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu\n</span><span class=\"gi\">+Exec=env DISPLAY=\":0\" GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu\n</span> TryExec=/usr/bin/gnome-shell\n Type=Application\n DesktopNames=ubuntu:GNOME\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nローカル端末でログインするときはユーザ名選択後、画面右下の歯車アイコンをクリックし、\n「Ubuntu on local」を選択(一度選択すれば記憶されるので2度目以降は確認だけでOK)してログインする。\n (作成したセッションを選択可能にするには、リブートが必要)</p>\n</blockquote>\n\n<h2 id=\"chromeとリモートデスクトップのインストール-1\">chromeとリモートデスクトップのインストール</h2>\n\n<p>手間を省くためにコマンドラインで以下を実行(sshからで可)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール時にエラーにならないようおまじない</span>\n<span class=\"nb\">mkdir</span> ~/.config/chrome-remote-desktop\n\n<span class=\"c\"># リブート時に消せるようにダウンロード先に/tmpを使う</span>\n<span class=\"nb\">cd</span> /tmp\n\n<span class=\"c\"># chromeのダウンロード</span>\nwget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb\n<span class=\"c\"># chromeのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> ./google-chrome-stable_current_amd64.deb\n\n<span class=\"c\"># remote desktopのダウンロード</span>\nwget https://dl.google.com/linux/direct/chrome-remote-desktop_current_amd64.deb\n<span class=\"c\"># remote desktopのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> ./chrome-remote-desktop_current_amd64.deb\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nインストール時、以下のように提案/推奨されるが、入れなくても大丈夫。<br />\n提案パッケージ:<br />\n  python-psutil-doc x11-xfs-utils<br />\n推奨パッケージ:<br />\n  xserver-xorg-video-dummy pipewire</p>\n</blockquote>\n\n<h2 id=\"chrome起動して初期設定googleにログイン\">chrome起動して初期設定&Googleにログイン</h2>\n<p>ローカル端末でchrome起動</p>\n<ul>\n  <li>既定のブラウザにするか、障害レポートを送信するかを選んでOK</li>\n  <li>「Chromeを独自にカスタマイズ」で「開始する」をクリック\n    <ul>\n      <li>あとはお好みで設定</li>\n    </ul>\n  </li>\n  <li>「あなたのChromeをいつでもどこでも」で「続行」をクリック\n    <ul>\n      <li>chromeへのログインで使用するGoogleアカウントにログイン</li>\n    </ul>\n  </li>\n  <li>リモートデスクトップを検索し、「Chromeリモートデスクトップ」を開く\n    <ul>\n      <li><a href=\"https://remotedesktop.google.com/?hl=ja&pli=1\" target=\"_blank\">https://remotedesktop.google.com/?hl=ja&pli=1</a></li>\n    </ul>\n  </li>\n  <li>「パソコンにアクセス」をクリック</li>\n  <li>「リモートアクセスの設定」の「ONにする」ボタンをクリック</li>\n  <li>「名前の設定」で名前を設定して「次へ」</li>\n  <li>「PINの入力」で設定するPINを2回入力して「起動」</li>\n  <li>\n    <p>パスワード入力を求められるのでパスワード入力</p>\n  </li>\n  <li>ローカル端末でログアウト\n    <blockquote>\n      <p>[!WARNING]\nローカル端末でログインしたままだとリモートデスクトップがつながっても画面表示されない</p>\n    </blockquote>\n  </li>\n</ul>\n\n<h2 id=\"window-pc側から接続\">Window PC側から接続</h2>\n<p>Windows PCでリモートデスクトップアプリを起動し、Ubuntuマシンに接続する<br />\nセッションの選択ではUbunto on Xorg または Ubuntuを選択(たぶんどっちも同じ)</p>\n\n<h3 id=\"おまじない1\">おまじない1</h3>\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。<br />\nこのダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下の内容で作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n<p>参考: <a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></p>\n\n<h3 id=\"おまじない2\">おまじない2</h3>\n<p>接続時、毎回セッションの選択をするのは面倒なので、自動で選択できるようにしようとしたが、<br />\nこれをやるとローカル端末でログインできなくなるのでやめておく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n参考までに手順を記載しておく<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.chrome-remote-desktop-session</code>を以下の内容で作成する</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>exec /etc/X11/Xsession 'env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu'\n</code></pre></div>  </div>\n  <p>env以下は使用するセッションに合わせて変更すること。<br />\n(<code class=\"language-plaintext highlighter-rouge\">/usr/share/xsessions/≪セッション名≫.desktop</code>の<code class=\"language-plaintext highlighter-rouge\">Exec</code>行の内容)</p>\n</blockquote>\n\n<h1 id=\"使いそうなプログラムのインストールと使わないプログラムのアンインストール\">使いそうなプログラムのインストールと使わないプログラムのアンインストール</h1>\n\n<h2 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h2>\n\n<p>ま、使うでしょ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweaks \n</code></pre></div></div>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>使うツールがあったら残してちょ。</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h2 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"お好みで-1\">お好みで</h2>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>ディレクトリにコピるだけ。<br />\n下では全部コピってるけど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.0.0/UDEVGothic_v1.0.0.zip \nunzip UDEVGothic_v1.0.0.zip \n<span class=\"nb\">mkdir</span> ~/.fonts\n<span class=\"nb\">cp </span>UDEVGothic_v1.0.0/<span class=\"k\">*</span>.ttf ~/.fonts/\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。<br />\nさっきフォントのインストールに使った端末ウィンドウを使うと\nエラーで端末ウィンドウが落ちるかもしれないんで一旦終了して新しいウィンドウで。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<h1 id=\"その他設定\">その他設定</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>~/.bashrcに以下を追記。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"c\"># Ubuntu22.04だとwaylandになるらしい</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"wayland\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vi\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># # venvの仮想環境名を表示するための設定</span>\n    <span class=\"c\"># show_virtual_env() {</span>\n    <span class=\"c\">#   if [ -n \"$VIRTUAL_ENV\" ]; then</span>\n    <span class=\"c\">#     echo \"($(basename $VIRTUAL_ENV))\"</span>\n    <span class=\"c\">#   fi</span>\n    <span class=\"c\"># }</span>\n    <span class=\"c\"># PS1='$(show_virtual_env)'$PS1</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nUbuntu20.04とちょっとキーが変更されてる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-home <span class=\"nb\">false \n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"ファイルnautilusのデフォルト動作変更\">ファイル(nautilus)のデフォルト動作変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アドレスバーをテキスト形式にする</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences always-use-location-entry <span class=\"nb\">true</span> \n\n<span class=\"c\"># 詳細表示をデフォルトに</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences default-folder-viewer <span class=\"s1\">'list-view'</span> \n\n<span class=\"c\"># 隠しファイルを表示する</span>\n<span class=\"c\"># 隠しファイルの表示はちょっと場所が違う</span>\ngsettings <span class=\"nb\">set </span>org.gtk.Settings.FileChooser show-hidden <span class=\"nb\">true</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアの更新(update-manager)を起動\n    <ul>\n      <li>更新のチェックが始まった場合はちょっと待つ</li>\n      <li>設定…をクリック\n        <ul>\n          <li>アップデートタブを選択</li>\n          <li>アップデートの自動確認を「なし」に変更</li>\n          <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n          <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n          <li>閉じるをクリック</li>\n        </ul>\n      </li>\n      <li>OKで終了</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Chromeリモートデスクトップ環境ではWindowsで設定したのが有効になっているので必要ないが、\nローカル端末で使用する場合に備えて入れ替えを設定しておく。<br />\n方法は、<code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code> に <code class=\"language-plaintext highlighter-rouge\">XKBOPTIONS=\"ctrl:nocaps\"</code> を追加。<br />\n設定を有効にするにはリブート必要。</p>\n\n<p>参考:<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a><br />\nリンク先は「Ubuntu 20.04/18.04 LTS」となっているが、Ubuntu22.04でも同じらしい。</p>\n\n<h3 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h3>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h1 id=\"sambaのインストール\">sambaのインストール</h1>\n\n<p>ツール本体のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加<br />\n作らなかったワークディレクトリの部分は削除してね。<br />\n他にも共有したいディレクトリがあったら追加してちょ。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">force group</code>に設定するグループは存在するグループ(またはユーザ)名に変更してください。</p>\n\n<p>ここではちょっと見たいファイルがあったのでoptも共有してます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"nfsのインストール\">NFSのインストール</h1>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/exports</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n<span class=\"c\"># abcの下にリモートのファイルが見えたらOK</span>\n</code></pre></div></div>\n\n<h1 id=\"pyenvのインストール\">pyenvのインストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<h3 id=\"必要なモジュールをインストール\">必要なモジュールをインストール</h3>\n<p>インストールに必要なモジュールをインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div></div>\n\n<h3 id=\"bluetoothを使用する場合\">bluetoothを使用する場合</h3>\n<p>bluetoothを使用する場合は以下も必要</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>pyenvの設定のため、~/.bashrc に以下を追加。 <br />\n(上記手順で記載済み。念のため再掲しておく)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h2 id=\"sudoでpyenv環境を実行するように設定する\">sudoでpyenv環境を実行するように設定する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo</code>でpythonを実行すると、pyenvの設定に関係なくsystemのpythonが実行されてしまいます。<br />\nこれを防ぐためには、<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers</code>の<code class=\"language-plaintext highlighter-rouge\">Defaults secure_path</code>に以下のpathを追加します。</p>\n\n<ul>\n  <li>«pyenvインストール先»/plugins/pyenv-virtualenv/shims:</li>\n  <li>«pyenvインストール先»shims:</li>\n  <li>«pyenvインストール先»/bin:</li>\n</ul>\n\n<p>具体的には以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 変更前\nDefaults  secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n    ↓\n# 変更後\nDefaults  secure_path=\"/proj/.pyenv/plugins/pyenv-virtualenv/shims:/proj/.pyenv/shims:/proj/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n</code></pre></div></div>\n<ul>\n  <li></li>\n</ul>\n\n<h2 id=\"pythonのインストール-以降\">pythonのインストール 以降</h2>\n\n<p>参考: <a href=\"http://localhost:4000/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 22.04のVirtualBoxへのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 22.04のVirtualBoxへのインストール</h1>\n      <p>Ubuntu 22.04のVirtualBoxへのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 22.04のVirtualBoxへのインストール手順をまとめてみた。\n20.04と大差ないけど、微妙に違う点もあるので。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2204-インストール媒体の入手\">Ubuntu 22.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら:\n<a href=\"https://www.ubuntulinux.jp/products/JA-Localized/download\" target=\"_blank\">Ubuntu Desktop 日本語 Remixのダウンロード</a><br />\n日本語環境構築するなら本家よりRemix版を使った方がなにかと便利(な気がする)。<br />\n<a href=\"https://jp.ubuntu.com/download\" target=\"_blank\">本家はこちら</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを4096MB以上に設定しておくこと</strong></p>\n<blockquote>\n  <p>[!NOTE]\n推奨環境が4GB以上なので。<br />\nウィンドウマネージャだけ動いている状態で1GBちょい使用だったので、\n2048MBでも動くと思う。でも、何か動かしたらすぐ足りなくなりそう。 <br />\nそれにしても、どんどん必要メモリが大きくなるな。<br />\n仮想環境で4GBってことは、HostOS環境下には8GB以上は必要ってことだよな。<br />\nプロセッサも2個割り当てておいた方が良いのかな?<br />\nこれは様子見てからどうするか決めよう。</p>\n</blockquote>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<blockquote>\n  <p>[!TIP]\nウィンドウが画面からはみ出して「続ける」ボタンが押せないときは、Alt+F7キーを押したあと、マウスでドラッグすると\nウィンドウを移動できるので、ボタンが見えるようところまで移動してクリックしてちょ。</p>\n</blockquote>\n\n<p>以下の説明が図付きで分かりやすい:\n<a href=\"https://qiita.com/HirMtsd/items/d43fc5215a88cbf414c9\" target=\"_blank\">Windows11上のVirtualBoxにUbuntu22.04LTSをインストール</a><br />\nWindows11って書いてあるけど、Windows10でも同じ。<br />\nここの説明では「不完全な言語サポート」うんぬんの説明があるけど、日本語Remix版でインストールすると、この部分は不要みたい。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<p>まだGuestAdditionをインストールしてないからコピペできないけど、BashのTab補完が効くので、\nちょろっと入力してあとは補完に頼れば大丈夫。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面 を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源管理を選択<br />\n右側で画面のブランクのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>裏でソフトウェアの更新が動いていると、ロックファイルがロックされてしばらく適用できないので、<br />\nそうなっちゃったらお茶でも飲んでしばらくお待ちください。<br />\nソフトウェアの更新による自動更新を止める方法は後ほど。</p>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweaks \n</code></pre></div></div>\n\n<h3 id=\"一旦リブート\">一旦リブート</h3>\n<p>更新適用のため。</p>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>以前にマウントしたものが残ってたらアンマウントしておくこと(インストール後初めてなのでマウントされてることはないけれど)。<br />\nVirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<blockquote>\n  <p>[!TIPS]\nプログラムが自動で始まらない場合は、CDROMのマウント先(たぶん、<code class=\"language-plaintext highlighter-rouge\">/media/<USER>/VBox_GAs_x.x.xx/</code>)に移動して<code class=\"language-plaintext highlighter-rouge\">sudo VBoxLinuxAdditions.run</code>を実行すれば良い。</p>\n</blockquote>\n\n<h3 id=\"再度リブート\">再度リブート</h3>\n<p>GuestAdditionによる更新適用のため。</p>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから「デバイス」→「クリップボードの共有」→「双方向」<br />\nを選択。\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<h3 id=\"使わないのでアンインストール\">使わないのでアンインストール</h3>\n\n<p>使うツールがあったら残してちょ。</p>\n\n<h4 id=\"ツール類\">ツール類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h4 id=\"ゲーム類\">ゲーム類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h4 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"お好みで\">お好みで</h2>\n\n<h3 id=\"フォントのインストール\">フォントのインストール</h3>\n\n<p>最近は<a href=\"https://github.com/yuru7/udev-gothic\" target=\"_blank\">UDEVゴシック</a> がお気に入りなのでインストールしておく。<br />\nもちろん、他のフォントでもいいよ。<br />\nブラウザでダウンロードしてもいいけど、あちこちファイルコピーしたり削除したりが面倒なので、\n一時ファイルは<code class=\"language-plaintext highlighter-rouge\">/tmp</code>に突っ込んでリブート時にまとめて消してもらおう。</p>\n\n<p>フォントのインストールと言っても、ttfファイルを入手して<code class=\"language-plaintext highlighter-rouge\">~/.fonts/</code>ディレクトリにコピるだけ。<br />\n下では全部コピってるけど、もちろん使いたいものだけでもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /tmp\nwget https://github.com/yuru7/udev-gothic/releases/download/v1.0.0/UDEVGothic_v1.0.0.zip \nunzip UDEVGothic_v1.0.0.zip \n<span class=\"nb\">mkdir</span> ~/.fonts\n<span class=\"nb\">cp </span>UDEVGothic_v1.0.0/<span class=\"k\">*</span>.ttf ~/.fonts/\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<h3 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h3>\n\n<p>で、入手したフォントを端末のフォントに設定しておこう。<br />\nさっきフォントのインストールに使った端末ウィンドウを使うと\nエラーで端末ウィンドウが落ちるかもしれないんで一旦終了して新しいウィンドウで。</p>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nさっきインストールした「UDEV Gothic JPDOC」を選んでサイズを指定。<br />\nついでに起動時の端末サイズも修正しておくとよい<br />\n終わったら×で終了。</p>\n\n<h3 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h3>\n\n<p>もちろん、使うものだけでOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h3 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h3>\n\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h3 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h3>\n\n<p>デフォルトのshがdashなのはなんとなくイヤなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<h3 id=\"bashの設定変更\">bashの設定変更</h3>\n\n<p>~/.bashrcに以下を追記。<br />\nもちろんお好みで。<br />\n「# for pyenv」以降はそれぞれのツールをインストールしたとき用なので、インストールしないならなくて可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"c\"># Ubuntu22.04だとwaylandになるらしい</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"wayland\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vi\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># # venvの仮想環境名を表示するための設定</span>\n    <span class=\"c\"># show_virtual_env() {</span>\n    <span class=\"c\">#   if [ -n \"$VIRTUAL_ENV\" ]; then</span>\n    <span class=\"c\">#     echo \"($(basename $VIRTUAL_ENV))\"</span>\n    <span class=\"c\">#   fi</span>\n    <span class=\"c\"># }</span>\n    <span class=\"c\"># PS1='$(show_virtual_env)'$PS1</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># openVINO の設定はdirenvで</span>\n<span class=\"c\"># for openVINO</span>\n<span class=\"c\"># source /opt/intel/openvino_2021/bin/setupvars.sh</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nfocus-mode の設定値 mouse と sloppy の違い<br />\nmouse は マウスカーソルをウィンドウからデスクトップに移すとフォーカスがはずれる。<br />\nsloppy は マウスカーソルをウィンドウからデスクトップに移してもフォーカスされたまま。</p>\n</blockquote>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>以下のコマンドで設定できる<br />\nUbuntu20.04とちょっとキーが変更されてる<br />\nゴミ箱は最初から表示されてないけど…ま、ついでに書いとく。<br />\n表示したければ、設定値をtrueにすれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-home <span class=\"nb\">false \n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.ding show-trash <span class=\"nb\">false</span> \n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"sambaのインストール\">sambaのインストール</h3>\n\n<p>ツール本体のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加<br />\n作らなかったワークディレクトリの部分は削除してね。<br />\n他にも共有したいディレクトリがあったら追加してちょ。<br />\nここではOpenVINOのサンプルとか見たかったのでoptを共有してます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n<p>別のUbuntuマシンとか、RasberryPiとファイル共有したいときに備えて設定しておく。</p>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nもちろん、192.168.<em>.</em>に割り当てられたNICが有効化されている必要がある。<br />\nデフォルトのNATだけじゃダメよ~。<br />\nVirtualBoxの設定のネットワークアダプタでホストオンリーアダプタを割り当てておけば、\n同一ホストマシン上の他の仮想マシンと通信できる。<br />\nVirtualBoxの設定のネットワークアダプタでブリッジアダプタを割り当てておけば\nRaspberryPi等ホストマシン外のマシンとも通信できる。<br />\nネットワークアダプタは4つまで設定できるので、両方有効化しておくことも可。</p>\n</blockquote>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認 <br />\nIPアドレスは<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>で調べてちょ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>abc\n<span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\n<span class=\"c\"># abcの下にリモートのファイルが見えたらOK</span>\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"ファイルnautilusのデフォルト動作変更\">ファイル(nautilus)のデフォルト動作変更</h3>\n\n<p>ファイル(nautilus)の設定をお好みに合わせて。<br />\nファイル(nautilus)はすべて終了しておいた方が無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アドレスバーをテキスト形式にする</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences always-use-location-entry <span class=\"nb\">true</span> \n\n<span class=\"c\"># 詳細表示をデフォルトに</span>\ngsettings <span class=\"nb\">set </span>org.gnome.nautilus.preferences default-folder-viewer <span class=\"s1\">'list-view'</span> \n\n<span class=\"c\"># 隠しファイルを表示する</span>\n<span class=\"c\"># 隠しファイルの表示はちょっと場所が違う</span>\ngsettings <span class=\"nb\">set </span>org.gtk.Settings.FileChooser show-hidden <span class=\"nb\">true</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ソフトウェアの自動更新の無効化\">ソフトウェアの自動更新の無効化</h3>\n\n<p>自分のタイミングでソフトのアップデートができないのがストレスなので、以下で自動確認を停止。<br />\nもちろん、<strong>適時手動でアップデートするのを忘れずに</strong>。</p>\n\n<ul>\n  <li>ソフトウェアの更新(update-manager)を起動\n    <ul>\n      <li>更新のチェックが始まった場合はちょっと待つ</li>\n      <li>設定…をクリック\n        <ul>\n          <li>アップデートタブを選択</li>\n          <li>アップデートの自動確認を「なし」に変更</li>\n          <li>セキュリティアップデートがあるときを「すぐに表示」に変更</li>\n          <li>Ubuntuの新バージョンの通知を「なし」に変更</li>\n          <li>閉じるをクリック</li>\n        </ul>\n      </li>\n      <li>OKで終了</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h3>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a><br />\nリンク先は「Ubuntu 20.04/18.04 LTS」となっているが、Ubuntu22.04でも同じらしい。<br />\nNative環境にインストールしてないので未確認だけど…</p>\n\n<p>リブート必要だが、以下のIPv6無効化とまとめてリブートでも可。</p>\n\n<h3 id=\"ipv6を無効化する\">IPv6を無効化する</h3>\n\n<p>IPv6動いていて何度かハマったので無効化しておく。<br />\nsysctrlで無効化する方法もあるけど、ちょっと手順が面倒なので、起動オプションで無効化してしまおう。</p>\n\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n\n<p>元から設定されている”quiet splash”を削除すれば起動時のスプラッシュスクリーンが表示されず、ブートシーケンスのログが表示されるようになるので、お好みで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>これだけだとまだ設定有効にならない。<br />\n以下のコマンドでgrubメニューの更新を行う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<p>リブート後、<code class=\"language-plaintext highlighter-rouge\">ip address</code>とか<code class=\"language-plaintext highlighter-rouge\">ifconfig</code>でIPv6のアドレスが割り当てられていないことを確認。</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<p>マスタイメージを残しておいて、色々な環境をお試しするには仮想マシンをクローンして使うのがおススメ。<br />\nVirtualBoxのメインウィンドウでマスタイメージの仮想マシンを右クリック→クローンを選択、名前とパスを設定し、あとはごにょごにょ…</p>\n\n<p>クローンした仮想マシンを起動し、必要な変更を加える。</p>\n\n<h2 id=\"ネットワーク設定の変更\">ネットワーク設定の変更</h2>\n\n<p>マシン名とか同じ名前だと色々不都合があるので、変更しておく。<br />\n他のクローン仮想環境と同時に使わないならそのままでも良いけど。<br />\nIPアドレスも固定で割り振っておくと名前が引けない時にさくっと分かってなにかと便利…なんだけど、最近はWindowsもUbuntuもRaspberryPiもmDNSがサポートされてるから自動割り当てのままでもそんなに不便はないかも。</p>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<p>このコマンドで<code class=\"language-plaintext highlighter-rouge\">/etc/hostname</code>が書き換えられる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<p>もちろん、vimとかで書き換えても可。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<p>下のコマンドを実行するための接続名を確認しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<p>IPアドレスを手動割り当てに変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> \n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<p>IPアドレスを手動割り当てに変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> gw4 <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nIPアドレスの変更をGUIで行うには以下。<br />\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>まとめて実行するならこちら。<br />\nホスト名、接続名、IPアドレスなどは適宜変更。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># マシン番号の設定とホスト名の設定</span>\n<span class=\"nv\">number</span><span class=\"o\">=</span>30\n<span class=\"nv\">new_hostname</span><span class=\"o\">=</span>skull<span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span>\n\n<span class=\"c\"># HOSTNAMEの変更</span>\n<span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/ubuntu-22.*</span><span class=\"nv\">$/</span><span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span><span class=\"s2\">/\"</span> /etc/hosts\n\n<span class=\"c\"># HOST ONLY ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.56.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n\n<span class=\"c\"># BRIDGE ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.method manual ipv4.addresses <span class=\"s2\">\"192.168.78.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> gw4 <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span>\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<h2 id=\"あとはお約束\">あとはお約束</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>VirtalBoxのバージョンが変更されているときは、GuestAdditionのバージョンアップも忘れずに。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</h1>\n      <p>Raspberry Pi OS(64bit)のRaspberry Pi Imagerを使用したインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>また手順が変わったみたいなので、メモも更新。<br />\n(2023/10/15 最新版での試行結果を反映)</p>\n\n<h1 id=\"sdカードへの書き込み\">SDカードへの書き込み</h1>\n\n<p>Raspberry Pi Imager なるツールを使うようになったらしい。<br />\n使い方はあちこちに書いてあるけど、例えばこちら。</p>\n<ul>\n  <li><a href=\"https://ascii.jp/elem/000/004/094/4094421/\" target=\"_blank\">Raspberry Pi Imagerの使い方 ― v1.7.2以降 対応版</a></li>\n  <li><a href=\"https://www.mikan-tech.net/entry/raspi-imager-headless-setup\" target=\"_blank\">Raspberry Pi Imagerが新しくなった!Lite版もらくらくHeadless Setup</a></li>\n</ul>\n\n<p>これを使うと、最初のユーザを自由に設定できるので、これまでのpiユーザを変更するなんてことはやらなくて済む。<br />\nWi-Fiの設定やSSHの設定も(なんかWindowsが適切に設定されてれば公開鍵が自動で設定されるみたい)ここでできる。</p>\n\n<p>パスワードが設定ファイルに書き出されるので(さすがに平文ではない、最初の起動が終わったら削除される)、<br />\nセキュリティ上気になる場合は仮パスワードを設定しておいて<br />\n最初にログインしたときに変更する、なんてことをやった方が良いと言ってる解説ページもあった。</p>\n\n<blockquote>\n  <p>[!WARNING]\n<del>なぜかSSHの認証方法が毎回「パスワード認証を使う」になってしまうので、公開鍵を使うときは再度設定が必要。</del> \n(1.7.5では改善された模様)</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\n<del>(少なくとも)2023/10以降のバージョンはopenSSHのバージョンがRSA非対応になっているので、 \n 鍵ファイル作成の際はRSA以外(ed25519など)で作成する必要がある。</del> <br />\n(2023/10/21 誤解してたので書き直し)<br />\n(少なくとも)2023/10以降のバージョンはopenSSHのバージョンが SSH-RSA 非対応になっているので、<br />\nTeraterm Ver4.106以前など RSA-SHA2未対応の環境ではRSA鍵では繋がらない。 \nその場合は RSA以外(ed25519など)で作成すれば良い。<br />\nssh-keygenのデフォルトはRSAなので、<code class=\"language-plaintext highlighter-rouge\">ssh-keygen -t ed25519</code> などとする。<br />\nもちろん、Teraterm Ver4.107以降に変更するという手もある。</p>\n</blockquote>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1\n</code></pre></div></div>\n<h2 id=\"ipv6の無効化\">IPv6の無効化</h2>\n<p>IPv6を無効化しておきたいときは、\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する。<br />\nこのファイルは1行で書かないといけないので、改行してはいけない。</p>\n\n<blockquote>\n  <p>[!WARNING]\n<del>以前はこれで無効化できていたはずだけど、2023/10現在 この手順では無効化できないらしい。<br />\n下でセットアップスクリプトで無効化処理を実行するように変更した。</del> <br />\n(2023/10/21 間違ってたので削除)</p>\n</blockquote>\n\n<h2 id=\"ブートログの表示\">ブートログの表示</h2>\n\n<p>ブートログが見えないと不安な人は、<br />\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> から <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code>\nを削除しておくとよい。</p>\n<blockquote>\n  <p>[!NOTE]\nLITE版では<code class=\"language-plaintext highlighter-rouge\">quiet</code>を削除(それ以外は指定されていないので)</p>\n</blockquote>\n\n<h1 id=\"最初の起動\">最初の起動</h1>\n<p>書き込んだSDカードをRaspberry Piに挿入して電源ON。<br />\nごちょごちょと設定したあと、起動する(途中2回ほどrebootしてるらしい)</p>\n\n<p>あとは起動後の設定。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># アップデート実行\nsudo apt update\nsudo apt upgrade\n\n# リブート\nsudo reboot\n</code></pre></div></div>\n\n<h1 id=\"カスタマイズ\">カスタマイズ</h1>\n\n<blockquote>\n  <p>[!NOTE]\n以降の処理をスクリプトにまとめました。<br />\n<a href=\"https://gist.github.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c\" target=\"_blank\">Raspberry Pi セットアップスクリプト </a><br />\n以下の手順で実行できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.githubusercontent.com/ippei8jp/8053f0804a694c34cb18cd4035e0993c/raw/pi_setup1.sh\nbash pi_setup1.sh\n</code></pre></div>  </div>\n  <p>LITE版を使うときは変数<code class=\"language-plaintext highlighter-rouge\">LITE_OS</code>に<code class=\"language-plaintext highlighter-rouge\">1</code>を設定して実行します。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> <span class=\"nv\">LITE_OS</span><span class=\"o\">=</span>1 bash pi_setup1.sh\n</code></pre></div>  </div>\n\n  <p>途中でパスワード入力しないといけないので、完全自動じゃないけど、かなり手間は省けるはず。<br />\n実行後、<code class=\"language-plaintext highlighter-rouge\">pi_setup1.sh</code>は不要なので削除して可。<br />\n実行が終わったらリブートすること。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>reboot\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h2 id=\"resizeスクリプトの取得\">resizeスクリプトの取得</h2>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/4f39afbcd8471426421944b597f3a5f2963984c6/resize.py\n\n<span class=\"nb\">chmod</span> +x resize.py\n\n./resize.py\n</code></pre></div></div>\n\n<h2 id=\"ロケールの変更\">ロケールの変更</h2>\n<p>日本語表示のため、ロケールを変更する。<br />\n(imagerだとキーボードレイアウトの変更はやってくれるけど、ロケールの変更はやってくれないらしいので)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ロケールの変更</span>\n<span class=\"nb\">sudo </span>raspi-config nonint do_change_locale ja_JP.UTF-8\n\n<span class=\"c\"># リブートまでとりあえずLANGのみ変更で日本語表示</span>\n<span class=\"nb\">export </span><span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF-8\n</code></pre></div></div>\n\n<h2 id=\"bashrc-の変更\">.bashrc の変更</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n\n</code></pre></div></div>\n\n<h2 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h2>\n\n<p>物理キーボード接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]<br />\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n\n</blockquote>\n\n<h2 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h2>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h2 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h2>\n\n<p>まずはワークディレクトリの作成</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown $USER:$USER /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a $USER\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo service smbd reload\nsudo service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"vncサーバの有効化\">VNCサーバの有効化</h2>\n\n<p>リモートデスクトップを使うために、VNCサーバの有効化を行う。<br />\nLITE版では不要。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    # VNCサーバの有効化\n    3 Interfacing Options\n        I3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>\n            The VNC Server is enabled\n            と表示されるので <Ok>\n\n    # VNC解像度の設定\n    2 Display Options\n        D5 VNC Resolution\n        \n            解像度が色々表示されるので、\n            使いたい解像度を選択(例えば 1920x1080 )して<Select>\n            The resolution is set to «選択した解像度»\n            と表示されるので <Ok>\n    # 設定終了\n    <Finish>\n</code></pre></div></div>\n\n<h2 id=\"ipv6-の無効化\">IPv6 の無効化</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code>での設定では無効化できなくなったと思ったけど、勘違いだった。<br />\nなので、上記の<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code> に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加する方法でOK。</p>\n\n<p>でも、その時に<code class=\"language-plaintext highlighter-rouge\">mncli</code>コマンドで無効化するスクリプトを作ったので、せっかくなので残しておく。</p>\n\n<p>接続名一覧を取得し、 それぞれに対して無効化するコマンドを実行する。<br />\n接続名に「有線接続 1」と空白が含まれている接続があるので、一時的に空白をセミコロンに置換して処理を行っている。<br />\n(これをやらないと「有線接続」と「1」に分けて処理されてしまう)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 接続一覧を取得</span>\n<span class=\"nv\">conn_data</span><span class=\"o\">=</span><span class=\"si\">$(</span>nmcli <span class=\"nt\">-t</span> connection<span class=\"si\">)</span>\n\n<span class=\"c\"># 空白を\";\"に置換(配列代入時に誤動作するのを防止)</span>\n<span class=\"nv\">conn_data</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">conn_data</span><span class=\"p\">// /</span><span class=\"s2\">\";\"</span><span class=\"k\">}</span>\n\n<span class=\"c\"># ':'区切りで1列目をconnections配列に格納</span>\n<span class=\"nv\">connections</span><span class=\"o\">=(</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"s2\">\"</span><span class=\"nv\">$conn_data</span><span class=\"s2\">\"</span> | <span class=\"nb\">cut</span> <span class=\"nt\">-d</span><span class=\"s2\">\":\"</span> <span class=\"nt\">-f1</span><span class=\"si\">)</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 配列の要素を処理</span>\n<span class=\"k\">for </span>connection <span class=\"k\">in</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">connections</span><span class=\"p\">[@]</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 上で;に置換した空白を戻す</span>\n    <span class=\"nv\">connection</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"p\">//</span><span class=\"s2\">\";\"</span><span class=\"p\">/</span><span class=\"s2\">\" \"</span><span class=\"k\">}</span>\n\n    <span class=\"k\">if</span> <span class=\"o\">[[</span> <span class=\"s2\">\"</span><span class=\"nv\">$connection</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s1\">'lo'</span> <span class=\"o\">]]</span><span class=\"p\">;</span> <span class=\"k\">then</span>    <span class=\"c\"># loデバイスは無効にできないので除外</span>\n      <span class=\"nb\">echo</span> <span class=\"s2\">\"disable </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span> \n      <span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"sudo nmcli connection modify </span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">connection</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\"> ipv6.method </span><span class=\"se\">\\\"</span><span class=\"s2\">disabled</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span>\n      <span class=\"c\"># 有効にする場合はこちら</span>\n      <span class=\"c\"># cmd=\"sudo nmcli connection modify \\\"${connection}\\\" ipv6.method \\\"auto\\\"\"</span>\n      <span class=\"nb\">echo</span> <span class=\"nv\">$cmd</span>\n      <span class=\"nb\">eval</span> <span class=\"nv\">$cmd</span>\n    <span class=\"k\">fi\ndone</span>\n</code></pre></div></div>\n\n<h1 id=\"splash-screenの再有効化\">Splash screenの再有効化</h1>\n\n<p>セットアップ時にブートログが表示されるようにしたけど、<br />\nやっぱり表示したくなくなった(Splash screenを表示)、てなときは以下で。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S6 Splash Screen\n            Would you like to show the splash screen at boot?\n            と聞かれるので有効化するときは <Yes> を選択\n            Splash screen at boot is enabled)\n            と表示されるので <Ok>\n\n    Would you like to reboot now?\n    と聞かれるので、その場でリブートしてよければ<Yes>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n直接<code class=\"language-plaintext highlighter-rouge\">/boot/cmdline.txt</code> に <code class=\"language-plaintext highlighter-rouge\">quiet</code> <code class=\"language-plaintext highlighter-rouge\">splash</code> <code class=\"language-plaintext highlighter-rouge\">plymouth.ignore-serial-consoles</code> を追加しても良い。<br />\nLITE版では <code class=\"language-plaintext highlighter-rouge\">quiet</code>のみ追加。</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストール</h1>\n      <p>Raspberry Pi OS(64bit)(Jan 28th 2022)のインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロード\">ダウンロード</h1>\n\n<p><a href=\"https://www.raspberrypi.com/software/operating-systems/\" target=\"_blank\">Raspberry Pi OS</a>ページの <br />\n「Manually install an operating system image」の「See all download options」をクリック、<br />\n「Raspberry Pi OS (64-bit)」の「Raspberry Pi OS with desktop」の「Download」をクリックしてダウンロード<br />\n試したのは Release date: January 28th 2022</p>\n\n<blockquote>\n  <p>[!NOTE]\n「Archive」リンクから過去のリリースも入手できる</p>\n</blockquote>\n\n<p>なんか見るたびにページ構成変わるよなぁ….😩💨</p>\n\n<h1 id=\"ブート前の設定\">ブート前の設定</h1>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h2 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h2>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の 最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nシリアルコンソールの送信改行コードはCRにしておくこと。<br />\nそうしないと、ビミョーに悲しいことが起こる場合がある。</p>\n\n</blockquote>\n\n<h2 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h2>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>の  最後の <code class=\"language-plaintext highlighter-rouge\">[all]</code> の行の下に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group</code>と<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>については使用するモニタに合わせる。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group=2</code>はモニタ種別でDMT(一般的にモニタディスプレイ)、<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_mode=82</code>が 1920x1080 60Hz(1080p)を示している。<br />\n設定値の内容については、<a href=\"https://www.raspberrypi.com/documentation/computers/config_txt.html#hdmi-mode\" target=\"_blank\">HDMI Mode</a>を参照。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>はテキストモードで表示したいサイズに合わせる。1920と1080とか、1280と720とか。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># display resolution force setting</span>\n<span class=\"nv\">hdmi_group</span><span class=\"o\">=</span>2\n<span class=\"nv\">hdmi_mode</span><span class=\"o\">=</span>82\n<span class=\"nv\">framebuffer_width</span><span class=\"o\">=</span>1920\n<span class=\"nv\">framebuffer_height</span><span class=\"o\">=</span>1080\n<span class=\"nv\">hdmi_force_hotplug</span><span class=\"o\">=</span>1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nHDMIディスプレイを常に接続しているなら設定しなくても問題ないが、\nHDMIディスプレイをはずしてVNCでリモート接続だけする場合は設定しておかないと\n解像度が1024x768までしか設定できなくなるので注意。</p>\n</blockquote>\n\n<h3 id=\"vncが遅い問題対応\">VNCが遅い問題対応</h3>\n<p>このバージョンではHDMIディスプレイを繋いでいない状態でVNCで接続すると表示がとても遅くなる問題がある。<br />\n回避するには、<code class=\"language-plaintext highlighter-rouge\">cmdline.txt</code>に以下追記する。<br />\n<code class=\"language-plaintext highlighter-rouge\">1920x1080@60D</code>の部分は上記の<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>や<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>の設定値に合わせる。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>video=HDMI-A-1:1920x1080@60D\n</code></pre></div></div>\n\n<p>具体的にはこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>console=serial0,115200 console=tty1 root=PARTUUID=b635b4ec-02 rootfstype=ext4 fsck.repair=yes video=HDMI-A-1:1920x1080@60D rootwait\n</code></pre></div></div>\n\n<p>参考URL:<a href=\"https://forums.raspberrypi.com/viewtopic.php?p=1935714#p1935711\">Re: Bullseye vncserver is very slow without display</a></p>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。<br />\nSSID名は ダブルクォーテーションで囲む。<br />\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://qiita.com/mt08/items/2da1cce534dfdc84f5e3#%E7%92%B0%E5%A2%83\" target=\"_blank\">[メモ] (らずぱい)Windows上から固定IP設定 (Raspberry Pi Static IP)</a>\nにWindows版の<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase.exe</code>へのリンクがある。<br />\nワタシはUbuntuや別のRasberryPiで作ったから使ってないけど…</p>\n</blockquote>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase \"SSID名\" \"暗号化キー\"\n        ↓ 実行結果\nnetwork={\n        ssid=\"SSID名\"\n        #psk=\"暗号化キー\"\n        psk=ほにゃらら~~~ほにゃらら~~~\n}\n</code></pre></div></div>\n\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。<br />\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<blockquote>\n  <p>[!NOTE]\n起動後、公開鍵ファイルの設置を行うには、<br />\n<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">ubuntuにSSHサーバをセットアップする</a> <br />\nの「秘密鍵と公開鍵の生成と公開鍵ファイルの設置」の部分を参照。<br />\n(ページはUbuntuについて書いてあるけど、サーバがセットアップ済みなことを除けばRaspberry Pi OSでも同じ)</p>\n</blockquote>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># アップデート実行\nsudo apt update\nsudo apt upgrade\n# リブート\nsudo reboot\n</code></pre></div></div>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S7 Splash Screen\n            Would you like to show the splash screen at boot?\n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこの操作で/boot/cmdline.txtが書き換えられるらしい。</p>\n\n</blockquote>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# 新ユーザのパスワード変更する\npasswd\n《パスワードを設定》\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\" target=\"_blank\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n            B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/4f39afbcd8471426421944b597f3a5f2963984c6/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nresize.pyは以前python2ベースで作ってあったが、<br />\nこのバージョンからpython2がデフォルトでインストールされなくなったので、<br />\npython3ベースに修正したのでURLが変更されています。</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n\n<p>物理キーボード接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]<br />\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n\n</blockquote>\n\n<h1 id=\"bashのクリップボードの挙動が以前と異なるようになったので対策\">bashのクリップボードの挙動が以前と異なるようになったので対策</h1>\n\n<p>bashでクリップボードからペーストするとペーストした文字が選択状態になったり、改行がその場で入力されなかったりするようになった。<br />\nこればbash 5.1からブラケットペーストモード というのがデフォルトで有効になったためらしい。<br />\n(余計なことをしてくれる…😩💨)<br />\nこれを回避するには<code class=\"language-plaintext highlighter-rouge\">/etc/inputrc</code>の最後に以下を追記する。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># disable bracked-paste mode\nset enable-bracketed-paste off\n</code></pre></div></div>\n<p>起動済みのbashには効かないが、設定以降に起動したbashでは有効になる(システムの再起動は不要)。</p>\n\n<p>参考: <a href=\"https://freebsd.sing.ne.jp/shell/03/04.html\" target=\"_blank\">シェル - bash - ブラケットペーストモード(Bracketed Paste Mode)</a></p>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n\n<p>まずはワークディレクトリの作成</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo service smbd reload\nsudo service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo vi /etc/hostname\nsudo vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>s``udo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    3 Interfacing Options\n        I3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>\n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n\n<p>Windows側のクライアントは、<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a>\nから VNC Viewerをダウンロード。\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。\n日本語化の手順はこちらを参考に。 <a href=\"http://xn--u9j0md1592aqmt715c.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>SDカードイメージのバックアップを取るならこちら。<br />\n<a href=\"/memoBlog/2021/07/18/sd_image_2.html\" target=\"_blank\">Raspbian SDカードイメージファイルの作成(改訂版)</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian SDカードイメージファイルの作成(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian SDカードイメージファイルの作成(改訂版)</h1>\n      <p>Raspbian SDカードイメージファイルの縮小</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/07/17/raspios_20210507.html\" target=\"_blank\">Raspberry Pi OS(May 7th 2021)のインストール</a> \nでセットアップしたSDカードをバックアップしておけば逐一セットアップ作業を行わなくても環境を復元できます。</p>\n\n<p>ただ、そのままSDカードをイメージファイル化しただけでは復元するSDカードのサイズが微妙に小さい場合などは、復元できなくなってしまいます。<br />\nそこで、バックアップしtイメージファイル内のパーティションサイズを縮小し、イメージファイルを小さくして保存します。</p>\n\n<p>以前、<a href=\"/memoBlog/2019/09/15/sd_image.html\" target=\"_blank\">Raspbian SDカードイメージファイルの縮小</a>、\n<a href=\"/memoBlog/2020/10/25/Jetson_nano_backup.html\" target=\"_blank\">Jetson nano のSDカードをバックアップする</a>\nでも書いていますが、今回はSDカード上でパーティションを縮小する方法にしてみました。<br />\nこれだと、不要な部分のバックアップを行わなくて済むので、ディスク領域/時間敵に有利かと思います。</p>\n\n<p>Windowsでは出来ない操作があるので、Ubuntu PCが必要です。<br />\nWSLではたぶん出来ません。<br />\nVirtualboxだと出来そうな気がしますが、試していません。</p>\n\n<h1 id=\"事前準備\">事前準備</h1>\n<h2 id=\"raspberrypiの準備\">RaspberryPiの準備</h2>\n<p>コピーしたSDカードで初回Boot時にパーティションを拡張するためのスクリプト<code class=\"language-plaintext highlighter-rouge\">expand_partition.sh</code>を\n<a href=\"/memoBlog/misc/stock/diskimage_shrink.sh\" target=\"_blank\">ここ</a> \nから適当なディレクトリにダウンロードしておきます。<br />\n(SDカードのコピーからブートしたあとに実行するので、コピーからブートした環境でダウンロードしても良いですが、\nマスタにダウンロードしておけばコピーの度にダウンロードしなくて済むので。)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/first_boot_settings\n<span class=\"nb\">cd</span>  ~/first_boot_settings\nwget https://ippei8jp.github.io/memoBlog/misc/stock/expand_partition.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPiの場合は<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>でパーティション拡張できるので、このスクリプトはなくても良い。</p>\n</blockquote>\n\n<p>RaspberryPiの電源をOFFし、SDカードを取り外してubuntu PCに挿入しておきます。</p>\n\n<h1 id=\"ubuntu-pcでの操作\">Ubuntu PCでの操作</h1>\n\n<p>以下、SDカードは<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0</code>に割り当てられているものとします。</p>\n\n<blockquote>\n  <p>[!NOTE]\nSDカードが自動マウントされている場合はアンマウントしておいてください。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount /dev/mmcblk0p1\n<span class=\"nb\">sudo </span>umount /dev/mmcblk0p2\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"gpartedのインストール\">gpartedのインストール</h2>\n<p>パーティション操作を行うため、gpartedがインストールされていなければインストールしておきます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gparted\n</code></pre></div></div>\n\n<h2 id=\"gpartedによりパーティションを縮小\">gpartedによりパーティションを縮小</h2>\n<ul>\n  <li>goartedを起動</li>\n  <li>対象デバイスとして<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0</code>を選択。</li>\n  <li>配置図またはパーティション一覧で<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0p2</code>を右クリックし、「リサイズ/移動」を選択</li>\n  <li>ダイアログで「新しいサイズ」に縮小したサイズを設定。 ダイアログ左上に表示されている「最小サイズ」よりも少し多めに。<br />\n(後方の空き領域は自動計算されます)</li>\n  <li>メニューの「編集」→「保留中の全ての操作を適用する」を選択し、パーティションを縮小する</li>\n  <li>gpartedを終了</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\ngpartedによるパーティションの縮小はマウントしたままではできません。<br />\nしたがって、RaspberryPiでは作業できず、Ubuntu PCで行う必要があります。</p>\n</blockquote>\n\n<h2 id=\"データサイズを確認\">データサイズを確認</h2>\n<p>以下のコマンドを実行し、コピーすべきデータサイズを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>parted /dev/mmcblk0 unit MiB print\n</code></pre></div></div>\n<p>以下が実行結果例。<br />\nここで、パーティション2の終了位置をメモ(ここでは<code class=\"language-plaintext highlighter-rouge\">3760</code>)しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>モデル: SD SA16G <span class=\"o\">(</span>sd/mmc<span class=\"o\">)</span>\nディスク /dev/mmcblk0: 14772MiB\nセクタサイズ <span class=\"o\">(</span>論理/物理<span class=\"o\">)</span>: 512B/512B\nパーティションテーブル: msdos\nディスクフラグ: \n\n番号  開始     終了     サイズ   タイプ   ファイルシステム  フラグ\n 1    4.00MiB  260MiB   256MiB   primary  fat32             lba\n 2    260MiB   3760MiB  3500MiB  primary  ext4\n</code></pre></div></div>\n\n<h2 id=\"イメージファイルの作成\">イメージファイルの作成</h2>\n<p>以下のコマンドでSDカードのデータをイメージファイルに保存します。<br />\nここで、<code class=\"language-plaintext highlighter-rouge\">of=</code>で指定しているのが作成するイメージファイル名、<br />\n<code class=\"language-plaintext highlighter-rouge\">count=</code>は上で調べたパーティションの終了位置をしていします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>/dev/mmcblk0 <span class=\"nv\">of</span><span class=\"o\">=</span>hoge1.img <span class=\"nv\">bs</span><span class=\"o\">=</span>1M <span class=\"nv\">count</span><span class=\"o\">=</span>3760 <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div></div>\n\n<p>必要ならzip圧縮しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>zip hoge1.zip hoge1.img \n</code></pre></div></div>\n\n<h1 id=\"新しい環境での起動\">新しい環境での起動</h1>\n\n<h2 id=\"新しいsdカードにバックアップを復元\">新しいSDカードにバックアップを復元</h2>\n\n<p>上で作成したイメージファイルをSDカードに書き込み(WindowsでもUbuntuでもお好きにどうぞ)、</p>\n\n<h2 id=\"最初のブート\">最初のブート</h2>\n<p>RaspberryPiに挿入しBootします(特別な手順は特にありません)。</p>\n\n<h2 id=\"新しいsdカードのパーティションを拡張\">新しいSDカードのパーティションを拡張</h2>\n\n<p>Boot完了したらlog inしてパーティションサイズを変更するために\n以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash first_boot_settings/expand_partition.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nまたは、RaspberryPiにgpartedをインストールして、<br />\nパーティションを縮小したときと同様に最大サイズまでパーティションサイズを拡大しても良いです。<br />\nパーティションの拡大はマウントしたままでも可能。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPiの場合は<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>でパーティション拡張できる</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config --expand-rootfs  \n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">Please reboot</code>と言われたらrebootする。</p>\n</blockquote>\n\n<h2 id=\"その他\">その他</h2>\n<p>必要であれば、ホスト名など必要な変更を行います。</p>\n\n<h2 id=\"リブート\">リブート</h2>\n<p>リブートします。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi OS(May 7th 2021)のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi OS(May 7th 2021)のインストール</h1>\n      <p>Raspberry Pi OS(May 7th 2021)のインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>前にやった <a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\" target=\"_blank\">Raspbian Busterのインストール</a>\nからあまり違わないけど、微妙に違いもあるので、もう一度メモしておく。</p>\n\n<h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspberry Pi OS with desktop」 の 「Download」でダウンロードしてSDカードに書き込む。<br />\n(「・・・ and recommended software」 の方ではない)<br />\n以下の手順は、RaspberryPi4 model B で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code> の <code class=\"language-plaintext highlighter-rouge\">[pi4]</code>の行の前に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\nシリアルコンソールの送信改行コードは<code class=\"language-plaintext highlighter-rouge\">CR</code>にしておくこと。<br />\nそうしないと、ビミョーに悲しいことが起こる場合がある。</p>\n</blockquote>\n\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>の <code class=\"language-plaintext highlighter-rouge\">[pi4]</code>の行の前に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group</code>と<code class=\"language-plaintext highlighter-rouge\">hdmi_mode</code>については使用するモニタに合わせる。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_group=2</code>はモニタ種別でDMT(一般的にモニタディスプレイ)、<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_mode=82</code>が 1920x1080 60Hz(1080p)を示している。<br />\n設定値の内容については、<a href=\"https://www.raspberrypi.org/documentation/configuration/config-txt/video.md\" target=\"_blank\">Video options in config.txt</a>\nを参照。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>はテキストモードで表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nhdmi_group=2\nhdmi_mode=82\nframebuffer_width=1920\nframebuffer_height=1080\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nHDMIディスプレイを常に接続しているなら設定しなくても問題ないが、<br />\nHDMIディスプレイをはずしてVNCでリモート接続だけする場合は設定しておかないと<br />\n解像度が1024x768までしか設定できなくなるので注意。</p>\n</blockquote>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S7 Splash Screen\n            Would you like to show the splash screen at boot? \n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nこの操作で<code class=\"language-plaintext highlighter-rouge\">/boot/cmdline.txt</code>が書き換えられるらしい。</p>\n</blockquote>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\" target=\"_blank\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    1 System Options\n        S5 Boot / Auto Login\n            B1 Console\n            B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    3 Interfacing Options        \n        P3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>    \n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n<p>Windows側のクライアントは、<br />\n<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a> \nから VNC Viewerをダウンロード。<br />\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。<br />\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。<br />\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。<br />\n日本語化の手順はこちらを参考に。 <a href=\"http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を必要に応じて修正。<br />\n例えば、以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"--enable-ipv6</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-unicode=ucs4</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-dbmliborder=bdb:gdbm</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-expat</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-system-ffi</span><span class=\"se\">\\</span><span class=\"s2\">\n     --with-fpectl\"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マウスフォーカスの変更\">マウスフォーカスの変更</h1>\n\n<p>ウィンドウをクリックしないとフォーカスが移動しないのはイライラするので x-mouse相当の設定をする。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/xdg/openbox/lxde-pi-rc.xml</code>の以下の部分をnoからyesに変更。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><followMouse>yes</followMouse>\n</code></pre></div></div>\n\n<h1 id=\"ipv6の無効化\">IPv6の無効化</h1>\n<p>IPv6を無効化したい場合は以下を設定。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/sysctl.conf</code>に以下を追加する\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Disable IPv6\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\n</code></pre></div>    </div>\n  </li>\n  <li>以下を実行する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sysctl <span class=\"nt\">-p</span>\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>UbuntuをNative環境にインストールする(20.04)</title>\n  </head>\n  <body>\n    <header>\n      <h1>UbuntuをNative環境にインストールする(20.04)</h1>\n      <p>Ubunt(20.04)をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"インストール\">インストール</h1>\n<p>最初の起動まではこちらに詳しく書かれています。<br />\n<a href=\"https://qiita.com/koba-jon/items/019a3b4eac4f60ca89c9\" target=\"_blank\">Ubuntu 20.04 LTS インストール方法(外付けドライブ用)</a></p>\n\n<blockquote>\n  <p>[!WARNING]\nEFIシステムパーティションを作成するのを忘れがち。<br />\n外付けだと作成忘れると内蔵HDDのEFIシステムパーティションに追記されちゃうので注意。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\nユーザ名に英数字以外を含むとChrome remote desktop の インストール&設定でエラーになることがあるので、<br />\n英数字以外を含まないユーザ名を設定することをおススメします。</p>\n</blockquote>\n\n<h1 id=\"その後の設定手順\">その後の設定手順</h1>\n\n<h2 id=\"最新版にアップデート\">最新版にアップデート</h2>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h2 id=\"ipアドレス確認したいとき\">IPアドレス確認したいとき</h2>\n<p>SSHのクライアントからの接続先が分からないと困るので、\nIPアドレスを確認するためにnet-toolsをインストールして\nifconfigで確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\nifconfig\n</code></pre></div></div>\n\n<h2 id=\"sshのインストール\">sshのインストール</h2>\n<p>WindowsPCにあるデータをubuntuPCにキーボードで打ち込むのは効率が悪いので、最も簡単なsshでリモートログインできるようにしてみる。</p>\n\n<p>以下のコマンドでsshサーバをインストールし、サーバを開始する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n\n<p>クライアントからTeraTermなどでsshで対象マシンのポート22に接続する</p>\n\n<h2 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面ロック を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h2 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h2>\n\n<p>とりあえず入れとこう</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\n</code></pre></div></div>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが…</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h3 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>NFSサーバの再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.XX.XX:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"bashの設定変更\">bashの設定変更</h2>\n\n<p>~/.bashrcに以下を追記</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h2 id=\"guiの動作の設定変更をお好みで\">GUIの動作の設定変更をお好みで</h2>\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.mutter auto-maximize\ngsettings get org.gnome.mutter edge-tiling\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.desktop.wm.preferences auto-raise \ngsettings get org.gnome.desktop.wm.preferences focus-mode \ngsettings get org.gnome.desktop.wm.preferences raise-on-click\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h3>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.shell.extensions.desktop-icons show-home\ngsettings get org.gnome.shell.extensions.desktop-icons show-trash\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h3>\n<p>なんとなく使いにくいので好みのデザインに変更。<br />\ndconf-editorでも良いよ(しつこい…)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 ==================================</span>\n<span class=\"c\"># Dockバー上のゴミ箱表示有無</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock show-trash\n\n<span class=\"c\"># アプリケーションのDockバー上の表示位置</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock show-apps-at-top\n\n<span class=\"c\"># Dockバー表示位置</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock dock-position\n\n<span class=\"c\"># Dockバー上のアイコンサイズ</span>\ngsettings get org.gnome.shell.extensions.dash-to-dock dash-max-icon-size\n\n<span class=\"c\"># 設定 ==================================</span>\n<span class=\"c\"># Dockバー上のゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># Dockバー上のアイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h3 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h3>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.interface cursor-size\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h3 id=\"capsキーをctrlキーに変更\">CAPSキーをCtrlキーに変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.input-sources xkb-options\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.input-sources xkb-options <span class=\"se\">\\[\\'</span>ctrl:nocaps<span class=\"se\">\\'\\]</span>\n\n<span class=\"c\"># 設定を有効にするにはGUIでのlogout&再loginが必要</span>\n\n</code></pre></div></div>\n\n<h2 id=\"日本語入力\">日本語入力</h2>\n<p>前は設定必要だったけど、なんか大丈夫になったみたい</p>\n<blockquote>\n  <p>[!NOTE]\n以前の設定手順<br />\n右上の「A」または「あ」と書かれたアイコンをクリック→「テキスト入力設定」を選択\n一番下の「インストールされている言語の管理」をクリック\n「言語サポートが完全にはインストールされていません」と出るので「インストール」をクリック\n一旦log offして再log in\n右上のJaまたはMoと書かれたアイコンをクリック\n    Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)\nキーボードの全角/半角キーで切り替えられるようになる</p>\n</blockquote>\n\n<h2 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h2>\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nUbuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>IPv6が動いてるとうまく行かない環境のときは無効化しておく。<br />\n参考:<a href=\"https://www.server-memo.net/ubuntu/ubuntu_disable_ipv6.html#IPv6-4\" target=\"_blank\">UbuntuでIPv6を無効化する方法</a></p>\n\n<p>sysctlで設定するのがお手軽かな?</p>\n\n<h2 id=\"システムバックアップ\">システムバックアップ</h2>\n<p>Nativeならバックアップしといた方がいいかな。<br />\n参考:<a href=\"https://gihyo.jp/admin/serial/01/ubuntu-recipe/0588\">第588回 TimeShiftでUbuntuをホットバックアップする 2019年版</a> <br />\n<code class=\"language-plaintext highlighter-rouge\">add-apt-repository</code> でリポジトリを追加しなくても大丈夫。標準リポジトリにも入ってるから。</p>\n\n<h2 id=\"chrome-remote-desktopインストール\">chrome remote desktopインストール</h2>\n\n<p>remote desktop使いたいので、インストールする。</p>\n\n<h3 id=\"chromeのインストール\">chromeのインストール</h3>\n<p><a href=\"https://www.google.com/chrome/\">Google Chrome - Google の高速で安全なブラウザをダウンロード</a>からダウンロードしてインストール。</p>\n\n<h3 id=\"おまじない\">おまじない</h3>\n<p>remote desktopのインストール時にエラーが発生するので、以下のディレクトリを作成しておく。<br />\n(インストーラのバグらしい)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/.config/chrome-remote-desktop\n</code></pre></div></div>\n\n<h3 id=\"remote-desktopのインストール\">remote desktopのインストール</h3>\n<p>以下参考ページ</p>\n<ul>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>パソコンでリモート アクセスを設定する</li>\n      <li>パソコンにリモート アクセスする</li>\n    </ul>\n  </li>\n</ul>\n\n<p>接続すると、開始するセッションの選択画面になるので、「Ubuntu」を選択。</p>\n\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。<br />\nこのダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></li>\n</ul>\n\n<p>要約すると\n<code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下の内容で作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 20.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 20.04のインストール</h1>\n      <p>Ubuntu 20.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>VirtualBox へのインストール前提で書いてます。<br />\nでも、仮想マシンの作成以外は同じかな。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-2004-インストール媒体の入手\">Ubuntu 20.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら:\n<a href=\"https://www.ubuntulinux.jp/products/JA-Localized/download\" target=\"_blank\">Ubuntu Desktop 日本語 Remixのダウンロード</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを2048MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<p>以下の説明が図付きで分かりやすい:\n<a href=\"https://qiita.com/HirMtsd/items/225c20b77a7cd5194834\" target=\"_blank\">Windows10上のVirtualBoxにUbuntu20.04をインストール</a></p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ブランクスクリーン しない</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.session idle-delay 0\n<span class=\"c\"># 自動画面ロック OFF</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.screensaver lock-enabled <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>GUIで設定する場合は以下の手順で。</p>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシー > 画面ロック を選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<p>ここでVirtualboxの拡張機能が使えるようになっているので、<br />\nVirtualboxのメニューから「デバイス」→「クリップボードの共有」→「双方向」<br />\nを選択。\nこれでホストとゲストでクリップボードが共有できる。</p>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが</p>\n\n<h3 id=\"ツール類\">ツール類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird libreoffice-<span class=\"k\">*</span> simple-scan gnome-todo remmina cheese rhythmbox\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n<span class=\"nb\">sudo </span>apt remove rhythmbox\n</code></pre></div></div>\n\n<h3 id=\"ゲーム類\">ゲーム類</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot gnome-mahjongg gnome-mines gnome-sudoku\n\n<span class=\"c\"># 個別に実行する場合はこちらでどうぞ。</span>\n<span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h3 id=\"要らなくなったパッケージのお掃除\">要らなくなったパッケージのお掃除</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt autoremove\n</code></pre></div></div>\n\n<h2 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h2>\n<blockquote>\n  <p>[!NOTE]\n前のバージョンまでは、WMをGnome Flashbackに変更してたけど、<br />\n日本語入力とかと相性悪いみたいなので、やめといた方が無難<br />\nインストールする場合はここを参考に: <a href=\"https://goto-linux.com/ja/2020/3/13/ubuntu-20.04-gnome-flashback%E3%83%86%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%95%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB/\" target=\"_blank\">Ubuntu 20.04 Gnome Flashbackデスクトップのインストール</a></p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-session-flashback\n</code></pre></div>  </div>\n  <p>「GNOME Flashback(Compiz)」はなくなったらしい</p>\n</blockquote>\n\n<h2 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h2>\n\n<p>端末を起動し、右上の「≡」→「設定」を選択\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\n「フォントを指定」にチェックを入れ、その右側でフォントを選ぶ<br />\nUbuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work /work1 /work2 /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h2 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h2>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"bashの設定変更\">bashの設定変更</h2>\n\n<p>~/.bashrcに以下を追記</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"c\"># export VIRTUAL_ENV_DISABLE_PROMPT=1</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h2 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで無効化できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h2 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode mouse\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h2 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h2>\n<p>dconf-editorでも良いけど、以下のコマンドで設定できる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.desktop-icons show-trash <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nFlashbackの場合は以下らしい。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.gnome-flashback.desktop.icons show-home <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.gnome-flashback.desktop.icons show-trash <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockのカスタマイズ\">Dockのカスタマイズ</h2>\n<p>なんとなく使いにくいので好みのデザインに変更。<br />\ndconf-editorでも良いよ(しつこい…)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#ゴミ箱削除</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-trash <span class=\"nb\">false</span>\n\n<span class=\"c\"># アプリケーションをDockバーの上(または左)に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock show-apps-at-top <span class=\"nb\">true</span>\n\n<span class=\"c\"># Dockバーを画面下に表示</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM\n\n<span class=\"c\"># アイコンサイズの変更</span>\ngsettings <span class=\"nb\">set </span>org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 16\n</code></pre></div></div>\n\n<h2 id=\"日本語入力\">日本語入力</h2>\n<p>前は設定必要だったけど、なんか大丈夫になったみたい</p>\n<blockquote>\n  <p>[!NOTE]\n以前の設定手順<br />\n右上の「A」または「あ」と書かれたアイコンをクリック→「テキスト入力設定」を選択\n一番下の「インストールされている言語の管理」をクリック\n「言語サポートが完全にはインストールされていません」と出るので「インストール」をクリック\n一旦log offして再log in\n右上のJaまたはMoと書かれたアイコンをクリック\n    Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)\nキーボードの全角/半角キーで切り替えられるようになる</p>\n</blockquote>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[opt]\npath = /opt\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"nfsのインストール\">NFSのインストール</h2>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>exportできているか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>exportfs \n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h2 id=\"マウスカーソルを大きくする\">マウスカーソルを大きくする</h2>\n\n<p>マウスカーソル小さくて見失う人は大きくしましょう。<br />\n最後の数字がカーソルの大きさなので、お好みのサイズで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.desktop.interface cursor-size 48\n</code></pre></div></div>\n\n<p>または「設定」→「ユニバーサルアクセス」→「カーソルの大きさ」で選択</p>\n\n<h2 id=\"ctrlキーとcapsキーを入れ替える\">CTRLキーとCAPSキーを入れ替える</h2>\n\n<p>Virtualbox環境ではWindowsで設定したのが有効になっているので必要ないが、Native Installの場合は以下のページを参考に入れ替えを設定する。<br />\n<a href=\"https://www.yokoweb.net/2019/08/07/ubuntu-18_04-desktop-caps-ctrl/\" target=\"_blank\">【Ubuntu 20.04/18.04 LTS】CapsLockとControlキーを入れ替える </a></p>\n\n<p>リブート必要だが、以下のIPv6無効化とまとめてリブートでも可。</p>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>参考:<a href=\"https://goto-linux.com/ja/2019/11/24/ubuntu-20.04-lts-focal-fossa%E3%81%A6ipv6%E3%82%A2%E3%83%88%E3%83%AC%E3%82%B9%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/\" target=\"_blank\">Ubuntu 20.04 LTS Focal FossaでIPv6アドレスを無効にする方法</a></p>\n\n<p>/etc/default/grubの以下の部分(10行目あたり)に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash\"</span>\n↓\n<span class=\"nv\">GRUB_CMDLINE_LINUX_DEFAULT</span><span class=\"o\">=</span><span class=\"s2\">\"quiet splash ipv6.disable=1\"</span>\n<span class=\"c\"># または、ブートシーケンスのログを表示したい場合は以下。</span>\n<span class=\"c\"># GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"</span>\n\n</code></pre></div></div>\n\n<p>grubメニューの更新</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>update-grub\n</code></pre></div></div>\n\n<p>リブートする</p>\n\n<h2 id=\"以上でインストールは終了\">以上でインストールは終了</h2>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hosts は書き換えられないので、手動で書き換える</p>\n</blockquote>\n\n<p>IPアドレスの変更(固定アドレスにしたい場合)</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n<p>まとめて実行するならこちら。<br />\n接続名があってるかは確認しておくこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># マシン番号の設定とホスト名の設定</span>\n<span class=\"nv\">number</span><span class=\"o\">=</span>30\n<span class=\"nv\">new_hostname</span><span class=\"o\">=</span>skull<span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span>\n\n<span class=\"c\"># HOSTNAMEの変更</span>\n<span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/ubuntu-20.*</span><span class=\"nv\">$/</span><span class=\"k\">${</span><span class=\"nv\">new_hostname</span><span class=\"k\">}</span><span class=\"s2\">/\"</span> /etc/hosts\n\n<span class=\"c\"># HOST ONLY ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n\n<span class=\"c\"># BRIDGE ADAPTERの設定変更</span>\n<span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.</span><span class=\"k\">${</span><span class=\"nv\">number</span><span class=\"k\">}</span><span class=\"s2\">/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>UbuntuをNative環境にインストールする(18.04)</title>\n  </head>\n  <body>\n    <header>\n      <h1>UbuntuをNative環境にインストールする(18.04)</h1>\n      <p>Ubunt(18.04)をNative環境にインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntu-をnative環境virtualboxではなくにインストールする\">Ubuntu をNative環境(Virtualboxではなく)にインストールする</h1>\n\n<p><a href=\"/memoBlog/2019/06/26/install1804.html\">Ubuntu 18.04のインストール</a>ではVirtualbox環境にUbuntuをインストールする手順を書いたが、ここではNative環境にインストールする手順を説明する。</p>\n\n<p>ハードウェア構成としては、Ubuntuを外付けHDDにインストールし、内蔵ディスクのWindowsは消さずにデュアルブート環境にする。<br />\n手順はPCはNECのLavie all-in-oneタイプ(ちょっと古い奴)で確認している。<br />\nBIOS関連など、PC固有の機能に左右される部分は機種によって異なるので注意。</p>\n\n<h2 id=\"前準備\">前準備</h2>\n\n<h3 id=\"hddをgpt化\">HDDをGPT化</h3>\n<p>インストールするHDDのパーティションがMBRだとEFIブートができないので、<br />\n対象ハードディスクのパーテイションテーブルをGPTに変更<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://pc-karuma.net/windows-10-convert-mbr-gpt-disk/\">Windows10 - MBRディスク ⇔ GPTディスクに変換(変更)</a></li>\n</ul>\n\n<h3 id=\"インストールメディアでインストーラ起動\">インストールメディアでインストーラ起動</h3>\n<p>インストールメディアはブータブルUSBメモリを作成すると便利<br />\nブータブルUSBメモリの作成は以下を参照</p>\n<ul>\n  <li><a href=\"https://forest.watch.impress.co.jp/library/software/rufus/?fbclid=IwAR0Ry5oRt3jOegmkkswUQmudtvuleLCkH44-Tx8brnS0VYQJLQLBmGtT5Lw\">窓の杜 Rufus</a></li>\n  <li><a href=\"https://pc-freedom.net/software/how-to-use-rufus/?fbclid=IwAR1bXsLVQviiwpcQSZapci1vgJKF4rFv1nmIh7knZkrdQDJkGh7BLTrcXi4\">RufusでLinuxのインストールメディアを作る</a></li>\n  <li><a href=\"https://rufus.ie/\">本家</a></li>\n</ul>\n\n<p>ダウンロードしたファイルはインストーラではなく、ポータブル版の実行ファイル。<br />\n大体直感的に使えるけど、<strong><em>UEFI モードで起動できるようにするにはパーティション構成でGPTを選択しないといけない</em></strong>らしい。<br />\nGPT にしておけば、UEFI モードでブートするPCのbootデバイスの優先順位をUSBをHDDより高くしておけば対象のHDDからブートできる。</p>\n\n<p>これで逐一CD-Rを焼かなくて済む。<br />\nまた、起動もCD-Rより高速。</p>\n\n<h2 id=\"対象ハードディスクにインストール\">対象ハードディスクにインストール</h2>\n<p>以下を参照。</p>\n<ul>\n  <li><a href=\"https://linuxfan.info/ubuntu-18-04-install-guide\">Ubuntu 18.04 LTSインストールガイド【スクリーンショットつき解説】</a></li>\n</ul>\n\n<h2 id=\"再起動してbiosセットアップメニューを起動\">再起動してBIOSセットアップメニューを起動</h2>\n<p>NEC LAVIEの場合、電源ON時にF2キーを連打し、BIOSセットアップメニューを表示<br />\n「Boot」の「Boot Priority Order」の起動順序で「Ubuntu」を「Windows」の上に持ってくる。<br />\nその後、 saveしてreset。</p>\n\n<h2 id=\"基本的な初期設定\">基本的な初期設定</h2>\n<p>Virtualbox版の手順の<a href=\"/memoBlog/2019/06/26/install1804.html\">Ubuntu 18.04のインストール</a>を参照。<br />\n基本的にこれと同じで大丈夫(GuestAdditionのインストール、grub-pcのインストール先情報の変更を除く)</p>\n\n<h3 id=\"もっと簡単に設定する方法があった\">もっと簡単に設定する方法があった</h3>\n<p>以下の項目はもっと簡単に設定する方法があったのでメモ。</p>\n\n<ul>\n  <li>「ウィンドウが勝手に最大化するのをやめる」</li>\n  <li>「ウィンドウにマウスを乗せるとフォーカスされるようにする」</li>\n  <li>「デスクトップからゴミ箱とホームを消す」</li>\n</ul>\n\n<p>これらの設定はdconf-editorでなく、gnome-tweaksを使うと簡単(dconf-editorでもOK)</p>\n\n<p>gnome-tweaksのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\ngnome-tweaks\n</code></pre></div></div>\n<ul>\n  <li>「ウィンドウにマウスを乗せるとフォーカスされるようにする」\n    <ul>\n      <li>「ウィンドウ」で「ウィンドウフォーカス」を「Sloppy」にする</li>\n    </ul>\n  </li>\n  <li>「デスクトップからゴミ箱とホームを消す」\n    <ul>\n      <li>「デスクトップ」で選択</li>\n    </ul>\n  </li>\n  <li>「CTRLとCapsLockの入れ替えを行う」(Virtualboxではホスト側で入れ替えてたので不要だった)\n    <ul>\n      <li>「キーボードとマウス」で「追加のレイアウトオプション」をクリック\n        <ul>\n          <li>Ctrl position」の「CapsLockをCtrlとして扱う」を選択する。\n            <ul>\n              <li>「CtrlとCapsLockを入れ替える」だとうまく動かないので注意。</li>\n              <li>UnityとGNOME Flashbackでは設定は別らしい。</li>\n              <li>GNOME Flashbackでは「CtrlとCapsLockを入れ替える」でもOK。</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>「ウィンドウが勝手に最大化するのをやめる」\n    <ul>\n      <li>設定項目が見当たらないので、dconf editorで設定する。\n        <ul>\n          <li>dconf editor起動して以下を変更\n            <ul>\n              <li>/org/gnome/metacity/edge-tiling false</li>\n              <li>/org/gnome/mutter/edge-tiling false</li>\n              <li>/org/gnome/shell/overrides/edge-tiling false</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"sshのインストール\">sshのインストール</h1>\n<p>WindowsPCにあるデータをubuntuPCにキーボードで打ち込むのは効率が悪いので、最も簡単なsshでリモートログインできるようにしてみる。</p>\n\n<p>以下のコマンドでsshサーバをインストールし、サーバを開始する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n<p>クライアントからTeraTermなどでsshで対象マシンのポート22に接続する</p>\n\n<h1 id=\"vncで画面共有する\">vncで画面共有する</h1>\n\n<p>sshリモートログインよりもうちょっと使いやすくしたいので、vncで画面共有するようにしてみる。</p>\n\n<p>chrome リモートデスクトップ等とは異なり、コンソールに表示している画面を共有して操作するもの。<br />\n使用したクライアント(VNC-Viewer)がヘボいからなのか、ちょっと反応鈍いけど、<br />\nコンソールで作業していた実行状況を確認したり<br />\n会社でトラブった人のリモートサポートなんかに使えるかも。</p>\n\n<p>やり方自体はとてもシンプル。<br />\n特にインストールとかも必要ない。<br />\n(クライアント側はVNC viewerなどを実行する必要があるけど、こっちもインストールは不要(単体実行))</p>\n\n<p>例によって手順の説明は他力本願(^^ゞ<br />\n参照:</p>\n<ul>\n  <li><a href=\"https://www.yokoweb.net/2019/12/09/ubuntu-18_04-desktop-vnc-remote/\">【Ubuntu 18.04 Desktop】WinやMacパソコンからVNCでリモート接続し画面共有する </a></li>\n</ul>\n\n<p>そのままトレースすればできるけど、ちょっと「ん?」と思ってしまうエラーが。<br />\n同じページの<a href=\"https://www.yokoweb.net/2019/12/09/ubuntu-18_04-desktop-vnc-remote/#toc5\">ココ</a>に解決策がかかれているけど、ちゃんと前もって書いておいてほしいもんだ(笑)。<br />\n解決策の要約は以下の通り。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false</span>\n<span class=\"c\"># 実行後再起動必要</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ndconf editor でも設定可能。<br />\nなので、dconf editorとの設定操作とバッティングしないように注意<br />\ndconf editorで設定する場合は以下<br />\n   /org/gnome/desktop/remote-access/require-encryption</p>\n</blockquote>\n\n<p>あくまで共有なのでコンソール側でGUIログインしてないとつながらない。<br />\n反応鈍いので、普段使いにはちょっとストレスかも。<br />\nchrome リモートデスクトップ使えるならそっち使ったほうがいいかな。</p>\n\n<h1 id=\"chromeリモートデスクトップのインストール\">chromeリモートデスクトップのインストール</h1>\n\n<p>chromeリモートデスクトップ による接続は画面の共有ではなく、新しいセッションによる接続となる(Xclientみたいなもん?)。<br />\nwindowsマシンに接続した場合は表示画面のミラーリングだったが。</p>\n\n<p>chromeのインストール&リモートデスクトップのインストールはWindowsとほぼ同じ。<br />\n以下参考ページ</p>\n<ul>\n  <li><a href=\"https://www.google.com/chrome/\">Google Chrome フェブブラウザ</a></li>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>パソコンでリモート アクセスを設定する</li>\n      <li>パソコンにリモート アクセスする</li>\n    </ul>\n  </li>\n</ul>\n\n<p>接続すると、開始するセッションの選択画面になるので、「Ubuntu」を選択。GNOME Flashbackだとつながらない…なんで??</p>\n\n<p>接続すると、「カラーマネジメントされたデバイスを作成するには認証が必要です」ダイアログが出る場合がある。このダイアログはパスワード入れてもキャンセルしても結果は同じで問題なく操作できるが、逐一やるのはめんどっちいので出なくする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qastack.jp/ubuntu/1031519/xrdp-on-ubuntu-18-04lts\">Ubuntu 18.04LTS上のXRDP</a></li>\n</ul>\n\n<p>要約すると\n<code class=\"language-plaintext highlighter-rouge\">/etc/polkit-1/localauthority/50-local.d/45-allow.colord.pkla</code> で以下を入力</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Allow Colord all Users]\nIdentity=unix-user:*\nAction=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile\nResultAny=no\nResultInactive=no\nResultActive=yes\n</code></pre></div></div>\n\n<p>設定を有効にするのは再起動必要。</p>\n\n<h2 id=\"コンソール画面を共有したい場合\">コンソール画面を共有したい場合</h2>\n\n<p>chromeリモートデスクトップでvnc同様のコンソール画面の共有をすることも可能。<br />\n設定方法は以下を参照。</p>\n<ul>\n  <li><a href=\"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DDesktop&hl=ja\">Chrome リモート デスクトップを使って他のパソコンにアクセスする</a>\n    <ul>\n      <li>他のユーザとパソコンを共有する</li>\n    </ul>\n  </li>\n</ul>\n\n<p>この方法だと、アクセスコードの生成(コンソール側)/アクセスコードの入力(リモート側)/アクセス許可(コンソール側)と手続きが少々煩雑(毎回必要)。<br />\n画面共有で操作するにはvncのほうが簡単かな?</p>\n\n<h1 id=\"biosセットアップメニューでのブートマネージャの表示名を変更する\">BIOSセットアップメニューでのブートマネージャの表示名を変更する</h1>\n\n<p>ubuntu をインストールした後、BIOSセットアップメニューでブート優先順位を指定しようとすると<br />\nubuntuのブートマネージャが2つ表示されて、どちらを選べばよいのか見分けがつかない。<br />\n(機種によってはpathが表示されて見分けられるものもあるらしいが、私のPCはそうなってない)</p>\n\n<p>そこで、表示名を変更して見分けがつくようにしてみる。</p>\n\n<p>以下、参考ページ</p>\n<ul>\n  <li><a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1383uefinvnm/uefinvnm.html\">bcdeditでUEFIのブート・エントリの名前を変更する</a></li>\n</ul>\n\n<p>まず、Windowsを起動し、管理者権限でコマンドプロンプト(cmd.exe)を実行する。\nPowerShellではちょっとテクニックが要る(というほど大げさではないが)みたいなので、\nコマンドプロンプトで実行するのが無難。</p>\n\n<p>現在の状態の確認</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /enum firmware\n</code></pre></div></div>\n\n<p>実行結果</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ファームウェアのブート マネージャー\n--------------------------------\nidentifier              {fwbootmgr}\ndisplayorder            {bootmgr}\n                        {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\n                        {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ntimeout                 1\n\nWindows ブート マネージャー\n--------------------------------\n《省略》\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\ubuntu\\shimx64.efi\ndescription             ubuntu\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\Ubuntu\\grubx64.efi\ndescription             ubuntu\n</code></pre></div></div>\n\n<p>表示名を変更する<br />\n指定するuuidは現状の確認で確認したuuidに置き換えること。<br />\ndescriptionが表示名なので、これを好みの名前に変更する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /set {9b7f627e-7edc-11ea-84b2-806e6f6e6963} description  \"ubuntu shimx64\"\nbcdedit /set {9b7f627f-7edc-11ea-84b2-806e6f6e6963} description  \"ubuntu grubx64\"\n</code></pre></div></div>\n\n<p>結果を確認する</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bcdedit /enum firmware\n</code></pre></div></div>\n\n<p>実行結果</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ファームウェアのブート マネージャー\n--------------------------------\nidentifier              {fwbootmgr}\ndisplayorder            {bootmgr}\n                        {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\n                        {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ntimeout                 1\n\nWindows ブート マネージャー\n--------------------------------\n《省略》\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627e-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\ubuntu\\shimx64.efi\ndescription             ubuntu shimx64\n\nファームウェア アプリケーション (101fffff\n--------------------------------\nidentifier              {9b7f627f-7edc-11ea-84b2-806e6f6e6963}\ndevice                  partition=\\Device\\HarddiskVolume2\npath                    \\EFI\\Ubuntu\\grubx64.efi\ndescription             ubuntu grubx64\n</code></pre></div></div>\n\n<p>ちなみに、shimx64.efi と grubx64.efi の違いは、セキュアブートの対応/非対応の違いである。<br />\n通常(セキュアブート有効のハズ)はshimx64.efiで良いと思われる。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://netlog.jpn.org/r271-635/2019/08/uefi_windows10_ubuntu_install.html\">UEFIのWindows 10マシンにUbuntu 18.04を追加インストールしデュアルブート化する</a>\n    <ul>\n      <li>「UbuntuがUEFIのブートメニューに登録されていることを確認」のあたり</li>\n    </ul>\n  </li>\n</ul>\n\n<p>この設定はbuntuを再インストールすると上書きされてしまうので、再度変更する必要がある。</p>\n\n<h1 id=\"grubのboot-menuの表示などの変更方法\">GRUBのboot menuの表示などの変更方法</h1>\n\n<p>デフォルトのubuntuインストール状態では、GRUBのブートメニューが表示されない。<br />\nそこで、ブートメニューを表示するように変更してみる。<br />\nついでに、設定する箇所が同じなので、</p>\n\n<ul>\n  <li>タイムアウトまでの時間の変更(あっ?と思った瞬間にブートされちゃうと悲しいので)</li>\n  <li>スプラッシュスクリーンを表示しなくする(ちゃんとブートしてるか心配なので(笑))</li>\n</ul>\n\n<p>も設定しておく。</p>\n\n<p>まず、ubuntuを起動してターミナル起動</p>\n\n<p>rootでないとできないことなので、rootでbashを実行しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>bash                                     \n</code></pre></div></div>\n\n<p>設定ファイル <code class=\"language-plaintext highlighter-rouge\">/etc/default/grub</code> を以下の内容で変更する</p>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- grub.org\t2020-05-08 06:16:59.908079737 +0900\n</span><span class=\"gi\">+++ grub\t2020-05-08 06:17:13.540255464 +0900\n</span><span class=\"p\">@@ -3,11 +3,11 @@</span>\n # For full documentation of the options in this file, see:\n #   info -f grub -n 'Simple configuration'\n \n<span class=\"gd\">-GRUB_DEFAULT=0\n-GRUB_TIMEOUT_STYLE=hidden\n-GRUB_TIMEOUT=10\n</span><span class=\"gi\">+GRUB_DEFAULT=saved\n+GRUB_TIMEOUT_STYLE=menu\n+GRUB_TIMEOUT=30\n</span> GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`\n<span class=\"gd\">-GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash\"\n</span><span class=\"gi\">+GRUB_CMDLINE_LINUX_DEFAULT=\n</span> GRUB_CMDLINE_LINUX=\"\"\n \n # Uncomment to enable BadRAM filtering, modify to suit your needs\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">GRUB_DEFAULT</code> がデフォルトの選択項目。 <code class=\"language-plaintext highlighter-rouge\">saved</code> は前回選択項目。rebootのときだけ??動きがイマイチわからんかった。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_TIMEOUT_STYLE</code> がメニュー表示形式。<code class=\"language-plaintext highlighter-rouge\">hidden</code> は表示しない、<code class=\"language-plaintext highlighter-rouge\">menu</code> はメニューを表示する。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_TIMEOUT</code> がタイムアウトまでの時間。単位は秒。<br />\n<code class=\"language-plaintext highlighter-rouge\">GRUB_CMDLINE_LINUX_DEFAULT</code> がLinux起動時のコマンドラインオプション。<code class=\"language-plaintext highlighter-rouge\">quiet splash</code> を指定すると起動メッセージを表示せず、スプラッシュスクリーンを表示する。これを削除することで起動メッセージが表示される</p>\n\n<p>変更した設定をcfgファイルに反映する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>grub-mkconfig <span class=\"nt\">-o</span> /boot/grub/grub.cfg            \n</code></pre></div></div>\n\n<p>これで、次回起動時からGRUBのブートメニューが変更される</p>\n\n<p>以下、参考ページ:</p>\n<ul>\n  <li><a href=\"http://www.usupi.org/sysad/202.html\">いますぐ実践! Linux システム管理</a></li>\n</ul>\n\n<p>この項目と直接関係ないけど、起動時にのfsckを実行する方法の参考ページ。</p>\n<ul>\n  <li><a href=\"https://linux.just4fun.biz/?Linux%E7%92%B0%E5%A2%83%E8%A8%AD%E5%AE%9A/%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E9%96%93%E9%9A%94%E3%81%AE%E7%A2%BA%E8%AA%8D\">Linux環境設定/起動時のファイルシステムチェック間隔の確認 </a></li>\n</ul>\n\n<h1 id=\"usb-hdd接続-ubuntuのboot未接続windowsのbootにする方法\">USB-HDD接続→ Ubuntuのboot、未接続→Windowsのbootにする方法</h1>\n\n<p>ubuntuがインストールされたUSB-UDDが接続されていたらubuntuが、接続されていなければ内蔵HDDのWindowsが自動的に起動するようにしてみる。<br />\n(デフォルトのインストール状態だとブート優先順位を変更しないと切り替えられない)<br />\nちょうどFDDブートのような感じ。</p>\n\n<p>BIOSセットアップにより、ブートモードはUEFIブートで、ブート優先順位はubuntuの方を高く設定しておく。</p>\n\n<p>まず、ubuntuを起動する</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/boot/efi/EFI/ubuntu/grub.cfg</code> を以下のように変更する。<br />\nrootでないとアクセスできないので、<code class=\"language-plaintext highlighter-rouge\">sudo bash</code>  して rootでshellを動かして作業するのが良い。</p>\n\n<ul>\n  <li>元のファイル\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>search.fs_uuid 60c491cd-126d-4f4a-a321-84bb2e0d9068 root hd1,gpt1 \nset prefix=($root)'/boot/grub'\nconfigfile $prefix/grub.cfg\n</code></pre></div>    </div>\n  </li>\n  <li>変更後のファイル\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>if search.fs_uuid 60c491cd-126d-4f4a-a321-84bb2e0d9068 root hd1,gpt1 ;then\n set prefix=($root)'/boot/grub'\n configfile $prefix/grub.cfg\nelse\n set timeout_style=menu\n set timeout=0\n menuentry 'Windows Boot Manager (on /dev/sda2)' --class windows --class os $menuentry_id_option 'osprober-efi-2A43-3D28' {\n    insmod part_gpt\n    insmod fat\n    set root='hd0,gpt2'\n    if [ x$feature_platform_search_hint = xy ]; then\n       search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  2A43-3D28\n    else\n       search --no-floppy --fs-uuid --set=root 2A43-3D28\n    fi\n    chainloader /EFI/Microsoft/Boot/bootmgfw.efi\n}\nfi\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>メモ:</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">60c491cd-126d-4f4a-a321-84bb2e0d9068</code>  は ubuntuのインストールされたパーティションのuuidなので、接続したUSB-HDDDのuuidに合わせて変更する。\n    <ul>\n      <li>パーティションのuuidは以下で確認可能。\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"s1\">' \\/boot\\/efi '</span> /etc/mtab         <span class=\"c\"># デバイスファイルを確認する</span>\n<span class=\"nb\">sudo </span>blkid /dev/sda2                   <span class=\"c\"># 確認したデバイスファイルを指定する</span>\n</code></pre></div>        </div>\n      </li>\n      <li>あるいは、元のファイルのuuidをコピるのでもOK。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">2A43-3D28</code>はEFIシステムパーティションのuuidなので、環境に合わせて変更する。\n    <ul>\n      <li>パーティションのuuidは以下で確認可能。\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"s1\">' \\/ '</span> /etc/mtab                  <span class=\"c\"># デバイスファイルを確認する</span>\n<span class=\"nb\">sudo </span>blkid /dev/sdb1                   <span class=\"c\"># 確認したデバイスファイルをしてする</span>\n</code></pre></div>        </div>\n      </li>\n      <li>あるいは、<code class=\"language-plaintext highlighter-rouge\">/boot/grub/grub.cfg</code> の <code class=\"language-plaintext highlighter-rouge\">menuentry 'Windows Boot Manager ~</code>  の部分をパクってきても可。</li>\n    </ul>\n  </li>\n  <li>このファイルはbuntuを再インストールすると上書きされてしまうので、再度編集する必要がある。</li>\n</ul>\n\n<p>処理の解説:<br />\n元のgrub.cfgではUSB-HDDが接続されていなければ <code class=\"language-plaintext highlighter-rouge\">$prefix/grub.cfg</code>  が見つからないので、GRUBメニューが表示されない。<br />\nそこで、<code class=\"language-plaintext highlighter-rouge\">search.fs_uuid</code> の実行結果により、ディスクが見つかったら従来通りの処理、<br />\n見つからなかったらWindows Boot Managerを起動するようにしている。</p>\n\n<h3 id=\"参考情報\">参考情報</h3>\n<p>WindowsからEFIシステムパーティションのファイルを編集するには、このあたりを参考に。</p>\n<ul>\n  <li><a href=\"https://bi.biopapyrus.jp/os/win/dualboot-fix-bootmenu.html\">デュアルブートから Ubuntu を削除する方法</a><br />\nマウントする部分だけね。</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbianのディスクイメージのアーカイブ</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbianのディスクイメージのアーカイブ</h1>\n      <p>Raspbianのディスクイメージのアーカイブのありかをすぐ忘れてしまうのでメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"メモ\">メモ</h1>\n\n<p>Raspbianのディスクイメージのアーカイブは以下にある。<br />\n各バージョン(日付)別にディレクトリ分けされている。<br />\nミラーサイトが爆速なのでおススメ。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>項目</th>\n      <th>URL</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>最新版</td>\n      <td><a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(本家)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_armhf/images/\">https://downloads.raspberrypi.org/raspios_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Full版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_full_armhf/images/\">https://downloads.raspberrypi.org/raspios_full_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspios_lite_armhf/images/\">https://downloads.raspberrypi.org/raspios_lite_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(ミラーサイト)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Full版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/\">http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/</a></td>\n    </tr>\n    <tr>\n      <td>アーカイブ(2020/02以前版)</td>\n      <td> </td>\n    </tr>\n    <tr>\n      <td>デスクトップ版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspbian/images/\">https://downloads.raspberrypi.org/raspbian/images/</a></td>\n    </tr>\n    <tr>\n      <td>Lite版</td>\n      <td><a href=\"https://downloads.raspberrypi.org/raspbian_lite/images/\">https://downloads.raspberrypi.org/raspbian_lite/images/</a></td>\n    </tr>\n  </tbody>\n</table>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian SDカードイメージファイルの縮小</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian SDカードイメージファイルの縮小</h1>\n      <p>Raspbian SDカードイメージファイルの縮小</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2020/10/25/Jetson_nano_backup.html\">Jetson nano のSDカードをバックアップする</a> \nに改訂版を公開しました。そちらを参照してください。</p>\n\n<h1 id=\"イメージファイルの縮小\">イメージファイルの縮小</h1>\n\n<h3>『イメージファイルの縮小』はUbuntuで実行することを前提に書いてあります。</h3>\n\n<p>SDカードに作成した、RaspberryPiのオリジナルのカスタムブートディスク\n(<a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\">Raspbian Busterのインストール</a>、\n<a href=\"/memoBlog/2019/09/13/raspbian_buster_2.html\">Raspbian Buster Lite版のインストール</a>参照)\nは、イメージファイルにバックアップしておくと、\n再度カスタマイズ作業を行わなくても同じ環境を作成できる。</p>\n\n<p>ただ、このイメージファイルはSDカードを丸ごとファイル化するので、元のSDカードより小さなSDカードにコピーできない。<br />\n(スペック上同じ容量のSDカードでも微妙にサイズが違ったりするので入らないことがある)</p>\n\n<p>そこで、イメージファイルを縮小しておけば、小さなSDカードにもコピーできる(コピー時間も短縮できて一石二鳥)。<br />\nこのとき、ディスクイメージ内部のパーティション情報/ファイルシステム情報をきちんと縮小処理しておかないと\nファイルシステムエラーになってしまうので、注意が必要。</p>\n\n<p>今回はSDカードから作成したイメージファイルを<strong>Ubuntuで</strong>縮小処理するスクリプトを書いてみた。<br />\nとりあえず、手元の環境では動いているが、詳細評価したわけではないので、\n実行する場合は自己責任で。</p>\n\n<p>また、途中<strong>エラーチェックは行っていない</strong>ので、エラーが発生していないか、実行結果を注意深く確認すること。</p>\n\n<h2 id=\"virtualbox-共有フォルダのマウント\">Virtualbox 共有フォルダのマウント</h2>\n\n<p>SDカードのイメージファイルは大きいので、共有フォルダを使ってWindows側のフォルダをアクセスできるようにしておけばディスク領域を圧迫しなくて済む。<br />\nVirtualbox側で共有フォルダ「Share」を作成済みで、/Shareディレクトリにマウントする場合は以下のコマンドで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> vboxsf Share /Share/\n</code></pre></div></div>\n\n<h2 id=\"ツールのインストール\">ツールのインストール</h2>\n\n<p>イメージファイル内のパーティションをそれぞれloopデバイスに割り当てるツールを使用する。<br />\n以下のコマンドでインストールできる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>kpartx\n</code></pre></div></div>\n\n<h2 id=\"スクリプト\">スクリプト</h2>\n\n<p>以下のスクリプトを適当な名前(例えば<code class=\"language-plaintext highlighter-rouge\">shrink_img.sh</code>)で保存し、実行する(<code class=\"language-plaintext highlighter-rouge\">bash shrink_img.sh</code>)。<br />\n実行する前に使用するファイル名を設定すること。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: left\">変数</th>\n      <th style=\"text-align: left\">内容</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: left\">WORK_IMG_FILE</td>\n      <td style=\"text-align: left\">作業用イメージファイルのファイル名</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: left\">NEW_IMG_FILE</td>\n      <td style=\"text-align: left\">小さくしたイメージファイルのファイル名</td>\n    </tr>\n  </tbody>\n</table>\n\n<p>WORK_IMG_FILE で指定したファイルは書き変えられるので、オリジナルのイメージファイルは 別途残しておくこと。</p>\n\n<p>内部で<code class=\"language-plaintext highlighter-rouge\">sudo</code>を実行しているので、パスワードを聞かれたら入力する。</p>\n\n<p>途中、『警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?』と聞かれたら「y」を入力する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># イメージファイル</span>\n<span class=\"nv\">WORK_IMG_FILE</span><span class=\"o\">=</span>/Share/tmp.img            <span class=\"c\"># 作業ファイル</span>\n<span class=\"nv\">NEW_IMG_FILE</span><span class=\"o\">=</span>/Share/shrink.img          <span class=\"c\"># 縮小した(作成する)ファイル</span>\n\n<span class=\"c\"># イメージファイルをマッピング(マッピング済みでも問題ない) </span>\n<span class=\"c\"># 前回の操作が終わるのを待つため-sを付けておく</span>\n<span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-asv</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span>\n\n<span class=\"c\"># loopデバイス名を取得</span>\n<span class=\"c\"># 前回の操作が終わるのを待つため-sを付けておく</span>\n<span class=\"nv\">tmp_var</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-ls</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">LOOP_DEV</span><span class=\"o\">=</span>/dev/mapper/<span class=\"k\">${</span><span class=\"nv\">tmp_var</span><span class=\"p\">[6]</span><span class=\"k\">}</span>          <span class=\"c\"># 結果の位置は決め打ちで(姑息だけど)</span>\n\n<span class=\"c\"># 要求するブロックサイズの取得</span>\n<span class=\"nv\">tmp_var</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>resize2fs <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">req_fs_block</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">tmp_var</span><span class=\"p\">[-1]</span><span class=\"k\">}</span>                 <span class=\"c\"># サイズは結果の最後に入っている</span>\n\n<span class=\"c\"># パーティション情報の取得</span>\n<span class=\"nv\">part_info</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>parted <span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> unit B print<span class=\"sb\">`</span>\n<span class=\"c\"># 1行毎に分割</span>\n<span class=\"nv\">line</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">part_info</span><span class=\"p\">//;/ </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># ext4のパーティション番号を探す</span>\n<span class=\"nv\">part_number</span><span class=\"o\">=</span>0\n<span class=\"nv\">part_start</span><span class=\"o\">=</span>0\n<span class=\"nv\">target_type</span><span class=\"o\">=</span><span class=\"s2\">\"ext4\"</span>\n<span class=\"k\">for </span>l <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span> <span class=\"p\">;</span> <span class=\"k\">do</span>\n    <span class=\"c\"># 各要素に分割</span>\n    <span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">l</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n    <span class=\"nv\">elm_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[0]</span><span class=\"k\">}</span>             <span class=\"c\"># パーティション番号</span>\n    <span class=\"nv\">elm_start</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[1]//B/</span><span class=\"k\">}</span>          <span class=\"c\"># ついでに最後のBを取り除いておく</span>\n    <span class=\"nv\">elm_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>               <span class=\"c\"># ファイルシステムタイプ</span>\n    <span class=\"c\"># echo $elm_number $elm_start $elm_type</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n        if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n            <span class=\"c\"># 対象のパーティションが見つかった</span>\n            <span class=\"nv\">part_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_number</span><span class=\"k\">}</span>\n            <span class=\"nv\">part_start</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_start</span><span class=\"k\">}</span>\n            <span class=\"nb\">break\n        </span><span class=\"k\">fi\n    fi\ndone\nif</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"o\">=</span> 0 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"s2\">\"のパーティションが見つかりませんでした\"</span>\n<span class=\"k\">else</span>\n    <span class=\"c\"># 新しいパーティション終了位置を計算</span>\n    <span class=\"nv\">new_fs_block</span><span class=\"o\">=</span><span class=\"k\">$((</span>req_fs_block <span class=\"o\">+</span> <span class=\"m\">100000</span><span class=\"k\">))</span>             <span class=\"c\"># 少し余裕(100000block=390MB)を持たせる</span>\n    <span class=\"nv\">new_fs_byte</span><span class=\"o\">=</span><span class=\"k\">$((</span>new_fs_block <span class=\"o\">*</span> <span class=\"m\">4096</span><span class=\"k\">))</span>                <span class=\"c\"># byteに換算</span>\n    <span class=\"nv\">part_end</span><span class=\"o\">=</span><span class=\"k\">$((</span>part_start <span class=\"o\">+</span> new_fs_byte <span class=\"o\">+</span> <span class=\"m\">2048</span><span class=\"k\">))</span>       <span class=\"c\"># さらに少し余裕を持たせる</span>\n    <span class=\"nv\">img_size_mb</span><span class=\"o\">=</span><span class=\"k\">$((</span><span class=\"o\">(</span>part_end <span class=\"o\">/</span> <span class=\"o\">(</span><span class=\"m\">1024</span> <span class=\"o\">*</span> <span class=\"m\">1024</span><span class=\"k\">))</span> + 10<span class=\"o\">))</span>    <span class=\"c\"># MBに換算 ついでにしつこいくらいに余裕を持たせる </span>\n\n    <span class=\"nb\">set</span> <span class=\"nt\">-x</span>          <span class=\"c\">#--------------------------------------</span>\n\n    <span class=\"c\"># ファイルシステムとパーティションの縮小</span>\n    <span class=\"nb\">sudo </span>e2fsck <span class=\"nt\">-f</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span> \n    <span class=\"nb\">sudo </span>resize2fs <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">LOOP_DEV</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">new_fs_block</span><span class=\"k\">}</span>\n    parted <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> unit B resizepart <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">part_end</span><span class=\"k\">}</span>\n\n    <span class=\"c\"># 縮小コピー</span>\n    <span class=\"nb\">dd </span><span class=\"k\">if</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span> <span class=\"nv\">of</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">NEW_IMG_FILE</span><span class=\"k\">}</span> <span class=\"nv\">count</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">img_size_mb</span><span class=\"k\">}</span> <span class=\"nv\">bs</span><span class=\"o\">=</span>1M\n\n    <span class=\"nb\">set</span> +x          <span class=\"c\">#--------------------------------------</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># マッピング解除</span>\n<span class=\"nb\">sudo </span>kpartx <span class=\"nt\">-d</span> <span class=\"k\">${</span><span class=\"nv\">WORK_IMG_FILE</span><span class=\"k\">}</span>\n \n</code></pre></div></div>\n\n<h1 id=\"新しいイメージファイルでブートsdを作る\">新しいイメージファイルでブートSDを作る</h1>\n\n<p>縮小したイメージファイルから作成したSDカードはSDカードの容量をすべて使用できるようになっていない。<br />\nそこで、コピーしたSDカードでブートした後、パーティションを拡張する必要がある。</p>\n\n<h2 id=\"sdカードへの書き込みは通常通り\">SDカードへの書き込みは通常通り</h2>\n\n<h2 id=\"書き込んだsdカードでブートする\">書き込んだSDカードでブートする</h2>\n\n<h2 id=\"sdカードのパーティション拡張\">SDカードのパーティション拡張</h2>\n\n<p>色々手順がめんどっちいので、スクリプト作成してみた。<br />\nとりあえず、手元の環境では動いているが、詳細評価したわけではないので、\n実行する場合は自己責任で。</p>\n\n<p>以下のスクリプトを適当な名前(例えば<code class=\"language-plaintext highlighter-rouge\">expand_partition.sh</code>)で保存し、実行する(<code class=\"language-plaintext highlighter-rouge\">bash expand_partition.sh</code>)<br />\n成功したらリブートすること。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># ターゲットのデバイス</span>\n<span class=\"nv\">target_device</span><span class=\"o\">=</span>/dev/mmcblk0\n\n<span class=\"c\"># パーティション情報の取得</span>\n<span class=\"nv\">part_info</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">sudo </span>parted <span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span> unit s print free<span class=\"sb\">`</span>\n\n<span class=\"c\"># 1行毎に分割</span>\n<span class=\"nv\">line</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">part_info</span><span class=\"p\">//;/ </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 最終行</span>\n<span class=\"c\"># declare -i last_index=${#line[@]}-1</span>\n<span class=\"c\"># last_line=${line[$last_index]}</span>\n<span class=\"nv\">last_line</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[</span><span class=\"k\">$((${#</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span><span class=\"o\">-</span><span class=\"m\">1</span><span class=\"k\">))</span><span class=\"p\">]</span><span class=\"k\">}</span>\n\n<span class=\"c\"># :で区切られた各要素に分割</span>\n<span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">last_line</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n\n<span class=\"c\"># 変数名付け替え</span>\n<span class=\"c\"># last_number=${elm[0]}</span>\n<span class=\"c\"># last_start=${elm[1]}</span>\n<span class=\"nv\">last_end</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[2]</span><span class=\"k\">}</span>\n<span class=\"c\"># last_size=${elm[3]}</span>\n<span class=\"nv\">last_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>\n\n<span class=\"c\"># 確認</span>\n<span class=\"c\"># echo last_number=  $last_number</span>\n<span class=\"c\"># echo last_start=   $last_start</span>\n<span class=\"c\"># echo last_end=     $last_end</span>\n<span class=\"c\"># echo last_size=    $last_size</span>\n<span class=\"c\"># echo last_type=    $last_type</span>\n\n<span class=\"c\"># 最後のパーティションがfreeか確認</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">last_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> free <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># ext4のパーティション番号を探す</span>\n    <span class=\"nv\">part_number</span><span class=\"o\">=</span>0\n    <span class=\"nv\">target_type</span><span class=\"o\">=</span><span class=\"s2\">\"ext4\"</span>\n    <span class=\"k\">for </span>l <span class=\"k\">in</span> <span class=\"k\">${</span><span class=\"nv\">line</span><span class=\"p\">[@]</span><span class=\"k\">}</span> <span class=\"p\">;</span> <span class=\"k\">do</span>\n        <span class=\"c\"># 各要素に分割</span>\n        <span class=\"nv\">elm</span><span class=\"o\">=(</span><span class=\"k\">${</span><span class=\"nv\">l</span><span class=\"p\">//</span>:/<span class=\"p\"> </span><span class=\"k\">}</span><span class=\"o\">)</span>\n        <span class=\"nv\">elm_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[0]</span><span class=\"k\">}</span>\n        <span class=\"nv\">elm_type</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm</span><span class=\"p\">[4]</span><span class=\"k\">}</span>\n        <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n            <span class=\"c\"># echo $elm_number $elm_type</span>\n            <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">elm_type</span><span class=\"k\">}</span> <span class=\"o\">=</span> <span class=\"k\">${</span><span class=\"nv\">target_type</span><span class=\"k\">}</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n                </span><span class=\"nv\">part_number</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">elm_number</span><span class=\"k\">}</span>\n                <span class=\"nb\">break\n            </span><span class=\"k\">fi\n        fi\n    done\n    if</span> <span class=\"o\">[</span> <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"o\">=</span> 0 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"ext4のパーティションが見つかりませんでした\"</span>\n    <span class=\"k\">else</span>\n        <span class=\"c\"># リサイズの実行</span>\n        <span class=\"nb\">set</span> <span class=\"nt\">-x</span>\n        <span class=\"nb\">sudo </span>parted <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span> resizepart <span class=\"k\">${</span><span class=\"nv\">part_number</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">last_end</span><span class=\"k\">}</span>\n        <span class=\"nb\">sudo </span>resize2fs <span class=\"k\">${</span><span class=\"nv\">target_device</span><span class=\"k\">}</span>p2\n        <span class=\"nb\">set</span> +x\n        <span class=\"nb\">echo</span> <span class=\"s2\">\"リブートしてください\"</span>\n    <span class=\"k\">fi\nelse\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"最終パーティションがfreeではありません\"</span>\n<span class=\"k\">fi</span>\n \n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian Buster Lite版のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian Buster Lite版のインストール</h1>\n      <p>Raspbian Buster with desktopのインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspbian Buster Lite」 の 「DownloadZIP」でダウンロードする。<br />\n以下の手順は、RaspberryPi Zero W、「Version: July 2019」 で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>は表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nframebuffer_width=1280\nframebuffer_height=720\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"ロケールやらタイムゾーンやらの設定\">ロケールやらタイムゾーンやらの設定</h1>\n\n<p>日本語表示や時刻を日本時間に設定するための設定を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    4 Localisation Options\n        I1 Change Locale\n            [ ] ja_JP.UTF-8 UTF-8     でスペースを押して[*] にする\n            TABを押して<Ok>を選んでリターン\n                Default locale for~ と聞かれるので、\n                ja_JP.UTF-8          を選択\n                TABを押して<Ok>を選んでリターン\n    4 Localisation Options\n        I2 Change Timezon\n            Asia\n                Tokyo\n    <Finish>\n</code></pre></div></div>\n\n<p>設定変更を有効にするにはrebootが必要。</p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"c\"># export PYENV_ROOT=/proj/.pyenv</span>\n<span class=\"c\"># export PATH=$PYENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(pyenv init -)\"</span>\n<span class=\"c\"># eval \"$(pyenv virtualenv-init -)\"</span>\n\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"c\"># export NODENV_ROOT=/proj/.nodenv</span>\n<span class=\"c\"># export PATH=$NODENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(nodenv init -)\"</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nSSHなら関係ないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"hdmiコンソール用日本語入力表示環境構築\">HDMIコンソール用日本語入力&表示環境構築</h1>\n\n<p>デフォルトのままだと、HDMIコンソールは日本語の入力はおろか、表示もできない。<br />\nそこで、日本語入力&表示環境を整備する。<br />\nHDMIコンソールで日本語を使わないなら本章は設定不要。</p>\n\n<h2 id=\"フォントのインストール\">フォントのインストール</h2>\n\n<p>フォントをインストールしないと表示できないのでまずはフォントのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk \n</code></pre></div></div>\n\n<h2 id=\"ターミナルエミュレータのインストール\">ターミナルエミュレータのインストール</h2>\n\n<p>デフォルトのターミナルは日本語を表示できないので、日本語対応のターミナルエミュレータを使う。<br />\nネット上にはjfbtermを使用する記事が多いが、jfbtermはイマイチらしいのでfbtermを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fbterm\n</code></pre></div></div>\n\n<h2 id=\"日本語変換システムのインストール\">日本語変換システムのインストール</h2>\n\n<p>日本語入力のためのプログラム。Windowsで言うところのMS-IMEやATOKに相当するもの。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>uim-fep uim-anthy\n</code></pre></div></div>\n\n<h2 id=\"fbtermの設定\">fbtermの設定</h2>\n\n<p>fbtermの設定は、 ~/.fbtermrc で行う。<br />\n<strong>HDMIコンソールから</strong> fbtermを一度起動すると ~/.fbtermrc ができるので、設定変更するときはこれを書き換える。<br />\n例えばこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>font-size<span class=\"o\">=</span>18\n</code></pre></div></div>\n\n<p>fbtermを起動したときに<code class=\"language-plaintext highlighter-rouge\">[input] can’t change kernel keymap table ~</code>と表示されるときは以下を実行すると良い。(表示されるだけで実害はないらしい)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>setcap <span class=\"s1\">'cap_sys_tty_config+ep'</span> /usr/bin/fbterm\n</code></pre></div></div>\n\n<p>または、以下でも良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chmod </span>u+s /usr/bin/fbterm\n</code></pre></div></div>\n\n<p>参考: <a href=\"https://qiita.com/mtomoaki_96kg/items/e5a946fd38f7318d3758?fbclid=IwAR2d8ekXNiD9cqvpqycdfinDZMHZ0OcTmaETTsci1UA9T-aDtc3LvfOiaa0\">https://qiita.com/mtomoaki_96kg/items/e5a946fd38f7318d3758?fbclid=IwAR2d8ekXNiD9cqvpqycdfinDZMHZ0OcTmaETTsci1UA9T-aDtc3LvfOiaa0</a></p>\n\n<h2 id=\"uim日本語変換システムの設定\">uim(日本語変換システム)の設定</h2>\n\n<p>uimでCTRL+SPACEでFEPの切り替えの設定。\n~/.uim に以下の内容を記述(なければ新規作成)。<br />\n参考: <a href=\"https://qiita.com/tukiyo3/items/376e3a2895a71ff9bfc7\">https://qiita.com/tukiyo3/items/376e3a2895a71ff9bfc7</a></p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>(define default-im-name 'anthy)\n(define-key generic-on-key? '(\"<Control> \" \"`\"))\n(define-key generic-off-key? '(\"<Control> \" \"`\"))\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n各行のシングルクォーテーションは1個だけ。文字列として区切っている訳ではない。<br />\n余計なシングルクォーテーションを入れると動かなくなるので注意!!</p>\n</blockquote>\n\n<h2 id=\"起動時にfbtermを起動する\">起動時にfbtermを起動する</h2>\n\n<p>起動時にfbtermを起動するには以下を ~/.profile 、 ~/.bashrc に追加</p>\n\n<h3 id=\"profile\">~/.profile</h3>\n\n<p>最後に以下の内容を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"o\">=</span> <span class=\"s2\">\"linux\"</span> <span class=\"o\">]</span>\n<span class=\"k\">then</span>\n<span class=\"c\">#   FBTERM=1 exec fbterm -- uim-fep</span>\n   <span class=\"nv\">FBTERM</span><span class=\"o\">=</span>1 fbterm <span class=\"nt\">--</span> uim-fep\n   <span class=\"nb\">exit\n</span><span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<p>本当はコメントアウトされてる方の exec を使うようにしないといけないが、現状うまく動かないらしい。<br />\n(Strechでは動いていたと思う)<br />\n仕方ないので、fbtermをbashの子プロセスとして実行するようにしてある。<br />\nこれだとうまく動いている(当然、メモリ消費量は増えるけど)。</p>\n\n<p>また、ログアウトの際にCTRL+Dを2回入力しないといけなくなる(fbtermからのexitとbashからのexit)のを回避するため、 fbterm終了時にexitコマンドを実行している。</p>\n\n<h3 id=\"bashrc\">~/.bashrc</h3>\n\n<p>最後に(でなくてもいいけど)、以下を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>linux<span class=\"p\">)</span>\n        <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$FBTERM</span><span class=\"s2\">\"</span> <span class=\"o\">]</span> <span class=\"o\">&&</span> <span class=\"nb\">export </span><span class=\"nv\">TERM</span><span class=\"o\">=</span>fbterm\n        <span class=\"p\">;;</span>\n    fbterm<span class=\"p\">)</span>\n        <span class=\"c\"># 何もしない</span>\n        <span class=\"p\">;;</span>\n    <span class=\"k\">*</span><span class=\"p\">)</span>\n        <span class=\"c\"># 何もしない</span>\n        <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n</code></pre></div></div>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspbian Busterのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspbian Busterのインストール</h1>\n      <p>Raspbian Buster with desktopのインストールと初期設定。</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ダウンロードとsdカードの用意\">ダウンロードとSDカードの用意</h1>\n\n<p>ダウンロードはこちら。<a href=\"https://www.raspberrypi.org/downloads/raspbian/\">https://www.raspberrypi.org/downloads/raspbian/</a> <br />\n「Raspbian Buster with desktop」 の 「DownloadZIP」でダウンロードしてSDカードに書き込んでブート。<br />\n(「・・・ and recommended software」 の方ではない)<br />\n以下の手順は、RaspberryPi3 model B+、「Version: July 2019」 で確認。</p>\n\n<h2 id=\"ブート前の設定\">ブート前の設定</h2>\n\n<p>ブートの前にSDカードのFATパーティションのファイルをいじっておく。</p>\n\n<h3 id=\"uartコンソールの有効化\">UARTコンソールの有効化</h3>\n\n<p>UARTをコンソールとして使用するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># enable uart\nenable_uart=1 \n</code></pre></div></div>\n<h3 id=\"ディスプレイ解像度の設定\">ディスプレイ解像度の設定</h3>\n\n<p>ついでにディスプレイ出力の解像度を変更するために<code class=\"language-plaintext highlighter-rouge\">config.txt</code>に以下も追加。<br />\n<code class=\"language-plaintext highlighter-rouge\">framebuffer_XXX</code>は表示したいサイズに合わせる。1920と1080とか、1280と720とか。<br />\n<code class=\"language-plaintext highlighter-rouge\">hdmi_force_hotplug</code>を1に設定することで、ホットプラグを無効にし、常に接続状態となる。<br />\nこれはHDMIを後から接続したら表示が出ないのを防ぐため。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># display resolution force setting\nframebuffer_width=1920\nframebuffer_height=1080\nhdmi_force_hotplug=1\n</code></pre></div></div>\n\n<h3 id=\"wi-fiの設定\">Wi-Fiの設定</h3>\n\n<p>Wi-Fiのアクセスポイントに接続するために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code> という名前のファイルを以下の内容で作成する。<code class=\"language-plaintext highlighter-rouge\">ssid</code>と<code class=\"language-plaintext highlighter-rouge\">psk</code>は使用する環境に合わせて修正すること。\nSSID名は ダブルクォーテーションで囲む。\n暗号化キーは平文で記載する場合は ダブルクォーテーションで囲む。256bitキーの場合はダブルクォーテーションで囲まない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>country=JP\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\nnetwork={\n    ssid=\"SSID名\"\n    psk=\"暗号化キー\"\n}\n</code></pre></div></div>\n\n<p>なお、暗号化キーの256bitキーは<code class=\"language-plaintext highlighter-rouge\">wpa_passphrase</code>コマンドで作成できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wpa_passphrase <span class=\"s2\">\"SSID名\"</span> <span class=\"s2\">\"暗号化キー\"</span>\n        ↓ 実行結果\n<span class=\"nv\">network</span><span class=\"o\">={</span>\n        <span class=\"nv\">ssid</span><span class=\"o\">=</span><span class=\"s2\">\"SSID名\"</span>\n        <span class=\"c\">#psk=\"暗号化キー\"</span>\n        <span class=\"nv\">psk</span><span class=\"o\">=</span>ほにゃらら~~~ほにゃらら~~~\n<span class=\"o\">}</span>\n</code></pre></div></div>\n<p>この実行結果を<code class=\"language-plaintext highlighter-rouge\">wpa_supplicant.conf</code>の該当部分に転記すればよい。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">#psk=\"暗号化キー\"</code>の部分は削除しておくのが良い。(そうでないと何のために暗号化したのか分からなくなる。\nそのままでもコメントとして扱われるので実動作に影響はないが。)<br />\nまた、既に接続済みのシステムがある場合は、そのシステムの<code class=\"language-plaintext highlighter-rouge\">/etc/wpa_supplicant/wpa_supplicant.conf</code>をコピーして使用しても良い。</p>\n\n<h3 id=\"ssh接続の有効化\">SSH接続の有効化</h3>\n\n<p>SSH接続を有効にするために<br />\nSDカードのFATパーティションに <code class=\"language-plaintext highlighter-rouge\">ssh</code> (または <code class=\"language-plaintext highlighter-rouge\">ssh.txt</code> ) という名前の空ファイルを作成する。</p>\n\n<p>ここまでPCでの作業。</p>\n\n<h1 id=\"起動\">起動</h1>\n\n<p>作成したSDカードをRaspberryPiに挿入し、起動。<br />\n起動ログはHDMI、シリアルコンソール両方に表示される。(SplashScreenをOFFしていた場合:後述)</p>\n\n<h1 id=\"デフォルトのユーザ名を変更\">デフォルトのユーザ名を変更</h1>\n\n<p>RaspberryPiを使うとき、デフォルトパスワードの変更は言わずもがなですが、<br />\nできればユーザ名も変更しておきましょう。<br />\n追加してもいいけど、今あるユーザをリネームした方がなにかと便利。</p>\n\n<p>GUIログインしているとpiユーザ使用中になってしまうので、GUIを無効化しておく。<br />\nGUI使えないとシリアルコンソールかSSH接続が必須になるので、つながることを以下の手順を実行する前に確認しておくこと。</p>\n\n<p>手順はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B1 Desktop / CLI\n            B1 Console\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>ついでにSplash Screenも無効化するならこんな感じで設定。<br />\nシリアルコンソールに起動ログが表示されるようにするにはSplash Screenを無効化しないといけない。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B3 Splash Screen\n            Would you like to show the splash screen at boot? \n            に対して <No> を選択\n            Splash screen at boot is disabled\n            と表示されるので <OK>\n    <Finish>\n</code></pre></div></div>\n\n<p>以下はシリアルコンソール or SSHで接続して行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo useradd -M temp                    # デフォルトユーザの変更のためにtemporary userを作る\nsudo gpasswd -a temp sudo               # temporary user にsudoグループを追加\nsudo passwd temp                        # temporary user にパスワード設定\n\n# 一旦log offしてtempでlog in\n\nsudo usermod -l <新ユーザ名> pi                     # usermod -lでユーザ名をpiから<新ユーザ名>に変更\nsudo usermod -d /home/<新ユーザ名> -m <新ユーザ名>  # usermod -dでホームディレクトリを/home/piから/home/<新ユーザ名>に変更\nsudo groupmod -n <新ユーザ名> pi                    # groupmod -nでpiグループを<新ユーザ名>グループに変更\n\n# log offして新ユーザでlog in\n\nsudo userdel temp                       # temporary user を削除\n\n# パスワード変更する\npasswd\n《パスワードを設定》\n\n</code></pre></div></div>\n\n<p>参考情報はこちら。<a href=\"https://jyn.jp/raspberrypi-username-change/\">https://jyn.jp/raspberrypi-username-change/</a></p>\n\n<p>↑にも書いてあるが、ユーザ名を変更するとsudoではパスワードを聞かれるようになる。<br />\n(おススメしないが)新しいユーザでも<code class=\"language-plaintext highlighter-rouge\">sudo</code>のパスワードを省略したい場合は<code class=\"language-plaintext highlighter-rouge\">/etc/sudoers.d/010_pi-nopasswd</code>の先頭の<code class=\"language-plaintext highlighter-rouge\">pi</code>を<新ユーザ名>に変更する。</新ユーザ名></p>\n\n<p>GUIログインに戻す。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo raspi-config\n    3 Boot Options\n        B4 Desktop Autologin\n    <Finish>\n Would you like to reboot now?\n と聞かれるので <Yes>\n</code></pre></div></div>\n\n<p>GUIログインのユーザは<code class=\"language-plaintext highlighter-rouge\">raspi-config</code>を実行したユーザに設定される。なので、ちゃんと変更したユーザで実行しないとダメです。</p>\n\n<h1 id=\"何はともあれ最新版へ\">何はともあれ、最新版へ</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># アップデート実行</span>\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"c\"># リブート</span>\n<span class=\"nb\">sudo </span>reboot\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">sudo rpi-update</code> は前は実行してたけど、なんか「通常は実行するな」と言われるのでやめておこう。</p>\n\n<h1 id=\"vncサーバのインストール\">VNCサーバのインストール</h1>\n\n<p>リモートデスクトップを使うために、VNCサーバのインストールと有効化を行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install realvnc-vnc-server   # インストール済みみたいだけど、念のため。\nsudo raspi-config\n    5 Interfacing Options        \n        P3 VNC\n            Would you like the VNC Server to be enabled?\n            と聞かれるので <Yes>    \n            The VNC Server is enabled\n            と表示されるので <Ok>\n    <Finish>\n</code></pre></div></div>\n<p>Windows側のクライアントは、<br />\n<a href=\"https://www.realvnc.com/en/connect/download/viewer/\">https://www.realvnc.com/en/connect/download/viewer/</a> \nから VNC Viewerをダウンロード。<br />\nWindowsを選択してStandalone EXE x64(またはx86)を選択、ダウンロードボタンをクリック。<br />\nインストールは不要でダウンロードしたファイルを実行したら、あとは良きにはからえ。<br />\nVNC経由だと、日本語キーボードの設定しなくても日本語キーボードが使えるらしい。<br />\n日本語化の手順はこちらを参考に。 <a href=\"http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2\">http://俺の技術メモ.net/raspbian-jessie-startup-conf/#i-2</a></p>\n\n<h1 id=\"bashrcの設定など\">~/.bashrcの設定など</h1>\n\n<p>シリアルコンソールを使用する場合、コンソールサイズがあってなくてイライラするので、シリアルコンソールの設定用スクリプトを以下の手順で取得。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~\nwget https://gist.githubusercontent.com/ippei8jp/8179edb10867faf98e233a52965a9e53/raw/c397ae5cd29948a940117ab7baf1b4c6a664b33e/resize.py\n<span class=\"nb\">chmod</span> +x resize.py\n\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n<span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> ~/resize.py <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"c\"># export PYENV_ROOT=/proj/.pyenv</span>\n<span class=\"c\"># export PATH=$PYENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(pyenv init -)\"</span>\n<span class=\"c\"># eval \"$(pyenv virtualenv-init -)\"</span>\n\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"c\"># export NODENV_ROOT=/proj/.nodenv</span>\n<span class=\"c\"># export PATH=$NODENV_ROOT/bin:$PATH</span>\n<span class=\"c\"># eval \"$(nodenv init -)\"</span>\n</code></pre></div></div>\n\n<h1 id=\"マシン名の変更\">マシン名の変更</h1>\n\n<p>お好みでマシン名を変更(対応する部分を変更各1カ所)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>vi /etc/hostname\n<span class=\"nb\">sudo </span>vi /etc/hosts\n</code></pre></div></div>\n\n<h1 id=\"キーボードのcaps---ctrlの入れ替え\">キーボードのCAPS - CTRLの入れ替え</h1>\n<p>HDMI接続で使わないなら設定不要</p>\n\n<p>参考:  <a href=\"https://qiita.com/Pseudonym/items/12e447557a5234bb265b\">https://qiita.com/Pseudonym/items/12e447557a5234bb265b</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/default/keyboard</code>ファイルの以下の部分を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XKBOPTIONS=\"\"\n    ↓\n# XKBOPTIONS=\"ctrl:nocaps\"        # CapsLock --> Ctrl\nXKBOPTIONS=\"ctrl:swapcaps\"      # CapsLock <-> Ctrl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!WARNING]\nこれでできるハズなんだけど、なんかうまく行かない。。。<br />\nVNCしか使わないから、ま、いっか。</p>\n</blockquote>\n\n<h1 id=\"ワークディレクトリの作成とsambaの設定\">ワークディレクトリの作成とsambaの設定</h1>\n<p>まずはワークディレクトリの作成</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo mkdir /work\nsudo mkdir /proj\nsudo chown `whoami`:`whoami` /work /proj\n</code></pre></div></div>\n\n<p>sambaのインストールと設定</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install samba\nsudo smbpasswd -a `whoami`\n    パスワードを設定\n</code></pre></div></div>\n\n<p>設定変更のため、<code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> を編集</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[global]</code> の下に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>map archive = no  \n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">[homes]</code> の下の以下を修正</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>read only = no\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nhome は一旦log inしないと見えない</p>\n</blockquote>\n\n<p>最後に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = <ユーザ名>\nforce create mode = 0664\n\n</code></pre></div></div>\n\n<p>サービスの再起動</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h1 id=\"マウスフォーカスの変更\">マウスフォーカスの変更</h1>\n\n<p>ウィンドウをクリックしないとフォーカスが移動しないのはイライラするので x-mouse相当の設定をする。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/xdg/openbox/lxde-pi-rc.xml</code>の以下の部分をnoからyesに変更。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><followMouse>yes</followMouse>\n</code></pre></div></div>\n\n<h1 id=\"まこんな感じかな\">ま、こんな感じかな。</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 16.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 16.04のインストール</h1>\n      <p>Ubuntu 16.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu 16.04 のインストール手順のメモです。<br />\nVirtualBox へのインストール前提で書いてます。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-1604-インストール媒体の入手\">Ubuntu 16.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら</p>\n\n<p><a href=\"http://old-releases.ubuntu.com/releases/16.04.5/\">http://old-releases.ubuntu.com/releases/16.04.5/</a></p>\n\n<p>ファイル一覧の下の方の<br />\n<a href=\"http://old-releases.ubuntu.com/releases/16.04.5/ubuntu-16.04.5-desktop-amd64.iso\">「ubuntu-16.04.5-desktop-amd64.iso」</a><br />\nを選択する</p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを1024MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動し、画面の明るさとロックを選択<br />\n「次の時間アイドル状態が続けば画面をオフにする」を「しない」に設定。<br />\n「ロックする」を「オフ」に設定。</p>\n</blockquote>\n\n<h3 id=\"ap-getよりaptが使いやすい\">ap-getよりaptが使いやすい</h3>\n\n<p>最初から入ってたっけ??<br />\n入ってなかったら以下で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>apt\n</code></pre></div></div>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"nb\">sudo </span>apt dist-upgrade <span class=\"o\">(</span>必要なら<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p>終わったらリブート</p>\n\n<h3 id=\"gccとかmakeとかは最初からインストールされているはず\">gccとかmakeとかは最初からインストールされているはず</h3>\n\n<p>入っていない場合は以下でインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<h4 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h2 id=\"使わないパッケージをアンインストール\">使わないパッケージをアンインストール</h2>\n\n<p>使わないパッケージはディスクの肥やしになるだけでなく、余計なアップデートで時間を食うので、以下の感じでアンインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove <package name>\n</code></pre></div></div>\n<p>インストール済みのパッケージは以下で確認できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--manual-installed</span>\n</code></pre></div></div>\n\n<p>依存関係によってインストールされたパッケージも含めて確認するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span>\n</code></pre></div></div>\n\n<h4 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-panel\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n一旦ログアウトして<br />\nサインインボタン横のUbuntuアイコンで「GNOME Flashback (Compiz)」を選択してログインする<br />\n選択した内容は次回起動時も覚えている。</p>\n</blockquote>\n\n<h4 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h4>\n<blockquote>\n  <p>[!TIP]\n端末を起動し、メニューの「編集」→「設定」を選択<br />\n「プロファイル」タブを選択<br />\n使用中のプロファイル(最初のは「default」)を選択し、「編集」をクリック<br />\n「全般」タブの「フォントを指定する」 にチェックを入れ、その右側でフォントを選ぶ<br />\n        Takao ゴシック Regular あたりがおススメ<br />\nついでに「起動時の端末サイズ」も修正しておくとよい</p>\n</blockquote>\n\n<h4 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj\n<span class=\"nb\">sudo mkdir</span> /work1\n<span class=\"nb\">sudo mkdir</span> /work2\n<span class=\"nb\">sudo mkdir</span> /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h4 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h4>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h4 id=\"bashの設定変更\">bashの設定変更</h4>\n<p>~/.bashrcに以下を追記</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n</code></pre></div></div>\n\n<h4 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>compizconfig-settings-manager \n</code></pre></div></div>\n<p>アプリケーション→システムツール→Preference→CompizeConfigSettingsManager でプログラム起動<br />\nウィンドウ・マネジメントのGridのチェックをはずす</p>\n\n<h4 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferenceを選択<br />\n    auto-rise             false<br />\n    focus-mode            sloppy or mouse<br />\n    rise-on-click         true</p>\n</blockquote>\n\n<h4 id=\"ウィンドウのボタンの位置を右側にする\">ウィンドウのボタンの位置を右側にする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferenceを選択<br />\n    「button-layout」に 「menu:minimize,maximize,close」を設定</p>\n</blockquote>\n\n<h4 id=\"日本語入力\">日本語入力</h4>\n<ul>\n  <li>アプリケーション→システムツール→システム設定→言語サポートを選択</li>\n  <li>「言語サポートが完全にはインストールされていません」と出るので<br />\n「インストール」をクリック</li>\n  <li>一旦ログアウトして再ログイン</li>\n  <li>アプリケーション→システムツール→システム設定→テキスト入力設定を選択</li>\n  <li>入力ソースタブを選択</li>\n  <li>左下の+ボタンを押してMozc(Fcitx)を選択して追加ボタンを押す</li>\n</ul>\n\n<h4 id=\"sambaのインストール\">sambaのインストール</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h4 id=\"nfsのインストール\">NFSのインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認(IPアドレスは環境に合わせて変更してね)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h4 id=\"apache-のインストール\">apache のインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>apache2\n<span class=\"nb\">mkdir</span> /proj/wwwroot\n</code></pre></div></div>\n\n<p>/etc/apache2/apache2.conf に以下を追加<br />\n<Directory ~と書いてあるところがあるので、その並びに追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><Directory /proj/wwwroot/>\n    Options Indexes FollowSymLinks\n    AllowOverride None\n    Require all granted\n</Directory>\n</code></pre></div></div>\n\n<p>/etc/apache2/sites-available/000-default.conf の以下を修正</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>DocumentRoot /proj/wwwroot\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/apache2 restart\n</code></pre></div></div>\n\n<h3 id=\"以上でインストールは終了\">以上でインストールは終了</h3>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"nmcliが入ってなかったら以下でインストール\">nmcliが入ってなかったら以下でインストール</h3>\n\n<p>入ってたか、入れたか、何かの依存関係で入ったか覚えてない…</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>network-manager\n</code></pre></div></div>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hostnameを直接エディタで書き換えても可。</p>\n</blockquote>\n\n<h3 id=\"etchosts-の変更\">/etc/hosts の変更</h3>\n<p>旧ホスト名を「old_hostname」、新しいホスト名を「new_hostname」とした場合、以下のコマンドで書き換えられる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/old_hostname/new_hostname/'</span> /etc/hosts\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nエディタで書き換えても可。/etc/hostsを開いて旧ホスト名を新しいものに書き換える。</p>\n</blockquote>\n\n<h3 id=\"ipアドレスの変更固定アドレスにしたい場合\">IPアドレスの変更(固定アドレスにしたい場合)</h3>\n<blockquote>\n  <p>[!TIP]\nシステム設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん。<br />\nなんかこんな感じ。</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"各接続の設定値の表示\">各接続の設定値の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show  <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n<p>「”有線接続 2”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n<p>「”有線接続 2”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n<p>「”有線接続 3”」は接続一覧で表示された名前に変更のこと。</p>\n\n<h1 id=\"共有フォルダの設定とマウント\">共有フォルダの設定とマウント</h1>\n\n<h2 id=\"virtualboxでの共有フォルダの設定\">VirtualBoxでの共有フォルダの設定</h2>\n\n<ul>\n  <li>仮想マシン→設定で設定ダイアログを表示\n    <ul>\n      <li>「共有フォルダ」で「共有フォルダの追加」ボタンをクリック\n        <ul>\n          <li>「フォルダーのパス」に共有するフォルダを指定</li>\n          <li>「フォルダ名」に名前を付ける(例:Share))</li>\n          <li>その他は空欄のまま</li>\n          <li>「OK」をクリック</li>\n        </ul>\n      </li>\n      <li>「OK」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"マウントポイントの作成\">マウントポイントの作成</h2>\n\n<p>マウントポイントを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /Share\n</code></pre></div></div>\n\n<h2 id=\"手動でマウント\">手動でマウント</h2>\n\n<p>以下のコマンドでマウントできる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> vboxsf Share /Share/\n</code></pre></div></div>\n\n<p>アンマウントするときはこちら。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount /Share/\n</code></pre></div></div>\n\n<h2 id=\"自動でマウント\">自動でマウント</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/fstab</code> に以下の内容を追加。\nこれで、起動時に自動でマウントされる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Share /Share vboxsf defaults 0 0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu 18.04のインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu 18.04のインストール</h1>\n      <p>Ubuntu 18.04のインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Facebook noteに書いておいたら、消されちゃったみたいなので、メモから再度作成<br />\nメモから書き起こしているので、細かいところが違うかも。<br />\n最新版では変更されている箇所があるかも。</p>\n\n<p>VirtualBox へのインストール前提で書いてます。</p>\n\n<h1 id=\"マスタイメージのインストール\">マスタイメージのインストール</h1>\n\n<h2 id=\"ubuntu-1804-インストール媒体の入手\">Ubuntu 18.04 インストール媒体の入手</h2>\n\n<p>インストール媒体のダウロードはこちら</p>\n\n<p><a href=\"https://www.ubuntulinux.jp/download)\">https://www.ubuntulinux.jp/download)</a></p>\n\n<h2 id=\"インストール\">インストール</h2>\n\n<p><strong>VirtualBox でインストールするときは、メインメモリーを2048MB以上に設定しておくこと</strong></p>\n\n<p>普通にインストール媒体からインストール。<br />\n終わったら、リブート。<br />\n初期設定は「次へ」を押すだけ   「Ubuntuの改善を支援する」のところは気になるなら「送信しません」に変更。</p>\n\n<h2 id=\"その後の設定手順\">その後の設定手順</h2>\n\n<h3 id=\"インストール中にロックされるとうざいので先に設定しておく\">インストール中にロックされるとうざいので、先に設定しておく</h3>\n<blockquote>\n  <p>[!TIP]\n==== 画面ロックの抑制 ==============================================<br />\nシステムの設定を起動し、左側でプライバシーを選択<br />\n右側で画面ロックをクリックし、自動画面ロックをoffにする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n==== スクリーンセーバ(ブランクスクリーン)の抑制=====================<br />\nシステムの設定を起動し、左側で電源を選択<br />\n右側でブランクスクリーンのドロップダウンリストで「しない」を選択</p>\n</blockquote>\n\n<h3 id=\"最新版にアップデート\">最新版にアップデート</h3>\n\n<p>お約束。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n<span class=\"nb\">sudo </span>apt dist-upgrade <span class=\"o\">(</span>必要なら<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"gccとかmakeとかをインストールする\">gccとかmakeとかをインストールする</h3>\n\n<p>これが入ってないとGuestAdditionのインストールで失敗する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>build-essential\n</code></pre></div></div>\n\n<h3 id=\"色々使うのでインストール\">色々使うのでインストール</h3>\n\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n</code></pre></div></div>\n\n<h2 id=\"再度リブート念のため\">再度リブート(念のため)</h2>\n\n<h3 id=\"guestadditionのインストール\">GuestAdditionのインストール</h3>\n\n<p>VirtualBox のメニューの「デバイス」→「Guest Additions CDイメージの挿入…」を選択<br />\n以下、ごにょごにょ。</p>\n\n<h2 id=\"再度リブート念のため-1\">再度リブート(念のため)</h2>\n\n<h2 id=\"使わないのでアンインストール\">使わないのでアンインストール</h2>\n\n<p>最小インストールすれば良いという説もあるが</p>\n\n<h4 id=\"amazonなんちゃらのやつ\">amazonなんちゃらのやつ</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove ubuntu-web-launchers\n</code></pre></div></div>\n\n<h4 id=\"ツール類\">ツール類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove thunderbird\n<span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove simple-scan\n<span class=\"nb\">sudo </span>apt remove gnome-todo\n<span class=\"nb\">sudo </span>apt remove remmina\n<span class=\"nb\">sudo </span>apt remove cheese\n</code></pre></div></div>\n\n<h4 id=\"ゲーム類\">ゲーム類</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove aisleriot\n<span class=\"nb\">sudo </span>apt remove gnome-mahjongg\n<span class=\"nb\">sudo </span>apt remove gnome-mines\n<span class=\"nb\">sudo </span>apt remove gnome-sudoku\n</code></pre></div></div>\n\n<h4 id=\"shellをgnome-flashbackに変更するお好みで\">shellをGNOME Flashbackに変更する(お好みで)</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-panel\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n一旦再起動して<br />\nサインインボタン横の歯車ボタンで「GNOME Flashback (Metacity)」を選択してログインする</p>\n</blockquote>\n\n<blockquote>\n  <p>[!IMPORTANT]\n「GNOME Flashback(Compiz)」だとうまく動かない。<br />\n以前はログアウトだけで良かったはずなんだけど、<br />\n再起動しないとダメみたい</p>\n</blockquote>\n\n<h4 id=\"gnome-terminalのフォントの変更\">gnome-terminalのフォントの変更</h4>\n<blockquote>\n  <p>[!TIP]\n端末を起動し、メニューの「編集」→「Preferences」を選択<br />\n使用中のプロファイル(最初のは「名前なし」)を選択し、<br />\nCustom font にチェックを入れ、その右側でフォントを選ぶ<br />\n    Ubuntu Mono Regular あたりがおススメ<br />\nついでに起動時の端末サイズも修正しておくとよい</p>\n</blockquote>\n\n<h4 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj\n<span class=\"nb\">sudo mkdir</span> /work1\n<span class=\"nb\">sudo mkdir</span> /work2\n<span class=\"nb\">sudo mkdir</span> /NFSROOT\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work<span class=\"k\">*</span> /NFSROOT\n</code></pre></div></div>\n\n<h4 id=\"grub-pcのインストール先情報の変更\">grub-pcのインストール先情報の変更</h4>\n<p>クローンしたディスクでGUIからgrubのupdateが行われるとハングアップするので変更しておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"set grub-pc/install_devices /dev/sda\" | debconf-communicate'</span>\n<span class=\"c\"># 確認</span>\n<span class=\"nb\">sudo </span>sh <span class=\"nt\">-c</span> <span class=\"s1\">'echo \"get grub-pc/install_devices\" | debconf-communicate'</span>\n</code></pre></div></div>\n\n<h4 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h4 id=\"bashの設定変更\">bashの設定変更</h4>\n<p>~/.bashrcに以下を追記</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n</code></pre></div></div>\n\n<h4 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/metacity/edge-tiling                false<br />\n       /org/gnome/mutter/edge-tiling                  false<br />\n       /org/gnome/shell/overrides/edge-tiling         false</p>\n</blockquote>\n\n<h4 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/descktop/wm/preferences/auto-rise             false<br />\n       /org/gnome/descktop/wm/preferences/focus-mode            sloppy or mouse<br />\n       /org/gnome/descktop/wm/preferences/rise-on-click         true</p>\n</blockquote>\n\n<h4 id=\"デスクトップからゴミ箱とホームを消す\">デスクトップからゴミ箱とホームを消す</h4>\n<p>dconf-editorで以下を設定する</p>\n<blockquote>\n  <p>[!TIP]\n       /org/gnome/nautilus/desktop/trash-icon-visible         false<br />\n       /org/gnome/nautilus/desktop/home-icon-visible          false</p>\n</blockquote>\n\n<h4 id=\"日本語入力\">日本語入力</h4>\n<ul>\n  <li>右上のJaまたはMoと書かれたアイコンをクリック→テキスト入力設定を選択</li>\n  <li>インストールされている言語の管理をクリック</li>\n  <li>「言語サポートが完全にはインストールされていません」と出るので<br />\n「インストール」をクリック</li>\n  <li>一旦log offして再log in</li>\n  <li>右上のJaまたはMoと書かれたアイコンをクリック\n    <ul>\n      <li>Mo(Mozc-jp) を選択(既にMoになってたら一度Jaを選んでからMoに戻す)</li>\n    </ul>\n  </li>\n  <li>キーボードの全角/半角キーで切り替えられるようになる</li>\n</ul>\n\n<h4 id=\"sambaのインストール\">sambaのインストール</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<p>/etc/samba/smb.conf に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work1]\npath = /work1\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work2]\npath = /work2\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[NFSROOT]\npath = /NFSROOT\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n</code></pre></div></div>\n\n<p>ユーザの追加と再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h4 id=\"nfsのインストール\">NFSのインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nfs-kernel-server\n</code></pre></div></div>\n\n<p>/etc/exportsに以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/NFSROOT 192.168.0.0/255.255.0.0(rw,sync,no_root_squash)\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/nfs-kernel-server restart\n</code></pre></div></div>\n\n<p>別のマシンからマウントできるか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount 192.168.56.101:/NFSROOT abc/\nabcの下にリモートのファイルが見えたらOK\n</code></pre></div></div>\n\n<h4 id=\"apache-のインストール\">apache のインストール</h4>\n\n<p>インストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>apache2\n<span class=\"nb\">mkdir</span> /proj/wwwroot\n</code></pre></div></div>\n\n<p>/etc/apache2/apache2.conf に以下を追加<br />\n<Directory ~と書いてあるところがあるので、その並びに追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><Directory /proj/wwwroot/>\n    Options Indexes FollowSymLinks\n    AllowOverride None\n    Require all granted\n</Directory>\n</code></pre></div></div>\n\n<p>/etc/apache2/sites-available/000-default.conf の以下を修正</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>DocumentRoot /proj/wwwroot\n</code></pre></div></div>\n\n<p>再起動</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /etc/init.d/apache2 restart\n</code></pre></div></div>\n\n<h3 id=\"以上でインストールは終了\">以上でインストールは終了</h3>\n\n<hr />\n\n<h1 id=\"仮想マシンをクローンした後の設定\">仮想マシンをクローンした後の設定</h1>\n\n<h3 id=\"ホスト名を変更\">ホスト名を変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname</span> <span class=\"o\"><<</span><span class=\"no\">new_hostname</span><span class=\"sh\">>>\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\n上記コマンドで /etc/hostname は書き換えられる<br />\n/etc/hosts は書き換えられないので、手動で書き換える</p>\n</blockquote>\n\n<p>IPアドレスの変更(固定アドレスにしたい場合)</p>\n<blockquote>\n  <p>[!TIP]\nシステムの設定を起動(gnome-control-centerを実行)<br />\n左側のネットワークを選択し、対象のNICの設定を変更する</p>\n</blockquote>\n\n<p>nmcli コマンドを使うと出来そうな気がするが、いまいちよう分からん</p>\n\n<h3 id=\"接続一覧の表示\">接続一覧の表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nmcli connection show \n</code></pre></div></div>\n\n<h3 id=\"ホスト名の変更\">ホスト名の変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli general <span class=\"nb\">hostname </span>hogehoge123\n</code></pre></div></div>\n\n<h3 id=\"この他etchosts-の変更も必要\">この他、/etc/hosts の変更も必要</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"nt\">-e</span> <span class=\"s1\">'s/orghostname/hogehoge123/'</span> /etc/hosts\n</code></pre></div></div>\n\n<h3 id=\"host-only-adapterの設定変更\">HOST ONLY ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 2\"</span> ipv4.addresses <span class=\"s2\">\"192.168.56.123/24\"</span> ipv4.method manual ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 2\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 2\"</span>\n</code></pre></div></div>\n\n<h3 id=\"bridge-adapterの設定変更\">BRIDGE ADAPTERの設定変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>nmcli connection modify <span class=\"s2\">\"有線接続 3\"</span> ipv4.addresses <span class=\"s2\">\"192.168.78.123/24\"</span> ipv4.gateway <span class=\"s2\">\"192.168.78.1\"</span> ipv4.dns <span class=\"s2\">\"192.168.78.1\"</span> ipv4.method manual\n<span class=\"nb\">sudo </span>nmcli connection down   <span class=\"s2\">\"有線接続 3\"</span>\n<span class=\"nb\">sudo </span>nmcli connection up     <span class=\"s2\">\"有線接続 3\"</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Node.js": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その9)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その9)</h1>\n      <p>Node-REDのメモ 応用編 Google spreadsheet Read</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGoogle spreadsheet からデータを取得したときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><strong>その8</strong> に従って準備済みであるものとする。</p>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で作成済みの認証情報を選択するか、「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に操作対象のスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:zzz」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n          <li>Rangeのフォーマットはシート名!開始セル:終了セル\n            <ul>\n              <li>開始セルと終了セルを両方省略することは可能(片方のみ省略は不可のよう)。<br />\nこの場合、シート全体が取得される。ただし、↑のように特定のシート名はダメかもしれない。</li>\n              <li>開始セル/終了セルはカラム名と行番号で構成されるが、カラム名か行番号は省略可能。\nたぶん、こんな感じ。\n                <ul>\n                  <li>開始カラム名を省略するとAが指定されたとみなす</li>\n                  <li>開始行番号を省略すると1が指定されたとみなす</li>\n                  <li>終了カラム名を省略すると最終カラム(zzz?)が指定されたとみなす</li>\n                  <li>終了行番号を省略すると最終行が指定されたとみなす</li>\n                </ul>\n              </li>\n              <li>大きな範囲を指定しても、以降空白セルであった場合は無視される(有効なデータがある範囲だけ読み込まれる)</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n          <li>プロパティ名はシート名_開始セル_終了セル</li>\n          <li>globalに記録しておけば、キャッシュとして使用出来て、なんども同じデータを読まなくて済む、という使い方かな?</li>\n        </ul>\n      </li>\n      <li>\n        <p>「Action」に「Get Data」を選択し、その右は「By line」を選択</p>\n      </li>\n      <li>「Labels」の「First line for labels」を選択しすると、outputの型がDictionaryになる。指定したセル範囲の開始カラム(シート全体の開始カラムではない)がキー名となる。<br />\n 選択しなければ、outputの型がArrayになる</li>\n      <li>「Labels」の「First column for labels」を選択しすると、outputの各要素の型がDictionaryになる。指定したセル範囲の開始行(シート全体の開始行ではない)の内容がキー名となる。<br />\n 選択しなければ、outputの各要素の型がArrayになる</li>\n      <li>\n        <p>この2つ、なんか逆な気もするけど…</p>\n      </li>\n      <li>outputにリード結果が入る。とりあえず「msg」を選択し、「_output」にしておく\n内容は「Labels」の設定内容によって変わる</li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>設定内容と取得内容の関係はよくワカランので、色々試してみてください。<br />\n現実的には、細かくデータを取得してどうこうするより、シート全体を取得して処理するような使い方になるのかな??</p>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、スプレッドシートの内容が取得されるハズ。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"5eb2475f.ea747\",\n        \"type\": \"tab\",\n        \"label\": \"spreadsheet_read\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"60d62f37.80a8a\",\n        \"type\": \"inject\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"bba510f2.5bb2d8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e183b4f0.c372f\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"37bd743e.1ca96c\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"bba510f2.5bb2d8\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"spreadsheet read\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:zzz\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"get\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": true,\n        \"fields\": \"all\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"\",\n        \"output\": \"_output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 290,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"e183b4f0.c372f\"\n            ],\n            [\n                \"37bd743e.1ca96c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その8)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その8)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Google spreadsheet</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをGoogle spreadsheet に記録するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"google-spreadsheet用ノードのインストール\">Google spreadsheet用ノードのインストール</h2>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-contrib-viseo-google-」と入力</li>\n  <li>下に検索結果が出るので、「node-red-contrib-viseo-google-authentication」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら続けて「node-red-contrib-viseo-google-spreadsheet」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h2 id=\"googleの準備\">Googleの準備</h2>\n\n<p><a href=\"https://techblog.lclco.com/entry/2018/11/30/120000\">具体的な手順はこちらを参考にしてくだされ。</a> (コードの実装の手前まで)  <br />\nただし、<span style=\"color: red; \">有効にするAPI</span>は「Google Drive API」ではなく、「<span style=\"color: red; \">Google Sheets API</span>」なので、注意!!</p>\n\n<h3 id=\"認証情報の作成\">認証情報の作成</h3>\n\n<ul>\n  <li><a href=\"https://console.developers.google.com/project\">Google Developers Console</a> でプロジェクトを作成</li>\n  <li>Google Sheets APIを有効化</li>\n  <li>認証情報(サービスアカウント キー)を作成</li>\n  <li>保存された認証情報の秘密鍵をダウンロード<br />\n  このファイルはセキュリティ上 <strong>超重要</strong> なので、まちがって公開しないように!!!!<br />\n  ・・・・公開して後悔…なんちゃって(^^ゞ</li>\n</ul>\n\n<h3 id=\"記録用スプレッドシートの作成\">記録用スプレッドシートの作成</h3>\n\n<ul>\n  <li><a href=\"https://drive.google.com/drive/u/0/my-drive\">Google Drive</a>から記録するスプレッドシートを作成する(マイドライブからgoogleスプレッドシートを選択すると新規ファイルが作成される)</li>\n  <li>作成されたスプレッドシートに共有ユーザ(サービスアカウントキーのメールアドレス)を追加。権限を編集者、通知のチェックははずしてOKする</li>\n  <li>必要ならシートの追加や名前の変更を行っておく(以下ではシート名が「BME280」になっているものとして説明)</li>\n  <li>1行目に項目名を入れておく。ここではA列から「epoch」「日付」「温度」「湿度」「気圧」としている</li>\n  <li>B列(「日付」の列)を選択し、メニューから「表示形式」→「数値」→「日時」を選択(これをやらないと時刻が見えない))</li>\n  <li>作成されたスプレッドシートのID(URLの docs.google.com/spreadsheets/d/<span style=\"color: red; \">この部分</span>/edit~)をメモしておく</li>\n</ul>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"bme280ノード\">BME280ノード</h3>\n\n<ul>\n  <li><strong>その2</strong>の<strong>BME280を使用するフローを作成する</strong>と同様の手順でBME280ノードを作成する</li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>出力側にFunctionノードを接続\n  コードは以下。<br />\n  あとで時刻を使用しやすいようにエポック時刻で記録するようにしている。<br />\n  また、エポック時刻のままだとスプレッドシーで見たときに日時が分かり難いので、エポック時刻から日時に変更する計算式を入れておく。(ここで直接文字列にすることもできるが)<br />\n  また、Google Sheetsノードの入力はArrayである必要があるようで、Ayyayでラップしておく。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">var</span> <span class=\"nx\">date</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">epoch</span> <span class=\"o\">=</span> <span class=\"nx\">date</span><span class=\"p\">.</span><span class=\"nx\">getTime</span><span class=\"p\">();</span>\n<span class=\"c1\">// msg.payload.date  = date.toString();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">date</span>  <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">=indirect(\"R[0]C[-1]\", false) / (1000*60*60*24) + (9/24) + DATE(1970, 1, 1)</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">];</span>\n\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に上でメモっておいたスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:z」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>set dataのときは使用されないようだ</li>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n        </ul>\n      </li>\n      <li>「Action」に「Set Data」を選択し、その右は「Append」を選択</li>\n      <li>「input」は「msg」を選択し、「payload」を入力</li>\n      <li>「Fields」で「Select」を選択</li>\n      <li>その下に「key」と入力欄が表示されるので、「epoch」と入力し、「追加」をクリック</li>\n      <li>「date」と入力し、「追加」をクリック</li>\n      <li>「temperature_C」と入力し、「追加」をクリック</li>\n      <li>「humidity」と入力し、「追加」をクリック</li>\n      <li>「pressure_hPa」と入力\n        <ul>\n          <li>このデータの並びが入力のプロパティ名とスプレッドシートのセルの並びに対応する</li>\n        </ul>\n      </li>\n      <li>outputもよー分からんけど、とりあえず「msg」を選択し、「_output」にしておく\n        <ul>\n          <li>set dataのときは処理結果が入るようだ</li>\n          <li>get dataのときはリード結果が入るようだ</li>\n        </ul>\n      </li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>このノードの入力にファンクションノードの出力を接続</li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、温度等を測定、スプレッドシートに送信される。<br />\nスプレッドシートを確認すれば、そのデータが記録されているハズである。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1a4f21c6.53e09e\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+spreadsheet\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"b4e73f33.99aec8\",\n        \"type\": \"Bme280\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 220,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"a54ed898.2a114\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"b74c37d3.63a48\",\n        \"type\": \"inject\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 90,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"b4e73f33.99aec8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a54ed898.2a114\",\n        \"type\": \"function\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"データ整形\",\n        \"func\": \"var date = new Date();\\nmsg.payload.epoch = date.getTime();\\n// msg.payload.date  = date.toString();\\n// msg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\",false)/1000/60/60/24 + 9/24 + DATE(1970,1,1)';\\nmsg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\", false) / (1000*60*60*24) + (9 / 24) + DATE(1970, 1, 1)';\\n\\nmsg.payload = [msg.payload];\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 390,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"6a4f8cc4.882e54\",\n                \"adad9a.88697a68\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6a4f8cc4.882e54\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:z\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"set\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": false,\n        \"fields\": \"select\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"epoch\",\n            \"date\",\n            \"temperature_C\",\n            \"humidity\",\n            \"pressure_hPa\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"payload\",\n        \"output\": \"__output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 620,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"93209cb1.cd86\"\n            ],\n            [\n                \"9a8717a8.88bae8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"93209cb1.cd86\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9a8717a8.88bae8\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 220,\n        \"wires\": []\n    },\n    {\n        \"id\": \"adad9a.88697a68\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 850,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node.jsでGoogle spreadsheet にデータを書き込む</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node.jsでGoogle spreadsheet にデータを書き込む</h1>\n      <p>Node.jsでGoogle spreadsheet にデータを書き込む</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Node.jsでGoogle spreadsheet にデータを書き込む方法。<br />\nサンプルプログラムを<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>に置きました。</p>\n\n<p>Google Drive API を サービスアカウントで操作する方法を取りました。</p>\n\n<p>OAuth認証を使う方法は事前準備がめんどっちいので、パス。<br />\nAPIキー認証はリードはできたけど、ライトが出来んかった。あと、シートを公開しないといけないが、やな感じだった。</p>\n\n<h1 id=\"詳細\">詳細</h1>\n\n<p>詳細は\n<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>\nのREADME おひび ソースコードを参照してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その7)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その7)</h1>\n      <p>Node-REDのメモ 応用編 GPIO+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIOの入出力データをWebsocketで飛ばして、Dashboardから操作/Dashboardで表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"gpio入出力データをwebsocketで送受信raspberrypi\">GPIO入出力データをWebsocketで送受信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>RaspberryPiでGPIO出力</strong>、<strong>RaspberryPiでGPIO入力</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>、<strong>Websocketでデータを受信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、GPIO入力データをそのまま送信すると、受け取り側で「0はON?それともOFF?」となってしまうので、GPIO入力の0/1をON/OFFの文字列に変換するファンクションノードを追加している。\n  また、GPIO出力側も同様に、送信側から送られてきたON/OFFの文字列をGPIO出力データの1/0の数値に変換するファンクションノードを挿入している。<br />\n  ターゲットボードの正論理/負論理が変更になった場合はこれらのファンクションノードで調整すれば良い。</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"6e229d5a.774af4\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"109b9bce.e015e4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 730,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4834db5b.5c24d4\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": true,\n        \"x\": 190,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"3ff59514.52c732\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7d90bda.d7b4b8\",\n        \"type\": \"websocket in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"47e24d88.c603e4\",\n        \"x\": 280,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"a38bd8a1.0a5bd8\",\n                \"5e99ea44.cfdac4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9bc37a7.e1e9808\",\n        \"type\": \"websocket out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"c4985621.1edb48\",\n        \"x\": 830,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"a38bd8a1.0a5bd8\",\n        \"type\": \"debug\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 730,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3ff59514.52c732\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"1/0→OFF/ON\",\n        \"func\": \"if (msg.payload) {\\n    msg.payload = 'OFF';\\n}\\nelse {\\n    msg.payload = 'ON';\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"9bc37a7.e1e9808\",\n                \"a38bd8a1.0a5bd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5e99ea44.cfdac4\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"OFF/ON→0/1\",\n        \"func\": \"if (msg.payload == 'OFF') {\\n    msg.payload = 0;\\n}\\nelse {\\n    msg.payload = 1;\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"109b9bce.e015e4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47e24d88.c603e4\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/led0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"c4985621.1edb48\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/sw0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからgpio入出力データを送受信サーバ\">WebsocketからGPIO入出力データを送受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータ送信(サーバ)</strong>、<strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノードに<strong>その4</strong> の <strong>Dashboard のUIを作成する(ボタン)</strong>、<strong>Dashboardでテキストを表示する</strong>で作成したノードを接続すれば良い。</li>\n</ul>\n\n<p>この状態でRaspberryPi側でスイッチをON/OFFすると、Dashboardの「SW」の文字列のON/OFFが切り替わる。\nまた、DashboardのLLED_ON/LED_OFFのボタンをクリックすると、LEDが点灯/消灯する</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"ca6a740f.4d43b8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_GPIO\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"ac19aeee.9f8f5\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 260,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"2098e31e.e6832c\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 270,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8db70b6.86a1178\",\n        \"type\": \"ui_text\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 610,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f45af19.269e\",\n        \"type\": \"websocket in\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"fad64a63.6141a\",\n        \"client\": \"\",\n        \"x\": 270,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"8db70b6.86a1178\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"299e8287.226e6e\",\n        \"type\": \"websocket out\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"d7b33218.4a1f28\",\n        \"client\": \"\",\n        \"x\": 630,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"95b08556.d2cce\",\n        \"type\": \"debug\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 610,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"b7e42e0e.52bdb\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"1b4acf7b.a194c9\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"fad64a63.6141a\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/sw0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"d7b33218.4a1f28\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/led0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"1b4acf7b.a194c9\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ3\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その6)</h1>\n      <p>Node-REDのメモ MQTT編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでMQTT通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"mqttでデータを送受信\">MQTTでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにmosquitto broker および mosquitto client toolsを使うこととします。<br />\nこれらは以下のコマンドでインストールできます。</p>\n\n<p>Ubuntuで動作確認。RaspberryPiでも大丈夫なはず。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mosquitto mosquitto-clients\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータ送信publish\">MQTTでデータ送信(Publish)</h2>\n\n<p>MQTTでデータを送信してみます</p>\n\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要なら「名前」を設定\n            <ul>\n              <li>省略するとサーバアドレスとポート番号が表示される</li>\n            </ul>\n          </li>\n          <li>「サーバ」 でブローカのアドレス(またはホスト名)を設定(例: PiDev25.local)</li>\n          <li>「ポート」 でポート番号を設定(一般的な設定なら1883のままで大丈夫)</li>\n          <li>SSL/TLS接続を使用する場合は「SSL/TLS接続を使用」のチェックを入れる</li>\n          <li>クライアントIDを指定したい場合は「クライアント」に設定。通常は空欄で大丈夫</li>\n          <li>キープアライブ時間を「キープアライブ時間」に設定</li>\n          <li>「セッションの初期化」?とりあえず初期設定のままで</li>\n          <li>「旧MQTT 3.1のサポート」?とりあえず初期設定のままで</li>\n          <li>「セキュリティ」タブ、「メッセージ」タブの内容は必要なら設定する。設定しなくても大丈夫</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に送信するトピックを設定\n        <ul>\n          <li>省略すると、トリガノードの出力に設定されているtopicが使用される</li>\n        </ul>\n      </li>\n      <li>「QoS」を「0」/「1」/「2」から選択</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される\n            <ul>\n              <li>トピックも省略されている場合はmqttと表示される</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のようにsubscriberコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> 《トピック》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカからすべてのトピック(“#”)を取得するよう指定しています。<br />\n-v 指定により、対象メッセージのトピックも表示されます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> Pidev25.local <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> <span class=\"s2\">\"#\"</span>\n</code></pre></div></div>\n<p>Node-RED側で mqttの送信をトリガするとmosquitto_subの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>test_data 0\ntest_data 1\ntest_data true\ntest_data false\ntest_data 文字列\ntest_data {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"f580f01a.f771f\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_publish\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"33450bad.82764c\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ea6d9236.74e038\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d7baa4c.08385\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"82148e63.4b97e\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d0b1ac7f.0ac0b\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7e6180b5.f29098\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"test_data\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6f26fe46.a01f58\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"バッファ\",\n        \"topic\": \"test_data\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 140,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d5a5b2db.83462\",\n        \"type\": \"debug\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 500,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"e6218cda.844308\",\n        \"type\": \"mqtt out\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"\",\n        \"qos\": \"\",\n        \"retain\": \"\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 570,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータを受信subscribe\">MQTTでデータを受信(subscribe)</h2>\n\n<p>MQTTでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に受信するトピックを設定\n        <ul>\n          <li>すべてのトピックを受信するには#を設定</li>\n          <li>省略することはできない</li>\n        </ul>\n      </li>\n      <li>「QoS」を設定</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>デプロイ後、ターミナル or コンソールで以下のようにpublisherコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-t</span> 《トピック》 <span class=\"nt\">-m</span> 《メッセージ》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカへ、トピック test_data で、メッセージ test を送信しています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> PiDev25.local <span class=\"nt\">-t</span> <span class=\"s2\">\"test_data\"</span> <span class=\"nt\">-m</span> <span class=\"s2\">\"test\"</span>\n</code></pre></div></div>\n\n<p>コマンドを実行するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"13f22fdd.2e009\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_subscribe\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1760f49a.fd2d3b\",\n        \"type\": \"debug\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 420,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"30229cea.13aba4\",\n        \"type\": \"mqtt in\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"#\",\n        \"qos\": \"2\",\n        \"datatype\": \"auto\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 150,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"1760f49a.fd2d3b\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その5)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをWebsocketで飛ばして、Dashboardでグラフ表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"bme280データをwebsocketで送信raspberrypi\">BME280データをWebsocketで送信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>BME280を使用するフローを作成する</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、送信されるデータはmsg.payloadなので、文字列ではなく、object。<br />\n  (WebsocketのパケットにはobjectをJSON文字列化したものが入る)</p>\n  </li>\n  <li>BME280のデータを送信するためのトリガとなるノードをBME280ノードの入力に接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"411d9021.cb1948\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"72021e21.cce078\",\n        \"type\": \"Bme280\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"571951b6.480168\",\n        \"type\": \"websocket out\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"f24a6df3.ed0608\",\n        \"x\": 660,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4ce01eb0.f1d438\",\n        \"type\": \"debug\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 570,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"480f869f.968e18\",\n        \"type\": \"function\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"DummyData\",\n        \"func\": \"msg.payload = {\\n\\t\\t\\\"temperature_C\\\": Math.floor((Math.random() * (  40 - (-30)) * 100) / 100) + (-30),\\n\\t\\t\\\"humidity\\\":      Math.floor((Math.random() * ( 100 -    0 ) * 100) / 100) +    0,\\n\\t\\t\\\"pressure_hPa\\\":  Math.floor((Math.random() * (1100 -  800 ) * 100) / 100) +  800,\\n\\t\\t\\\"model\\\":\\\"DUMMY\\\"\\n}\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 310,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"c6ba67a3.1c69c\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"72021e21.cce078\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ab623444.9c5148\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"480f869f.968e18\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f24a6df3.ed0608\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/bme280\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからbme280データを受信サーバ\">WebsocketからBME280データを受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノード</li>\n</ul>\n\n<p>これだけでWebsocketからデータは受信できる。<br />\nこのとき、Websocketの受信ノードのmag.payloadはJSON文字列なので、objectに変換してやらないと後段で使用できない。<br />\nそのため、Websocketのノードの出力をjsonノードで変換してやる必要がある。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「json」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「json」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「動作」で「常にJavascriptオブジェクトに変換」を選択</li>\n      <li>プロパティは「msg.payload」を設定(デフォルトのまま)</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとjsonが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力側にWebsocketのノードを接続</li>\n  <li>\n    <p>出力側に受信データを処理するノードを接続</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>この状態でRaspberryPi側でBME280のデータ送信をトリガすれば、受信したデータで処理ノードが実行される</p>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その1サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その1)(サーバ)</h1>\n\n<p>上記、<strong>WebsocketからBME280データを受信(サーバ)</strong>の処理ノードとして</p>\n<ul>\n  <li><strong>その4</strong> の <strong>Dashboardでゲージグラフを表示する</strong>の手順で作成したノードを接続すれば良い。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nこれで理屈的には大丈夫なハズなんだけど、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.pressure_hPa}}</code>を指定すると、値は正常に表示されるけど、グラフが正常に表示されないことがある。。。<br />\nどうやら、この形で指定すると、値が1000を超えるとグラフ表示がおかしくなるようだ。バグか?<br />\n下の(その2)の方法で回避可能。</p>\n</blockquote>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"61238c01.1e1fdc\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"2163c454.8e4654\",\n        \"type\": \"json\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"8a687382.d3a38\",\n                \"54ecaf20.30611\",\n                \"1e9e6439.3de04c\",\n                \"54f5a1ee.e4fb5\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"de53f105.be0bb\",\n        \"type\": \"websocket in\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"2163c454.8e4654\",\n                \"8a687382.d3a38\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8a687382.d3a38\",\n        \"type\": \"debug\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 530,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54ecaf20.30611\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{msg.payload.temperature_C | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 510,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1e9e6439.3de04c\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度\",\n        \"label\": \"%\",\n        \"format\": \"{{msg.payload.humidity| number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 510,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54f5a1ee.e4fb5\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧\",\n        \"label\": \"hPa\",\n        \"format\": \"{{msg.payload.pressure_hPa| number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 510,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"9912b800.6921d8\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その2サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その2)(サーバ)</h1>\n\n<p><strong>(その1)</strong>での不具合を回避するため、msg.payloadのオブジェクト内のそれぞれの変数をバラすfunctionノードを追加する</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「function」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら名前にノード名を設定</li>\n      <li>コードを設定(下記参照)</li>\n      <li>出力数に「3」を設定</li>\n      <li>右上の「完了」をクリック。</li>\n    </ul>\n  </li>\n  <li>これでfunctionノードの出力端子が3個になり、上から温度、湿度、気圧データが出力される。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>// make deep copy\nvar msg_temp  <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_hum   <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_press <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\n\nmsg_temp.topic    <span class=\"o\">=</span> <span class=\"s2\">\"temperature_C\"</span><span class=\"p\">;</span>\nmsg_temp.payload  <span class=\"o\">=</span> msg.payload.temperature_C<span class=\"p\">;</span>\nmsg_hum.topic     <span class=\"o\">=</span> <span class=\"s2\">\"humidity\"</span><span class=\"p\">;</span>\nmsg_hum.payload   <span class=\"o\">=</span> msg.payload.humidity<span class=\"p\">;</span>\nmsg_press.topic   <span class=\"o\">=</span> <span class=\"s2\">\"pressure_hPa\"</span><span class=\"p\">;</span>\nmsg_press.payload <span class=\"o\">=</span> msg.payload.pressure_hPa<span class=\"p\">;</span>\n\n<span class=\"k\">return</span> <span class=\"o\">[</span>msg_temp, msg_hum, msg_press]<span class=\"p\">;</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">var msg_temp  = msg;</code>などとしてはいけない。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">msg_temp</code>は<code class=\"language-plaintext highlighter-rouge\">msg</code>の浅いコピーとなってしまうため、その下で<code class=\"language-plaintext highlighter-rouge\">msg_temp.payload</code>を変更すると、<code class=\"language-plaintext highlighter-rouge\">msg.payload</code>も変更されてしまうことになる。<br />\nこれを防ぐため、深いコピーを作成している。これには<code class=\"language-plaintext highlighter-rouge\">msg</code>をJSON文字列化して、再度パースすることで対応している。</p>\n</blockquote>\n\n<p>フローエディタ上で、どの端子がどの信号か分からなくなるのを防ぐため、端子に名前を付けることができる。<br />\n(付けなくても動作上は問題ない)</p>\n\n<ul>\n  <li>「function」ノードをダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>右上の「完了」ボタンの下にある「外観」ボタン(ウィンドウ表示のアイコン)をクリック</li>\n      <li>ポートラベルの下の出力の下、1、2、3に対して、それぞれ分かりやすい名前を付ける</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>functionノードの入力にjsonノードの出力を接続</li>\n  <li>functionノードのそれぞれの出力にそれぞれを表示するゲージグラフノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"9c09bf08.8c36a8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280_2\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1e53a14c.4133a7\",\n        \"type\": \"json\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"855491ee.723a88\",\n                \"3cee4c1c.c6861c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ada05d07.d2d8b\",\n        \"type\": \"websocket in\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"1e53a14c.4133a7\",\n                \"855491ee.723a88\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"855491ee.723a88\",\n        \"type\": \"debug\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 690,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"51b57ef4.80809\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度2\",\n        \"label\": \"℃\",\n        \"format\": \"{{value | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 670,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"be7cac56.7bcc4\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度2\",\n        \"label\": \"%\",\n        \"format\": \"{{value | number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 670,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"f36e338d.e77e6\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧2\",\n        \"label\": \"hPa\",\n        \"format\": \"{{value | number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 670,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3cee4c1c.c6861c\",\n        \"type\": \"function\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"BME280\",\n        \"func\": \"// make deep copy\\nvar msg_temp  = JSON.parse(JSON.stringify(msg));\\nvar msg_hum   = JSON.parse(JSON.stringify(msg));\\nvar msg_press = JSON.parse(JSON.stringify(msg));\\n\\nmsg_temp.topic    = \\\"temperature_C\\\";\\nmsg_temp.payload  = msg.payload.temperature_C;\\nmsg_hum.topic     = \\\"humidity\\\";\\nmsg_hum.payload   = msg.payload.humidity;\\nmsg_press.topic   = \\\"pressure_hPa\\\";\\nmsg_press.payload = msg.payload.pressure_hPa;\\n\\nreturn [msg_temp, msg_hum, msg_press];\",\n        \"outputs\": 3,\n        \"noerr\": 0,\n        \"x\": 460,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"51b57ef4.80809\"\n            ],\n            [\n                \"be7cac56.7bcc4\"\n            ],\n            [\n                \"f36e338d.e77e6\"\n            ]\n        ],\n        \"inputLabels\": [\n            \"BME280データ\"\n        ],\n        \"outputLabels\": [\n            \"温度\",\n            \"湿度\",\n            \"気圧\"\n        ]\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"34e8ddba.6c67fa\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ2\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その4)</h1>\n      <p>Node-REDのメモ Dashboard編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでDashboardでUIを作成するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"dashboardをインストールする\">Dashboardをインストールする</h1>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-dashboard」と入力</li>\n  <li>下に検索結果が出るので。「node-red-dashboard」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するボタン\">Dashboard のUIを作成する(ボタン)</h1>\n\n<ul>\n  <li>パレット(左側のペイン)の「dashboard」の下の「button」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「button」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「名前」は適当に設定</li>\n          <li>「タブ」 で「新規に ui_tab を追加…」を選択してその右の編集ボタンをクリック\n            <ul>\n              <li>適当に値を設定する</li>\n              <li>右上の「追加」をクリック</li>\n            </ul>\n          </li>\n          <li>または、既存のタブを選択</li>\n          <li>右上の「追加」をクリック</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Icon」「Tooltip」「Colour」「Background」はオプションなので空欄のままで可</li>\n      <li>「Payload」 に クリックされたときに送信するデータを設定</li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"ブラウザでdashboardのuiに接続する\">ブラウザでDashboardのUIに接続する</h1>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/ui に接続\n    <ul>\n      <li>Dashboardが表示されるハズ\n        <ul>\n          <li>複数のタブがある場合、左上の3本線メニュー(≡)から切り替えられる</li>\n        </ul>\n      </li>\n      <li>ボタンをクリックしたらフローが動作する。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するスライダ\">Dashboard のUIを作成する(スライダ)</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「slider」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「slider」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Tooltip」はオプションなので空欄のままで可</li>\n      <li>「Range」に値の最小値、最大値、刻みを設定</li>\n      <li>「Output」を設定\n        <ul>\n          <li>「continuously while sliding」:操作中、一定時間ごとにメッセージを出力</li>\n          <li>「only on release」:スライダを離したとき(値を確定したとき)にメッセージを出力</li>\n        </ul>\n      </li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"dashboardでゲージグラフを表示する\">Dashboardでゲージグラフを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「guage」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「guage」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>デフォルトの<code class=\"language-plaintext highlighter-rouge\">{{value}}</code>では受信したデータのpayload(<code class=\"language-plaintext highlighter-rouge\">msg.payload</code> )が使用される</li>\n          <li>payloadがobjectの場合、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.XXX}}</code>のように指定すると特定の変数が表示できる</li>\n          <li>このとき、<code class=\"language-plaintext highlighter-rouge\">{{</code> と <code class=\"language-plaintext highlighter-rouge\">}}</code> は波括弧を2つ重ねたもの。波括弧1つだと正常に処理されないので、注意</li>\n          <li>表示する数値の有効桁数を設定したい場合は以下のようにフィルタを設定\n            <ul>\n              <li>小数点以下1桁まで表示:<code class=\"language-plaintext highlighter-rouge\">{{value | number:1 }}</code></li>\n              <li>整数部のみ表示:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:0 }}</code></li>\n              <li>10の位へ丸める:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:-1 }}</code></li>\n            </ul>\n          </li>\n          <li>単位を表示するなど、決まった文字列を追加したい場合は「<code class=\"language-plaintext highlighter-rouge\">{{・・・}}℃</code>」のように波括弧の外側に追加</li>\n        </ul>\n      </li>\n      <li>「units」 で単位を設定する。温度なら「℃」など。これは数値表示には表示されず、グラフ内部の単位情報として表示される</li>\n      <li>「Range」 でグラフの値の範囲を指定する。「-20」~「40」など。\n        <ul>\n          <li>入力値が範囲外になった場合はグラフが上下限に張り付くだけで、エラーなどにはならない。また値そのものは数値表示される</li>\n        </ul>\n      </li>\n      <li>「Colour gradient」 でグラフの色を指定する。3つの色は下で設定するSectors の範囲に対応する</li>\n      <li>「Sectors」 で 上で指定した色を表示する範囲を設定する\n        <ul>\n          <li>これはオプションなので設定しなくても良い。指定しなかった場合は上の「Range」で指定した値の範囲を3等分して使用される</li>\n        </ul>\n      </li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nValue formatのフィルタの詳細は<a href=\"https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters\">https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters</a>を見ろと書かれていましたが、残念ながら私にはよく分かりませんでした…</p>\n</blockquote>\n\n<h1 id=\"dashboardでテキストを表示する\">Dashboardでテキストを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「text」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「text」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>上記参照</li>\n        </ul>\n      </li>\n      <li>「Layout」でレイアウトを選択。お好みで</li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a226513f.c36b1\",\n        \"type\": \"tab\",\n        \"label\": \"Dashboard_1\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"160486fa.dc7159\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e89b8821.ec65e8\",\n        \"type\": \"debug\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 580,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d4346336.cf1228\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e403fdac.aa3748\",\n        \"type\": \"ui_slider\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"label\": \"温度\",\n        \"tooltip\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 4,\n        \"width\": 0,\n        \"height\": 0,\n        \"passthru\": true,\n        \"outs\": \"all\",\n        \"topic\": \"\",\n        \"min\": \"-30\",\n        \"max\": \"50\",\n        \"step\": 1,\n        \"x\": 140,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"78c10ecb.1eb67\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"78c10ecb.1eb67\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 6,\n        \"width\": 4,\n        \"height\": 4,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{value}}℃\",\n        \"min\": \"-20\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 570,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"84bd2adf.3b5df8\",\n        \"type\": \"ui_text\",\n        \"z\": \"a226513f.c36b1\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 560,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1127e563.00001b\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"6547952b.517b34\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"6547952b.517b34\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ1\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"dashboard-のレイアウトを修正する\">Dashboard のレイアウトを修正する</h1>\n\n<p>ボタンのサイズを小さくしたり、複数のボタンを横に並べたい場合はレイアウトの修正を行う。</p>\n\n<ul>\n  <li>サイドバー(右側のペイン)の「dashboard」ボタン(グラフのアイコン)をクリック</li>\n  <li>配置タブをクリック</li>\n  <li>タブの部分(「ホーム」など)をマウスでポイントし、「レイアウト」をクリック\n    <ul>\n      <li>表示領域の幅を変更するには、右上の「幅」の設定値を変更する。(単位はグリッド数)</li>\n      <li>各要素をドラッグすると、表示位置を入れ替えられる。</li>\n      <li>各要素のサイズを変更するには、\n        <ul>\n          <li>右上の鍵アイコンをクリックして閉じた状態にする(鍵が開いた状態では表示領域幅に一致するように自動変更される)</li>\n          <li>右下に矢印アイコンが表示されるので、これをつまんでサイズを変更</li>\n        </ul>\n      </li>\n      <li>各要素を横並びにしたい場合は、各要素をドラッグして移動する(表示幅に収まらない場合は移動できない)</li>\n      <li>各要素のサイズ/位置はグリッド単位でのみ可能</li>\n      <li>右上の完了をクリック\nー デプロイする</li>\n    </ul>\n  </li>\n</ul>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その3)</h1>\n      <p>Node-REDのメモ TCP通信編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでTCP通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"udpで送信\">UDPで送信</h1>\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「送信」で出力するメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト)/「ブロードキャストメッセージ」/「マルチキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で送信先ポート番号を設定\n        <ul>\n          <li>受信プログラムが待ち受けしているポート番号を指定</li>\n        </ul>\n      </li>\n      <li>「アドレス」に送信先アドレス(名前 or IPアドレス)を指定</li>\n      <li>さらにその右で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>特定のポートから送信したいときは「ローカルポートを使用」を選択し、その右に送信元ポート番号を指定する\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n          <li>通常は「ローカルポートをランダムに使用」で大丈夫</li>\n        </ul>\n      </li>\n      <li>入力データがBase64エンコードされたBufferオブジェクトの場合は「Base64形式のペイロードを複合」にチェックを入れる\n        <ul>\n          <li>入力データがBase64文字列かをチェックするだけで、ここでデータを変換するわけではない(?)</li>\n          <li>通常はチェックしないでOK</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると送信先アドレスとポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>送信データを作成するノードを接続\n    <ul>\n      <li>UDPノードはmsg.payloadを送信する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"udpで受信\">UDPで受信</h1>\n<ul>\n  <li>パレットの「入力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「待ち受け」で受信待ちするするメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト or マルチキャスト)/「ブロードキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で受信待ちポート番号を設定\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n        </ul>\n      </li>\n      <li>「種類」で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>「出力」で受信したデータをどのような形式で次段のノードに出力するかを選択する\n        <ul>\n          <li>「バイナリバッファ」を選択すると受信したデータをそのままbufferオブジェクトとして出力</li>\n          <li>「文字列」を選択すると受信したデータをStringオブジェクトにデコードする</li>\n          <li>「Base64文字列」を選択すると受信したデータをBase64 Stringオブジェクトにデコードする</li>\n          <li>「Base64文字列」と「文字列」は内部でtoStringのencodingに’base64’を指定するか’utf8’を指定するかの違い(?)</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると受信待ちポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>受信データを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"2506be7d.1b5332\",\n        \"type\": \"tab\",\n        \"label\": \"UDP\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"44364ec0.0b59b8\",\n        \"type\": \"udp out\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"addr\": \"localhost\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"outport\": \"\",\n        \"base64\": false,\n        \"multicast\": \"false\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"20cee006.2fee4\",\n        \"type\": \"inject\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"\",\n        \"payloadType\": \"date\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 150,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"44364ec0.0b59b8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"eb875fd8.7aa5f8\",\n        \"type\": \"udp in\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"multicast\": \"false\",\n        \"group\": \"\",\n        \"datatype\": \"utf8\",\n        \"x\": 160,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"a6b72636.514e2\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a6b72636.514e2\",\n        \"type\": \"debug\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 140,\n        \"wires\": []\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"httpでrest-api\">HTTPでREST API</h1>\n\n<h2 id=\"http入力ノードの作成\">HTTP入力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「入力」の下の「http」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「メソッド」でメソッド種別を選択\n        <ul>\n          <li>ここでは「GET」で設定を進める(他のメソッドは他所で調べてね)</li>\n        </ul>\n      </li>\n      <li>「URL」でエンドポイント(要はパス)を設定</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとメソッドとURLが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>レスポンスを作成するノード(下記)を接続</li>\n</ul>\n\n<h2 id=\"レスポンス生成ノードの作成\">レスポンス生成ノードの作成</h2>\n\n<p>ここでは、簡単にfunctionノードで固定文字列を返すものを作っています。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると空欄になるので、なるべく識別できる名前を付けましょう</li>\n        </ul>\n      </li>\n      <li>「コード」に処理するプログラムを記述\n        <ul>\n          <li>msg.payloadに表示するページの本文を設定する</li>\n          <li>例えば以下</li>\n        </ul>\n      </li>\n      <li>「名前」の横のアイコンをクリックすると作成したノードの保存/読み込みが出来る\n        <ul>\n          <li>コードは <code class=\"language-plaintext highlighter-rouge\">~/.node-red/lib/functions/</code> に指定したフォルダとファイル名で保存される</li>\n          <li>保存したコードは別のノードで読み込むことができる</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"dl\">\"</span><span class=\"s2\"><h1> ぼ~っと生きてんじゃね~よ! </H1></span><span class=\"dl\">\"</span><span class=\"p\">;</span>\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h2 id=\"http出力ノードの作成\">HTTP出力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「出力」の下の「http response」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「http」と表示される</li>\n        </ul>\n      </li>\n      <li>必要なら「状態コード」を設定</li>\n      <li>必要なら「ヘッダ」を設定</li>\n      <li>シンプルな処理の場合、何も設定しなくてもOK</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"入力レスポンス生成出力を接続\">入力、レスポンス生成、出力を接続</h2>\n\n<ul>\n  <li>上記で作成したノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"ブラウザでアクセス接続\">ブラウザでアクセス接続</h2>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/《HTTP入力ノードに設定したURL》 に接続\n    <ul>\n      <li>ブラウザにレスポンス生成ノードで作成したメッセージが表示される</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"7508e635.c8bf48\",\n        \"type\": \"tab\",\n        \"label\": \"HTTP_REST\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c7938d8a.3ae9d\",\n        \"type\": \"http in\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"url\": \"/rest_api_1\",\n        \"method\": \"get\",\n        \"upload\": false,\n        \"swaggerDoc\": \"\",\n        \"x\": 160,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"fb01d5fd.b76918\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fb01d5fd.b76918\",\n        \"type\": \"function\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"ぼ~っと生きてんじゃね~よ!\",\n        \"func\": \"msg.payload = \\\"<h1> ぼ~っと生きてんじゃね~よ! </H1>\\\";\\nreturn msg;\\n\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 430,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"8d3518af.f9da7\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d3518af.f9da7\",\n        \"type\": \"http response\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"statusCode\": \"\",\n        \"headers\": {},\n        \"x\": 690,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"86c0f820.b0a56\",\n        \"type\": \"debug\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 700,\n        \"y\": 120,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"websocketでデータを送受信\">Websocketでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにwscatを使うこととします。<br />\nwscat は 以下のコマンドでインストールできます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> wscat\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信クライアント\">Websocketでデータ送信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「種類」 で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「URL」 でサーバのURLを設定(例: ws://PiDev25.local:5000/ws/data01)</li>\n          <li>「送信/受信」でペイロードのみ送受信するか、メッセージ全体を送受信するかを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5000で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5000\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5000 (press CTRL+C to quit)\nclient connected\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"75e44664.73e018\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"49b725b6.0e0934\",\n        \"type\": \"websocket out\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"99ad88ce.8bcf7\",\n        \"x\": 600,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"762ccf62.73a48\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fe2498d8.71c17\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47ef3c99.d6eefc\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f97b4d60.afc278\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6d15d519.6289ec\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"87c94e6f.db3458\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"175e465.15aaa3a\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e7c2219c.07acf8\",\n        \"type\": \"debug\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"99ad88ce.8bcf7\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5000/ws/data01\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信サーバ\">Websocketでデータ送信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata1 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest1で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wstest1\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-3\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"22d6d63b.99a952\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"d64e2a6a.27ead8\",\n        \"type\": \"websocket out\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"server\": \"d7536de3.b48578\",\n        \"client\": \"\",\n        \"x\": 520,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"79358fcc.5a5a68\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"cd6acb87.0a77\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7991d417.429124\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ee88046b.37b298\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7eac2c2e.6fa39c\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"650517e9.5e34a8\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d197151e.8b01e\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5871022e.6bbb1c\",\n        \"type\": \"debug\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d7536de3.b48578\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wstest1\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信クライアント\">Websocketでデータを受信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>URL でサーバのURLを設定(例: ws://PiDev25.local:5002/ws/wsdata2)</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-2\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5002で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5002\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5002 (press CTRL+C to quit)\nclient connected\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-4\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a45bd125.622fb8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"24a93730.cf2a7\",\n        \"type\": \"websocket in\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"server\": \"45ba6028.84fc88\",\n        \"client\": \"\",\n        \"x\": 220,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"15576052.1536\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"15576052.1536\",\n        \"type\": \"debug\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"45ba6028.84fc88\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5002/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信サーバ\">Websocketでデータを受信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata2 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-3\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest2で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wsdata2\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-5\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"15604b9.9721eb4\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"80f59585.469758\",\n        \"type\": \"websocket in\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"server\": \"11528a5d.783b0e\",\n        \"client\": \"\",\n        \"x\": 140,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"f37c8fe9.6307c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f37c8fe9.6307c\",\n        \"type\": \"debug\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"11528a5d.783b0e\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その2)</h1>\n      <p>Node-REDのメモ GPIO & I2C編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIO操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDはRaspberryPiで起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"raspberrypiでgpio出力\">RaspberryPiでGPIO出力</h1>\n<ul>\n  <li>パレット(左側のペイン)の「Raspberry Pi」の下の「rpi gpio」(出力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で出力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「出力形式」で「デジタル出力」を選択</li>\n      <li>デプロイしたときに端子状態を初期化したい場合は「端子の状態を初期化」をチェック\n        <ul>\n          <li>「端子の初期状態レベル」を選択</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「LED_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>トリガノードはGPIOから出力する値(0 または 1)を出力する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"51e0a206.805964\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_OUT\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"597df548.0311f4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"89834ee2.89e27\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b020b32.e26818\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"21621e60.e300ba\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_1\",\n        \"pin\": \"22\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"87abb89b.307418\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7ae7810.959a88\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 220,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでgpio入力\">RaspberryPiでGPIO入力</h1>\n\n<ul>\n  <li>パレットの「Raspberry Pi」の下の「rpi gpio」(入力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で入力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「抵抗」で端子に接続するプルアップ/ダウン種別を選択\n        <ul>\n          <li>端子の初期化時に内部のプルアップ/ダウン抵抗のどちらを有効にするかを選択</li>\n          <li>ボード上で処理してれば「なし」を選ぶ</li>\n        </ul>\n      </li>\n      <li>デバウンスにチャタリング除去時間を設定</li>\n      <li>デプロイしたときに端子状態を読み込みたい場合は「~初期状態を読み込む」をチェック</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「SWITCH_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力信号を処理するノードを接続\n    <ul>\n      <li>処理ノードへはGPIOから入力された値(0 または 1)が入力される</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1385085c.ab8648\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_IN\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"e9177a48.70b74\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"932b0e92.05cdd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"932b0e92.05cdd8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f31f20e.4b6d28\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW1\",\n        \"pin\": \"16\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d27c860d.7de3a8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d27c860d.7de3a8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 160,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでi2cを使用する\">RaspberryPiでI2Cを使用する</h1>\n\n<h2 id=\"事前準備\">事前準備</h2>\n\n<p>以下はターミナルやコンソールでの作業</p>\n\n<ul>\n  <li>I2Cを有効化する\n    <ul>\n      <li>リブートは不要らしい</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config\n    5 Interfacing Options\n        P5 I2C\n            Would you like the ARM I2C interface to be enabled?\n            に対して<はい>を選択\n            The ARM I2C interface is enabled\n            と表示されるので<了解>\n    <Finish>\n</code></pre></div></div>\n<ul>\n  <li>I2Cデバイスアクセス用ツールをインストールする</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>i2c-tools\n</code></pre></div></div>\n\n<ul>\n  <li>i2cバスをスキャンしてみる(RasbberryPi2/3のI2Cバスはバス1が出てる。古いのだと0のもあるらしい)</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#   ↓結果(例)</span>\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00:          <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n10: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n20: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n30: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n40: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n50: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n60: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n70: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> 76 <span class=\"nt\">--</span>\n<span class=\"c\"># 76がBME280(Bosch温湿度センサ)</span>\n</code></pre></div></div>\n\n<ul>\n  <li>I2Cデバイスのレジスタをリードしてみる</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cget <span class=\"nt\">-y</span> 1 0x76 0xd0\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ↓ 結果</span>\n0x60\n<span class=\"c\"># レジスタ 0xd0(CHIP ID)をリードするとデバイスのID 0x60が読める</span>\n</code></pre></div></div>\n\n<h2 id=\"bme280用ノードをインストールする\">BME280用ノードをインストールする</h2>\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「bme280」と入力</li>\n  <li>下に検索結果が出るので。「node-red-contrib-bme280」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\n2019/09/13現在、何やらインストール時にエラーになるが、<br />\nモジュールのコンパイル時にwarning/noteが出ているだけのようなので、インストール自体はできているようだ。<br />\nとりあえず下記サンプルは動いているので、大丈夫でしょう。</p>\n</blockquote>\n\n<h2 id=\"bme280を使用するフローを作成する\">BME280を使用するフローを作成する</h2>\n<ul>\n  <li>パレットの「入力」の下の「Bme280」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Bme280」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略するとBme280が表示される</li>\n        </ul>\n      </li>\n      <li>Bus# にバス番号(1)を設定</li>\n      <li>I2C Address にI2Cアドレス(0x76)を設定</li>\n      <li>Topicが必要なら設定(デフォルトはbme280)</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>信号を処理するノードを出力側に接続\n    <ul>\n      <li>Bme280ノードの出力メッセージの内容は以下の通り</li>\n    </ul>\n  </li>\n</ul>\n\n<table>\n  <thead>\n    <tr>\n      <th>変数名</th>\n      <th>値の例</th>\n      <th>項目</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>msg.topic</td>\n      <td>“bme280”</td>\n      <td>ノードの設定で設定したTopic</td>\n    </tr>\n    <tr>\n      <td>msg.payload.temperature_C</td>\n      <td>34.23</td>\n      <td>温度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.humidity</td>\n      <td>54.402349427117336</td>\n      <td>湿度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.pressure_hPa</td>\n      <td>1013.9016246356634</td>\n      <td>気圧</td>\n    </tr>\n    <tr>\n      <td>msg.payload.model</td>\n      <td>“BME280”</td>\n      <td>センサ名</td>\n    </tr>\n  </tbody>\n</table>\n\n<ul>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n    {\n        \"id\": \"e4065603.3c6dc\",\n        \"type\": \"tab\",\n        \"label\": \"BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c0602bca.110b8\",\n        \"type\": \"Bme280\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"8b845ce5.ec2fd\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b845ce5.ec2fd\",\n        \"type\": \"debug\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 630,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"cdbf55ce.3aa94\",\n        \"type\": \"inject\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"c0602bca.110b8\"\n            ]\n        ]\n    }\n]\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その1)</h1>\n      <p>Node-REDのインストール他のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDをインストールや、フローを作成する際の手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"ubuntu-に-node-red-をインストールする\">ubuntu に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejsとnpmのインストール\">Node.jsとnpmのインストール</h2>\n\n<p>自動起動とかやらないなら、Node.js は nodenv とか使っても良い気がするが、\n念のためシステムに直接インストールしておく。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">apt install</code> だと古いバージョンになってしまうので、<br />\nnコマンド をインストールし、<br />\nnコマンドで安定版をインストールする。<br />\nその後、<code class=\"language-plaintext highlighter-rouge\">apt</code> でインストールしたNode.jsは削除。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n\n<span class=\"c\"># nコマンドのインストール</span>\n<span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> n\n\n<span class=\"c\"># 安定版のインストール</span>\n<span class=\"nb\">sudo </span>n stable\n\n<span class=\"c\"># aptでインストールしたnode.jsをアンインストール</span>\n<span class=\"nb\">sudo </span>apt purge <span class=\"nt\">-y</span> nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h2 id=\"node-redのインストール\">Node-REDのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> <span class=\"nt\">--unsafe-perm</span> node-red node-red-admin\n</code></pre></div></div>\n\n<p>どうも、ノードの追加とかすると、npmのキャッシュをアクセスするときにpermission deniedと言われてしまうみたいなので、\n以下のコマンドで .npm ディレクトリ以下の所有権を自分にしておく。<br />\n(キャッシュだから削除しても良い気がするが)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> ~/.npm\n</code></pre></div></div>\n\n<h2 id=\"起動\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"停止\">停止</h2>\n\n<p>CTRL-Cで停止する。</p>\n\n<h2 id=\"参考\">参考</h2>\n\n<p><a href=\"https://qiita.com/seibe/items/36cef7df85fe2cefa3ea\">https://qiita.com/seibe/items/36cef7df85fe2cefa3ea</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"windows10-に-node-red-をインストールする\">Windows10 に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npmの-インストール\">Node.js と npmの インストール</h2>\n\n<ul>\n  <li><a href=\"https://nodejs.org/ja/\">Node.jsのサイト</a>からWindows版をダウンロードします。\n  推奨版(2019/09/16現在、10.16.3 LTS)をダウンロードしてください。<br />\n  (もし、別のプラットフォームのものが必要なら上部のメニューの「ダウンロード」からダウンロードします)</li>\n  <li>ダウンロードしたnode-vXX.XX.XX-YY.msiを実行してインストーラを起動し、インストールします。\n  特に迷うところはないと思います。大体、そのまま「次へ」で大丈夫。</li>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell を起動します。\n  念のため、<code class=\"language-plaintext highlighter-rouge\">node -v</code> を実行して、<code class=\"language-plaintext highlighter-rouge\">v10.16.3</code>と表示されることを確認します。\n  次にnpmのアップデートを行います。以下のコマンドを実行してください。( 2019/09/16現在、6.11.3 でした)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g npm\n</code></pre></div></div>\n<h2 id=\"node-redのインストール-1\">Node-REDのインストール</h2>\n\n<ul>\n  <li>コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してインストールします。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g --unsafe-perm node-red\n</code></pre></div></div>\n\n<ul>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してNode-REDを起動します。<br />\n実行したウィンドウは閉じないでください。閉じるとNode-REDが終了してしまいます。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>なお、初めてNode-REDを起動したとき、\n『このアプリの機能のいくつかがWindows Defender ファイアウォールでブロックされています』\nと警告が表示されることがある。</p>\n\n<p>この場合、\n「通信を許可するネットワーク」を選択して「アクセスを許可する」をクリック\nすれば良い。</p>\n\n<h2 id=\"ちょっとヒトコトメモ\">ちょっとヒトコトメモ</h2>\n\n<p>(ぜんぜんヒトコトじゃないけど。。。)</p>\n\n<p>Node-REDを起動したPCからのアクセス(ブラウザ接続など)は成功するのに、\n外部PCやRaspberryPi(もちろん、同一サブネット上の)からのアクセス(ブラウザやWebsocket接続)が失敗する場合がある。</p>\n\n<p>考えられる原因は色々あるが、最も多そうな原因のひとつにファイアウォールでのブロックが考えられる。<br />\n上の警告ダイアログでアクセス許可した際に、プライベートネットワークのみに通信を許可していて、\nかつ、現在接続されているネットワークがパブリックネットワークである場合である。</p>\n\n<p>ファイアウォールでのブロックされているかは<strong>Node-REDを起動した状態</strong>で以下のコマンドで確認できる。</p>\n\n<ul>\n  <li>RaspberryPiの場合</li>\n</ul>\n\n<p>以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 《IPアドレス》 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 192.168.1.2 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、コマンドが終了しないので、CTRL+Cで終了する。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">Connection to 《IPアドレス》 《ポート番号》port [tcp/*] succeeded!</code>と表示される。</p>\n\n<ul>\n  <li>Windowsの場合</li>\n</ul>\n\n<p>Windows Poewrshellで(コマンドプロンプトでは不可)以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 《IPアドレス》  <span class=\"nt\">-port</span> 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 192.168.1.2 <span class=\"nt\">-port</span> 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : False</code>と表示される。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : True</code>と表示される。</p>\n\n<p>これを解決するには、Node-REDを実行しているWindows PCで<br />\n「コントロールパネル」→「Windows Defender ファイアウォール」を開き、<br />\n左側のリストから「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック<br />\n「設定の変更」をクリック\n下のリストから「Node.js: Server-side JavaScript」の右側 パブリックのチェックボックスにチェックを入れる<br />\n「OK」をクリック</p>\n\n<p>この状態で再度RaspberryPi または PCからファイアウォールでのブロックの確認を実行し、ブロックされていないことを確認してください。</p>\n\n<h1 id=\"raspbian-に-node-red-をインストールする\">Raspbian に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npm-と-node-red-のインストール\">Node.js と npm と Node-RED のインストール</h2>\n\n<p>インストールスクリプトを実行すればイッパツで解決。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストールスクリプトの取得</span>\nwget  https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered\n\n<span class=\"c\"># 必要なら中身確認してね</span>\n\n<span class=\"c\"># インストールスクリプトの実行</span>\nbash update-nodejs-and-nodered \n</code></pre></div></div>\n\n<h2 id=\"起動-1\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-start \n</code></pre></div></div>\n<p>CTRL-Cでログ表示のみ止まる(Node-RED自体は動作したまま)</p>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"ログ表示\">ログ表示</h2>\n\n<p>Node-RED で console.log などを実行したときは、ログに表示される。<br />\n<code class=\"language-plaintext highlighter-rouge\">node-red-start</code>したままなら表示されるが、CTRL-Cでログ表示を止めていた場合は\n以下のコマンドでログ表示を再開できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-log\n</code></pre></div></div>\n\n<h2 id=\"停止-1\">停止</h2>\n\n<p>Node-RED自体を停止する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-stop\n</code></pre></div></div>\n\n<h2 id=\"参考-1\">参考</h2>\n\n<p><a href=\"https://qiita.com/utaani/items/7155c62d6c5e96822afb\">https://qiita.com/utaani/items/7155c62d6c5e96822afb</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"フローの操作\">フローの操作</h1>\n\n<h2 id=\"フローを保存するエクスポート\">フローを保存する(エクスポート)</h2>\n\n<p>作成したフローは保存することができます。<br />\nしばらく使わないフローを削除したり、別の環境にコピーする場合に保存しておくと良いでしょう。</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「書き出し」→「クリップボード」をクリック →書き出しダイアログが表示される\n    <ul>\n      <li>書き出す範囲を「現在のタブ」「すべてのタブ」から選択。(フローの一部を選択していた場合は「選択したフロー」も選択可能)</li>\n      <li>その下にはその時のJSONファイルの内容が表示されていますので、ここから</li>\n      <li>さらにその下で出力形式を「インデントのないJSONフォーマット」「インデント付きのJSONフォーマット」から選択。多少ファイルサイズが増減しますが、どちらを選んでも特に問題になるようなことはないでしょう。「インデント付き」の方が目視で確認しやすいと思います。</li>\n      <li>「ダウンロード」をクリックすると、ブラウザのファイル保存(ダウンロード)ダイアログが開くので、保存処理を行う(このときのファイル名はflows.json固定なので、必要に応じて保存後リネームしてください)</li>\n      <li>または、「書き出し」をクリックすると、クリップボードへコピーされるので、直接 別の環境の読み込みダイアログやエディタへペーストすることも可能</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"フローを読み込むインポート\">フローを読み込む(インポート)</h2>\n\n<p>保存したフローは読み込んで使用することができます(当然か)</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「読み込み」→「クリップボード」をクリック →読み込みダイアログが表示される\n    <ul>\n      <li>「読み込むファイルを選択してください」をクリックして読み込むファイルを選択 → ファイルの内容がその下のエディットボックスに表示される</li>\n      <li>または、その下のエディットボックスにJSONデータをペースト</li>\n      <li>読み込み先を「現在のタブ」「新規のタブ」から選択(「選択したフロー」で保存してないとどっちでも同じ気がする)</li>\n      <li>「読み込み」をクリック</li>\n    </ul>\n  </li>\n  <li>読み込まれるので、内容を確認。必要なら修正。</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"フローを削除する\">フローを削除する</h2>\n\n<p>使用しなくなったフローをいつまでも残しておくとトラブルの元ですから、削除しましょう。<br />\n(念のため保存しておくのを忘れずに)</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、削除したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>左上の「削除」をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(次回デプロイするまで処理は残っているので注意)</li>\n</ul>\n\n<h2 id=\"フローを一時的に停止する\">フローを一時的に停止する</h2>\n\n<p>後で使うから削除したくはないけど、今デバッグしてる作業の邪魔になる、というような場合、\n作成したフローを削除せずに一時的に停止することができます。</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、停止したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>状態を「無効」にする</li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(デプロイしないといつまで経っても停止しないので注意)</li>\n</ul>\n\n<p>再開する場合は上記手順と同じで、状態を「有効」にする。</p>\n\n<h2 id=\"フローを全削除する\">フローを全削除する</h2>\n\n<p>色々フローを作成したけど、一回チャラにしてやりなおしたいときは、\n一旦Node-REDを停止(ブラウザ切断だけじゃなく、サーバプログラムを停止)して\n以下の2つのファイルを削除する</p>\n\n<ul>\n  <li>~/.node-red/flows_《ホスト名》.json</li>\n  <li>~/.node-red/.flows_《ホスト名》.json.backup</li>\n</ul>\n\n<p>もちろん、念のためバックアップ取っておくのが好ましい。<br />\nバックアップから復元すれば元通りになるはず。</p>\n\n<p>その後、Node-Redを起動すると、フローが綺麗さっぱり消えているハズ。</p>\n\n<h2 id=\"その2以降のフローの例について\">その2以降の「フローの例」について</h2>\n\n<p>「フローの例」に書かれたJSONコードはテスト用に作成したフローをエクスポート(書き出し)したものです。<br />\nこのコードの表示部分にマウスを乗せると、右上に「Copy」ボタンが表示されますので、このボタンをクリックしてください。JSONコードがクリップボードにコピーされます(マウスをドラッグしての選択は不要)。</p>\n\n<p>この状態で、上記<strong>フローを読み込む(インポート)</strong>に示した方法でフローをインポートするとフローがコピーされます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n複数のフローをインポートした場合、既に存在するノードと同名のノードは別のノードとして生成されます。このとき、名前に「(_1)」などの別ノードを識別できるような記号は付きません。<br />\n特に、WebsocketのノードやDashboardのタブ/グループはシステムの動作や見た目に影響しますので、注意してください。<br />\n自動でよしなにする方法はありませんので、手動でチマチマと修正してください。<br />\nサイドバー(右側のペイン)の「▼」ボタンをクリックし、ノードの設定を表示でノードの設定を表示し、<br />\n各ノードの右側の数字をクリックすると、そのノードを参照しているノードの一覧が表示されます。<br />\nさらにそのノード一覧の各ノードをダブルクリックすると、そのノードが点滅表示されるので、そのノードのプロパティで参照先を変更すれば良いでしょう。</p>\n\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(RaspberryPi編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(RaspberryPi編)</h1>\n      <p>過去のブログ(RaspberryPi編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"センサ接続gpio\">センサ接続/GPIO</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4f2290b79f3005f839afe798c424fadd\">BOSCH 9軸センサ bmx055 ドライバ(Node.js用) </a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/310580fc726f8b2315d2a81486cbe551\">RaspberryPi向けBOSCH 温度/湿度/気圧センサ(BME280)、9軸センサ(加速度/ジャイロ/地磁気)(BMX055)動作確認プログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/dc6f4c0987e462ca94f003b8d20ea456\">RaspberryPi向けGPIO操作テストプログラム</a></li>\n</ol>\n\n<h1 id=\"webサーバ\">WEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/e37a1d11ac25cf7e421f4d6c32d9a03c\">RaspberryPi向けWEBサーバ&センサテストプログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/18ee6da1c77671949e881eb45dda6edf\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/b23849cf9b82b83fe0c2df22836b6c27\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ/ついでに3D姿勢計算もブラウザでやるっちゃ</a></li>\n</ol>\n\n<h1 id=\"もう一つのwebサーバ\">もう一つのWEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/bcaa47ce1b04bd6b8285e553d6fb9f4f\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/11cc216ffde610e26a5b8cd4ee5b599b\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js/webサーバにExpressを使ってサッパリと</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/8179edb10867faf98e233a52965a9e53\">Raspbianのシリアルコンソールでloginするとイケてないのを改善する</a></li>\n</ol>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>nodenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>nodenvのインストール</h1>\n      <p>nodenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonのpyenvと同様にNode.jsのバージョン管理システムのnodenvを使用する。<br />\n(両方インストールするくらいならanyenvを使えという説もあるが…)</p>\n\n<p>他にもnvmやnodebrewなんてのもあるらしい。nodenvはディレクトリごとにローカルバージョンを設定できてとても便利なのでおススメ。<br />\nnodeenv(eが2つ)という超マイナーなのもあるけど、間違わないように。</p>\n\n<p>Node.jsはリポジトリにバイナリパッケージが用意されているバージョンはバイナリインストールできる。用意されていないバージョンはソースからコンパイルされるが、必要なライブラリ類のインストールなど必要。ここでは手順は割愛。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>インストールに必要なモジュールをインストールする。インストール済みならスキップして可。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>git\n</code></pre></div></div>\n\n<h2 id=\"nodenv本体のインストール\">nodenv本体のインストール</h2>\n\n<p>nodenv本体をインストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\ngit clone git://github.com/nodenv/nodenv.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/nodenv/node-build.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build\n</code></pre></div></div>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>nodenvの設定のため、~/.bashrc に以下を追加。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h1 id=\"設定\">設定</h1>\n\n<h3 id=\"nodenvでインストールできるバージョンの一覧を表示\">nodenvでインストールできるバージョンの一覧を表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install</span> <span class=\"nt\">-l</span>\n</code></pre></div></div>\n<p>バイナリインストールできるか確認したい場合は以下。<br />\nバイナリがなければソースからコンパイルされるが、時間がかかるのが嫌な場合に(大抵のバージョンはバイナリが用意されているようだ)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"nt\">-r</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/share/\n<span class=\"c\"># ただし、uname -m が x86_64 | amd64 | i686-64 のときはx64に置き換える</span>\n</code></pre></div></div>\n\n<h3 id=\"nodejsのインストール\">Node.jsのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">install </span>10.15.3 \n</code></pre></div></div>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv global 10.15.3\n</code></pre></div></div>\n<p>念のため指定したバージョンが実行されることを確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h3 id=\"仮想環境について\">仮想環境について</h3>\n\n<p>pyenvと異なり、nodenvは仮想環境をサポートしていない。<br />\nNode.jsはローカルモジュールのインストールが簡単なので、仮想環境を構築しなくても個々のディレクトリでローカルモジュールをインストールすることで仮想環境相当のことが実現できる。</p>\n\n<h3 id=\"npmのバージョンアップ\">npmのバージョンアップ</h3>\n\n<p>「npmが古い~」と言われる前にバージョンアップ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> npm\n</code></pre></div></div>\n\n<h3 id=\"ローカルで使用するバージョンの設定\">ローカルで使用するバージョンの設定</h3>\n<p>ディレクトリ毎に使用するバージョンを指定するには(例えば、このディレクトリ下で作業するプロジェクトは9.11.1を使う、みたいな時)<br />\nそのディレクトリで以下のように実行する。<br />\n指定はそのディレクトリ直下だけでなく、その子ディレクトリ、孫ディレクトリ、・・・で有効。<br />\nshellを閉じても設定は残る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">local</span> <バージョン名>\n</code></pre></div></div>\n\n<h3 id=\"一時的なバージョンの切り替え\">一時的なバージョンの切り替え</h3>\n\n<p>そのshellだけ使用するバージョンを変更したい場合は、以下のよう実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv shell <バージョン名>\n</code></pre></div></div>\n<p>別のターミナルでの実行には影響しない。</p>\n\n<h1 id=\"nodenvのバージョンアップ\">nodenvのバージョンアップ</h1>\n\n<p>Node.jsの新しいバージョンがリリースされ、それをインストールしたい場合など、nodenvのバージョンアップが必要。<br />\n<strong>下記その2の方がおススメ。こっちの手順は参考までに。</strong></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>\ngit pull\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/node-build/\ngit pull\n</code></pre></div></div>\n<p>実行後、ターミナルを開きなおす</p>\n\n<h1 id=\"nodenvのバージョンアップ-その2\">nodenvのバージョンアップ その2</h1>\n<p>nodenv-updateをインストールしておけば、<code class=\"language-plaintext highlighter-rouge\">nodenv update</code>を実行するだけですべてのプラグインを含めてバージョンアップしてくれるので、おススメ。インストール方法は下記。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/nodenv/nodenv-update.git <span class=\"k\">${</span><span class=\"nv\">NODENV_ROOT</span><span class=\"k\">}</span>/plugins/nodenv-update\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n\n<p>ちょっとだけ使い方一覧。</p>\n\n<h3 id=\"システムのnodejsを使いたい場合\">システムのNode.jsを使いたい場合</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"o\">[</span>global | <span class=\"nb\">local</span> | shell] system\n</code></pre></div></div>\n\n<h3 id=\"現在の状態で使用されるバージョン仮想環境を確認\">現在の状態で使用されるバージョン/仮想環境を確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv version\n</code></pre></div></div>\n\n<h3 id=\"nodenvでインストールされているnodejsのバージョンを確認\">nodenvでインストールされているNode.jsのバージョンを確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv versions \n</code></pre></div></div>\n<p>現在の状態で使用されるバージョンの先頭に「*」 が付く。</p>\n\n<h3 id=\"nodenv自体のバージョン確認\">nodenv自体のバージョン確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nt\">--version</span>\n</code></pre></div></div>\n\n<h3 id=\"nodenvで使用できるコマンドの確認\">nodenvで使用できるコマンドの確認</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv commands\n</code></pre></div></div>\n\n<h3 id=\"nodenvのヘルプの表示\">nodenvのヘルプの表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nodenv <span class=\"nb\">help</span>\n\n<span class=\"c\"># 各コマンドのヘルプを表示するには以下</span>\nnodenv <span class=\"nb\">help</span> <<span class=\"nb\">command</span><span class=\"o\">></span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Ruby": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのWindows環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのWindows環境での実行</h1>\n      <p>github pagesをWindows環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行できるようにした(<a href=\"/memoBlog/2019/07/17/githubpages.html\">参照</a>)が、\nわざわざUbuntu立ち上げるのが面倒になってきたので、Windows上で実行できるようにしてみた。</p>\n\n<h1 id=\"何はともあれrubyのインストール\">何はともあれRubyのインストール</h1>\n<p>Windows版Rubyをインストールしないとはじまらないので、\n<a href=\"https://www.ruby-lang.org/ja/\">Rubyの総本山</a> から(RubyInstaller のダウンロード](https://rubyinstaller.org/downloads/)\nへ行ってダウンロード。<br />\nWITH DEVKIT を選んでおく方が良いらしい。<br />\nバージョンは最新で良いでしょう(私は Ruby+Devkit 2.6.3-1 (x64) を選びました)。</p>\n\n<p>ダウンロードしたらなんとなーくインストーラ実行して案内にしたがってなんとな~く進んでちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\ngccも要るのかな?Rubyインストール時にMSYS64環境がインストールされるみたいなので、大丈夫かな?<br />\nちなみに、うちの環境はmingw-w64が入ってる。</p>\n</blockquote>\n\n<p>とりあえずbundlerはグローバルに入れとく。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem install bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。<br />\n一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをローカルにインストールする。<br />\nUbuntuみたいにrdenv環境じゃないので、グローバル環境はなるべく汚染したくないので、<code class=\"language-plaintext highlighter-rouge\">--path</code>指定してローカルにインストールする。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div></div>\n\n<p>あるいは、<code class=\"language-plaintext highlighter-rouge\">install.cmd</code>に登録してあるので、そっちを実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRubyのバージョンを変更したり、ディレクトリを移動した場合はgemsディレクトリを削除してから</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div>  </div>\n  <p>を実行する</p>\n</blockquote>\n\n<p>windows対応にあたって、リポジトリの _config.yml と .gitignore は対処済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>サーバ起動</p>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\\server.cmd\n</code></pre></div></div>\n\n<p>もちろん、エクスプローラなどから <code class=\"language-plaintext highlighter-rouge\">server.cmd</code> をダブルクリックして実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこのときのキモ、jekyll実行前に以下を実行してRubyのエンコードをUTF-8に設定している。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>set RUBYOPT=--encoding=UTF-8`  \n</code></pre></div>  </div>\n  <p>これがないとエンコードエラーが発生する。<br />\n環境変数で設定しておけば逐一設定しなくても良いが、どうせcmdファイル書いてあるので、ついでに設定している。</p>\n</blockquote>\n\n<p>firewallが警告を表示するので、許可してちょ。<br />\nまごまごしてるとjekyllがエラー終了しちゃうけど、その後でも許可してしまえば次回からは大丈夫。</p>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>以降は<a href=\"/memoBlog/2019/07/17/githubpages.html\">こっち</a>を見てちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのローカル環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのローカル環境での実行</h1>\n      <p>github pagesをローカル環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行することができる。</p>\n\n<p>以下の手順はUbuntu 16.04で動作確認した。他のバージョンでは、特にインストールの準備に微妙な違いがあるかもしれない。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<p>apt または rbenvでrubyをインストールしておく。</p>\n\n<p>aptの場合は以下(nativeなライブラリを使うので-devパッケージをインストール) 。<br />\nrbenvの場合は<a href=\"/memoBlog/2019/07/07/rbenv.html\">rbenvのインストール</a>参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ruby-dev\n</code></pre></div></div>\n\n<p>bundlerをインストールする。bundlerはNode.jsでいうところのnpmのうち、package.jsonでローカルインストールしたモジュールを管理する部分に相当するもの(かな?)。<br />\naptでrubyをインストールした場合はrootでインストール必要があるので、<code class=\"language-plaintext highlighter-rouge\">sudo</code>を付けて実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem <span class=\"nb\">install </span>bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span>\n</code></pre></div></div>\n\n<p>モジュールをローカルにインストールすることもできる。<br />\nその場合は以下で。<br />\n–pathオプションのパラメータはお好みで変更してちょ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span> <span class=\"nt\">--path</span> gems\n</code></pre></div></div>\n\n<p>このとき、<code class=\"language-plaintext highlighter-rouge\">_config.yml</code>の以下の部分にモジュールのインストール先(上の例では<code class=\"language-plaintext highlighter-rouge\">gems</code>)を追加しておく(追加しないとjekyll実行時にエラーになる)。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<div style=\"text-align: center;\">↓</div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [gems, server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n\n<h2 id=\"サーバ起動\">サーバ起動</h2>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./server.sh\n</code></pre></div></div>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>ブラウザ(firefoxとchromeで動作確認した。IEでは動かない。Edgeはよーわからん)を起動し、サーバを起動しているマシンのport 4000に接続。このとき、ブラウザはサーバと同じマシンである必要はない。</p>\n\n<h2 id=\"サーバの停止\">サーバの停止</h2>\n\n<p>CTRL+cで停止。</p>\n\n<h2 id=\"サーバの-listen-port-の変更\">サーバの listen port の変更</h2>\n\n<p>必要ならサーバの listen port を変更できる。<br />\nserver.sh 内のコマンドの <code class=\"language-plaintext highlighter-rouge\">--port</code> オプションを変更すればOK.</p>\n\n<h1 id=\"ディレクトリ構成\">ディレクトリ構成</h1>\n\n<p>ディレクトリ構成は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── _config.yml                             jekyllの設定ファイル\n├── Gemfile                                 bundlerの管理ファイル\n├── _layouts                                ページレイアウト用HTMLファイル置き場\n│   ├── default.html                           デフォルト使用\n│   ├── toppage.html                           トップページ用\n│   └── debug.html                             デバッグページ用\n│                                                 どのレイアウトを使うかは各MarkdownファイルのFront-matterで指定する\n├── _includes                               共通で使用するレイアウトはここに置いておく\n│   └── footer.html\n├── _posts                                   投稿記事置き場\n│   ├── 2019-06-22-asyncawait.md\n│   ├── ・・・・\n│   └── YYYY-MM-DD-title.md                     ブログの投稿記事  ファイル名は年-月-日-タイトル とする。\n├── _sass                                    sassのインクルードファイルを置いておく\n│   └── _my_theme.scss                          大本のテーマ設定用sassファイル\n├── assets\n│   ├── css\n│   │   ├── jquery.floatingscroll.css      jQuery の floatingscroll プラグインのCSSファイル\n│   │   └── style.scss                     このページのメインのcssになるsassファイル\n│   └── js\n│       ├── jquery.floatingscroll.min.js    jQuery の floatingscroll プラグインのスクリプトファイル\n│       └── main.js                         各ページで実行するjavascriptファイル\n├── index.md                                 トップページ\n├── misc                                     以下にその他のページデータを置く\n│   ├── debug.md\n│   └── sample.md\n├── favicon.ico                              favicon画像\n├── compile.sh                               サイト構築のみ行うスクリプト\n├── server.sh                                サーバ起動用スクリプト(サイト構築も同時に行う)\n└── _site                                    以下にサイト構築データが生成される\n</code></pre></div></div>\n\n<h1 id=\"投稿記事のファイル名\">投稿記事のファイル名</h1>\n\n<p>投稿記事のファイル名は<code class=\"language-plaintext highlighter-rouge\">YYYY-MM-DD-title.拡張子</code>とする。<br />\nそれ以外のファイル名を付けると無視される。</p>\n\n<p>日付、タイトルは後述のFrontMatterに設定があればそちらが優先される。</p>\n\n<h1 id=\"front-matterの構成\">Front Matterの構成</h1>\n\n<p>Front Matterの主な項目は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>---\ntitle: XXXX                タイトル  指定無ければファイル名のタイトル部分が使用される\ndate: 2019-07-07           日付 指定無ければファイル名の日付部分が使用される\ntags: [\"YYY\",\"ZZZ\"]        タグを指定  このタグでトップページでカテゴリを選択できる 大文字/小文字は区別される\nlayout: toppage            使用するレイアウト 指定無ければdefaultが使用される\nexcerpt: xxxxxx            抜粋  トップページのタイトルの下に表示される\n---\n</code></pre></div></div>\n\n<h1 id=\"あとはお好きに変更してちょ\">あとはお好きに変更してちょ</h1>\n\n<p>自分のリポジトリにpushして、そのリポジトリの設定でgithub pagesを有効にすればいっちょ上がり。</p>\n\n<p>ちなみに、ファイルが一つもないリポジトリではgithub pagesを有効にできないので、ダミーでもいいからファイルをpushしてから設定すること。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>rbenvのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>rbenvのインストール</h1>\n      <p>rbenvのインストール手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>pythonに対するpyenvのようにrubyのバージョンを変更したり、個別にモジュールを管理したりできるrbenvを導入する。<br />\nあと、モジュールをインストールする <code class=\"language-plaintext highlighter-rouge\">gem install</code> に <code class=\"language-plaintext highlighter-rouge\">sudo</code> を付けなくても良いのも地味に便利。<br />\ngemset(pyenvの仮想環境のようなもの)を作って個別にモジュール管理すれば、色々インストールして訳わからん状態になったときでも、一旦チャラにして観光構築をやりなおせる。</p>\n\n<p>なお、rbenvはrubyをバイナリインストールできなくて、ソースからコンパイルするので、インストールにはそれなりに時間がかかる。</p>\n\n<p>以下の手順はUbuntu 16.04で動作確認した。他のバージョンでは、特にインストールの準備に微妙な違いがあるかもしれない。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>インストールに必要なモジュールをインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>git autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev\n</code></pre></div></div>\n\n<h2 id=\"rbenv本体とプラグインのインストール\">rbenv本体とプラグインのインストール</h2>\n\n<p>rbenv本体とプラグインをインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">RBENV_ROOT</span><span class=\"o\">=</span>/proj/.rbenv    <span class=\"c\"># 環境に合わせて修正してね</span>\ngit clone https://github.com/sstephenson/rbenv.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/sstephenson/ruby-build.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/ruby-build\ngit clone git://github.com/jf/rbenv-gemset.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-gemset\ngit clone https://github.com/sstephenson/rbenv-gem-rehash.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-gem-rehash\ngit clone https://github.com/rkh/rbenv-update.git <span class=\"k\">${</span><span class=\"nv\">RBENV_ROOT</span><span class=\"k\">}</span>/plugins/rbenv-update\n</code></pre></div></div>\n<p>rbenv-gemset をインストールすることで、個別のモジュール環境を構築できる。pyenvのvirtualenvみたいな感じ。<br />\nrbenv-gem-rehashをインストールすることで、バージョン切り替えやgemのインストールの度にrbenv rehash を実行しなくてもよくなる。<br />\nrbenv-updateをインストールすることで、<code class=\"language-plaintext highlighter-rouge\">rbenv uppppdate</code> でrbenvと各プラグインのアップデートができる。</p>\n\n<h2 id=\"bashrcの編集\">~/.bashrcの編集</h2>\n\n<p>rbenvの設定のため、~/.bashrc に以下を追加。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">RBENV_ROOT</span><span class=\"o\">=</span>/proj/.rbenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$RBENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>rbenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<p>ここで設定を有効にするためにターミナルを開きなおす。</p>\n\n<h1 id=\"設定と使い方\">設定と使い方</h1>\n\n<h3 id=\"rbenvでインストールできるバージョンの一覧を表示\">rbenvでインストールできるバージョンの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span>\n</code></pre></div></div>\n\n<h3 id=\"rubyのインストール\">rubyのインストール</h3>\n\n<p>インストールしたいバージョンを指定して実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">install </span>2.6.3\n</code></pre></div></div>\n\n<p>・・・ 気長に待つ。 ・・・</p>\n\n<h3 id=\"デフォルトで使用するバージョンの設定\">デフォルトで使用するバージョンの設定</h3>\n\n<p>デフォルトで使用したいバージョンを指定して実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv global 2.6.3\n</code></pre></div></div>\n\n<p>念のため指定したバージョンが実行されることを確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ruby <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h3 id=\"gemsetの作成\">gemsetの作成</h3>\n\n<p>色々試したあとに、インストールしたモジュールをチャラにしたいときを考えて、gemset(仮想環境みたいなもん)を構築しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset create 《ベースバージョン》 《gemset名》\n</code></pre></div></div>\n\n<p>例えば、ruby 2.6.3 に test1 という名前のgemsetを作成する場合。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset create 2.6.3 test1\n</code></pre></div></div>\n\n<p>gemsetはインストールされた各バージョンに紐づいて作成される。</p>\n\n<h3 id=\"gemsetの設定\">gemsetの設定</h3>\n\n<p>gemsetはディレクトリ毎に指定する。<br />\nカレントディレクトリに設定されたgemset(なければその親、さらに親と探す)と\nカレントのRubyバージョンが使用される。<br />\nカレントのRubyのバージョンに指定されたgemsetが存在しなければ新しくgemsetを作成するが、中身は空。<br />\nなので、gemsetを指定したときは、同時に <code class=\"language-plaintext highlighter-rouge\">rbenv local</code> でローカルバージョンも指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> 《設定したいディレクトリ》\nrbenv <span class=\"nb\">local</span> 《バージョン》\nrbenv gemset init 《gemset名》\n</code></pre></div></div>\n<p>gemset名を省略するとカレントディレクトリ名と同じ名前でgemsetが作成され、そのgemsetに設定される</p>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\nrbenv gemset init test1\n</code></pre></div></div>\n\n<h3 id=\"作成されたgemsetの一覧表示\">作成されたgemsetの一覧表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset list\n</code></pre></div></div>\n<p>こんな感じで表示される。Rubyのバージョンが異なれば同名のgemsetも作成できる。<br />\nただし、中身は別物。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>rbenv gemset list\n2.3.8:\n  test1\n2.6.3:\n  test1\n</code></pre></div></div>\n\n<h3 id=\"カレントディレクトリで有効なgemsetの確認\">カレントディレクトリで有効なgemsetの確認</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv gemset active\n</code></pre></div></div>\n\n<p>ついでにRubyのバージョンも確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv version\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>rbenv gemset active\nenv1 global\n<span class=\"nv\">$ </span>rbenv version\n2.6.3 <span class=\"o\">(</span><span class=\"nb\">set </span>by /*******/.ruby-version<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"gemsetの指定を無効にするにはrbenv-gemsets-ファイルを削除する\">gemsetの指定を無効にするには.rbenv-gemsets ファイルを削除する</h3>\n\n<p>コマンドで指定を無効にできないので、指定ファイルを手動で削除する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> .rbenv-gemsets\n</code></pre></div></div>\n<p>使用するgemsetを変更したい場合、すでにgemset設定済みのディレクトリでは再設定できない。<br />\n一旦gemsetの指定を無効にしてから、再度 <code class=\"language-plaintext highlighter-rouge\">rbenv gemset init ~</code> する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n\n<h3 id=\"gem関連の設定を確認\">gem関連の設定を確認</h3>\n\n<p>gem関連の設定(GEM_PATHSなど)を確認したいときは以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem <span class=\"nb\">env</span>\n</code></pre></div></div>\n<h3 id=\"helpの表示\">helpの表示</h3>\n\n<p>rbenv 全体のヘルプ(コマンドの確認など)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">help</span>\n</code></pre></div></div>\n\n<p>各コマンドのヘルプ(パラメータやオプションの確認など)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv <span class=\"nb\">help</span> 《コマンド》\n</code></pre></div></div>\n\n<h1 id=\"メモ\">メモ</h1>\n\n<h3 id=\"rehashについて\">rehashについて</h3>\n\n<p>設定を変えたりした場合は以下を実行する必要があるが、rbenv-gem-rehashをインストールしてあれば必要なタイミングで自動で行われるので不要。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rbenv rehash \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "github": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>githubによるセキュリティチェック</title>\n  </head>\n  <body>\n    <header>\n      <h1>githubによるセキュリティチェック</h1>\n      <p>githubによるセキュリティチェックによるpullリクエストが来た場合の対処方法</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>githubによるセキュリティチェックによるpullリクエストが来た場合の対処方法</p>\n\n<p>例えば、tensorflow 1.15 を使用するような設定が書かれていた場合、2.1.0に変更しろと言ってくる。<br />\nでも、変更したら動かなくなるし…</p>\n\n<h1 id=\"対処方法\">対処方法</h1>\n\n<p>こんな場合は しかたないので、アラート無視するよう言い訳する。<br />\nやり方:<a href=\"https://blog.tmd45.jp/entry/2019/11/26/162157\">GitHub Security Alert の Dismiss 言い訳</a></p>\n\n<p>でもって、自動で作成されたpullリクエストをcloseすると勝手に作成されたブランチも消えるらしい。<br />\nやり方: <a href=\"https://help.github.com/ja/github/collaborating-with-issues-and-pull-requests/closing-a-pull-request\">プルリクエストをクローズする</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのWindows環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのWindows環境での実行</h1>\n      <p>github pagesをWindows環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行できるようにした(<a href=\"/memoBlog/2019/07/17/githubpages.html\">参照</a>)が、\nわざわざUbuntu立ち上げるのが面倒になってきたので、Windows上で実行できるようにしてみた。</p>\n\n<h1 id=\"何はともあれrubyのインストール\">何はともあれRubyのインストール</h1>\n<p>Windows版Rubyをインストールしないとはじまらないので、\n<a href=\"https://www.ruby-lang.org/ja/\">Rubyの総本山</a> から(RubyInstaller のダウンロード](https://rubyinstaller.org/downloads/)\nへ行ってダウンロード。<br />\nWITH DEVKIT を選んでおく方が良いらしい。<br />\nバージョンは最新で良いでしょう(私は Ruby+Devkit 2.6.3-1 (x64) を選びました)。</p>\n\n<p>ダウンロードしたらなんとなーくインストーラ実行して案内にしたがってなんとな~く進んでちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\ngccも要るのかな?Rubyインストール時にMSYS64環境がインストールされるみたいなので、大丈夫かな?<br />\nちなみに、うちの環境はmingw-w64が入ってる。</p>\n</blockquote>\n\n<p>とりあえずbundlerはグローバルに入れとく。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem install bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。<br />\n一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをローカルにインストールする。<br />\nUbuntuみたいにrdenv環境じゃないので、グローバル環境はなるべく汚染したくないので、<code class=\"language-plaintext highlighter-rouge\">--path</code>指定してローカルにインストールする。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div></div>\n\n<p>あるいは、<code class=\"language-plaintext highlighter-rouge\">install.cmd</code>に登録してあるので、そっちを実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRubyのバージョンを変更したり、ディレクトリを移動した場合はgemsディレクトリを削除してから</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle install --path gems\n</code></pre></div>  </div>\n  <p>を実行する</p>\n</blockquote>\n\n<p>windows対応にあたって、リポジトリの _config.yml と .gitignore は対処済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>サーバ起動</p>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\\server.cmd\n</code></pre></div></div>\n\n<p>もちろん、エクスプローラなどから <code class=\"language-plaintext highlighter-rouge\">server.cmd</code> をダブルクリックして実行しても可。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこのときのキモ、jekyll実行前に以下を実行してRubyのエンコードをUTF-8に設定している。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>set RUBYOPT=--encoding=UTF-8`  \n</code></pre></div>  </div>\n  <p>これがないとエンコードエラーが発生する。<br />\n環境変数で設定しておけば逐一設定しなくても良いが、どうせcmdファイル書いてあるので、ついでに設定している。</p>\n</blockquote>\n\n<p>firewallが警告を表示するので、許可してちょ。<br />\nまごまごしてるとjekyllがエラー終了しちゃうけど、その後でも許可してしまえば次回からは大丈夫。</p>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>以降は<a href=\"/memoBlog/2019/07/17/githubpages.html\">こっち</a>を見てちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>github pagesのローカル環境での実行</title>\n  </head>\n  <body>\n    <header>\n      <h1>github pagesのローカル環境での実行</h1>\n      <p>github pagesをローカル環境で実行する手順のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>github pagesの動作を確認するため、ローカル環境で実行することができる。</p>\n\n<p>以下の手順はUbuntu 16.04で動作確認した。他のバージョンでは、特にインストールの準備に微妙な違いがあるかもしれない。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n\n<p>apt または rbenvでrubyをインストールしておく。</p>\n\n<p>aptの場合は以下(nativeなライブラリを使うので-devパッケージをインストール) 。<br />\nrbenvの場合は<a href=\"/memoBlog/2019/07/07/rbenv.html\">rbenvのインストール</a>参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ruby-dev\n</code></pre></div></div>\n\n<p>bundlerをインストールする。bundlerはNode.jsでいうところのnpmのうち、package.jsonでローカルインストールしたモジュールを管理する部分に相当するもの(かな?)。<br />\naptでrubyをインストールした場合はrootでインストール必要があるので、<code class=\"language-plaintext highlighter-rouge\">sudo</code>を付けて実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem <span class=\"nb\">install </span>bundler\n</code></pre></div></div>\n\n<h2 id=\"準備\">準備</h2>\n\n<p>このページの一番下の中央にある、「 maintained by ippei8jp/memoBlog」のリンクからリポジトリをクローンする。一から環境を整えるのは面倒なので、今ある環境をコピって変更するのが簡単。</p>\n\n<p>必要なモジュールをインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span>\n</code></pre></div></div>\n\n<p>モジュールをローカルにインストールすることもできる。<br />\nその場合は以下で。<br />\n–pathオプションのパラメータはお好みで変更してちょ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle <span class=\"nb\">install</span> <span class=\"nt\">--path</span> gems\n</code></pre></div></div>\n\n<p>このとき、<code class=\"language-plaintext highlighter-rouge\">_config.yml</code>の以下の部分にモジュールのインストール先(上の例では<code class=\"language-plaintext highlighter-rouge\">gems</code>)を追加しておく(追加しないとjekyll実行時にエラーになる)。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<div style=\"text-align: center;\">↓</div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  _config.yml\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nexclude: [gems, server.sh, Gemfile, Gemfile.lock]\n・・・\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n\n<h2 id=\"サーバ起動\">サーバ起動</h2>\n\n<p>とりあえずそのままサーバを起動してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./server.sh\n</code></pre></div></div>\n\n<h2 id=\"ブラウザ接続\">ブラウザ接続</h2>\n\n<p>ブラウザ(firefoxとchromeで動作確認した。IEでは動かない。Edgeはよーわからん)を起動し、サーバを起動しているマシンのport 4000に接続。このとき、ブラウザはサーバと同じマシンである必要はない。</p>\n\n<h2 id=\"サーバの停止\">サーバの停止</h2>\n\n<p>CTRL+cで停止。</p>\n\n<h2 id=\"サーバの-listen-port-の変更\">サーバの listen port の変更</h2>\n\n<p>必要ならサーバの listen port を変更できる。<br />\nserver.sh 内のコマンドの <code class=\"language-plaintext highlighter-rouge\">--port</code> オプションを変更すればOK.</p>\n\n<h1 id=\"ディレクトリ構成\">ディレクトリ構成</h1>\n\n<p>ディレクトリ構成は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── _config.yml                             jekyllの設定ファイル\n├── Gemfile                                 bundlerの管理ファイル\n├── _layouts                                ページレイアウト用HTMLファイル置き場\n│   ├── default.html                           デフォルト使用\n│   ├── toppage.html                           トップページ用\n│   └── debug.html                             デバッグページ用\n│                                                 どのレイアウトを使うかは各MarkdownファイルのFront-matterで指定する\n├── _includes                               共通で使用するレイアウトはここに置いておく\n│   └── footer.html\n├── _posts                                   投稿記事置き場\n│   ├── 2019-06-22-asyncawait.md\n│   ├── ・・・・\n│   └── YYYY-MM-DD-title.md                     ブログの投稿記事  ファイル名は年-月-日-タイトル とする。\n├── _sass                                    sassのインクルードファイルを置いておく\n│   └── _my_theme.scss                          大本のテーマ設定用sassファイル\n├── assets\n│   ├── css\n│   │   ├── jquery.floatingscroll.css      jQuery の floatingscroll プラグインのCSSファイル\n│   │   └── style.scss                     このページのメインのcssになるsassファイル\n│   └── js\n│       ├── jquery.floatingscroll.min.js    jQuery の floatingscroll プラグインのスクリプトファイル\n│       └── main.js                         各ページで実行するjavascriptファイル\n├── index.md                                 トップページ\n├── misc                                     以下にその他のページデータを置く\n│   ├── debug.md\n│   └── sample.md\n├── favicon.ico                              favicon画像\n├── compile.sh                               サイト構築のみ行うスクリプト\n├── server.sh                                サーバ起動用スクリプト(サイト構築も同時に行う)\n└── _site                                    以下にサイト構築データが生成される\n</code></pre></div></div>\n\n<h1 id=\"投稿記事のファイル名\">投稿記事のファイル名</h1>\n\n<p>投稿記事のファイル名は<code class=\"language-plaintext highlighter-rouge\">YYYY-MM-DD-title.拡張子</code>とする。<br />\nそれ以外のファイル名を付けると無視される。</p>\n\n<p>日付、タイトルは後述のFrontMatterに設定があればそちらが優先される。</p>\n\n<h1 id=\"front-matterの構成\">Front Matterの構成</h1>\n\n<p>Front Matterの主な項目は以下の通り。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>---\ntitle: XXXX                タイトル  指定無ければファイル名のタイトル部分が使用される\ndate: 2019-07-07           日付 指定無ければファイル名の日付部分が使用される\ntags: [\"YYY\",\"ZZZ\"]        タグを指定  このタグでトップページでカテゴリを選択できる 大文字/小文字は区別される\nlayout: toppage            使用するレイアウト 指定無ければdefaultが使用される\nexcerpt: xxxxxx            抜粋  トップページのタイトルの下に表示される\n---\n</code></pre></div></div>\n\n<h1 id=\"あとはお好きに変更してちょ\">あとはお好きに変更してちょ</h1>\n\n<p>自分のリポジトリにpushして、そのリポジトリの設定でgithub pagesを有効にすればいっちょ上がり。</p>\n\n<p>ちなみに、ファイルが一つもないリポジトリではgithub pagesを有効にできないので、ダミーでもいいからファイルをpushしてから設定すること。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "samba": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git + samba環境</title>\n  </head>\n  <body>\n    <header>\n      <h1>git + samba環境</h1>\n      <p>gitのローカルリポジトリをsamba環境で使用する際の注意事項</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>gitのローカルリポジトリをsamba経由で見ると、ファイルのAttributeの実行属性が変更されたと誤検出してしまうことがある。\nそんなときは、以下のコマンドでファイルのAttributeを無視するように設定すれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--unset</span> core.filemode\ngit config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>サーバ側は以下を一回だけ実行しておけばサーバ側でのAttributeの管理は有効になる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<p>意図的に実行属性を設定したい場合などは、サーバ側で<code class=\"language-plaintext highlighter-rouge\">git add</code>する。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "git": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git の差分比較ツールにWinMergeを使用する</title>\n  </head>\n  <body>\n    <header>\n      <h1>git の差分比較ツールにWinMergeを使用する</h1>\n      <p>git の差分比較ツールに WinMerge を使用する方法</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows上のgit-の差分比較ツールに-winmerge-を使用する方法\">Windows上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows限定だが、git の差分比較ツールに WinMerge を使用する方法のメモ<br />\n参考: <a href=\"https://qiita.com/kobake@github/items/fb317b4fdacad718a4b2?fbclid=IwAR1eO6ENMKDeeY3PmGJWrKLf_n1rgC8NVPBF60xKMiG02yAFgCFS6ceC7IE\">git の差分比較・マージを WinMerge で行う</a><br />\n↑参考というよりパクリだが(^^ゞ</p>\n\n<p>git の差分比較の <code class=\"language-plaintext highlighter-rouge\">git diff</code> で見ると見難いので、WinmMergeを使えるようにしてみた。<br />\n普段はVS Code 使ってるけど…</p>\n\n<p>手順は、 <code class=\"language-plaintext highlighter-rouge\">C:\\Users\\〇〇\\.gitconfig</code> に以下を追記するだけ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n[difftool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -f \\\"*.*\\\" -e -u -r \\\"$LOCAL\\\" \\\"$REMOTE\\\"\n[merge]\n    tool = WinMerge\n[mergetool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -e -u \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$MERGED\\\"\n[alias]\n    windiff = difftool -y -d -t WinMerge\n    winmerge = mergetool -y -t WinMerge\n</code></pre></div></div>\n\n<p>差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力すれば良い。</p>\n\n<p>差分はファイル書き換えても自動的にアップデートされなので、都度<code class=\"language-plaintext highlighter-rouge\">git windiff</code> する必要がある。<br />\n(あくまでスナップショットでの比較を表示してるだけ)</p>\n\n<p>比較対象の指定とか、マージとかもできるみたいだけど、使ってないので、詳しくは↑の参考先を見てね。(^^ゞ</p>\n\n<h1 id=\"wsl上のgit-の差分比較ツールに-winmerge-を使用する方法\">WSL上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows上の場合とほぼ同じ。<code class=\"language-plaintext highlighter-rouge\">~/.gitconfig</code>に以下を追加しておき、差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力する。<br />\nマージは使わないので、diffだけ設定。<br />\n(上の方法をwslpathでLinux上のpath→Windows上のpath 変換してるだけ、かな?)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n\n[difftool]\n    prompt = false\n\n[difftool \"WinMerge\"]\n    cmd = '/mnt/c/Program Files/WinMerge/WinMergeU.exe' -e -r -u -wl -dl Local -wr -dr Remote \\\"`wslpath -wa $LOCAL`\\\" \\\"`wslpath -wa $REMOTE`\\\"\n    trustExitCode = false\n\n[alias]\n    windiff = difftool -y -d --no-symlinks -t WinMerge\n</code></pre></div></div>\n<p>参考:<a href=\"https://qiita.com/forest1/items/334b5d756b5696c63331\">WSL(Ubuntu 18.04)環境のgitでWinMergeを使う方法</a></p>\n\n<p>参考先ではUbuntu18.04となっているが、20.04でも問題なし。<br />\nまた、<code class=\"language-plaintext highlighter-rouge\">/mnt/c/Users/username</code>以下で作業と書いてあるが、どこで作業しても大丈夫。テンポラリパスの変更も不要。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git + samba環境</title>\n  </head>\n  <body>\n    <header>\n      <h1>git + samba環境</h1>\n      <p>gitのローカルリポジトリをsamba環境で使用する際の注意事項</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>gitのローカルリポジトリをsamba経由で見ると、ファイルのAttributeの実行属性が変更されたと誤検出してしまうことがある。\nそんなときは、以下のコマンドでファイルのAttributeを無視するように設定すれば良い。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--unset</span> core.filemode\ngit config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>サーバ側は以下を一回だけ実行しておけばサーバ側でのAttributeの管理は有効になる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git config <span class=\"nt\">--global</span> core.filemode <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<p>意図的に実行属性を設定したい場合などは、サーバ側で<code class=\"language-plaintext highlighter-rouge\">git add</code>する。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "BME280": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(RaspberryPi編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(RaspberryPi編)</h1>\n      <p>過去のブログ(RaspberryPi編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"センサ接続gpio\">センサ接続/GPIO</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4f2290b79f3005f839afe798c424fadd\">BOSCH 9軸センサ bmx055 ドライバ(Node.js用) </a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/310580fc726f8b2315d2a81486cbe551\">RaspberryPi向けBOSCH 温度/湿度/気圧センサ(BME280)、9軸センサ(加速度/ジャイロ/地磁気)(BMX055)動作確認プログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/dc6f4c0987e462ca94f003b8d20ea456\">RaspberryPi向けGPIO操作テストプログラム</a></li>\n</ol>\n\n<h1 id=\"webサーバ\">WEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/e37a1d11ac25cf7e421f4d6c32d9a03c\">RaspberryPi向けWEBサーバ&センサテストプログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/18ee6da1c77671949e881eb45dda6edf\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/b23849cf9b82b83fe0c2df22836b6c27\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ/ついでに3D姿勢計算もブラウザでやるっちゃ</a></li>\n</ol>\n\n<h1 id=\"もう一つのwebサーバ\">もう一つのWEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/bcaa47ce1b04bd6b8285e553d6fb9f4f\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/11cc216ffde610e26a5b8cd4ee5b599b\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js/webサーバにExpressを使ってサッパリと</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/8179edb10867faf98e233a52965a9e53\">Raspbianのシリアルコンソールでloginするとイケてないのを改善する</a></li>\n</ol>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "BMX055": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(RaspberryPi編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(RaspberryPi編)</h1>\n      <p>過去のブログ(RaspberryPi編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"センサ接続gpio\">センサ接続/GPIO</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4f2290b79f3005f839afe798c424fadd\">BOSCH 9軸センサ bmx055 ドライバ(Node.js用) </a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/310580fc726f8b2315d2a81486cbe551\">RaspberryPi向けBOSCH 温度/湿度/気圧センサ(BME280)、9軸センサ(加速度/ジャイロ/地磁気)(BMX055)動作確認プログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/dc6f4c0987e462ca94f003b8d20ea456\">RaspberryPi向けGPIO操作テストプログラム</a></li>\n</ol>\n\n<h1 id=\"webサーバ\">WEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/e37a1d11ac25cf7e421f4d6c32d9a03c\">RaspberryPi向けWEBサーバ&センサテストプログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/18ee6da1c77671949e881eb45dda6edf\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/b23849cf9b82b83fe0c2df22836b6c27\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ/ついでに3D姿勢計算もブラウザでやるっちゃ</a></li>\n</ol>\n\n<h1 id=\"もう一つのwebサーバ\">もう一つのWEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/bcaa47ce1b04bd6b8285e553d6fb9f4f\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/11cc216ffde610e26a5b8cd4ee5b599b\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js/webサーバにExpressを使ってサッパリと</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/8179edb10867faf98e233a52965a9e53\">Raspbianのシリアルコンソールでloginするとイケてないのを改善する</a></li>\n</ol>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "I2C": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(RaspberryPi編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(RaspberryPi編)</h1>\n      <p>過去のブログ(RaspberryPi編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"センサ接続gpio\">センサ接続/GPIO</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4f2290b79f3005f839afe798c424fadd\">BOSCH 9軸センサ bmx055 ドライバ(Node.js用) </a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/310580fc726f8b2315d2a81486cbe551\">RaspberryPi向けBOSCH 温度/湿度/気圧センサ(BME280)、9軸センサ(加速度/ジャイロ/地磁気)(BMX055)動作確認プログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/dc6f4c0987e462ca94f003b8d20ea456\">RaspberryPi向けGPIO操作テストプログラム</a></li>\n</ol>\n\n<h1 id=\"webサーバ\">WEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/e37a1d11ac25cf7e421f4d6c32d9a03c\">RaspberryPi向けWEBサーバ&センサテストプログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/18ee6da1c77671949e881eb45dda6edf\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/b23849cf9b82b83fe0c2df22836b6c27\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ/ついでに3D姿勢計算もブラウザでやるっちゃ</a></li>\n</ol>\n\n<h1 id=\"もう一つのwebサーバ\">もう一つのWEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/bcaa47ce1b04bd6b8285e553d6fb9f4f\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/11cc216ffde610e26a5b8cd4ee5b599b\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js/webサーバにExpressを使ってサッパリと</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/8179edb10867faf98e233a52965a9e53\">Raspbianのシリアルコンソールでloginするとイケてないのを改善する</a></li>\n</ol>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "GPIO": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi で python で PWM</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi で python で PWM</h1>\n      <p>Raspberry Pi 上で python で PWMの制御を行うブログラムの雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Piでロボットアームを制御するのに、PWMのテストを行ったときのプログラムソースを貼っておく。<br />\n使ったロボットアーム: <a href=\"https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1\" target=\"_blank\">https://www.amazon.co.jp/gp/product/B00YTLTIJ0/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1</a></p>\n\n<p>ソフトウェアPWMだと他の処理の負荷によってジッタが発生し、ガタガタいうのでこの使い方はあまり実用的ではない。<br />\nハードウェアPWMを使う(pigpio か wiringpi が必要)、PWM制御を担うMCUを用意してコマンド通信(TCP/IPやBluetoothなど経由)で制御するのが現実的かも。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>PRi.GPIOを使うので、インストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>RPi.GPIO\n</code></pre></div></div>\n\n<p>プログラムの設定にあわせてGPIOとサーボモータを接続しておく(または接続に合わせてプログラム修正)。<br />\nスイッチで調整できるようにしてあるけど、キーボードから調整できるのでスイッチの接続は必須ではない。</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/0e8eeedb37d59c85b6ae6085da2a2cb4.js\"></script>\n</dev>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">GPIO.add_event_detect()</code>には<code class=\"language-plaintext highlighter-rouge\">bouncetime=«チャタリング除去時間(msec)»</code>を追加しておくのが良いかも。<br />\n参考: <a href=\"https://tomosoft.jp/design/?p=8685\" target=\"_blank\">GPIOエッジ検出コールバック関数 | TomoSoft</a></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n公式マニュアルは存在しないらしい。<br />\n唯一以下のページがそれっぽい情報を掲載している。<br />\n<a href=\"https://sourceforge.net/p/raspberry-gpio-python/wiki/Examples/\" target=\"_blank\">raspberry-gpio-python / Wiki / Examples</a><br />\nあとはソース読むしかないんだけど、python - C インタフェースを理解してないと苦しい…<br />\nソース全体を<code class=\"language-plaintext highlighter-rouge\">python function</code>で検索すると出てくるけど全部じゃない…<br />\nソースはここ: <a href=\"https://pypi.org/project/RPi.GPIO/#files\" target=\"_blank\">RPi.GPIO · PyPI</a></p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>プログラム実行して、スイッチかキーボードで出力値変えてみる。<br />\n設定値の範囲は個体差があるので、適当に変更必要。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(RaspberryPi編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(RaspberryPi編)</h1>\n      <p>過去のブログ(RaspberryPi編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"センサ接続gpio\">センサ接続/GPIO</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4f2290b79f3005f839afe798c424fadd\">BOSCH 9軸センサ bmx055 ドライバ(Node.js用) </a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/310580fc726f8b2315d2a81486cbe551\">RaspberryPi向けBOSCH 温度/湿度/気圧センサ(BME280)、9軸センサ(加速度/ジャイロ/地磁気)(BMX055)動作確認プログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/dc6f4c0987e462ca94f003b8d20ea456\">RaspberryPi向けGPIO操作テストプログラム</a></li>\n</ol>\n\n<h1 id=\"webサーバ\">WEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/e37a1d11ac25cf7e421f4d6c32d9a03c\">RaspberryPi向けWEBサーバ&センサテストプログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/18ee6da1c77671949e881eb45dda6edf\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/b23849cf9b82b83fe0c2df22836b6c27\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ/ついでに3D姿勢計算もブラウザでやるっちゃ</a></li>\n</ol>\n\n<h1 id=\"もう一つのwebサーバ\">もう一つのWEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/bcaa47ce1b04bd6b8285e553d6fb9f4f\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/11cc216ffde610e26a5b8cd4ee5b599b\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js/webサーバにExpressを使ってサッパリと</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/8179edb10867faf98e233a52965a9e53\">Raspbianのシリアルコンソールでloginするとイケてないのを改善する</a></li>\n</ol>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "3D": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(RaspberryPi編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(RaspberryPi編)</h1>\n      <p>過去のブログ(RaspberryPi編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"センサ接続gpio\">センサ接続/GPIO</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4f2290b79f3005f839afe798c424fadd\">BOSCH 9軸センサ bmx055 ドライバ(Node.js用) </a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/310580fc726f8b2315d2a81486cbe551\">RaspberryPi向けBOSCH 温度/湿度/気圧センサ(BME280)、9軸センサ(加速度/ジャイロ/地磁気)(BMX055)動作確認プログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/dc6f4c0987e462ca94f003b8d20ea456\">RaspberryPi向けGPIO操作テストプログラム</a></li>\n</ol>\n\n<h1 id=\"webサーバ\">WEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/e37a1d11ac25cf7e421f4d6c32d9a03c\">RaspberryPi向けWEBサーバ&センサテストプログラム</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/18ee6da1c77671949e881eb45dda6edf\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/b23849cf9b82b83fe0c2df22836b6c27\">RaspberryPi向けWEBサーバ&センサテストプログラム/3D表示もやるぜよ/ついでに3D姿勢計算もブラウザでやるっちゃ</a></li>\n</ol>\n\n<h1 id=\"もう一つのwebサーバ\">もう一つのWEBサーバ</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/bcaa47ce1b04bd6b8285e553d6fb9f4f\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/11cc216ffde610e26a5b8cd4ee5b599b\">RaspberryPi向けWEBサーバ&センサテストプログラム with Vue.js/webサーバにExpressを使ってサッパリと</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/8179edb10867faf98e233a52965a9e53\">Raspbianのシリアルコンソールでloginするとイケてないのを改善する</a></li>\n</ol>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "VSCode": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico Wでmicropython with Visual Studio Code</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico Wでmicropython with Visual Studio Code</h1>\n      <p>Raspberry Pi Pico W でmicropython の開発にVisual Studio Codeを使用する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico Wでmicropython を使用する際の開発環境(IDE)に 公式では Thonny が推奨されていますが、\nVisual Studio Codeを使用することもできます。<br />\nこのとき、拡張機能 「MicroPico」(旧称Pico-W-Go) を使用します。<br />\nここでは先人の成果を<del>パクり</del> 参照しつつ、なんとなく手順を書いてみることにします。</p>\n\n<h1 id=\"環境構築\">環境構築</h1>\n\n<h2 id=\"pc側の準備\">PC側の準備</h2>\n<p>セットアップ手順は以下が分かりやすい。<br />\n<a href=\"https://flatisle.com/raspberrypi/2289/\" target=\"_blank\">Pico W で遊ぼう(環境構築)</a><br />\nただし、モジュール名が「Pico-W-Go」から「MicroPico」に変更されているので、読み替え必要。</p>\n\n<p>PC側はVisual Studio Code がインストールされていれば 拡張機能で「MicroPico」を検索してインストールするだけ。</p>\n\n<h2 id=\"本体側の準備\">本体側の準備</h2>\n<p>本体側はファームウェアの書き換えを行う。<br />\nファームウェアの最新版は\n<a href=\"https://www.raspberrypi.com/documentation/microcontrollers/micropython.html\" target=\"_blank\">Raspberry Pi Documentation > MicroPython</a>\nからダウンロードできます。<br />\nまた、<a href=\"https://micropython.org/download/RPI_PICO_W/\" target=\"_blank\">MicroPython > DOWNLOAD > Pico W</a>\nには、Nightly buildsのバイナリもあったりします。</p>\n\n<h2 id=\"動作確認\">動作確認</h2>\n<p>Raspberry pi Pico をPCに接続しておいて、Visual Studio Code を起動。</p>\n\n<ul>\n  <li>メニューの「ターミナル」→「新しいターミナル」でターミナルウィンドウを開く(デフォルト状態だとPowershellが実行される)。</li>\n  <li>ターミナルウィンドウの右上の「+」ボタン(新しいターミナル)のドロップダウンリストを開いて\n「Pico(W) vREPL」を選択してvREPLに接続する。<br />\n(+をクリックするとPowershellが新しく開かれるので右のvっぽい記号をクリックする)</li>\n  <li>以下のような表示が出る。<br />\n(バージョン番号とかはファームウェアによって異なる)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>MicroPython v1.20.0-198-g0eacdeb1c on 2023-06-13; Raspberry Pi Pico W with RP2040\nType \"help()\" for more information or .cls/.clear to clear the terminal.\n\n>>> \n</code></pre></div></div>\n\n<p>ここで色々コマンドを入力すれば実行できる</p>\n\n<h1 id=\"いつでもwifiにつなげるように準備\">いつでもwifiにつなげるように準備</h1>\n\n<p>適当なところにフォルダを作成し(以下の例では「test」)、その下にlibフォルダを作り、\nその下にmy_wifi.py として以下のファイルを作成しておく。<br />\n1行目~2行目は自分の環境に合わせて変更しておくこと。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    test\n     +-- lib\n          +-- my_wifi.py\n          \n</code></pre></div></div>\n\n<!-- ファイル名を付けたいときはこれを指定-->\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  my_wifi.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SSID_NAME</span> <span class=\"o\">=</span> <span class=\"s\">\"SSID名\"</span>\n<span class=\"n\">SSID_PASS</span> <span class=\"o\">=</span> <span class=\"s\">\"SSIDパスワード\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">utime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">network</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n<span class=\"c1\"># ==== connecti to wifi access point ============================================\n</span><span class=\"k\">def</span> <span class=\"nf\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">,</span> <span class=\"n\">timeout</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">):</span>\n    <span class=\"n\">wifi</span><span class=\"o\">=</span> <span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">WLAN</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">STA_IF</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'already Connected.    connect skip'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">active</span><span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">)</span>\n        <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"ow\">and</span> <span class=\"n\">timeout</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'.'</span><span class=\"p\">,</span> <span class=\"n\">end</span><span class=\"o\">=</span><span class=\"s\">''</span><span class=\"p\">)</span>\n            <span class=\"n\">utime</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">timeout</span> <span class=\"o\">-=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">():</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">Connected'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Connection failed!'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">False</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">disconnect</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">disconnect</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"n\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">SSID_NAME</span><span class=\"p\">,</span> <span class=\"n\">SSID_PASS</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">ifconfig</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n<p>Visual Studio Code のエクスプローラウィンドウで「フォルダを開く」ボタンをクリック\n(またはメニューの「ファイル」→「フォルダを開く」を選択)し、\n上で作成したフォルダ(例ではtest)を開きます。</p>\n\n<p>コマンドパレットで「MicroPico: Upload project to Pico」を選択します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n現在書き込まれているファイルをすべて消去するには<br />\nコマンドパレットで「MicroPico: Delete all files from board」を選択します。</p>\n\n</blockquote>\n\n<p>実際に書き込まれたかはターミナルウィンドウで以下のように実行することで確認できます。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">>>></span> <span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'lib'</span><span class=\"p\">]</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/lib'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'my_wifi.py'</span><span class=\"p\">]</span>\n</code></pre></div></div>\n<p>または後述の仮想ファイルシステムを使用しても確認できます。</p>\n\n<p>でもって、使用するプログラムで<code class=\"language-plaintext highlighter-rouge\">import my_wifi</code> とやれば接続できます。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">my_wifi.isconnected()</code> で接続中かが分かります。\n<code class=\"language-plaintext highlighter-rouge\">my_wifi.disconnect()</code> でAPから切断できます。</p>\n\n<h1 id=\"仮想ファイルシステムを使用する\">仮想ファイルシステムを使用する</h1>\n<p>仮想ファイルシステムを使用すると、現在PaspberryPi Pico(W)のストレージに書き込まれているファイルを\n直接確認/操作することができます。</p>\n\n<ul>\n  <li>コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n  <li>エクスプローラウィンドウに「Pico (W) Remote Workspace」ができ、その下にディレクトリ/ファイルが表示される</li>\n</ul>\n\n<p>ここのファイルを開くとPaspberryPi Pico(W)のストレージにあるファイルを直接参照できます。<br />\nまた、内容を変更して保存すると PaspberryPi Pico(W)のストレージに直接格納されます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPC上のファイルとPaspberryPi Pico(W)のストレージ上のファイルをあちこち弄くると\nどちらをどう書き換えたか分からなくなるので、できるだけPC上のファイルを書き換えて「Upload project to Pico」で\nPaspberryPi Pico(W)のストレージを同期するのが良いと思います。</p>\n</blockquote>\n\n<p>mipコマンドでダウンロードしたモジュールや、プログラムでPaspberryPi Pico(W)のストレージ上に作成したファイルをPCのコピーするには、</p>\n<ul>\n  <li>エクスプローラウィンドウで仮想ファイルシステム上のコピーしたいフォルダまたはファイルを選択</li>\n  <li>CTRLキーを押しながらコピーしたいPC上のフォルダの位置にドラッグ&ドロップ\n    <ul>\n      <li>CTRLキーを押さないでドラッグ&ドロップした場合は移動になるので、「移動しますか?」と聞かれる。移動するなら「移動」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<p>仮想ファイルシステムを消すには、</p>\n<ul>\n  <li>再度コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n</ul>\n\n<p>で、エクスプローラウィンドウから「Pico (W) Remote Workspace」が消えます。<br />\n(エクスプローラウィンドウの表示が消えるだけで、PaspberryPi Pico(W)のストレージから消えるわけではありません)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</h1>\n      <p>ローカル(Windows)のVSCodeからリモートホスト(ubuntu)上のDockerコンテナ内のプログラムをデバッグする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからUbuntu上のDockerコンテナに接続してデバッグする方法。</p>\n\n<p>UbuntuへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>\nsudo なしで Docker動かせるようにしとく必要あり</p>\n\n<h1 id=\"リモートホストへの接続\">リモートホストへの接続</h1>\n<p>UbuntuへのSSH接続の準備については<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">こちら</a></p>\n\n<h2 id=\"手順\">手順</h2>\n<ul>\n  <li>WindowsマシンでVScode 起動する</li>\n  <li>拡張機能「Remote Development」をインストールしておく。</li>\n  <li>左下にある「><」ボタンをクリック</li>\n  <li>上にメニューが出るので、「Connect to host…」 または「Connect Current Window to Host…」を選択</li>\n  <li>続いて「Select configured SSH host~」で接続するホストを選択。\n    <ul>\n      <li>新規接続の場合は「Add New SSH Host…」を選択</li>\n      <li>「ssh «user»@«IPアドレス or マシン名»」</li>\n      <li>設定を保存するファイルを選択。特に理由がなければ c:\\Users\\«ユーザ».config でいいかな。</li>\n      <li>右下に「Host added!」ウィンドウが出るので「Connect」をクリック</li>\n      <li>初めて接続するホストの場合、上にSelect the platform of remote host “~” と聞かれるのでOS種別を選択</li>\n      <li>「あんた«OS»を選らんだでー。~に保存したから変えたかったら ここ変更しぃや~」みたいなことを言ってるウィンドウが出るので「Don’t Show Again」をクリック</li>\n    </ul>\n  </li>\n  <li>接続された。右下の「><」ボタンが「>< SSH:«マシン名»」に変わっている。</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n一度接続すればリモートエクスプローラ(SSH TARGETS)に表示されるのでそこから接続しても良い。</p>\n</blockquote>\n\n<p>リモートホスト上のプログラムをデバッグしたい場合はここでフォルダを開いてごちょごちょやればよい。</p>\n\n<h1 id=\"dockerコンテナへの接続\">Dockerコンテナへの接続</h1>\n<h2 id=\"準備\">準備</h2>\n<p>WindowsマシンにDocker desktop for windows が必要になるので、インストールしておく。<br />\nWindowsへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\">こちら</a><br />\nCLIだけでよさそうなんだけど、CLIだけってのがどこかにあるのか分からんかったのでとりあえず全部入れた。<br />\nDocker Desktopは動いてなくて良いので、Exitして可。<br />\n普段から使わないならDocker Dashboardの設定のGeneralから「Start Docker Desktop when you log in」のチェックを はずしておけばOK。</p>\n\n<h2 id=\"dockerexeで疎通確認\">docker.exeで疎通確認</h2>\n<p>コマンドプロンプト等で以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">set </span><span class=\"nv\">DOCKER_HOST</span><span class=\"o\">=</span>ssh://«ユーザ名»@«ホスト»\ndocker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<p>リモートホスト上のコンテナの状態が返ってくるか確認。</p>\n\n<h2 id=\"docker-hostの設定\">DOCKER HOSTの設定</h2>\n<p>VScodeの<code class=\"language-plaintext highlighter-rouge\">settings.json</code> に以下の一文を追加する。もちろん上で確認した内容で。</p>\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\">    </span><span class=\"nl\">\"docker.host\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"ssh://«ユーザ名»@«ホスト»\"</span><span class=\"err\">,</span><span class=\"w\">\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルにつなぎたいときはこの行をコメントアウト(<code class=\"language-plaintext highlighter-rouge\">//</code>をつける)すればOK。<br />\n<code class=\"language-plaintext highlighter-rouge\">setting.json</code>はJSONファイルだけど、 <code class=\"language-plaintext highlighter-rouge\">//</code>でコメントアウトできる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nVScode settings.json の開き方</p>\n  <ul>\n    <li>メニュー ファイル→ユーザ設定→ 設定</li>\n    <li>設定画面の右上のボタン「設定(JSON)を開く」をクリック</li>\n  </ul>\n\n  <p>または</p>\n  <ul>\n    <li>メニュー表示→コマンドパレット</li>\n    <li>Preference:  Open Settings(JSON) を選択</li>\n  </ul>\n</blockquote>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その1\">VScodeでリモート エクスプローラからリモートホストに接続(その1)</h2>\n<p>リモートホストに拡張機能 Docker と Docker Explorer をインストールしておき、\nDockerペインを開くとリモートホスト上のコンテナとかが見える</p>\n\n<p>ここでは既にリモートホスト上でコンテナ作成済みとする。<br />\n(イメージからコンテナ作ったりDockerfileからBuildしたりできると思うけど、今はおいとく)</p>\n\n<ul>\n  <li>接続するコンテナが起動していない場合はDockerペインで使用するコンテナを右クリック→Start でコンテナを起動</li>\n  <li>起動したら対象コンテナのアイコンが三角マークになる</li>\n  <li>同じくDockerペインで使用するコンテナを右クリック→Attach Visual Studio Code を選択</li>\n  <li>select the container to attach VS Code と聞かれるのでアタッチするコンテナを選択(コンテナ選択してAttachしたはずだけど、なぜかここで再度選択が必要)</li>\n  <li>初めて接続した場合は「Attaching to a container may execute arbitrary code」<br />\nと言われるので、変なコードが実行されないことが分かっていれば Got it をクリック</li>\n  <li>接続された。右下の「><」ボタンが「>< Conteiner «コンテナ名»」に変わっている。</li>\n</ul>\n\n<p>あとはリモート SSH や ローカルのDockerでのデバッグと同じ。</p>\n\n<h2 id=\"接続の終了\">接続の終了</h2>\n<p>接続を終了する場合は</p>\n<ul>\n  <li>メニュー表示→コマンドパレット</li>\n  <li>Remote:  Close Remote Connection を選択</li>\n</ul>\n\n<p>このとき、コンテナからだけでなく、リモートホストからも切断される。</p>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その2\">VScodeでリモート エクスプローラからリモートホストに接続(その2)</h2>\n<p>リモートエクスプローラ(Containers)で接続するコンテナを右クリックし、「Attach to Container」または「Attach in New Window」を選択<br />\n(コンテナが起動されていなければ起動して)コンテナに接続される。</p>\n\n<p>あんまりごちょごちょしなくて済むのでこっちの方がおススメかな。</p>\n\n<h1 id=\"ネットワークポート\">ネットワークポート</h1>\n<p>通常Cockerコンテナ内のネットワークポートをホストや外部コンピュータからアクセスするには、<br />\nコンテナ作成時に-p (–publish) オプションで接続を受け入れるポート番号を指定する必要があるが、<br />\nVScodeから接続している場合は、Docker内のネットワークポートにVScodeが実行されているマシンからlocalhost:«ポート番号»で接続できる。<br />\n(アクセス遅いけど、ちょっと別のポート開けて試したい なんて時には便利)</p>\n\n<p>ただし、これはDockerが動作しているホストコンピュータや他のコンピュータからはアクセスできない。<br />\nこれらからアクセスするには-pオプションを指定する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n<p><a href=\"https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0\">https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0</a><br />\n↑ここにある、「Remote-Containers: Open Folder in Container…」での手順はリモートホストに接続した状態では実行できないらしい。<br />\nどうしてもこのコンテナでデバッグしたい場合は、<br />\n一旦リモートホスト上でVSCodeを起動してコンテナを作成しておき、<br />\nその後ローカルPCからこのコンテナにアタッチするような手順をふめばデバッグできる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>VSCodeでDocker内のpythonプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>VSCodeでDocker内のpythonプログラムをデバッグする</h1>\n      <p>VSCodeでDocker内のpythonプログラムをデバッグする(Windos/Ubuntu)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからWindows上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nubuntu上のVSCodeからubuntu上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nどちらもほぼ同じ手順でデバッグできる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>VScodeに拡張機能Python、Docker、Remote Containers をインストールしておく</p>\n\n<h1 id=\"コンテナ起動\">コンテナ起動</h1>\n<p>ターミナルからコンテナ起動する<br />\nソースの編集をしやすいように、ホストのフォルダを<code class=\"language-plaintext highlighter-rouge\">/work</code>に割り当てている。<br />\nいや、VSCodeで編集すれば問題ないんだけどさ…<br />\nいつも編集は別のエディタ使ってたりするとコンテナ内のファイルいじるのが面倒なので…</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Windows\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> /m/work/zzz:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ubuntu\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> <span class=\"sb\">`</span><span class=\"nb\">realpath</span> .<span class=\"sb\">`</span>:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンテナを一度作成してあれば起動していなくても大丈夫らしい。</p>\n</blockquote>\n\n<h1 id=\"コンテナに接続\">コンテナに接続</h1>\n<p>VScodeのリモートエクスプローラにコンテナが見える</p>\n<blockquote>\n  <p>[!NOTE]\nRemote SSHやRemote WSLがインストールされている場合はリモートエクスプローラ上部のドロップダウンリストからContainersを選択</p>\n</blockquote>\n\n<p>対象のコンテナを右クリックして<code class=\"language-plaintext highlighter-rouge\">Attach to Container</code> または<code class=\"language-plaintext highlighter-rouge\">Attach in New Window</code>をクリック<br />\n<code class=\"language-plaintext highlighter-rouge\">Attaching to a container may execute arbitrary code</code><br />\nと言われるたら、変なコードが実行されないことが分かっていれば <code class=\"language-plaintext highlighter-rouge\">Got it</code> をクリック</p>\n<blockquote>\n  <p>[!NOTE]\n一度開いたフォルダはその下にショートカットが表示されているので、そこから開けば手っ取り早い。</p>\n</blockquote>\n\n<p>コンテナが開く</p>\n\n<p>コンテナ内には拡張機能が入ってないので、必要な拡張機能をインストールする</p>\n\n<h1 id=\"デバッグ\">デバッグ</h1>\n<p>エクスプローラでデバッグしたいフォルダを開いてソースを開く(VSCodeの設定によっては前回開いていたフォルダが開かれる)<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Python: Select Interpreter</code> で 使用するpythonを選択する。<br />\nこのとき、必ずしも使用するpythonのpathが表示されているとは限らないので、<br />\n(逆にコンテナ内にないホスト側のものが表示されたりする😢)<br />\n表示されていない場合は<code class=\"language-plaintext highlighter-rouge\">+ Enter Interpreter path...</code>から使用するpythonを選択する。<br />\n上記イメージの場合、<code class=\"language-plaintext highlighter-rouge\">/usr/local/bin/python3</code> なので、これを設定。</p>\n<blockquote>\n  <p>[!NOTE]\nあらかじめコンソールで which python3 して調べておく</p>\n</blockquote>\n\n<p>あとはローカルと同じようにデバッグできる。</p>\n\n<h1 id=\"コンテナとの接続終了\">コンテナとの接続終了</h1>\n\n<p>コンテナとの接続を終了するときは<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Remote: Close Remote Connection</code> で終了する。</p>\n\n<p>接続終了してもコンテナを停止しないので、別途停止処理を行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker stop py_test2\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>こういうのもある。<br />\n(参照しているのはmicrosoft純正のサンプルらしい)<br />\n普通にDocker使うのと異なるファイル<code class=\"language-plaintext highlighter-rouge\">devcontainer.json</code>を使うので、\n便利なんだか不便なんだか…<br />\nDocker拡張機能なくても動かせた気がする。<br />\n<a href=\"https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html\">https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Visual Studio Code で Jupyter Notebook</title>\n  </head>\n  <body>\n    <header>\n      <h1>Visual Studio Code で Jupyter Notebook</h1>\n      <p>Visual Studio Code で Jupyter Notebookを実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Visual Studio CodeでJupyter Notebookを実行する。</p>\n\n<p>サンプルプログラムがJupyter Notebookだったりするとブラウザで動かすのめんどいので、Visual Studio Codeで動かしてみた。<br />\n参考:このあたりかな? <a href=\"https://codeaid.jp/vscode-jupyter/\" target=\"_blank\">Visual Studio CodeでJupyter Notebookを使う方法</a></p>\n\n<p>以下では、<a href=\"https://www.koi.mashykom.com/tensorflow.html\" target=\"_blank\">SSD と YOLO を用いた物体検出</a> の「Object Detection APIを用いた物体検出」を参考に進めてみる。</p>\n\n<h1 id=\"前準備\">前準備</h1>\n<p>作業ディレクトリとツール類のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Tensorflow\n<span class=\"nb\">cd</span> /work/Tensorflow\n\n<span class=\"c\"># pyenvの仮想環境作成と切り替え</span>\npyenv virtualenv 3.7.10 tensorflow\npyenv <span class=\"nb\">local </span>tensorflow\n<span class=\"c\"># お約束</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># Protocol buffers コンパイラのインストール(Jupyter Notebookの実行には関係ない)</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n\n<span class=\"c\"># Jupyter Notebook のモジュールインストール</span>\npip <span class=\"nb\">install </span>notebook\n</code></pre></div></div>\n\n<h1 id=\"modelsリポジトリのクローン\">modelsリポジトリのクローン</h1>\n<p>実行するプログラムの準備</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git\n</code></pre></div></div>\n\n<h1 id=\"visual-studio-codeの起動\">Visual Studio Codeの起動</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models/\ncode <span class=\"nb\">.</span>\n</code></pre></div></div>\n<p><strong>*** Visual Studio Code起動 ***</strong></p>\n\n<h1 id=\"visual-studio-codeでの作業\">Visual Studio Codeでの作業</h1>\n<p>以下、Visual Studio Codeで作業する</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>拡張機能から「Jupyter」と「Python」を選択し、対象マシンにインストール</p>\n\n<h2 id=\"使用するpythonを選択その1\">使用するpythonを選択その1</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n<ul>\n  <li>Python: インタプリター選択\n    <ul>\n      <li>これはどこで有効なんだろうか?念のため設定しておこう。</li>\n    </ul>\n  </li>\n  <li>Jupyter: Select interpreter to start jupyter server\n    <ul>\n      <li>たぶん、Jupyter Notebookそのものを実行するためのPython<br />\njupyter-notebookモジュールがインストールされている必要がある</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"対象ファイルをオープン\">対象ファイルをオープン</h2>\n<p>エクスプローラから<br />\n<code class=\"language-plaintext highlighter-rouge\">research/object_detection/colab_tutorials/object_detection_tutorial.ipynb</code>\nを開く<br />\n<code class=\"language-plaintext highlighter-rouge\">a notebook could execute harmful code when opened. ~</code>\nと言われるので、<code class=\"language-plaintext highlighter-rouge\">Trust</code> をクリック</p>\n\n<h2 id=\"使用するpythonを選択その2\">使用するpythonを選択その2</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する<br />\n(ipynbファイルを開かないと選べない)</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n\n<ul>\n  <li>Jupyter: Select a Kernel\n    <ul>\n      <li>たぶん、Notebook内のpythonスクリプトを実行するためのPython<br />\nシステムコマンド(!を行頭につけて指定)として実行したり、<code class=\"language-plaintext highlighter-rouge\">%%bash</code> で指定したCode cell で実行した<br />\npython スクリプト(pipコマンドなども含む)を実行した場合もこのバージョンが使用される</li>\n      <li>ipykernelモジュールをインストールしておく必要があるが、入ってなければVSCodeからインストールできるので気にしなくても大丈夫。<br />\n(Jupyter Notebook のモジュールがインストールされていれば同時にインストールされている)</li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nその1、その2で選択するバージョンはそれぞれ異なるバージョンを設定できるが、<br />\n上でpyenvで選択したバージョンで統一しておくのが混乱しなくて良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSelect a Kernel の設定内容は以下のファイルに保存されるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.vscode-server/data/User/globalStorage/ms-toolsai.jupyter/kernelSpecPaths.json</code><br />\nこの設定はシステム(ターゲットマシン)で1つのようなので、他のプロジェクトで設定を変更した場合は再度確認しておくのが良いと思う。</p>\n</blockquote>\n\n<h2 id=\"エラーになる部分の対策\">エラーになる部分の対策</h2>\n\n<h3 id=\"その1\">その1</h3>\n<p>「Get tensorflow/models or cd to parent directory of the repository.」\nの下のCode cellの最後に以下を追加</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n<span class=\"n\">cwd</span><span class=\"o\">=</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getcwd</span><span class=\"p\">()</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research/slim\"</span><span class=\"p\">)</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research\"</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"その2\">その2</h3>\n<p>以下のcellを削除(エラーになる)<br />\n(おそらく、その1で追加している処理に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>%%bash \ncd models/research\npip install .\n</code></pre></div></div>\n\n<h3 id=\"その3\">その3</h3>\n<p>「Instance Segmentation」以下はエラーになる(RCNNのモデル形状が変更された?)ので削除しておく。<br />\n(手順の本筋に関係ないので)</p>\n\n<h2 id=\"実行\">実行</h2>\n<p>最初のCode cell(Installの下)で▶(Run)をクリック<br />\nあとは、続くcellで▶(Run)をクリックしていく。</p>\n\n<p>または、ツールバーの⏩(Run all cells)をクリックする</p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<h2 id=\"ipynbファイルをpythonファイルにエクスポートする\">ipynbファイルをpythonファイルにエクスポートする。</h2>\n\n<p>Visual Studio Codeのエクスプローラペインで対象のipynbファイルを右クリックして<br />\n<code class=\"language-plaintext highlighter-rouge\">Convert a Notebook to Python Script</code>を選択すると、変換結果が新しいファイルとしてエディタに開かれる。<br />\nこれを名前を付けて保存する。</p>\n\n<p>または、コマンドラインから以下のコマンドを実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>jupyter nbconvert «対象ファイル».ipynb <span class=\"nt\">--to</span> python\n</code></pre></div></div>\n<p>デフォルトの出力ファイル名は«対象ファイル名».py(拡張子をipynb→pyに変えたもの)になる。</p>\n\n<p>ただし、単独で動かす場合は <code class=\"language-plaintext highlighter-rouge\">get_ipython()</code> で始まる行(システムコマンドを実行する部分)はエラーになるので、コメントアウトしておくこと。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(Windows編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(Windows編)</h1>\n      <p>過去のブログ(Windows編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"リモートデバッグ\">リモートデバッグ</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4784a559cb0e78d060fe01d69a3c829d\">windowsのVisualStudioCodeでRasPiのNode.jsをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/aed3ddde84d76cca5c5be62df1120f81\">windowsのVisualStudioCodeでRasPiのPythonをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/46e92ee968b99174c1e1fa3199465877\">VisualStudioCodeのリモート開発が使えるようになったらしいので試してみる</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/c9bf43575d8fce47233bf191b21fbaad\">NW.jsによるWebアプリのデスクトップアプリ化</a></li>\n</ol>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "リモートデバッグ": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Visual Studio Code で Jupyter Notebook</title>\n  </head>\n  <body>\n    <header>\n      <h1>Visual Studio Code で Jupyter Notebook</h1>\n      <p>Visual Studio Code で Jupyter Notebookを実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Visual Studio CodeでJupyter Notebookを実行する。</p>\n\n<p>サンプルプログラムがJupyter Notebookだったりするとブラウザで動かすのめんどいので、Visual Studio Codeで動かしてみた。<br />\n参考:このあたりかな? <a href=\"https://codeaid.jp/vscode-jupyter/\" target=\"_blank\">Visual Studio CodeでJupyter Notebookを使う方法</a></p>\n\n<p>以下では、<a href=\"https://www.koi.mashykom.com/tensorflow.html\" target=\"_blank\">SSD と YOLO を用いた物体検出</a> の「Object Detection APIを用いた物体検出」を参考に進めてみる。</p>\n\n<h1 id=\"前準備\">前準備</h1>\n<p>作業ディレクトリとツール類のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Tensorflow\n<span class=\"nb\">cd</span> /work/Tensorflow\n\n<span class=\"c\"># pyenvの仮想環境作成と切り替え</span>\npyenv virtualenv 3.7.10 tensorflow\npyenv <span class=\"nb\">local </span>tensorflow\n<span class=\"c\"># お約束</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># Protocol buffers コンパイラのインストール(Jupyter Notebookの実行には関係ない)</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n\n<span class=\"c\"># Jupyter Notebook のモジュールインストール</span>\npip <span class=\"nb\">install </span>notebook\n</code></pre></div></div>\n\n<h1 id=\"modelsリポジトリのクローン\">modelsリポジトリのクローン</h1>\n<p>実行するプログラムの準備</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git\n</code></pre></div></div>\n\n<h1 id=\"visual-studio-codeの起動\">Visual Studio Codeの起動</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models/\ncode <span class=\"nb\">.</span>\n</code></pre></div></div>\n<p><strong>*** Visual Studio Code起動 ***</strong></p>\n\n<h1 id=\"visual-studio-codeでの作業\">Visual Studio Codeでの作業</h1>\n<p>以下、Visual Studio Codeで作業する</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>拡張機能から「Jupyter」と「Python」を選択し、対象マシンにインストール</p>\n\n<h2 id=\"使用するpythonを選択その1\">使用するpythonを選択その1</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n<ul>\n  <li>Python: インタプリター選択\n    <ul>\n      <li>これはどこで有効なんだろうか?念のため設定しておこう。</li>\n    </ul>\n  </li>\n  <li>Jupyter: Select interpreter to start jupyter server\n    <ul>\n      <li>たぶん、Jupyter Notebookそのものを実行するためのPython<br />\njupyter-notebookモジュールがインストールされている必要がある</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"対象ファイルをオープン\">対象ファイルをオープン</h2>\n<p>エクスプローラから<br />\n<code class=\"language-plaintext highlighter-rouge\">research/object_detection/colab_tutorials/object_detection_tutorial.ipynb</code>\nを開く<br />\n<code class=\"language-plaintext highlighter-rouge\">a notebook could execute harmful code when opened. ~</code>\nと言われるので、<code class=\"language-plaintext highlighter-rouge\">Trust</code> をクリック</p>\n\n<h2 id=\"使用するpythonを選択その2\">使用するpythonを選択その2</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する<br />\n(ipynbファイルを開かないと選べない)</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n\n<ul>\n  <li>Jupyter: Select a Kernel\n    <ul>\n      <li>たぶん、Notebook内のpythonスクリプトを実行するためのPython<br />\nシステムコマンド(!を行頭につけて指定)として実行したり、<code class=\"language-plaintext highlighter-rouge\">%%bash</code> で指定したCode cell で実行した<br />\npython スクリプト(pipコマンドなども含む)を実行した場合もこのバージョンが使用される</li>\n      <li>ipykernelモジュールをインストールしておく必要があるが、入ってなければVSCodeからインストールできるので気にしなくても大丈夫。<br />\n(Jupyter Notebook のモジュールがインストールされていれば同時にインストールされている)</li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nその1、その2で選択するバージョンはそれぞれ異なるバージョンを設定できるが、<br />\n上でpyenvで選択したバージョンで統一しておくのが混乱しなくて良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSelect a Kernel の設定内容は以下のファイルに保存されるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.vscode-server/data/User/globalStorage/ms-toolsai.jupyter/kernelSpecPaths.json</code><br />\nこの設定はシステム(ターゲットマシン)で1つのようなので、他のプロジェクトで設定を変更した場合は再度確認しておくのが良いと思う。</p>\n</blockquote>\n\n<h2 id=\"エラーになる部分の対策\">エラーになる部分の対策</h2>\n\n<h3 id=\"その1\">その1</h3>\n<p>「Get tensorflow/models or cd to parent directory of the repository.」\nの下のCode cellの最後に以下を追加</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n<span class=\"n\">cwd</span><span class=\"o\">=</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getcwd</span><span class=\"p\">()</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research/slim\"</span><span class=\"p\">)</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research\"</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"その2\">その2</h3>\n<p>以下のcellを削除(エラーになる)<br />\n(おそらく、その1で追加している処理に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>%%bash \ncd models/research\npip install .\n</code></pre></div></div>\n\n<h3 id=\"その3\">その3</h3>\n<p>「Instance Segmentation」以下はエラーになる(RCNNのモデル形状が変更された?)ので削除しておく。<br />\n(手順の本筋に関係ないので)</p>\n\n<h2 id=\"実行\">実行</h2>\n<p>最初のCode cell(Installの下)で▶(Run)をクリック<br />\nあとは、続くcellで▶(Run)をクリックしていく。</p>\n\n<p>または、ツールバーの⏩(Run all cells)をクリックする</p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<h2 id=\"ipynbファイルをpythonファイルにエクスポートする\">ipynbファイルをpythonファイルにエクスポートする。</h2>\n\n<p>Visual Studio Codeのエクスプローラペインで対象のipynbファイルを右クリックして<br />\n<code class=\"language-plaintext highlighter-rouge\">Convert a Notebook to Python Script</code>を選択すると、変換結果が新しいファイルとしてエディタに開かれる。<br />\nこれを名前を付けて保存する。</p>\n\n<p>または、コマンドラインから以下のコマンドを実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>jupyter nbconvert «対象ファイル».ipynb <span class=\"nt\">--to</span> python\n</code></pre></div></div>\n<p>デフォルトの出力ファイル名は«対象ファイル名».py(拡張子をipynb→pyに変えたもの)になる。</p>\n\n<p>ただし、単独で動かす場合は <code class=\"language-plaintext highlighter-rouge\">get_ipython()</code> で始まる行(システムコマンドを実行する部分)はエラーになるので、コメントアウトしておくこと。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>過去のブログ(Windows編)</title>\n  </head>\n  <body>\n    <header>\n      <h1>過去のブログ(Windows編)</h1>\n      <p>過去のブログ(Windows編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、gistでまとめたブログもどきへのリンク集</p>\n\n<h1 id=\"リモートデバッグ\">リモートデバッグ</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/4784a559cb0e78d060fe01d69a3c829d\">windowsのVisualStudioCodeでRasPiのNode.jsをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/aed3ddde84d76cca5c5be62df1120f81\">windowsのVisualStudioCodeでRasPiのPythonをリモートデバッグする方法</a></li>\n  <li><a href=\"https://gist.github.com/ippei8jp/46e92ee968b99174c1e1fa3199465877\">VisualStudioCodeのリモート開発が使えるようになったらしいので試してみる</a></li>\n</ol>\n\n<h1 id=\"その他\">その他</h1>\n\n<ol>\n  <li><a href=\"https://gist.github.com/ippei8jp/c9bf43575d8fce47233bf191b21fbaad\">NW.jsによるWebアプリのデスクトップアプリ化</a></li>\n</ol>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "DeepLearning": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その3)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(VAE+SAC編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_1.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a>、\n<a href=\"/memoBlog/2021/12/09/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その2)</a>\nではDonkeyCar simulatorに添付のサンプルプログラムを実行してみたが、結果がイマイチだったので別のプログラムを試してみる。<br />\n<del>パクった</del> 参考にしたのは、<a href=\"https://masato-ka.hatenablog.com/entry/2020/04/29/153505?fbclid=IwAR1sjfiN1dAGRn6vIKU9vOSnfoCCsmgvVXRV_MWaLdUr3FeIUvUAr1Ef_yo\" target=\"_blank\">Jetson Nanoで動く深層強化学習を使ったラジコン向け自動運転ソフトウェアの紹介</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim3\n<span class=\"nb\">cd</span> /work2/donkey_sim3/\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 donkey_sim3\npyenv <span class=\"nb\">local </span>donkey_sim3 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>torch\npip <span class=\"nb\">install </span>torchvision\npip <span class=\"nb\">install </span>pyyaml\npip <span class=\"nb\">install </span>stable_baselines3\npip <span class=\"nb\">install </span>gym\npip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n\n<span class=\"c\"># tensorboard も必要</span>\npip <span class=\"nb\">install </span>tensorboard\n<span class=\"c\"># たぶん要らないけど、念のため入れとく(tensorboard 実行時になんか言われるので)</span>\npip <span class=\"nb\">install </span>tensorflow\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n今回は stable-baselines3 を使用するので、 tensorflow ではなく、pytorch。<br />\nしかし、tensorboardは必要(学習ログ記録のため)。<br />\ntensorboardで可視化機能を使用する際はtensorflowが入ってないと実行時になんか言われるので\n念のためtensorflowも入れとく(たぶん入れなくても大丈夫)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n試したときのモジュール類のバージョンは以下の通り</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>opencv-python                4.5.4.60\ntorch                        1.10.0\ntorchvision                  0.11.1\nPyYAML                       6.0\nstable-baselines3            1.3.0\ngym                          0.19.0\ngym-donkeycar                1.1.1      ← Githubのtagはv21.07.24\ntensorboard                  2.7.0\ntensorflow                   2.7.0\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a> と同じ</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n<h3 id=\"プログラム拾ってくる\">プログラム拾ってくる。</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/masato-ka/airc-rl-agent.git\n<span class=\"nb\">cd </span>airc-rl-agent/\ngit checkout <span class=\"nt\">-b</span> release-v1.5.2 refs/tags/release-v1.5.2\n</code></pre></div></div>\n\n<h3 id=\"パッチをあてる\">パッチをあてる。</h3>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/config.yml b/config.yml\nindex bda2308..3bf2ad4 100644\n</span><span class=\"gd\">--- a/config.yml\n</span><span class=\"gi\">+++ b/config.yml\n</span><span class=\"p\">@@ -48,8 +48,8 @@</span> AGENT_SETTING:\n   N_COMMAND_HISTORY: 20\n   MIN_STEERING: -1.0\n   MAX_STEERING: 1.0\n<span class=\"gd\">-  MIN_THROTTLE: 0.7 # 0.4\n-  MAX_THROTTLE: 0.95 # 0.9\n</span><span class=\"gi\">+  MIN_THROTTLE: 0.3  # 0.7  # 0.4\n+  MAX_THROTTLE: 0.95 # 0.95 # 0.9\n</span>   MAX_STEERING_DIFF: 0.9 #0.35\n \n JETRACER_SETTING:\n<span class=\"gh\">diff --git a/learning_racer/commands/subcommand.py b/learning_racer/commands/subcommand.py\nindex 0cf6eac..e4474e7 100644\n</span><span class=\"gd\">--- a/learning_racer/commands/subcommand.py\n</span><span class=\"gi\">+++ b/learning_racer/commands/subcommand.py\n</span><span class=\"p\">@@ -56,6 +56,7 @@</span> def command_train(args, config):\n     model = CustomSAC(agent, args, config)\n     model.lean(callback=callback)\n     model.save(args.save)\n<span class=\"gi\">+    agent.close()\n</span> \n \n def command_demo(args, config):\n<span class=\"p\">@@ -65,4 +66,14 @@</span> def command_demo(args, config):\n     for step in range(args.time_steps):\n         if step % 100 == 0: print(\"step: \", step)\n         action, _states = model.predict(obs)\n<span class=\"gi\">+        steer = action[0]\n+        throttle = action[1]\n</span>         obs, rewards, dones, info = agent.step(action)\n<span class=\"gi\">+        steer2 = agent.action_history[-2]\n+        throttle2 = agent.action_history[-1]\n+        speed = info[\"speed\"]\n+        cte = info[\"cte\"]\n+        print(f'steer:{steer:9.5f}    steer2:{steer2:9.5f}    throttle:{throttle:9.5f}    throttle2:{throttle2:9.5f}    speed:{speed:9.5f}    cte:{cte:9.5f}')\n+        if dones :\n+            obs = agent.reset()\n+    agent.close()\n</span><span class=\"gh\">diff --git a/learning_racer/racer.py b/learning_racer/racer.py\nindex 3e67ca2..dee0905 100644\n</span><span class=\"gd\">--- a/learning_racer/racer.py\n</span><span class=\"gi\">+++ b/learning_racer/racer.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import sys\n+import os\n+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))\n+\n</span> import argparse\n from learning_racer.commands.subcommand import command_demo, command_train\n from learning_racer.config import ConfigReader\n<span class=\"p\">@@ -8,6 +12,20 @@</span> logger = getLogger(__name__)\n \n __version__ = '1.5.1'\n \n<span class=\"gi\">+track_list = [\n+    \"donkey-generated-roads-v0\",\n+    \"donkey-warehouse-v0\",\n+    \"donkey-avc-sparkfun-v0\",\n+    \"donkey-generated-track-v0\",\n+    \"donkey-mountain-track-v0\",\n+    \"donkey-roboracingleague-track-v0\",\n+    \"donkey-waveshare-v0\",\n+    \"donkey-minimonaco-track-v0\",\n+    \"donkey-warren-track-v0\",\n+    \"donkey-thunderhill-track-v0\",\n+    \"donkey-circuit-launch-track-v0\",\n+]\n+\n</span> parser = argparse.ArgumentParser(description='Learning Racer command.')\n parser.add_argument('--version', action='version', version='learning_racer version {} .'.format(__version__))\n subparser = parser.add_subparsers()\n<span class=\"p\">@@ -39,7 +57,7 @@</span> parser_train.add_argument('-host', '--sim-host', help='Define host IP of DonkeyS\n parser_train.add_argument('-port', '--sim-port', help='Define port number of DonkeySim host.',\n                           default='9091', type=int)\n parser_train.add_argument('-track', '--sim-track', help='Define track name for DonkeySim',\n<span class=\"gd\">-                          default='donkey-generated-track-v0', type=str)\n</span><span class=\"gi\">+                          default='donkey-generated-track-v0', type=str, choices=track_list)\n</span> parser_train.set_defaults(handler=command_train)\n \n # demo subcommand.\n<span class=\"p\">@@ -63,7 +81,7 @@</span> parser_demo.add_argument('-host', '--sim-host', help='Define host IP of DonkeySi\n parser_demo.add_argument('-port', '--sim-port', help='Define port number of DonkeySim host.',\n                          default='9091', type=int)\n parser_demo.add_argument('-track', '--sim-track', help='Define track name for DonkeySim',\n<span class=\"gd\">-                         default='donkey-generated-track-v0', type=str)\n</span><span class=\"gi\">+                         default='donkey-generated-track-v0', type=str, choices=track_list)\n</span> parser_demo.add_argument('-user', '--sim-user', help='Define user name for own car that showed DonkeySim',\n                          default='anonymous', type=str)\n parser_demo.add_argument('-car', '--sim-car', help='Define car model type for own car that showed DonkeySim',\n<span class=\"gh\">diff --git a/learning_racer/sac/custom_sac.py b/learning_racer/sac/custom_sac.py\nindex 734fd95..3642ca8 100644\n</span><span class=\"gd\">--- a/learning_racer/sac/custom_sac.py\n</span><span class=\"gi\">+++ b/learning_racer/sac/custom_sac.py\n</span><span class=\"p\">@@ -21,6 +21,7 @@</span> def _load_sac(agent, args, config, policy):\n                     sde_sample_freq=config.sac_sde_sample_freq()\n                     )\n     else:\n<span class=\"gi\">+        print(f\"**** load model{args.load_model} ****\")\n</span>         model = SAC.load(args.load_model, env=agent,\n                          policy_kwargs=policy,\n                          verbose=config.sac_verbose(),\n<span class=\"p\">@@ -31,7 +32,7 @@</span> def _load_sac(agent, args, config, policy):\n                          ent_coef=config.sac_ent_coef(), learning_rate=config.sac_learning_rate(),\n                          tensorboard_log=\"tblog\", gamma=config.sac_gamma(), tau=config.sac_tau(),\n                          use_sde_at_warmup=config.sac_use_sde_at_warmup(), use_sde=config.sac_use_sde(),\n<span class=\"gd\">-                         sde_sample_freq=config.sac_sample_freq(), n_episodes_rollout=1)\n</span><span class=\"gi\">+                         sde_sample_freq=config.sac_sde_sample_freq(), n_episodes_rollout=1)\n</span>     return model\n \n \n<span class=\"gh\">diff --git a/learning_racer/sac/hyperparam.py b/learning_racer/sac/hyperparam.py\nindex e58b3fa..5b4b3f0 100644\n</span><span class=\"gd\">--- a/learning_racer/sac/hyperparam.py\n</span><span class=\"gi\">+++ b/learning_racer/sac/hyperparam.py\n</span><span class=\"p\">@@ -2,7 +2,6 @@</span> import math\n \n from learning_racer.config.config import ConfigReader\n \n<span class=\"gd\">-hit_counter = 0\n</span> speed_counter = 0\n config = ConfigReader()\n \n<span class=\"p\">@@ -27,29 +26,32 @@</span> def reward_sim(self, done):\n \n \n # For gym_donkey\n<span class=\"gd\">-hit_counter = 0\n</span> speed_counter = 0\n initial = False\n \n \n def episode_over_sim(self):\n<span class=\"gd\">-    global hit_counter, speed_counter, initial\n</span><span class=\"gi\">+    global speed_counter, initial\n</span>     #    print(self.speed)\n \n     if not initial and self.speed > 3.0:\n         initial = True\n \n     if self.hit != \"none\":\n<span class=\"gd\">-        hit_counter += 1\n-        if hit_counter > 5:\n-            self.over = True\n-            hit_counter = 0\n</span><span class=\"gi\">+        self.over = True\n+        initial = False\n+    elif math.fabs(self.cte) > self.max_cte * 1.5:\n+        self.over = True\n+        initial = False\n</span>     elif self.speed < 0.03 and initial:\n         speed_counter += 1\n         if speed_counter > 10:\n             self.over = True\n             speed_counter = 0\n<span class=\"gi\">+            initial = False\n</span>     elif self.missed_checkpoint:\n         self.over = True\n<span class=\"gi\">+        initial = False\n</span>     elif self.dq:\n         self.over = True\n<span class=\"gi\">+        initial = False\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n主な変更内容は、</p>\n  <ul>\n    <li>config.yml\n      <ul>\n        <li>MIN_THROTTLE の値修正(ちょっと速すぎな感じだったので)</li>\n      </ul>\n    </li>\n    <li>learning_racer/commands/subcommand.py\n      <ul>\n        <li>simulatorのクローズ処理を追加</li>\n        <li>demo時の状態表示を追加</li>\n        <li>demo時のdonesステータスでsimulator初期化を追加</li>\n      </ul>\n    </li>\n    <li>learning_racer/racer.py\n      <ul>\n        <li>pip installせずに実行できるよう、sys.pathを修正する部分の追加</li>\n      </ul>\n    </li>\n    <li>learning_racer/sac/custom_sac.py\n      <ul>\n        <li>typo修正</li>\n      </ul>\n    </li>\n    <li>learning_racer/sac/hyperparam.py\n      <ul>\n        <li>エピソード終了判定<code class=\"language-plaintext highlighter-rouge\">episode_over_sim()</code>の変更</li>\n      </ul>\n    </li>\n  </ul>\n\n</blockquote>\n\n<h3 id=\"vaeの学習済みモデルを拾ってくる\">VAEの学習済みモデルを拾ってくる</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>learning_racer/\nwget <span class=\"s2\">\"https://drive.google.com/uc?export=download&id=19r1yuwiRGGV-BjzjoCzwX8zmA8ZKFNcC\"</span> <span class=\"nt\">-O</span> vae.torch\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこのVAEの学習済みモデルは<code class=\"language-plaintext highlighter-rouge\">donkey-generated-track-v0</code>用なので、\n以下の実行ではこのコースを使用する(<code class=\"language-plaintext highlighter-rouge\">-track</code>オプションのデフォルト)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">donkey-waveshare-v0</code>は簡単なコースなので流用できるっぽい。</p>\n</blockquote>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習。<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\nシミュレータ実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python racer.py train <span class=\"nt\">-robot</span><span class=\"o\">=</span>sim <span class=\"nt\">-vae</span><span class=\"o\">=</span>./vae.torch <span class=\"nt\">-config</span><span class=\"o\">=</span>../config.yml <span class=\"nt\">-device</span><span class=\"o\">=</span>cpu <span class=\"nt\">-host</span><span class=\"o\">=</span>192.168.78.200 \n</code></pre></div></div>\n\n<p>追加学習する場合は元のモデルファイルを<code class=\"language-plaintext highlighter-rouge\">-l</code>オプションで指定します。<br />\n学習に使用するステップ数を変更する場合は<code class=\"language-plaintext highlighter-rouge\">-steps</code>オプションで指定します(デフォルトは5000)。<br />\nその他詳細はソースを見てちょ。</p>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンド<code class=\"language-plaintext highlighter-rouge\">train</code>を<code class=\"language-plaintext highlighter-rouge\">demo</code>に変更するだけです。<br />\nテストを実行するステップ数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--steps</code>オプションで指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python racer.py demo <span class=\"nt\">-robot</span><span class=\"o\">=</span>sim <span class=\"nt\">-vae</span><span class=\"o\">=</span>./vae.torch <span class=\"nt\">-config</span><span class=\"o\">=</span>../config.yml <span class=\"nt\">-device</span><span class=\"o\">=</span>cpu <span class=\"nt\">-host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<p>途中で止めたい場合はCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>のはやめとく。</p>\n\n<p>おおざっぱに言うと、コースの画像を入力してその特徴を抽出するVAE(Variational Auto Encoder)と\nVAEの出力と過去の操作(steering/throttle)の履歴を入力に次の操作を決定するSAC(Soft-Actor-Critic)で構成されている。</p>\n\n<p>VAEはあらかじめ大量のコース画像を撮影したデータで学習しておく(<code class=\"language-plaintext highlighter-rouge\">airc-rl-agent/notebooks/colabo/VAE_CNN.ipyn</code>)。<br />\nこの学習はカメラ画像さえ用意できていれば実機(or シミュレータ)は不要なので、Google Colaboratoryなど高性能のマシンで一気に学習できる。<br />\n上記では参照元ページで用意されていた学習済みモデルを使用している。</p>\n\n<p>VAEは車載カメラ画像(RGBのカラー画像)で160x120pixelにリサイズしたものの下部160x80pixelを入力としている。<br />\n出力は32個のデータ。</p>\n\n<p>VAEは160x80x3(38400)の画素データを32の出力に圧縮するので、そのまま画素データを入力するより学習効率が上がるのかな??<br />\nちゃんと検証してないけど、「右カーブ」とか「左カーブ」とか「直進」みたいな情報に集約されるのかな?</p>\n\n<p>SACの入力はVAEの出力(32個)と過去の操作履歴(過去何回分かは<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.N_COMMAND_HISTOR</code>で指定。\n上記手順で使用した設定値は20なので、steeringとthrottleの2個 × 20 で40個)を使用。<br />\n出力はsteeringとthrottleの2個のデータ。</p>\n\n<p>SACの出力はそのまま車の操作に使用するのではなく、<br />\nthrottleは<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.MIN_THROTTLE</code>と<code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.MAX_THROTTLE</code>で指定した範囲に変換。<br />\nsteeringは前回の設定値との差が<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">MAX_STEERING_DIFF</code>で指定した値を超えないように制限処理、<br />\nを行って使用する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その2)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(PPO2編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_1.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a>\nではポリシーにDDQNを使用したサンプルを実行してみたが、今回はもう一つのサンプル(PPO2を使用)を試してみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim2\n<span class=\"nb\">cd</span> /work2/donkey_sim2\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv <span class=\"nb\">install </span>3.7.12 \npyenv virtualenv 3.7.12 donkey_sim2\npyenv <span class=\"nb\">local </span>donkey_sim2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>stable-baselines\npip <span class=\"nb\">install </span><span class=\"nv\">tensorflow</span><span class=\"o\">==</span>1.14.0\n\n<span class=\"c\"># 現時点での最新リリース v21.7.24 をcheckoutしておく</span>\ngit clone https://github.com/tawnkramer/gym-donkeycar <span class=\"nt\">-b</span> v21.07.24\n\n<span class=\"c\"># gym-donkeycarライブラリのインストール</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-e</span> gym-donkeycar\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nstable-baselines は tensorflow ~1.14.0 しかサポートしていないので、バージョン指定してインストールする。<br />\ntensorflow 1.14.0 は python ~3.7 しかサポートしていないので、3.7系の最新版を使用している。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ngym-donkeycar は -e (–editable) オプション付きでインストールしているので、編集も可能。 \ngit cloneした先を参照しているので、インストール後もgym-donkeycarを削除しちゃダメ。</p>\n\n  <p>githubから直接インストールする場合は以下。<br />\nこの場合、パッケージは通常のディレクトリにインストールされる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n</code></pre></div>  </div>\n  <p>でも、以下でサンプルプログラム使うので、git cloneもしないとダメ。</p>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a> と同じ</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<p>用意されているサンプルプログラムにパッチをあてようと思ったのだけど、<br />\n<code class=\"language-plaintext highlighter-rouge\">ppo_train.py</code> はやっつけ感満載のイマイチソースなので いっそ全書き換えで。</p>\n\n<p>主な対応内容は、</p>\n<ul>\n  <li>一定間隔でモデルの保存を行うようcallbackクラスの追加</li>\n  <li>シミュレータのリモート実行対応(<code class=\"language-plaintext highlighter-rouge\">--host</code>)</li>\n  <li>学習回数指定オプション(<code class=\"language-plaintext highlighter-rouge\">--step</code>)</li>\n  <li>テスト回数指定オプション(<code class=\"language-plaintext highlighter-rouge\">--test_step</code>)</li>\n  <li>保存したモデルファイルをロードしてからの学習に対応</li>\n  <li></li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ppo.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">signal</span>\n<span class=\"kn\">import</span> <span class=\"nn\">argparse</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">typing</span>\n<span class=\"kn\">from</span> <span class=\"nn\">typing</span> <span class=\"kn\">import</span> <span class=\"n\">Union</span><span class=\"p\">,</span> <span class=\"n\">List</span><span class=\"p\">,</span> <span class=\"n\">Dict</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">,</span> <span class=\"n\">Optional</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">gym</span>\n<span class=\"kn\">import</span> <span class=\"nn\">gym_donkeycar</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines</span> <span class=\"kn\">import</span> <span class=\"n\">PPO2</span>\n<span class=\"c1\"># from stable_baselines.common import set_global_seeds\n</span><span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.policies</span> <span class=\"kn\">import</span> <span class=\"n\">CnnPolicy</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.vec_env</span> <span class=\"kn\">import</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.callbacks</span> <span class=\"kn\">import</span> <span class=\"n\">EventCallback</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.base_class</span> <span class=\"kn\">import</span> <span class=\"n\">BaseRLModel</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MyCallback</span><span class=\"p\">(</span><span class=\"n\">EventCallback</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> \n                 <span class=\"n\">eval_env</span><span class=\"p\">:</span> <span class=\"n\">Union</span><span class=\"p\">[</span><span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">Env</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span><span class=\"p\">],</span>\n                 <span class=\"n\">save_freq</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">1000</span><span class=\"p\">,</span>\n                 <span class=\"n\">save_file</span><span class=\"p\">:</span> <span class=\"n\">Optional</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"bp\">None</span><span class=\"p\">,</span>\n                 <span class=\"n\">verbose</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">MyCallback</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"n\">verbose</span><span class=\"o\">=</span><span class=\"n\">verbose</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span> <span class=\"o\">=</span> <span class=\"n\">save_file</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">=</span> <span class=\"n\">save_freq</span>\n        \n        <span class=\"c1\"># Convert to VecEnv for consistency\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">eval_env</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span><span class=\"p\">):</span>\n            <span class=\"n\">eval_env</span> <span class=\"o\">=</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">([</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"n\">eval_env</span><span class=\"p\">])</span>\n            \n        <span class=\"k\">assert</span> <span class=\"n\">eval_env</span><span class=\"p\">.</span><span class=\"n\">num_envs</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"You must pass only one environment for evaluation\"</span>\n        \n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">eval_env</span> <span class=\"o\">=</span> <span class=\"n\">eval_env</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">init_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">model</span><span class=\"p\">:</span> <span class=\"s\">'BaseRLModel'</span><span class=\"p\">)</span> <span class=\"o\">-></span> <span class=\"bp\">None</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#### INIT ####\"</span><span class=\"p\">)</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">EventCallback</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">init_callback</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">_init_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#### _INIT ####\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">_on_step</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"o\">-></span> <span class=\"nb\">bool</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">></span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">n_calls</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">now</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">now</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">verbose</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">now</span><span class=\"si\">}</span><span class=\"s\"> saving...'</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span> <span class=\"p\">:</span>\n                <span class=\"n\">now_str</span>  <span class=\"o\">=</span> <span class=\"n\">now</span><span class=\"p\">.</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s\">'%y%m%d_%H%M%S'</span><span class=\"p\">)</span>\n                <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span>\n                <span class=\"c1\"># filename = os.path.join(os.path.dirname(self.save_file), f'{now_str}_{os.path.basename(self.save_file)}')\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">True</span>\n    \n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Initialize the donkey environment\n</span>    <span class=\"c1\"># where env_name one of:\n</span>    <span class=\"n\">env_list</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-roads-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-avc-sparkfun-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-roboracingleague-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-waveshare-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-minimonaco-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-warren-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-thunderhill-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-circuit-launch-track-v0\"</span><span class=\"p\">,</span>\n    <span class=\"p\">]</span>\n    \n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s\">\"ppo_train\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--sim\"</span><span class=\"p\">,</span>\n        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span>\n        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"sim_path\"</span><span class=\"p\">,</span>\n        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\"</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--model\"</span><span class=\"p\">,</span>     <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"ppo_donkey\"</span><span class=\"p\">,</span>  <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--host\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"127.0.0.1\"</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"simulator address\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--port\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">9091</span><span class=\"p\">,</span>          <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--step\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">,</span>         <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test_step\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">,</span>             <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test\"</span><span class=\"p\">,</span>      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">,</span>             <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"load the trained model and play\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--env_name\"</span><span class=\"p\">,</span>  <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"name of donkey sim environment\"</span><span class=\"p\">,</span> <span class=\"n\">choices</span><span class=\"o\">=</span><span class=\"n\">env_list</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">test_step</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test_step</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span> <span class=\"ow\">and</span> <span class=\"n\">test_step</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"n\">test_step</span> <span class=\"o\">=</span> <span class=\"mi\">1000</span>\n        \n    <span class=\"c1\"># Complement the file extension\n</span>    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s\">\".zip\"</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span> <span class=\"o\">+</span> <span class=\"s\">\".zip\"</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    \n    <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s\">\"exe_path\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sim</span><span class=\"p\">,</span>\n        <span class=\"s\">\"host\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">host</span><span class=\"p\">,</span>\n        <span class=\"s\">\"port\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">port</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_style\"</span><span class=\"p\">:</span> <span class=\"s\">\"car01\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_rgb\"</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span>\n        <span class=\"s\">\"car_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"me\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"font_size\"</span><span class=\"p\">:</span> <span class=\"mi\">100</span><span class=\"p\">,</span>\n        <span class=\"s\">\"racer_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"PPO\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"country\"</span><span class=\"p\">:</span> <span class=\"s\">\"USA\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"bio\"</span><span class=\"p\">:</span> <span class=\"s\">\"Learning to drive w PPO RL\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"guid\"</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"p\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()),</span>\n        <span class=\"s\">\"max_cte\"</span><span class=\"p\">:</span> <span class=\"mi\">10</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\"># Make an environment test our trained policy\n</span>    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">make</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">env_name</span><span class=\"p\">,</span> <span class=\"n\">conf</span><span class=\"o\">=</span><span class=\"n\">conf</span><span class=\"p\">)</span>\n    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">([</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"n\">env</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># hook terninate signal\n</span>    <span class=\"k\">def</span> <span class=\"nf\">signal_handler</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"catching ctrl+c\"</span><span class=\"p\">)</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGINT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGTERM</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGABRT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">try</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># check model path\n</span>        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">):</span>\n            <span class=\"c1\"># load model\n</span>            <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">PPO2</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">,</span> <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span> \n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">:</span>\n                <span class=\"c1\"># create model\n</span>                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"create new model\"</span><span class=\"p\">)</span>\n                <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">PPO2</span><span class=\"p\">(</span><span class=\"n\">CnnPolicy</span><span class=\"p\">,</span> <span class=\"n\">env</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">raise</span> <span class=\"nb\">ValueError</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Error: the file </span><span class=\"si\">{</span><span class=\"n\">model_path</span><span class=\"si\">}</span><span class=\"s\"> could not be found\"</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># change throttle lower limit\n</span>        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">action_space</span><span class=\"p\">.</span><span class=\"n\">low</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.1</span>\n        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">:</span>\n            <span class=\"c1\"># in training mode\n</span>            \n            <span class=\"n\">callback</span> <span class=\"o\">=</span> <span class=\"n\">MyCallback</span><span class=\"p\">(</span><span class=\"n\">env</span><span class=\"p\">,</span> <span class=\"n\">save_freq</span> <span class=\"o\">=</span> <span class=\"mi\">5000</span><span class=\"p\">,</span> <span class=\"n\">save_file</span> <span class=\"o\">=</span> <span class=\"n\">model_path</span><span class=\"p\">,</span> <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"c1\"># callback = MyCallback(env, save_freq = 10, verbose = 1)\n</span>            \n            <span class=\"c1\"># set up model in learning mode with goal number of timesteps to complete\n</span>            <span class=\"c1\"># model.learn(total_timesteps=10000)\n</span>            <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">learn</span><span class=\"p\">(</span><span class=\"n\">total_timesteps</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">,</span> <span class=\"n\">callback</span><span class=\"o\">=</span><span class=\"n\">callback</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># save model\n</span>            <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stert testing...\"</span><span class=\"p\">)</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">reset</span><span class=\"p\">()</span>\n        <span class=\"n\">prev_done_count</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">test_step</span><span class=\"p\">):</span>\n            <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">_states</span> <span class=\"o\">=</span> <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n            <span class=\"n\">obs</span><span class=\"p\">,</span> <span class=\"n\">rewards</span><span class=\"p\">,</span> <span class=\"n\">dones</span><span class=\"p\">,</span> <span class=\"n\">info</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">(</span><span class=\"n\">action</span><span class=\"p\">)</span>\n            <span class=\"c1\"># print(f\"cnt : {i}    rewards : {rewards[0]}    dones : {dones[0]}    pos : {info[0]['pos']}, CrossTrackError : {info[0]['cte']}, speed : {info[0]['speed']}\")\n</span>            <span class=\"c1\"># print(f\"+++ info: {info} +++\")\n</span>            <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">render</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">dones</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'dones flag detected : </span><span class=\"si\">{</span><span class=\"n\">i</span> <span class=\"o\">-</span> <span class=\"n\">prev_done_count</span><span class=\"si\">}</span><span class=\"s\">  (</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n                <span class=\"n\">prev_done_count</span> <span class=\"o\">=</span> <span class=\"n\">i</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done testing\"</span><span class=\"p\">)</span>\n        \n    <span class=\"k\">except</span> <span class=\"nb\">KeyboardInterrupt</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stopping run...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n</code></pre></div></div>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習。<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションに<code class=\"language-plaintext highlighter-rouge\">remote</code>を、実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>examples/reinforcement_learning\npython ppo.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n学習回数を指定するには<code class=\"language-plaintext highlighter-rouge\">--step</code>オプションで指定します。<br />\n指定する回数はエピソード数ではなく、アクション数。<br />\n例えば、<code class=\"language-plaintext highlighter-rouge\">--step=100000</code></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nローカルマシンでシミュレータを実行する場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションにDonkeyCar シミュレータ起動コマンドをフルパスで指定します。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションは不要です。<br />\nシミュレータをあらかじめ起動しておく必要はなく、自動的に起動されます。</p>\n</blockquote>\n\n<p>モデルの保存間隔は<code class=\"language-plaintext highlighter-rouge\">MyCallback</code>のインスタンス生成時に<code class=\"language-plaintext highlighter-rouge\">save_freq = 5000</code>で指定していますので、必要なら変更してください。</p>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンドに<code class=\"language-plaintext highlighter-rouge\">--test</code>を指定するだけです。<br />\nテストを実行するステップ数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--test_step</code>オプションで指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ppo.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--test</span> \n</code></pre></div></div>\n<p>途中で止めたい場合はCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>ほど複雑じゃないので省略。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その1)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(DDQN編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"https://qiita.com/bathtimefish/items/a9b23681720527c0bd7e?fbclid=IwAR3sbaoBn09U7pFL4AKyEOXMi0wNXyAYi9jODUzO1muYr-N7q6hFG-hDfKs\" target=\"_blank\">DonkeyCar3シミュレーターで強化学習してみる</a>のマネをしてDonkeyCarシミュレータライブラリの中にあるサンプルのddqn.pyを実行してみる。<br />\n参考:<br />\nDQNについてはここが分かりやすかったかな。<br />\n<a href=\"https://www.tcom242242.net/entry/ai-2/%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/%E6%B7%B1%E5%B1%A4%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/%E3%80%90%E6%B7%B1%E5%B1%A4%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92%E3%80%91deep_q_network_%E3%82%92tensorflow%E3%81%A7%E5%AE%9F%E8%A3%85/\" target=\"_blank\">【深層強化学習,入門】Deep Q Network(DQN)の解説とPythonで実装 〜図を使って説明〜 </a><br />\n<a href=\"https://www.tcom242242.net/entry/ai-2/%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92/%e3%80%90%e6%b7%b1%e5%b1%a4%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92%e3%80%91double-q-network/\" target=\"_blank\">【深層強化学習】Double Deep Q Network(DDQN)</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim\n<span class=\"nb\">cd</span> /work2/donkey_sim\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 donkey_sim\npyenv <span class=\"nb\">local </span>donkey_sim \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n\n<span class=\"c\"># 現時点での最新リリース v21.7.24 をcheckoutしておく</span>\ngit clone https://github.com/tawnkramer/gym-donkeycar <span class=\"nt\">-b</span> v21.07.24\n\n<span class=\"c\"># gym-donkeycarライブラリのインストール</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-e</span> gym-donkeycar\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ngym-donkeycar は -e (–editable) オプション付きでインストールしているので、編集も可能。 \ngit cloneした先を参照しているので、インストール後もgym-donkeycarを削除しちゃダメ。</p>\n\n  <p>githubから直接インストールする場合は以下。<br />\nこの場合、パッケージは通常のディレクトリにインストールされる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n</code></pre></div>  </div>\n  <p>でも、以下でサンプルプログラム使うので、git cloneもしないとダメ。</p>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p>以下のページから実行するプラットフォームに合わせて<code class=\"language-plaintext highlighter-rouge\">DonkeySimXXXX.zip</code>(XXXXはプラットフォーム名)をダウンロードし、<br />\n適当なディレクトリに展開しておきます。<br />\n(Linux/Macの場合は実行属性付けるのを忘れずに)<br />\n<a href=\"https://github.com/tawnkramer/gym-donkeycar/releases\">https://github.com/tawnkramer/gym-donkeycar/releases</a></p>\n\n<p>マシンスペックがそれほど高くない場合は別マシンで実行してリモート接続するのがおススメ。<br />\nSSH接続で実行する場合はリモート必須。</p>\n\n<h2 id=\"patchをあてる\">patchをあてる</h2>\n\n<p>以下のパッチファイルを使用してサンプルプログラムにパッチをあてます。<br />\n内容は、</p>\n<ul>\n  <li>なぜか<code class=\"language-plaintext highlighter-rouge\">gym_donkeycar</code>がimportされてなかった</li>\n  <li>tensorflow 1.13以降2.0未満用の設定をバージョン情報からスキップできるようにした</li>\n  <li>シミュレータのリモート実行対応(hostオプション追加)</li>\n  <li>探索率(ε値)の初期値設定オプションの追加<br />\n探索率(ε値)については<a href=\"https://www.tcom242242.net/entry/ai-2/%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/epsilon-greedy/\" target=\"_blank\">ε-greedy行動選択 </a>を参照</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  rl_sample.patch\n</p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/examples/reinforcement_learning/ddqn.py b/examples/reinforcement_learning/ddqn.py\nindex 87c74f0..5c32f49 100755\n</span><span class=\"gd\">--- a/examples/reinforcement_learning/ddqn.py\n</span><span class=\"gi\">+++ b/examples/reinforcement_learning/ddqn.py\n</span><span class=\"p\">@@ -21,6 +21,8 @@</span> from tensorflow.keras.layers import Activation, Conv2D, Dense, Flatten\n from tensorflow.keras.models import Sequential\n from tensorflow.keras.optimizers import Adam\n \n<span class=\"gi\">+import gym_donkeycar\n+\n</span> EPISODES = 10000\n img_rows, img_cols = 80, 80\n # Convert image into Black and white\n<span class=\"p\">@@ -121,6 +123,9 @@</span> class DQNAgent:\n         if self.epsilon > self.epsilon_min:\n             self.epsilon -= (self.initial_epsilon - self.epsilon_min) / self.explore\n \n<span class=\"gi\">+    def set_epsilon(self, epsilon):\n+        self.epsilon = epsilon\n+\n</span>     def train_replay(self):\n         if len(self.memory) < self.train_start:\n             return\n<span class=\"p\">@@ -196,15 +201,17 @@</span> def run_ddqn(args):\n     run a DDQN training session, or test it's result, with the donkey simulator\n     \"\"\"\n \n<span class=\"gd\">-    # only needed if TF==1.13.1\n-    config = tf.ConfigProto()\n-    config.gpu_options.allow_growth = True\n-    sess = tf.Session(config=config)\n-    K.set_session(sess)\n</span><span class=\"gi\">+    tf_ver = tf.__version__.split('.')\n+    if (tf_ver[0] == 1 and tf_ver[1] >= 13) :\n+        # only needed if TF==1.13.1\n+        config = tf.ConfigProto()\n+        config.gpu_options.allow_growth = True\n+        sess = tf.Session(config=config)\n+        K.set_session(sess)\n</span> \n     conf = {\n         \"exe_path\": args.sim,\n<span class=\"gd\">-        \"host\": \"127.0.0.1\",\n</span><span class=\"gi\">+        \"host\": args.host,\n</span>         \"port\": args.port,\n         \"body_style\": \"donkey\",\n         \"body_rgb\": (128, 128, 128),\n<span class=\"p\">@@ -237,6 +244,9 @@</span> def run_ddqn(args):\n     try:\n         agent = DQNAgent(state_size, action_space, train=not args.test)\n \n<span class=\"gi\">+        if args.epsilon > 0 :\n+            agent.set_epsilon(args.epsilon)\n+\n</span>         throttle = args.throttle  # Set throttle as constant value\n \n         episodes = []\n<span class=\"p\">@@ -350,6 +360,7 @@</span> if __name__ == \"__main__\":\n         default=\"manual\",\n         help=\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\",\n     )\n<span class=\"gi\">+    parser.add_argument(\"--host\", type=str, default=\"127.0.0.1\", help=\"simulator address\")\n</span>     parser.add_argument(\"--model\", type=str, default=\"rl_driver.h5\", help=\"path to model\")\n     parser.add_argument(\"--test\", action=\"store_true\", help=\"agent uses learned model to navigate env\")\n     parser.add_argument(\"--port\", type=int, default=9091, help=\"port to use for websockets\")\n<span class=\"p\">@@ -357,6 +368,7 @@</span> if __name__ == \"__main__\":\n     parser.add_argument(\n         \"--env_name\", type=str, default=\"donkey-warehouse-v0\", help=\"name of donkey sim environment\", choices=env_list\n     )\n<span class=\"gi\">+    parser.add_argument(\"--epsilon\", type=float, default=0.0, help=\"initial epsilon value\")\n</span> \n     args = parser.parse_args()\n</code></pre></div></div>\n\n<p>以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>gym-donkeycar/\npatch <span class=\"nt\">-p1</span> < rl_sample.patch \n</code></pre></div></div>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習しないと話にならないので学習します。<br />\n強化学習は教師データが要らないので、準備がラクチン…  でも学習には時間がかかる…<br />\nDonkeyCar シミュレータをリモートマシンで実行する場合、<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションに<code class=\"language-plaintext highlighter-rouge\">remote</code>を、実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>examples/reinforcement_learning\npython ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルマシンでシミュレータを実行する場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションにDonkeyCar シミュレータ起動コマンドをフルパスで指定します。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションは不要です。<br />\nシミュレータをあらかじめ起動しておく必要はなく、自動的に起動されます。</p>\n</blockquote>\n\n<p>エピソード毎に学習結果が <code class=\"language-plaintext highlighter-rouge\">rl_driver.h5</code>に保存されるので、任意のタイミングでCTRL-Cで中断できます。<br />\n次回学習を再開する場合は、ログとして表示されている<code class=\"language-plaintext highlighter-rouge\">epsilon: 0.XXXXXXX</code>の部分の最後の値を覚えておいてください。<br />\nこのプログラムではε値は0.02を下回ると固定されるので、ある程度学習が進んだ状態では<code class=\"language-plaintext highlighter-rouge\">0.02</code>だと思っても問題ないでしょう。</p>\n\n<p>学習を再開する場合は以下のように上記コマンドに<code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプションを追加して実行します。<br />\n(<code class=\"language-plaintext highlighter-rouge\">0.XXXXXXX</code>の部分は上で覚えておいた値。ピッタリ同じでなくて大体で可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--epsilon</span><span class=\"o\">=</span>0.XXXXXXX\n</code></pre></div></div>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンドに<code class=\"language-plaintext highlighter-rouge\">--test</code>を指定するだけです。<br />\n<code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプションは指定しません。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--test</span>\n</code></pre></div></div>\n<p>うまく学習が進んでいれば、コースアウトすることなく周回してくれるハズ。<br />\n学習時と同様、コースアウトすると自動的にスタート位置に戻って再スタートします。<br />\n適当にCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>以下はソースを読んだ時のメモです。<br />\n書いてみたけど、自分で読んでも なにが何だか分からない…😢</p>\n\n<h2 id=\"冒頭部分\">冒頭部分</h2>\n<p>この辺はお約束なので。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"s\">\"\"\"\nfile: ddqn.py\nauthor: Felix Yu\ndate: 2018-09-12\noriginal: https://github.com/flyyufelix/donkey_rl/blob/master/donkey_rl/src/ddqn.py\n\"\"\"</span>\n<span class=\"kn\">import</span> <span class=\"nn\">argparse</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">signal</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">from</span> <span class=\"nn\">collections</span> <span class=\"kn\">import</span> <span class=\"n\">deque</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">gym</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">tensorflow</span> <span class=\"k\">as</span> <span class=\"n\">tf</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras</span> <span class=\"kn\">import</span> <span class=\"n\">backend</span> <span class=\"k\">as</span> <span class=\"n\">K</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.layers</span> <span class=\"kn\">import</span> <span class=\"n\">Activation</span><span class=\"p\">,</span> <span class=\"n\">Conv2D</span><span class=\"p\">,</span> <span class=\"n\">Dense</span><span class=\"p\">,</span> <span class=\"n\">Flatten</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.models</span> <span class=\"kn\">import</span> <span class=\"n\">Sequential</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.optimizers</span> <span class=\"kn\">import</span> <span class=\"n\">Adam</span>\n\n</code></pre></div></div>\n<h2 id=\"冒頭部分その2\">冒頭部分その2</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">gym_donkey</code>をimportしないとDonkeyCarシミュレータと接続できないので。<br />\nなぜかオリジナルでは入ってなかった。<br />\n<code class=\"language-plaintext highlighter-rouge\">if __name__ == \"__main__\":</code>付けといた方が良いかもしれんが、とりあえずそのままimportしておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">gym_donkeycar</span>\n\n</code></pre></div></div>\n\n<h2 id=\"パラメータの設定\">パラメータの設定</h2>\n<p>意味は以下の通り。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: center\">変数</th>\n      <th style=\"text-align: left\">意味</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: center\">EPISODES</td>\n      <td style=\"text-align: left\">学習回数</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_rows</td>\n      <td style=\"text-align: left\">入力に使用する画像サイズ(Y)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_cols</td>\n      <td style=\"text-align: left\">入力に使用する画像サイズ(X)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_channels</td>\n      <td style=\"text-align: left\">入力に過去何フレーム分のデータを使用するか</td>\n    </tr>\n  </tbody>\n</table>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">EPISODES</span> <span class=\"o\">=</span> <span class=\"mi\">10000</span>\n<span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span> <span class=\"o\">=</span> <span class=\"mi\">80</span><span class=\"p\">,</span> <span class=\"mi\">80</span>\n<span class=\"c1\"># Convert image into Black and white\n</span><span class=\"n\">img_channels</span> <span class=\"o\">=</span> <span class=\"mi\">4</span>  <span class=\"c1\"># We stack 4 frames\n</span></code></pre></div></div>\n\n<h2 id=\"強化学習エージェントクラス\">強化学習エージェントクラス</h2>\n\n<p>強化学習のエージェントを定義したクラスです。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">DQNAgent</span><span class=\"p\">:</span>\n</code></pre></div></div>\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>クラス変数</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: center\">変数</th>\n      <th style=\"text-align: left\">意味</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: center\">t</td>\n      <td style=\"text-align: left\">実行カウンタ(ステータス表示用のみ使用)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">max_Q</td>\n      <td style=\"text-align: left\">Q値の最大値(ステータス表示用のみ使用)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">train</td>\n      <td style=\"text-align: left\">学習モード/テストモード(<code class=\"language-plaintext highlighter-rouge\">--test</code>オプションで指定)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">state_size</td>\n      <td style=\"text-align: left\">モデルの入力層のサイズ。現状未使用</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">action_space</td>\n      <td style=\"text-align: left\">シミュレータの現在のステアリング/スロットル設定値取得用</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">action_size</td>\n      <td style=\"text-align: left\">未使用。たぶん、ステアリング角を何分割するかの定義(15)にすべきだと思う</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">discount_factor</td>\n      <td style=\"text-align: left\">割引率(γ値) (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">learning_rate</td>\n      <td style=\"text-align: left\">学習率 (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">epsilon</td>\n      <td style=\"text-align: left\">現在の探索率(ε値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">initial_epsilon</td>\n      <td style=\"text-align: left\">探索率の最大値  最小率と共に探索率の変更率を計算する(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">epsilon_min</td>\n      <td style=\"text-align: left\">探索率の最小値 学習時の探索率をこれより小さくしない(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">explore</td>\n      <td style=\"text-align: left\">探索率を最小値にするまでの回数(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">batch_size</td>\n      <td style=\"text-align: left\">バッチサイズ (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">train_start</td>\n      <td style=\"text-align: left\">学習開始タイミング(最初は学習を行わない)(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">memory</td>\n      <td style=\"text-align: left\">Experience Buffer</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">model</td>\n      <td style=\"text-align: left\">メインモデル</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">target_model</td>\n      <td style=\"text-align: left\">ターゲットモデル(double DQNなので)</td>\n    </tr>\n  </tbody>\n</table>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state_size</span><span class=\"p\">,</span> <span class=\"n\">action_space</span><span class=\"p\">,</span> <span class=\"n\">train</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">max_Q</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train</span> <span class=\"o\">=</span> <span class=\"n\">train</span>\n\n        <span class=\"c1\"># Get size of state and action\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">state_size</span> <span class=\"o\">=</span> <span class=\"n\">state_size</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_space</span> <span class=\"o\">=</span> <span class=\"n\">action_space</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_size</span> <span class=\"o\">=</span> <span class=\"n\">action_space</span>\n\n        <span class=\"c1\"># These are hyper parameters for the DQN\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">discount_factor</span> <span class=\"o\">=</span> <span class=\"mf\">0.99</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">learning_rate</span> <span class=\"o\">=</span> <span class=\"mf\">1e-4</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1e-6</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1e-6</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span> <span class=\"o\">=</span> <span class=\"mf\">0.02</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">64</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train_start</span> <span class=\"o\">=</span> <span class=\"mi\">100</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">explore</span> <span class=\"o\">=</span> <span class=\"mi\">10000</span>\n\n        <span class=\"c1\"># Create replay memory using deque\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span> <span class=\"o\">=</span> <span class=\"n\">deque</span><span class=\"p\">(</span><span class=\"n\">maxlen</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Create main model and target model\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">build_model</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">build_model</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># Copy the model to target model\n</span>        <span class=\"c1\"># --> initialize the target model so that the parameters of model & target model to be same\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_target_model</span><span class=\"p\">()</span>\n\n</code></pre></div></div>\n<h3 id=\"モデルの生成\">モデルの生成</h3>\n\n<p>そんなに複雑なモデルではないみたい。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">build_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Sequential</span><span class=\"p\">()</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span>\n            <span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">24</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">,</span> <span class=\"n\">input_shape</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">,</span> <span class=\"n\">img_channels</span><span class=\"p\">))</span>\n        <span class=\"p\">)</span>  <span class=\"c1\"># 80*80*4\n</span>        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">32</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Flatten</span><span class=\"p\">())</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Dense</span><span class=\"p\">(</span><span class=\"mi\">512</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n\n        <span class=\"c1\"># 15 categorical bins for Steering angles\n</span>        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Dense</span><span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">activation</span><span class=\"o\">=</span><span class=\"s\">\"linear\"</span><span class=\"p\">))</span>\n\n        <span class=\"n\">adam</span> <span class=\"o\">=</span> <span class=\"n\">Adam</span><span class=\"p\">(</span><span class=\"n\">lr</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">learning_rate</span><span class=\"p\">)</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"nb\">compile</span><span class=\"p\">(</span><span class=\"n\">loss</span><span class=\"o\">=</span><span class=\"s\">\"mse\"</span><span class=\"p\">,</span> <span class=\"n\">optimizer</span><span class=\"o\">=</span><span class=\"n\">adam</span><span class=\"p\">)</span>\n\n        <span class=\"k\">return</span> <span class=\"n\">model</span>\n\n</code></pre></div></div>\n<h3 id=\"rgbグレースケール変換処理\">RGB→グレースケール変換処理</h3>\n<p>シミュレータの出力はRGB画像、モデルの入力はグレースケール画像なので、その変換を行うための関数。<br />\n<code class=\"language-plaintext highlighter-rouge\">cv2.dst = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)</code> で良い気もするが…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">rgb2gray</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">rgb</span><span class=\"p\">):</span>\n        <span class=\"s\">\"\"\"\n        take a numpy rgb image return a new single channel image converted to greyscale\n        \"\"\"</span>\n        <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">dot</span><span class=\"p\">(</span><span class=\"n\">rgb</span><span class=\"p\">[...,</span> <span class=\"p\">:</span><span class=\"mi\">3</span><span class=\"p\">],</span> <span class=\"p\">[</span><span class=\"mf\">0.299</span><span class=\"p\">,</span> <span class=\"mf\">0.587</span><span class=\"p\">,</span> <span class=\"mf\">0.114</span><span class=\"p\">])</span>\n\n</code></pre></div></div>\n\n<h3 id=\"入力画像前処理\">入力画像前処理</h3>\n<p>シミュレータの出力画像をモデルの入力データに変換する処理。<br />\nRGBからグレースケールに変換し、リサイズを行う。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">process_image</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">obs</span><span class=\"p\">):</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rgb2gray</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">obs</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ターゲットモデルのパラメータ更新\">ターゲットモデルのパラメータ更新</h3>\n\n<p>メインモデルのパラメータをターゲットモデルにコピーする</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">update_target_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span><span class=\"p\">.</span><span class=\"n\">set_weights</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">get_weights</span><span class=\"p\">())</span>\n\n</code></pre></div></div>\n\n<h3 id=\"現在の環境での次の行動を取得する\">現在の環境での次の行動を取得する</h3>\n\n<p>乱数を発生し、ε値以下だったら環境が生成したランダム値(<code class=\"language-plaintext highlighter-rouge\">self.action_space.sample()[0]</code>)を返す。<br />\nそれ以外はメインモデルで予測した結果を返す。<br />\nその際、モデルの出力結果そのままではなく、どのステアリング位置に当たるかの量子化を行って返す。<br />\n(得られるのはステアリング情報だけで、スロットル情報は固定値)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Get action from model using epsilon-greedy policy\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_action</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">rand</span><span class=\"p\">()</span> <span class=\"o\"><=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_space</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"c1\"># print(\"Return Max Q Prediction\")\n</span>            <span class=\"n\">q_value</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">)</span>\n\n            <span class=\"c1\"># Convert q array to steering value\n</span>            <span class=\"k\">return</span> <span class=\"n\">linear_unbin</span><span class=\"p\">(</span><span class=\"n\">q_value</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<h3 id=\"状態等の保存\">状態等の保存</h3>\n<p>現在の状態(state)、行動(action)、報酬(reward)、行動後の状態(next_state)、\n終了フラグ(done)をExperience Bufferに保存する。<br />\n(Experience Buffer は Experience Replayに使用するためのデータを保存しておくところ)<br />\n<code class=\"language-plaintext highlighter-rouge\">memory</code> は <code class=\"language-plaintext highlighter-rouge\">collections.dque()</code>で作成しているので、指定サイズを超えたときは古いデータから順に削除される。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">replay_memory</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">next_state</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">((</span><span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">next_state</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">))</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ε値の更新\">ε値の更新</h3>\n\n<p>現在のε値が最小値より大きかったら一定比率で小さくしていく。<br />\n最小値以下になっていたらそのまま。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">update_epsilon</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">></span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">-=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">-</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">explore</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ε値の初期設定\">ε値の初期設定</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプション追加したので、指定値でε値を変更する処理を追加。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">set_epsilon</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">epsilon</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"n\">epsilon</span>\n</code></pre></div></div>\n\n<h3 id=\"学習\">学習</h3>\n\n<p>Experience Bufferから任意の経験を取り出し、Q Networkをミニバッチ学習(Experience Replay)</p>\n\n<p>記憶したデータ数が<code class=\"language-plaintext highlighter-rouge\">self.train_start</code>に達するまでは何もしない。<br />\nバッチ学習に使用するデータをExperience Bufferから取り出し、<br />\nそれぞれの配列にバラす(<code class=\"language-plaintext highlighter-rouge\">state_t</code>,<code class=\"language-plaintext highlighter-rouge\">action_t</code>, <code class=\"language-plaintext highlighter-rouge\">reward_t</code>, <code class=\"language-plaintext highlighter-rouge\">state_t1</code>, <code class=\"language-plaintext highlighter-rouge\">terminal</code>)。<br />\n<code class=\"language-plaintext highlighter-rouge\">state_t</code>と<code class=\"language-plaintext highlighter-rouge\">state_t1</code>は<code class=\"language-plaintext highlighter-rouge\">np.concatenate()</code>でndarrayにまとめておく。<br />\n11行目の<code class=\"language-plaintext highlighter-rouge\">self.model.predict(state_t)</code>は<code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>の取得にしか使用されておらず、</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>はステータス表示にしか使用されてなく、無駄な計算なので、削除するのが良いと思われる(無駄な計算なので)。<br />\nその場合、<code class=\"language-plaintext highlighter-rouge\">targets</code>の初期化は<code class=\"language-plaintext highlighter-rouge\">targets = np.zeros((batch_size, 15))</code>で行う。<br />\n(<code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>を参照しているところも削除。あるいは<code class=\"language-plaintext highlighter-rouge\">get_action()</code>で戻り値として返すのも手か。)</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">state_t1</code>を入力としてメインモデルをターゲットモデルを使用して得られた出力から出力期待値を取得し、<br />\n学習を行う<code class=\"language-plaintext highlighter-rouge\">self.model.train_on_batch(state_t, targets)</code>。<br />\nこの辺は\n<a href=\"https://www.tcom242242.net/entry/ai-2/%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92/%e3%80%90%e6%b7%b1%e5%b1%a4%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92%e3%80%91double-q-network/\" target=\"_blank\">【深層強化学習】Double Deep Q Network(DDQN)</a>\nのソースとかを見ると分かったような分からないような気になれるかも…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">train_replay</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train_start</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span>\n\n        <span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">batch_size</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">))</span>\n        <span class=\"n\">minibatch</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">,</span> <span class=\"n\">batch_size</span><span class=\"p\">)</span>\n\n        <span class=\"n\">state_t</span><span class=\"p\">,</span> <span class=\"n\">action_t</span><span class=\"p\">,</span> <span class=\"n\">reward_t</span><span class=\"p\">,</span> <span class=\"n\">state_t1</span><span class=\"p\">,</span> <span class=\"n\">terminal</span> <span class=\"o\">=</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">minibatch</span><span class=\"p\">)</span>\n        <span class=\"n\">state_t</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">concatenate</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">)</span>\n        <span class=\"n\">state_t1</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">concatenate</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"n\">targets</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">max_Q</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n        <span class=\"n\">target_val</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"n\">target_val_</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">batch_size</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">terminal</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]:</span>\n                <span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">action_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">reward_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">target_val</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">])</span>\n                <span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">action_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">reward_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">discount_factor</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">target_val_</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">a</span><span class=\"p\">])</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">train_on_batch</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">,</span> <span class=\"n\">targets</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"モデルのロード\">モデルのロード</h3>\n\n<p>モデルの読み込み先はメインモデル。<br />\nこのあと、ターゲットモデルへコピーするので、ここではターゲットモデルは触らない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">load_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">load_weights</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"モデルの保存\">モデルの保存</h3>\n\n<p>メインモデルをファイルに保存する。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Save the model which is under training\n</span>    <span class=\"k\">def</span> <span class=\"nf\">save_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save_weights</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"ステアリング角モデル出力形式変換\">ステアリング角→モデル出力形式変換</h2>\n\n<p>ステアリング角(-1~1)をモデル出力形式(要素数15の配列のどれか1つに1が入る)に変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">linear_bin</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    Convert a value to a categorical array.\n\n    Parameters\n    ----------\n    a : int or float\n        A value between -1 and 1\n\n    Returns\n    -------\n    list of int\n        A list of length 15 with one item set to 1, which represents the linear value, and all other items set to 0.\n    \"\"\"</span>\n    <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    <span class=\"n\">b</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">a</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"mi\">2</span> <span class=\"o\">/</span> <span class=\"mi\">14</span><span class=\"p\">))</span>\n    <span class=\"n\">arr</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">)</span>\n    <span class=\"n\">arr</span><span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">b</span><span class=\"p\">)]</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">return</span> <span class=\"n\">arr</span>\n</code></pre></div></div>\n\n<h2 id=\"モデル出力形式ステアリング角変換\">モデル出力形式→ステアリング角変換</h2>\n\n<p>モデル出力のうち、最大値を持つindexに相当するステアリング角を取得する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">linear_unbin</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    Convert a categorical array to value.\n\n    See Also\n    --------\n    linear_bin\n    \"\"\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">15</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"nb\">ValueError</span><span class=\"p\">(</span><span class=\"s\">\"Illegal array length, must be 15\"</span><span class=\"p\">)</span>\n    <span class=\"n\">b</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">)</span>\n    <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">b</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"mi\">2</span> <span class=\"o\">/</span> <span class=\"mi\">14</span><span class=\"p\">)</span> <span class=\"o\">-</span> <span class=\"mi\">1</span>\n    <span class=\"k\">return</span> <span class=\"n\">a</span>\n</code></pre></div></div>\n\n<h2 id=\"メインルーチン\">メインルーチン</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">run_ddqn</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    run a DDQN training session, or test it's result, with the donkey simulator\n    \"\"\"</span>\n</code></pre></div></div>\n\n<h3 id=\"tensorflow-1131でのおまじない\">Tensorflow 1.13.1でのおまじない</h3>\n\n<p>Tensorflow 2 を使用したかったので、処理不要。<br />\nコメントアウトすれば良いのだけれど、なんとなくバージョンで分けてみた。<br />\n1.14以降では要るのかな?要ると思って書いてみた。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tf_ver</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">__version__</span><span class=\"p\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">'.'</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">tf_ver</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">tf_ver</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"mi\">13</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># only needed if TF==1.13.1\n</span>        <span class=\"n\">config</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">ConfigProto</span><span class=\"p\">()</span>\n        <span class=\"n\">config</span><span class=\"p\">.</span><span class=\"n\">gpu_options</span><span class=\"p\">.</span><span class=\"n\">allow_growth</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"n\">sess</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">Session</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">=</span><span class=\"n\">config</span><span class=\"p\">)</span>\n        <span class=\"n\">K</span><span class=\"p\">.</span><span class=\"n\">set_session</span><span class=\"p\">(</span><span class=\"n\">sess</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"シミュレータ環境の構築\">シミュレータ環境の構築</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">body_style</code> には <code class=\"language-plaintext highlighter-rouge\">donkey</code>、 <code class=\"language-plaintext highlighter-rouge\">bare</code>、<code class=\"language-plaintext highlighter-rouge\">car01</code>、<code class=\"language-plaintext highlighter-rouge\">cybertruck</code>、<code class=\"language-plaintext highlighter-rouge\">f1</code>が使用できるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">body_rgb</code> で 色を指定できるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">car_name</code> でシミュレータに表示される名前を指定。複数の車を走らせるときに見分けられるみたい。<br />\n<code class=\"language-plaintext highlighter-rouge\">font_size</code>で名前のフォントサイズを指定。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s\">\"exe_path\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sim</span><span class=\"p\">,</span>\n        <span class=\"s\">\"host\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">host</span><span class=\"p\">,</span>\n        <span class=\"s\">\"port\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">port</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_style\"</span><span class=\"p\">:</span> <span class=\"s\">\"donkey\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_rgb\"</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span>\n        <span class=\"s\">\"car_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"me\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"font_size\"</span><span class=\"p\">:</span> <span class=\"mi\">100</span><span class=\"p\">,</span>\n        <span class=\"s\">\"racer_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"DDQN\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"country\"</span><span class=\"p\">:</span> <span class=\"s\">\"USA\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"bio\"</span><span class=\"p\">:</span> <span class=\"s\">\"Learning to drive w DDQN RL\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"guid\"</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"p\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()),</span>\n        <span class=\"s\">\"max_cte\"</span><span class=\"p\">:</span> <span class=\"mi\">10</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\"># Construct gym environment. Starts the simulator if path is given.\n</span>    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">make</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">env_name</span><span class=\"p\">,</span> <span class=\"n\">conf</span><span class=\"o\">=</span><span class=\"n\">conf</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"プログラム終了時のフックルーチンの定義と登録\">プログラム終了時のフックルーチンの定義と登録</h3>\n\n<p>プログラム終了時にシミュレータの終了処理を行うようにフックルーチンを登録する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># not working on windows...\n</span>    <span class=\"k\">def</span> <span class=\"nf\">signal_handler</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"catching ctrl+c\"</span><span class=\"p\">)</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">unwrapped</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGINT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGTERM</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGABRT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"パラメータ用変数の定義\">パラメータ用変数の定義</h3>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Get size of state and action from environment\n</span>    <span class=\"n\">state_size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">,</span> <span class=\"n\">img_channels</span><span class=\"p\">)</span>\n    <span class=\"n\">action_space</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">action_space</span>  <span class=\"c1\"># Steering and Throttle\n</span></code></pre></div></div>\n\n<h3 id=\"エージェントの生成\">エージェントの生成</h3>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">agent</span> <span class=\"o\">=</span> <span class=\"n\">DQNAgent</span><span class=\"p\">(</span><span class=\"n\">state_size</span><span class=\"p\">,</span> <span class=\"n\">action_space</span><span class=\"p\">,</span> <span class=\"n\">train</span><span class=\"o\">=</span><span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ε値の設定\">ε値の設定</h3>\n\n<p>オプションでε値が指定されていたら設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">></span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">set_epsilon</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スロットル値の設定\">スロットル値の設定</h3>\n\n<p>スロットルの設定は固定値(コマンドラインオプションで設定)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">throttle</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">throttle</span>  <span class=\"c1\"># Set throttle as constant value\n</span>\n        <span class=\"n\">episodes</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n</code></pre></div></div>\n\n<h3 id=\"モデルのロード-1\">モデルのロード</h3>\n\n<p>モデルファイルがあれば読み込む。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">):</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"load the saved model\"</span><span class=\"p\">)</span>\n            <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">load_model</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"学習ループ\">学習ループ</h3>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">for</span> <span class=\"n\">e</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">EPISODES</span><span class=\"p\">):</span>\n\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Episode: \"</span><span class=\"p\">,</span> <span class=\"n\">e</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h4 id=\"スタート位置へ移動\">スタート位置へ移動</h4>\n\n<p><code class=\"language-plaintext highlighter-rouge\">obs</code> ← スタート時のカメラ画像<br />\n<code class=\"language-plaintext highlighter-rouge\">x_t</code> ← <code class=\"language-plaintext highlighter-rouge\">obs</code> をモデルの入力形式に合わせて変換(グレースケール化&リサイズ) <br />\n<code class=\"language-plaintext highlighter-rouge\">s_t</code> ← <code class=\"language-plaintext highlighter-rouge\">x_t</code>を4枚分コピー(入力画像は過去4枚分を使用するので)(ちゃんと<code class=\"language-plaintext highlighter-rouge\">img_channels</code>参照して欲しいけど)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"n\">done</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">reset</span><span class=\"p\">()</span>\n\n            <span class=\"n\">episode_len</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n            <span class=\"n\">x_t</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">process_image</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n\n            <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">stack</span><span class=\"p\">((</span><span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">),</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"c1\"># In Keras, need to reshape\n</span>            <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>  <span class=\"c1\"># 1*80*80*4\n</span></code></pre></div></div>\n\n<h4 id=\"エピソードループ\">エピソードループ</h4>\n\n<p>終了フラグがセットされるまでループ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">done</span><span class=\"p\">:</span>\n</code></pre></div></div>\n\n<h5 id=\"現在の状態から行動を予測しシミュレータで実行\">現在の状態から行動を予測し、シミュレータで実行</h5>\n\n<p><code class=\"language-plaintext highlighter-rouge\">steering</code> ← 予測結果<br />\n<code class=\"language-plaintext highlighter-rouge\">env.step()</code>でシミュレータステップ実行<br />\n<code class=\"language-plaintext highlighter-rouge\">x_t1</code> ←ステップ実行後のカメラ画像<br />\n<code class=\"language-plaintext highlighter-rouge\">s_t1</code> ← 現在の入力データの一番古いものを削除し、今回の画像を追加</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"c1\"># Get action for the current state and go one step in environment\n</span>                <span class=\"n\">steering</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">get_action</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">)</span>\n                <span class=\"n\">action</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">steering</span><span class=\"p\">,</span> <span class=\"n\">throttle</span><span class=\"p\">]</span>\n                <span class=\"n\">next_obs</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">,</span> <span class=\"n\">info</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">(</span><span class=\"n\">action</span><span class=\"p\">)</span>\n\n                <span class=\"n\">x_t1</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">process_image</span><span class=\"p\">(</span><span class=\"n\">next_obs</span><span class=\"p\">)</span>\n\n                <span class=\"n\">x_t1</span> <span class=\"o\">=</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"mi\">1</span><span class=\"p\">)</span>  <span class=\"c1\"># 1x80x80x1\n</span>                <span class=\"n\">s_t1</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">x_t1</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">:,</span> <span class=\"p\">:</span><span class=\"mi\">3</span><span class=\"p\">],</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>  <span class=\"c1\"># 1x80x80x4\n</span></code></pre></div></div>\n\n<h5 id=\"experience-bufferに現在の状態を保存\">Experience Bufferに現在の状態を保存</h5>\n\n<p>ε値の更新も</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"c1\"># Save the sample <s, a, r, s'> to the replay memory\n</span>                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">replay_memory</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">linear_bin</span><span class=\"p\">(</span><span class=\"n\">steering</span><span class=\"p\">)),</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">s_t1</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">)</span>\n                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">update_epsilon</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h5 id=\"学習実行\">学習実行</h5>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n                    <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train_replay</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h5 id=\"ループ更新処理とステータス表示\">ループ更新処理とステータス表示</h5>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">s_t1</span>\n                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"n\">episode_len</span> <span class=\"o\">=</span> <span class=\"n\">episode_len</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">%</span> <span class=\"mi\">30</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span>\n                        <span class=\"s\">\"EPISODE\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">e</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"TIMESTEP\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ ACTION\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">action</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ REWARD\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">reward</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ EPISODE LENGTH\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">episode_len</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ Q_MAX \"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">max_Q</span><span class=\"p\">,</span>\n                    <span class=\"p\">)</span>\n</code></pre></div></div>\n<h5 id=\"ループ更新処理とステータス表示-1\">ループ更新処理とステータス表示</h5>\n\n<p><code class=\"language-plaintext highlighter-rouge\">agent.update_target_model()</code>でターゲットモデルの更新\n<code class=\"language-plaintext highlighter-rouge\">episodes.append(e)</code>はデバッグ用?</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"k\">if</span> <span class=\"n\">done</span><span class=\"p\">:</span>\n\n                    <span class=\"c1\"># Every episode update the target model to be same with model\n</span>                    <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">update_target_model</span><span class=\"p\">()</span>\n\n                    <span class=\"n\">episodes</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n\n                    <span class=\"c1\"># Save model for each episode\n</span>                    <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">save_model</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n\n                    <span class=\"k\">print</span><span class=\"p\">(</span>\n                        <span class=\"s\">\"episode:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">e</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"  memory length:\"</span><span class=\"p\">,</span>\n                        <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">),</span>\n                        <span class=\"s\">\"  epsilon:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">,</span>\n                        <span class=\"s\">\" episode length:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">episode_len</span><span class=\"p\">,</span>\n                    <span class=\"p\">)</span>\n</code></pre></div></div>\n<h4 id=\"エピソードループと学習ループの終わり\">エピソードループと学習ループの終わり</h4>\n<p>キーボード割り込み例外と終了処理</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">except</span> <span class=\"nb\">KeyboardInterrupt</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stopping run...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">finally</span><span class=\"p\">:</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">unwrapped</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"コマンドライン解析処理まわり\">コマンドライン解析処理まわり</h2>\n\n<p>コマンドライン解析処理とメインルーチンへのジャンプ</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n\n    <span class=\"c1\"># Initialize the donkey environment\n</span>    <span class=\"c1\"># where env_name one of:\n</span>    <span class=\"n\">env_list</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-roads-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-avc-sparkfun-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-roboracingleague-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-waveshare-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-minimonaco-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-warren-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-thunderhill-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-circuit-launch-track-v0\"</span><span class=\"p\">,</span>\n    <span class=\"p\">]</span>\n\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s\">\"ddqn\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--sim\"</span><span class=\"p\">,</span>\n        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span>\n        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"manual\"</span><span class=\"p\">,</span>\n        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\"</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--host\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"127.0.0.1\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"simulator address\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"rl_driver.h5\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"agent uses learned model to navigate env\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--port\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">9091</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for websockets\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--throttle\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.3</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"constant throttle for driving\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--env_name\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"name of donkey sim environment\"</span><span class=\"p\">,</span> <span class=\"n\">choices</span><span class=\"o\">=</span><span class=\"n\">env_list</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--epsilon\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"initial epsilon value\"</span><span class=\"p\">)</span>\n\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n    <span class=\"n\">run_ddqn</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"でもってこんな改造をするとちょびっと計算量が減る\">でもって、こんな改造をするとちょびっと計算量が減る</h2>\n<p>シミュレータに表示される車を変更してるのはご愛敬😅</p>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ddqn.py.old\t2021-12-02 06:25:02.149997073 +0900\n</span><span class=\"gi\">+++ ddqn.py\t2021-12-03 07:14:49.346378878 +0900\n</span><span class=\"p\">@@ -98,9 +98,10 @@</span>\n         return np.dot(rgb[..., :3], [0.299, 0.587, 0.114])\n \n     def process_image(self, obs):\n<span class=\"gd\">-        obs = self.rgb2gray(obs)\n-        obs = cv2.resize(obs, (img_rows, img_cols))\n-        return obs\n</span><span class=\"gi\">+        # obs1 = self.rgb2gray(obs)\n+        obs1 = cv2.dst = cv2.cvtColor(obs, cv2.COLOR_RGB2GRAY)\n+        obs2 = cv2.resize(obs1, (img_rows, img_cols))\n+        return obs2\n</span> \n     def update_target_model(self):\n         self.target_model.set_weights(self.model.get_weights())\n<span class=\"p\">@@ -108,13 +109,17 @@</span>\n     # Get action from model using epsilon-greedy policy\n     def get_action(self, s_t):\n         if np.random.rand() <= self.epsilon:\n<span class=\"gd\">-            return self.action_space.sample()[0]\n</span><span class=\"gi\">+            return self.action_space.sample()[0], 0\n</span>         else:\n             # print(\"Return Max Q Prediction\")\n             q_value = self.model.predict(s_t)\n \n<span class=\"gi\">+            max_q = np.amax(q_value[0])\n+            if self.max_Q < max_q :\n+                self.max_Q = max_q\n+\n</span>             # Convert q array to steering value\n<span class=\"gd\">-            return linear_unbin(q_value[0])\n</span><span class=\"gi\">+            return linear_unbin(q_value[0]), max_q\n</span> \n     def replay_memory(self, state, action, reward, next_state, done):\n         self.memory.append((state, action, reward, next_state, done))\n<span class=\"p\">@@ -136,16 +141,16 @@</span>\n         state_t, action_t, reward_t, state_t1, terminal = zip(*minibatch)\n         state_t = np.concatenate(state_t)\n         state_t1 = np.concatenate(state_t1)\n<span class=\"gd\">-        targets = self.model.predict(state_t)\n-        self.max_Q = np.max(targets[0])\n-        target_val = self.model.predict(state_t1)\n-        target_val_ = self.target_model.predict(state_t1)\n</span><span class=\"gi\">+\n+        targets = np.zeros((batch_size, 15))\n+        q_val = self.model.predict(state_t1)\n+        target_q_val = self.target_model.predict(state_t1)\n</span>         for i in range(batch_size):\n             if terminal[i]:\n                 targets[i][action_t[i]] = reward_t[i]\n             else:\n<span class=\"gd\">-                a = np.argmax(target_val[i])\n-                targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_val_[i][a])\n</span><span class=\"gi\">+                a = np.argmax(q_val[i])\n+                targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_q_val[i][a])\n</span> \n         self.model.train_on_batch(state_t, targets)\n \n<span class=\"p\">@@ -213,8 +218,8 @@</span>\n         \"exe_path\": args.sim,\n         \"host\": args.host,\n         \"port\": args.port,\n<span class=\"gd\">-        \"body_style\": \"donkey\",\n-        \"body_rgb\": (128, 128, 128),\n</span><span class=\"gi\">+        \"body_style\": \"f1\",\n+        \"body_rgb\": (255, 128, 128),\n</span>         \"car_name\": \"me\",\n         \"font_size\": 100,\n         \"racer_name\": \"DDQN\",\n<span class=\"p\">@@ -273,7 +278,7 @@</span>\n             while not done:\n \n                 # Get action for the current state and go one step in environment\n<span class=\"gd\">-                steering = agent.get_action(s_t)\n</span><span class=\"gi\">+                steering, max_Q = agent.get_action(s_t)\n</span>                 action = [steering, throttle]\n                 next_obs, reward, done, info = env.step(action)\n \n<span class=\"p\">@@ -305,7 +310,7 @@</span>\n                         \"/ EPISODE LENGTH\",\n                         episode_len,\n                         \"/ Q_MAX \",\n<span class=\"gd\">-                        agent.max_Q,\n</span><span class=\"gi\">+                        max_Q,\n</span>                     )\n \n                 if done:\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</h1>\n      <p>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>SDカードのアクセスが遅いのと、USBドライブの方が大容量のメディアを入手しやすいので\nUSBドライブをブートデバイスに変更してみる。</p>\n\n<p>といっても、Jetpack4.5以降ではブートローダがUSBからのブートをサポートしたので、かなり簡単になった。</p>\n\n<p>Jetpack4.4のときのメモは<a href=\"/memoBlog/2020/10/30/Jetson_usb_boot.html\" target=\"_blank\">Jetson nano をUSBドライブからブートできるようにする</a> にあります。</p>\n\n<h1 id=\"ディスクイメージの書き込み\">ディスクイメージの書き込み</h1>\n<p>通常セットアップを行ったSDカードのディスクイメージをUSBドライブにコピーします。\nSDカード→USBドライブ直接でも構いませんし、バックアップとして作成したディスクイメージファイルからでも構いません。</p>\n\n<p>ubuntu PCでディスクイメージファイルからコピーする場合はこんな感じ。<br />\n<code class=\"language-plaintext highlighter-rouge\">/dev/sdc</code> の部分は環境により異なるので注意(間違って他のディスクに上書きしないように!!)。<br />\n<code class=\"language-plaintext highlighter-rouge\">jetpack46_XXXXXXXX.img</code>がディスクイメージファイルのファイル名です。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"nv\">of</span><span class=\"o\">=</span>/dev/sdc <span class=\"k\">if</span><span class=\"o\">=</span>jetpack46_XXXXXXXX.img <span class=\"nv\">bs</span><span class=\"o\">=</span>1M <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div></div>\n\n<h1 id=\"bootデバイス変更のための設定\">BOOTデバイス変更のための設定</h1>\n\n<p>ディスクイメージを書き込んたUSBドライブをSDカードブートした Jetson nano や ubuntu PCに接続し、\n設定ファイルを書き換えます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ディスクのマウント</span>\n<span class=\"nb\">sudo </span>mount /dev/sdc1 /mnt\n<span class=\"nb\">cd</span> /mnt/boot/extlinux/\n<span class=\"c\"># オリジナルファイルのバックアップ</span>\n<span class=\"nb\">sudo cp </span>extlinux.conf extlinux.conf.mmc\n<span class=\"c\"># 編集</span>\n<span class=\"nb\">sudo </span>vi extlinux.conf\n</code></pre></div></div>\n\n<p>以下のように変更します\n具体的には<code class=\"language-plaintext highlighter-rouge\">/mnt/boot/extlinux/extlinux.conf</code> 内の \n<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0p1</code>を<code class=\"language-plaintext highlighter-rouge\">/dev/sda1</code>に変更します。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- extlinux.conf.mmc\t2021-09-14 06:02:45.889520568 +0900\n</span><span class=\"gi\">+++ extlinux.conf\t2021-09-14 06:03:29.453873117 +0900\n</span><span class=\"p\">@@ -7,7 +7,7 @@</span>\n       MENU LABEL primary kernel\n       LINUX /boot/Image\n       INITRD /boot/initrd\n<span class=\"gd\">-      APPEND ${cbootargs} loglevel=6 root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 ipv6.disable=1\n</span><span class=\"gi\">+      APPEND ${cbootargs} loglevel=6 root=/dev/sda1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 ipv6.disable=1\n</span> \n # When testing a custom kernel, it is recommended that you create a backup of\n # the original kernel and add a new entry to this file so that the device can\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nrootパラメータはパーティションのUUIDを書いておくのが最近の作法らしいが\n大抵 マウント先は <code class=\"language-plaintext highlighter-rouge\">/dev/sda1</code> なので、お手軽にこっちで指定する。</p>\n</blockquote>\n\n<h1 id=\"ついでに設定\">ついでに設定</h1>\n<p>ついでにパーティションサイズも変更しておくと良いです。</p>\n\n<h1 id=\"boot\">BOOT</h1>\n<p>あとはJetson nano にUSBドライブを接続し、元々ブートに使用していた<strong>SDカードを取り外し</strong>て電源ON。</p>\n\n<p>起動後、USBドライブがrootにマウントされていることを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">mount</code>で確認しても良いけど、いっぱい出てきて鬱陶しいので<code class=\"language-plaintext highlighter-rouge\">df</code>で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">df</span> <span class=\"nt\">-h</span> /\n</code></pre></div></div>\n<p>こんな感じで行頭にマウント元が表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Filesystem      Size  Used Avail Use% Mounted on\n/dev/sda1       108G   13G   91G  13% /\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</h1>\n      <p>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/09/13/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする(Jetpack4.6)</a>\nではVNCにvinoをインストールしましたが、vinoはキー入力/画面描画のレスポンスがかなり遅く、\n結構なストレスになります。<br />\nそこで、代わりに<a href=\"https://tigervnc.org/\">tigerVNC</a>をインストールしてみます。</p>\n\n<p>最初に結論を書いておきますが、レスポンスはvinoより良くなるのですが、クリップボードの共有\n(ホスト/ターゲット間でのコピペ)ができないので、普段使いにはあまり使い勝手が良くありません。<br />\ngithubのリポジトリもずいぶん前から更新されていないみたいなので、今後改善される可能性も低そうです。<br />\nなので、私は使っていません(^^ゞ</p>\n\n<h1 id=\"前準備\">前準備</h1>\n<p>vinoをセットアップしてある場合は停止しておいてください。<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.config/autostart/vino-server.desktop</code> を削除しておけば大丈夫でしょう。<br />\n以下、vinoのセットアップは行っていないものとして記載します。</p>\n\n<h1 id=\"tigervncの設定\">tigerVNCの設定</h1>\n\n<h2 id=\"tiger-vnc-のインストール\">tiger VNC のインストール</h2>\n<p>必要なプログラムをインストールします</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tigervnc-standalone-server tigervnc-scraping-server\n</code></pre></div></div>\n\n<h2 id=\"vncのパスワードの設定\">VNCのパスワードの設定</h2>\n<p>接続パスワードを設定します</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vncpasswd\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">Password:</code>と<code class=\"language-plaintext highlighter-rouge\">Verify:</code>で設定するパスワードを入力<br />\n<code class=\"language-plaintext highlighter-rouge\">Would you like to enter a view-only password (y/n)?</code>には <code class=\"language-plaintext highlighter-rouge\">n</code>を入力<br />\nVNCクライアントから接続する際にこのパスワードを入力します</p>\n\n<h2 id=\"自動loginの設定\">自動loginの設定</h2>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定します</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h2 id=\"解像度の設定\">解像度の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n<h2 id=\"ここで一旦リブートする\">ここで一旦リブートする</h2>\n<p>リブートしないと下の単体テストで「displayがopenできない」とエラーになる模様。</p>\n\n<h2 id=\"手動で動かしてみる画面のミラーリング\">手動で動かしてみる(画面のミラーリング)</h2>\n\n<p>動作確認として、サーバを手動で起動してみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>x0vncserver <span class=\"nt\">-display</span> :0 <span class=\"nt\">-passwordfile</span> ~/.vnc/passwd\n</code></pre></div></div>\n\n<p>サーバが起動したら、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続します。</p>\n\n<p>正常に設定できていればVNCクライアントにデスクトップが表示されます。</p>\n\n<h2 id=\"自動起動の設定\">自動起動の設定</h2>\n<p>逐一<code class=\"language-plaintext highlighter-rouge\">x0vncserver</code>を起動するのは面倒なので、自動で起動するように設定しておきます。</p>\n\n<p>参考: <a href=\"https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f\">https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/systemd/system/x0vncserver.service</code> を以下の内容で作成します。<br />\nただし、<code class=\"language-plaintext highlighter-rouge\">XXXXXXXX</code>の部分は 自分のユーザ名に置き換えてください。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Remote desktop service (VNC)\nAfter=syslog.target\nAfter=network.target remote-fs.target nss-lookup.target\nAfter=x11-common.service \n\n[Service]\nType=forking\nUser=XXXXXXXX\nGroup=XXXXXXXX\nWorkingDirectory=/home/XXXXXXXX\nExecStart=/bin/sh -c 'sleep 10 && /usr/bin/x0vncserver -display :0  -rfbport 5900 -passwordfile /home/XXXXXXXX/.vnc/passwd &'\n\n[Install]\nWantedBy=multi-user.target\n</code></pre></div></div>\n\n<h2 id=\"サービスの起動と確認\">サービスの起動と確認</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl start x0vncserver\n<span class=\"nb\">sudo </span>systemctl status x0vncserver\n</code></pre></div></div>\n\n<p>以下のように出力されることを確認します</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>● x0vncserver.service - Remote desktop service (VNC)\n   Loaded: loaded (/etc/systemd/system/x0vncserver.service; enabled; vendor pres\n   Active: active (running) since Fri 2021-09-03 11:08:07 JST; 8s ago\n  Process: 14646 ExecStart=/bin/sh -c sleep 10 && /usr/bin/x0vncserver -display ・・・・\n Main PID: 14659 (sh)\n    Tasks: 2 (limit: 4172)\n   CGroup: /system.slice/x0vncserver.service\n           ├─14659 /bin/sh -c sleep 10 && /usr/bin/x0vncserver -display :0  ・・・・\n           └─14666 sleep 10\n\n 9月 03 11:08:07 jetson systemd[1]: Starting Remote desktop service (VNC)...\n 9月 03 11:08:07 jetson systemd[1]: Started Remote desktop service (VNC).\n</code></pre></div></div>\n\n<h2 id=\"サービスの有効化\">サービスの有効化</h2>\n<p>起動時に自動実行されるように、サービスの有効化を行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl <span class=\"nb\">enable </span>x0vncserver\n</code></pre></div></div>\n\n<h2 id=\"リブート\">リブート</h2>\n\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続します。</p>\n\n<p>正常に起動できていればVNCクライアントにデスクトップが表示されます。</p>\n\n<h1 id=\"別のやり方参考\">別のやり方(参考)</h1>\n<p>ディスプレイとは別のデスクトップを表示する場合は以下の手順で。<br />\nここではwindow managerにlxdeを使用していますので、モニタ表示とは異なる見た目になりますし、\nウィンドウマネージャの設定も同じではありません。</p>\n\n<p>参考:<a href=\"https://forums.developer.nvidia.com/t/how-to-setup-tigervnc-on-jetson-nano/174244\">https://forums.developer.nvidia.com/t/how-to-setup-tigervnc-on-jetson-nano/174244</a></p>\n\n<p>一回試しただけ(ちゃんとメモってなかった)なので、抜けとかあるかも。</p>\n\n<h2 id=\"tiger-vnc-のインストール-1\">Tiger VNC のインストール</h2>\n<p>必要なプログラムをインストールします</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tigervnc-standalone-server\n</code></pre></div></div>\n\n<h2 id=\"vncのパスワードの設定-1\">VNCのパスワードの設定</h2>\n<p>接続パスワードを設定します</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vncpasswd\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">Password:</code>と<code class=\"language-plaintext highlighter-rouge\">Verify:</code>で設定するパスワードを入力<br />\n<code class=\"language-plaintext highlighter-rouge\">Would you like to enter a view-only password (y/n)?</code>には <code class=\"language-plaintext highlighter-rouge\">n</code>を入力<br />\nVNCクライアントから接続する際にこのパスワードを入力します</p>\n\n<h2 id=\"自動loginの設定-1\">自動loginの設定</h2>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定します</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h2 id=\"解像度の設定-1\">解像度の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n\n<h2 id=\"vncxstartup-の作成\">~/.vnc/xstartup の作成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.vnc/xstartup</code> を以下の内容で作成します<br />\nXXXXXXXX は 自分のユーザ名に置き換えてください</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">!</span>/bin/sh\n<span class=\"nb\">export </span><span class=\"nv\">XDG_RUNTIME_DIR</span><span class=\"o\">=</span>/run/user/1000\n<span class=\"nb\">export </span><span class=\"nv\">XKL_XMODMAP_DISABLE</span><span class=\"o\">=</span>1\n<span class=\"nb\">unset </span>SESSION_MANAGER\n<span class=\"nb\">unset </span>DBUS_SESSION_BUS_ADDRESS\nxrdb /home/XXXXXXXX/.Xresources\nxsetroot <span class=\"nt\">-solid</span> grey\ngnome-session &\nstartlxde &\n</code></pre></div></div>\n\n<p>実行属性を付けます</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod </span>755 ~/.vnc/xstartup\n</code></pre></div></div>\n\n<h2 id=\"xresources-ファイルの作成\">.Xresources ファイルの作成</h2>\n<p>.Xresources ファイルを作成します</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">touch</span> ~/.Xresources\n</code></pre></div></div>\n\n<h2 id=\"vncの自動起動の設定\">VNCの自動起動の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/systemd/system/vncserver@.service</code>を以下の内容で作成します<br />\nXXXXXXXX は 自分のユーザ名に置き換えてください</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Start TigerVNC Server at startup\nAfter=syslog.target network.target\n\n[Service]\nType=forking\nUser=XXXXXXXX\nGroup=XXXXXXXX\nWorkingDirectory=/home/XXXXXXXX\nPIDFile=/home/XXXXXXXX/.vnc/%H:%i.pid\nExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1\nExecStart=/usr/bin/vncserver :%i -depth 24 -geometry 1920x1080 -nolisten tcp\n\nExecStop=/usr/bin/vncserver -kill :%i\n\n[Install]\nWantedBy=multi-user.target\n</code></pre></div></div>\n\n<h2 id=\"リモートからのアクセス許可\">リモートからのアクセス許可</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/vnc.conf</code> に以下を追記してリモートアクセスを許可します</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$localhost = “no”;\n</code></pre></div></div>\n\n<h2 id=\"systemctl-enable-の代わりにシンボリックリンクの作成\">systemctl enable の代わりにシンボリックリンクの作成</h2>\n<p>参照元がこうなってたので。<br />\n<code class=\"language-plaintext highlighter-rouge\">sudo systemctl enable vncserver@</code>でも良い気がするけど。ここのファイル名でポート番号決めてる?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /etc/systemd/system/multi-user.target.wants/\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /etc/systemd/system/vncserver@.service vncserver@1.service\n</code></pre></div></div>\n\n<h2 id=\"リブートする\">リブートする</h2>\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5901に接続します。<br />\n(VNCクライアントの接続先に<code class=\"language-plaintext highlighter-rouge\">«JetsonのIPアドレス»:5901</code> を指定します)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をセットアップする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をセットアップする(Jetpack4.6)</h1>\n      <p>Jetson nano をセットアップする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Nvidiaの<a href=\"https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/\">Jetson nano</a>をセットアップしたときのメモ<br />\nJetpack4.4のときのメモは<a href=\"/memoBlog/2020/10/23/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする</a> にあります。</p>\n\n<h1 id=\"参照先\">参照先</h1>\n<ul>\n  <li><a href=\"https://monoist.atmarkit.co.jp/mn/articles/1905/30/news029.html\">「Jetson Nano」の電源を入れて立ち上げる</a>\n    <ul>\n      <li>わりと詳しく書いてある</li>\n    </ul>\n  </li>\n  <li><a href=\"https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit\">Getting Started With Jetson Nano Developer Kit </a>\n    <ul>\n      <li>本家</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"シリアルコンソールの使用\">シリアルコンソールの使用</h1>\n<p>シリアルコンソールが必要なら接続できる。<br />\n特に設定等は必要ない。  <br />\n接続端子は以下を参照</p>\n<ul>\n  <li><a href=\"https://www.jetsonhacks.com/2019/04/19/jetson-nano-serial-console/\">Jetson Nano – Serial Console</a>\nの 「Wiring」の下の「Jetson Nano B01」を参照。</li>\n</ul>\n\n<p>シリアルポートの設定は115200bps/8bit/none/1bit/none</p>\n\n<p>その他、コネクタ類の配置が分かりにくい場合は、\n<a href=\"https://developer.download.nvidia.com/assets/embedded/secure/jetson/Nano/docs/NV_Jetson_Nano_Developer_Kit_User_Guide.pdf?yIbsUqvBKxI1G6r3WW7cOdheZGv2-eSfaFW_kMt3dSgi0NJ7h77OwFHr5b-rquc3IX7Tyrt8FV6IKD4DHqvP4_LzhWt55tb071gqXlNGwBPYCOC5pnEKAla8D-B82bPjhQMykANFyn-EhxZRHC8AIBYWuVwwwXVPWtCOjs34Tg50oBdN0vBNoyUlZMRFXLNJ2to\">JETSON NANO DEVELOPER KIT</a>\nのP22 に<strong>Developer kit module and carrier board: rev B01 top view</strong>として配置図が掲載されているので参照のこと。</p>\n\n<h1 id=\"sdカードの作成firstboot\">SDカードの作成~FirstBoot</h1>\n<p>基本的に参照先の通り。<br />\n<a href=\"https://developer.nvidia.com/embedded/downloads\">https://developer.nvidia.com/embedded/downloads</a>\nから「Jetson Nano Developer Kit SD Card Image」  の Version 「4.6」 をダウンロード<br />\n(他のバージョンが必要ならそのバージョンで)</p>\n\n<p>ファーストブートで設定が終わったら、何はともあれ最新版にアップデート。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ここで一旦リブートしておく。</p>\n\n<h1 id=\"sshでの接続\">SSHでの接続</h1>\n<p>特に設定などは必要ない。<br />\nTeraTermなどで接続すれば良い。\nUbuntuではmDNSが動いているので、«マシン名».localでアクセスできる。</p>\n\n<p>TeraTerm使用時のコマンドは以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\"C:\\Program Files (x86)\\teraterm\\ttermpro.exe\" /auth=password /user=«ユーザ名» /passwd=«パスワード» «JetsonのIPアドレス or マシン名.local»\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nSSHやmDNSは立ち上がるまで少し時間がかかるみたいなので、<br />\n起動後数十秒程度待ってから接続した方が良い。</p>\n</blockquote>\n\n<h2 id=\"ssh接続がタイムアウトする対策\">SSH接続がタイムアウトする対策</h2>\n<p>SSH接続したターミナルを触らずにしばらく置いておくと、タイムアウトしてクローズされてしまう。\nこれを防ぐにはクライアント側からkeep-aliveパケットを定期的に送信してやれば良いらしい。</p>\n\n<p>Teratermの場合、「設定」→「SSH」→「ハートビート(keep-alive)」を「8」とかに設定し、保存。\n次回接続時はこの保存した設定ファイルを読み込む</p>\n\n<h1 id=\"初期設定\">初期設定</h1>\n<h2 id=\"bashrcの修正\">.bashrcの修正</h2>\n<p>.bashrcの修正をお好みで。<br />\n以下は設定例</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> resize <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># numpy 1.19.5 のimportでcore dumpする対策</span>\n<span class=\"nb\">export </span><span class=\"nv\">OPENBLAS_CORETYPE</span><span class=\"o\">=</span>ARMV8\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"c\"># export PYTHON_CONFIGURE_OPTS=\"--enable-ipv6\\</span>\n    <span class=\"c\">#     --enable-unicode=ucs4\\</span>\n    <span class=\"c\">#     --enable-shared\\</span>\n    <span class=\"c\">#     --with-dbmliborder=bdb:gdbm\\</span>\n    <span class=\"c\">#     --with-system-expat\\</span>\n    <span class=\"c\">#     --with-system-ffi\\</span>\n    <span class=\"c\">#     --with-fpectl\"</span>\n    <span class=\"c\"># Ubuntu向け対策</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vim\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># venvの仮想環境名を表示するための設定</span>\n    show_virtual_env<span class=\"o\">()</span> <span class=\"o\">{</span>\n      <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"s2\">)\"</span>\n      <span class=\"k\">fi</span>\n    <span class=\"o\">}</span>\n    <span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s1\">'$(show_virtual_env)'</span><span class=\"nv\">$PS1</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># DISPLAYが未定義なら設定する</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-z</span> <span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n    <span class=\"k\">fi\nfi</span>\n</code></pre></div></div>\n\n<h2 id=\"不要なソフトのアンインストール\">不要なソフトのアンインストール</h2>\n<p>使わないのでアンインストールしておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\n</code></pre></div></div>\n\n<h2 id=\"guiの動作の設定変更をお好みで\">GUIの動作の設定変更をお好みで</h2>\n<!--\n「ウィンドウが勝手に最大化するのをやめる」はOK\n「ウィンドウにマウスを乗せるとフォーカスされるようにする」で \"focus-mode\" は 'mouse' ではなく 'sloppy'\n「デスクトップからゴミ箱とホームを消す」は項目としてないらしい\n「Dockのカスタマイズ」は設定できるけど有効でない?\n「マウスカーソルを大きくする」は設定できるけど有効でない?リブートすると元に戻る?\nwindowの閉じるボタンなどを右に移動するにはgnome-tweaskでWindowsのTitlebar Buttons を設定する → 反映されず\n「CAPSキーをCtrlキーに変更」はOK\n-->\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.mutter auto-maximize\ngsettings get org.gnome.mutter edge-tiling\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.desktop.wm.preferences auto-raise \ngsettings get org.gnome.desktop.wm.preferences focus-mode \ngsettings get org.gnome.desktop.wm.preferences raise-on-click\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode sloppy\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"capsキーをctrlキーに変更\">CAPSキーをCtrlキーに変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.input-sources xkb-options\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.input-sources xkb-options <span class=\"se\">\\[\\'</span>ctrl:nocaps<span class=\"se\">\\'\\]</span>\n\n<span class=\"c\"># 設定を有効にするにはGUIでのlogout&再loginが必要</span>\n\n</code></pre></div></div>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>IPv6を無効化したい場合は、\n/<code class=\"language-plaintext highlighter-rouge\">boot/extlinux/extlinux.conf</code>の<code class=\"language-plaintext highlighter-rouge\">APPEND</code>の行の最後に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加してリブートする<br />\n参考: <a href=\"https://www.rough-and-cheap.jp/ubuntu/ubuntu18_04_howto_diseable_ipv6/\" target=\"_blank\">Ubuntu 18.04 で ipv6 を無効にする</a></p>\n<blockquote>\n  <p>[!NOTE]\ngrubではなく、U-Bootなので設定するところが違う</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSysctl の設定ではうまくいかなかった。</p>\n</blockquote>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work\n</code></pre></div></div>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<h3 id=\"インストール\">インストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<h3 id=\"設定ファイル\">設定ファイル</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<h3 id=\"ユーザの追加と再起動\">ユーザの追加と再起動</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"vncサーバvinoの設定\">VNCサーバ(vino)の設定</h2>\n<p>参考: <a href=\"https://zenn.dev/tunefs/articles/9774eb8f229e1bf97a8c\">https://zenn.dev/tunefs/articles/9774eb8f229e1bf97a8c</a>\n以下、参考先をベースに説明</p>\n\n<h3 id=\"vinoのインストール\">Vinoのインストール</h3>\n<p>インストール済みなので不要</p>\n\n<h3 id=\"vinoの自動起動の設定\">Vinoの自動起動の設定</h3>\n<p>コピー先ディレクトリは作成済み</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> /usr/share/applications/vino-server.desktop ~/.config/autostart/\n</code></pre></div></div>\n\n<h3 id=\"vinoのコンフィグレーション\">Vinoのコンフィグレーション</h3>\n<p>実行は以下のみでOK</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.Vino prompt-enabled <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false</span>\n</code></pre></div></div>\n<p>以下は不要</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>set org.gnome.Vino authentication-methods は \"['vnc']\" でなく \"['none']\"   デフォルトと同じなので不要\ngsettings set org.gnome.Vino vnc-password $(echo -n 'thepassword'|base64) は不要\n</code></pre></div></div>\n\n<h3 id=\"自動loginの設定\">自動loginの設定</h3>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定する</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h3 id=\"解像度の設定\">解像度の設定</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n\n<h3 id=\"リブートする\">リブートする</h3>\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続する。</p>\n\n<h3 id=\"設定メニューを表示できるようにする\">設定メニューを表示できるようにする</h3>\n<p>上記だけで設定は完了するが、設定メニュー(Settings)から設定しようとするとエラーになるので、\nそれを修正しておく(やらなくても設定メニュー使わなければ問題ない)。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml</code>に以下のパッチを当てる</li>\n</ul>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  /tmp/a.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- org.gnome.Vino.gschema.xml.org      2020-10-19 06:21:32.034728957 +0900\n</span><span class=\"gi\">+++ org.gnome.Vino.gschema.xml  2020-10-19 06:22:30.887994965 +0900\n</span><span class=\"p\">@@ -154,5 +154,14 @@</span>\n       </description>\n       <default>true</default>\n     </key>\n<span class=\"gi\">+    <key name='enabled' type='b'>\n+      <summary>Enable remote access to the desktop</summary>\n+        <description>\n+          If true, allows remote access to the desktop via the RFB\n+          protocol. Users on remote machines may then connect to the\n+          desktop using a VNC viewer.\n+        </description>\n+      <default>false</default>\n+    </key>\n</span>   </schema>\n </schemalist>\n</code></pre></div></div>\n\n<ul>\n  <li>パッチを当てるコマンド\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>patch /usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml /tmp/a.patch\n</code></pre></div>    </div>\n  </li>\n  <li>さらにコンパイルが必要\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>glib-compile-schemas /usr/share/glib-2.0/schemas\n</code></pre></div>    </div>\n  </li>\n  <li>これで「settings」から「Desktop Sharing」が実行できるようになる</li>\n</ul>\n\n<h2 id=\"使用率等の確認ツールのインストールと起動\">使用率等の確認ツールのインストールと起動</h2>\n\n<p>pyenvインストール済みのときは念のため<code class=\"language-plaintext highlighter-rouge\">pyenv shell system</code>しておく。<br />\nvenv環境使用時はデアクティベートしておく。<br />\n(sudo付きで実行してるのでsystemのpython3が使用されるハズだけど)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip\n<span class=\"nb\">sudo </span>pip3 <span class=\"nb\">install </span>jetson-stats\n<span class=\"nb\">sudo </span>jtop \n</code></pre></div></div>\n<p>一度再起動したあとは、<code class=\"language-plaintext highlighter-rouge\">sudo</code>なしの<code class=\"language-plaintext highlighter-rouge\">jtop</code>のみで実行可能。</p>\n<blockquote>\n  <p>[!NOTE]\njtopは結構CPUパワーを喰うので、性能評価等の間は止めておくのが無難と思われる。</p>\n</blockquote>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"sdカードのイメージファイル化\">SDカードのイメージファイル化</h1>\n<p><a href=\"/memoBlog/2021/07/18/sd_image_2.html\" target=\"_blank\">Raspbian SDカードイメージファイルの作成(改訂版)</a>を参照。</p>\n\n<h1 id=\"イメージのコピーからの起動\">イメージのコピーからの起動</h1>\n<h2 id=\"縮小されたパーティションを拡張する\">縮小されたパーティションを拡張する</h2>\n<p>バックアップはパーティションが縮小されているので、拡張する。<br />\n上記参照先の拡張方法ではうまくいかない(JetsonはパーティションがGPTだから?)。<br />\nなので、GUIツールのgpartedを使用して拡張する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gparted\n<span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0       <span class=\"c\"># sshから実行するときはXserverが起動しているマシンをDISPLAY変数に設定</span>\n<span class=\"nb\">sudo </span>gparted /dev/mmcblk0\n</code></pre></div></div>\n\n<ul>\n  <li>Libparted Warning ダイアログで”Not all of the space available to ~”と出たらFixをクリック</li>\n  <li>Libparted Warning ダイアログで”The backup GPT table is corrupt, but the primary appears OK, so that will be used.”と出たらOKをクリック</li>\n  <li>以降も何度か出るが、以下の操作がすべて終わればbackup GPTが新たに作成されるので問題なし。\n    <ul>\n      <li>(これは、ディスクイメージを縮小したときにgdiskコマンドを実行しなかった場合に出ます)</li>\n    </ul>\n  </li>\n  <li>図の«SDカードのパーティション» を右クリック→「Resize/Move」をクリック\n    <ul>\n      <li>「New size」の欄に上にある「Maximum size」以下の値を入力(「Free space following」 に残したいサイズを入れても可)</li>\n      <li>他の入力欄をクリックして自動計算を反映</li>\n      <li>「Resize」をクリック\n-「Edit」→「Apply All Operations」をクリック</li>\n      <li>「Are you sure you want to apply the pending operations?」と聞かれるので、「Apply」をクリック</li>\n    </ul>\n  </li>\n  <li>処理が完了したら閉じるボタンでプログラム終了</li>\n</ul>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"venvによるpython-仮想環境の構築\">venvによるpython 仮想環境の構築</h1>\n<p>いつもはpyenv + virtualenv で環境構築しているが、この環境ではプリインストールされた opencv を使用できないらしい(core dumpする)。<br />\nなので、system上のpythonを使用してvenvで仮想環境を構築して使用するようにしてみた。<br />\n(これ、↓のnumpyの問題かも。でもtensorflowはpython3.6でないとダメだから、pyenv引っ張ってこなくてもいいか。)</p>\n\n<h2 id=\"venvのインストール\">venvのインストール</h2>\n<p>venv使用のためのプログラムをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-venv\n</code></pre></div></div>\n\n<h2 id=\"仮想環境の構築\">仮想環境の構築</h2>\n<p>仮想環境を構築する。<br />\nここで実行したpythonが仮想環境で実行されるpythonになる。<br />\n<code class=\"language-plaintext highlighter-rouge\">--system-site-packages</code> を付加しておくと元のパッケージも参照される。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> «venv_dir»\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">pip list/freeze</code> でも参照される。pipのバージョンが新しければ、<code class=\"language-plaintext highlighter-rouge\">pip -v list</code>と オプション<code class=\"language-plaintext highlighter-rouge\">-v</code>を付けることで インストール先を見分けることでどちらにインストールされているかが判別できる。</p>\n\n<p>例えばこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/TF2.5\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート\">仮想環境のアクティベート</h2>\n<p>pyenvではlocalで指定してあればディレクトリ移動で自動的に仮想環境を切り替えられたが、<br />\nvenvでは逐一仮想環境をアクティベートしなければならない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> «venv_dir»/bin/bin/activate\n</code></pre></div></div>\n\n<h2 id=\"お約束\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"仮想環境の終了\">仮想環境の終了</h2>\n<p>仮想環境を終了するときは以下のコマンドでデアクティベートする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>deactivate\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">deactivate</code>はアクティベート時に関数として登録されている<br />\n下記のようにdirenvで設定した場合は<code class=\"language-plaintext highlighter-rouge\">deactivate</code>は使えないが、ディレクトリから移動すれば元にもどるので問題ない</p>\n</blockquote>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"direnvのインストールと設定\">direnvのインストールと設定</h1>\n<p>仮想環境管理をvenvで行うようにしたが、venvだと逐一activateしないといけないので、pyenvに慣れたカラダでは なかなか 使いにくい。<br />\nそこで、direnvを使ってpyenvに近い使い勝手を実現してみる。</p>\n\n<p>参考:<a href=\"https://yoshitaku-jp.hatenablog.com/entry/2018/07/29/070000\">direnvを使って、source bin/activateを自動化する</a></p>\n\n<h2 id=\"インストール-1\">インストール</h2>\n<p>インストールは<code class=\"language-plaintext highlighter-rouge\">apt</code>でイッパツ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>direnv\n</code></pre></div></div>\n\n<h2 id=\"初期設定-1\">初期設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code> に以下の内容を追記。(上記<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>例では記載済み)<br />\nエディタはvimに設定してあるが、別のものを使いたければ設定変更のこと。<br />\n(direnv 未インストール時は設定はスキップされる)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vim\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># venvの仮想環境名を表示するための設定</span>\n    show_virtual_env<span class=\"o\">()</span> <span class=\"o\">{</span>\n      <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"s2\">)\"</span>\n      <span class=\"k\">fi</span>\n    <span class=\"o\">}</span>\n    <span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s1\">'$(show_virtual_env)'</span><span class=\"nv\">$PS1</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">source ~/.bashrc</code> するか、terminalを開きなおす。</p>\n\n<h2 id=\"対象ディレクトリに処理を登録する\">対象ディレクトリに処理を登録する</h2>\n<p>対象ディレクトリに移動して<code class=\"language-plaintext highlighter-rouge\">direnv edit .</code> を実行して中身を作成するか、 <code class=\"language-plaintext highlighter-rouge\">.envrc</code>を直接生成する。</p>\n\n<p>中身は以下の通り<br />\n他にも設定したい環境変数があれば設定しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> «venv_dir»/bin/activate\n</code></pre></div></div>\n<p>例えばこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/TF2.5/bin/activate\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">direnv: error .envrc is blocked. Run `direnv allow` to approve its content.</code>と言われたら、以下のように実行する。<br />\n(直接編集した時に言われるらしい)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>direnv allow\n</code></pre></div></div>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"tensorflow2-のインストール\">tensorflow2 のインストール</h1>\n<h2 id=\"仮想環境の構築-1\">仮想環境の構築</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/TF2.5\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート-1\">仮想環境のアクティベート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/TF2.5/bin/activate\n</code></pre></div></div>\n<p>またはdirenvで上記が実行されるように設定しておく</p>\n\n<h2 id=\"お約束-1\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<p>tensorflowをimportしたとき(具体的にはその中でnumpyをimportしたとき)に\n<code class=\"language-plaintext highlighter-rouge\">Illegal instruction (core dumped)</code>が発生する。<br />\nこれを回避するため、以下を<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に設定しておく(上記<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>例では記載済み) 。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">OPENBLAS_CORETYPE</span><span class=\"o\">=</span>ARMV8\n</code></pre></div></div>\n\n<p>tensoorflowはpypiではなく、nvidiaのサイトからダウンロードしてインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>https://developer.download.nvidia.com/compute/redist/jp/v46/tensorflow/tensorflow-2.5.0+nv21.7-cp36-cp36m-linux_aarch64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nn5pyインストールでエラーになった時は以下の手順で回避する。  <br />\nミソはh5pyのインストール時点でnumpy 1.19.5がインストールされているとエラーになるので、<br />\n一時的にnumpyのそれ以前のバージョンをインストールしてh5pyをインストールし、その後numpyを本来のバージョンに戻す。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libhdf5-serial-dev hdf5-tools libhdf5-dev\npip <span class=\"nb\">install </span>cython\n<span class=\"c\"># numpyのバージョン下げる  </span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">numpy</span><span class=\"o\">==</span>1.19.3\npip <span class=\"nb\">install </span><span class=\"nv\">h5py</span><span class=\"o\">==</span>2.10.0\n<span class=\"c\"># h5pyのインストールのためにインストールしたnumpyを本来のバージョンに更新  </span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">numpy</span><span class=\"o\">==</span>1.19.5\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"tensorflowなどのありか\">Tensorflowなどのありか</h2>\n<p>以下に色々まとめられている。<br />\n<a href=\"https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime\">https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime</a></p>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"onnx-runtimeのインストール\">onnx-runtimeのインストール</h1>\n<h2 id=\"仮想環境の構築-2\">仮想環境の構築</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/onnx\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート-2\">仮想環境のアクティベート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/onnx/bin/activate\n</code></pre></div></div>\n<p>またはdirenvで上記が実行されるように設定しておく</p>\n\n<h2 id=\"お約束-2\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"インストールファイルのダウンロード\">インストールファイルのダウンロード</h2>\n<p><a href=\"https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime\" target=\"_blank\">Jetson Zoo</a>\nから使用環境に対応するインストールファイルをダウンロードする。<br />\n表の下にあるコマンド例の<code class=\"language-plaintext highlighter-rouge\">wget</code>ではうまくダウンロードできないのでブラウザでダウンロードしてコピっておく。<br />\n以下、onnxruntime 1.8.0/Python 3.6 を選択したものとする。</p>\n\n<h2 id=\"インストール-2\">インストール</h2>\n\n<p>システムにインストールされたprotobufのバージョンが古くてエラーになるので、\nあらかじめ最新版にアップデートしておく。<br />\n(venv環境なので、システムのprotobufには影響ない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> protobuf\n</code></pre></div></div>\n\n<p>ダウンロードしたonnx-runtimeをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>onnxruntime_gpu-1.8.0-cp36-cp36m-linux_aarch64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tensorflowの転移学習に関するメモ</title>\n  </head>\n  <body>\n    <header>\n      <h1>tensorflowの転移学習に関するメモ</h1>\n      <p>tensorflowの転移学習を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"tensorflow-1xでのssdの転移学習の例\">tensorflow 1.XでのSSDの転移学習の例</h1>\n\n<p><a href=\"https://github.com/ippei8jp/tf1_TransferLearning\" target=\"_blank\">https://github.com/ippei8jp/tf1_TransferLearning</a></p>\n\n<h1 id=\"tensorflow-2xでのssdの転移学習の例\">tensorflow 2.XでのSSDの転移学習の例</h1>\n\n<p><a href=\"https://github.com/ippei8jp/tf2_TransferLearning\" target=\"_blank\">https://github.com/ippei8jp/tf2_TransferLearning</a></p>\n\n<h1 id=\"pascal-voc-で転移学習\">Pascal VOC で転移学習</h1>\n\n<p>ローカルマシン(Core-i7/Win10/WSL2/Ubuntu20.04/Tensorflow2.4)で試してみた手順が以下。<br />\nかなり時間がかかるけど、GPUなくても24時間もあればそれなりの回数がこなせる(5000回くらい?)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA  To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.</code> と言われているので、これらを有効にしてTensorflowを再構築すればもうちっと速くなるはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nずいぶん前にtensorflow 1.1.0でAVXを有効にしたら、MNISTの学習で実行時間が半分になった記憶もあるが、<br />\ntensorflow 1.6以降でAVXは有効になってて、AVX2,FMAの有無では10%くらいしか違わないらしい。<br />\n参考:<a href=\"https://www.acceluniverse.com/blog/developers/2019/05/tensorflowavx2-fma.html\" target=\"_blank\">TensorFlowのAVX2, FMAの有無で性能の比較をする</a><br />\ntensorflowのbuildに十何時間もかかることを考えたら 「ま、いっか」となっちゃうな…</p>\n</blockquote>\n\n<h2 id=\"実行手順\">実行手順</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">BASE_DIR</span><span class=\"o\">=</span>/work/test\n<span class=\"nv\">MODELS_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>/models\n<span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>/voc\n\n<span class=\"c\"># modelsリポジトリのclone</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>\ngit clone <span class=\"nt\">--depth</span> 1 https://github.com/tensorflow/models.git\n<span class=\"c\"># object_detectionモジュール未インストールならインストールすること</span>\n\n<span class=\"c\"># Pascal VOC データ取得</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>\nwget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar <span class=\"nt\">-O</span> - | <span class=\"nb\">tar </span>xvf -\n\n<span class=\"c\"># 学習データ(tf-record)の作成</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython create_pascal_tf_record.py <span class=\"nt\">--label_map_path</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"nt\">--data_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/VOCdevkit <span class=\"nt\">--year</span> VOC2007 <span class=\"nt\">--set</span> train <span class=\"nt\">--output_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pascal_train.record\npython create_pascal_tf_record.py <span class=\"nt\">--label_map_path</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"nt\">--data_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/VOCdevkit <span class=\"nt\">--year</span> VOC2007 <span class=\"nt\">--set</span> val <span class=\"nt\">--output_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pascal_val.record\n\n<span class=\"c\"># 元となるモデルのダウンロード</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/\nwget http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8.tar.gz <span class=\"nt\">-O</span> - | <span class=\"nb\">tar </span>xzvf -\n<span class=\"nb\">cp </span>ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/pipeline.config <span class=\"nb\">.</span>\n\n<span class=\"c\"># pipeline.config を編集(下記参照)</span>\n\n<span class=\"c\"># 学習実行</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython model_main_tf2.py <span class=\"nt\">--pipeline_config_path</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--model_dir</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--alsologtostderr</span>\n</code></pre></div></div>\n\n<h3 id=\"object_detectionモジュールのインストール方法\">object_detectionモジュールのインストール方法</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models/research\nprotoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n<span class=\"nb\">cp </span>object_detection/packages/tf2/setup.py <span class=\"nb\">.</span> \n<span class=\"c\"># ↑ tf1の場合はtf1ディレクトリを指定する</span>\n\npip <span class=\"nb\">install</span> <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"pipelineconfig-の修正例\">pipeline.config\tの修正例</h3>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/pipeline.config\t2020-07-11 09:16:11.000000000 +0900\n</span><span class=\"gi\">+++ pipeline.config\t2021-05-11 05:22:30.943865000 +0900\n</span><span class=\"p\">@@ -1,6 +1,6 @@</span>\n model {\n   ssd {\n<span class=\"gd\">-    num_classes: 90\n</span><span class=\"gi\">+    num_classes: 20\n</span>     image_resizer {\n       fixed_shape_resizer {\n         height: 320\n<span class=\"p\">@@ -132,7 +132,7 @@</span>\n   }\n }\n train_config {\n<span class=\"gd\">-  batch_size: 128\n</span><span class=\"gi\">+  batch_size: 64\n</span>   data_augmentation_options {\n     random_horizontal_flip {\n     }\n<span class=\"p\">@@ -162,19 +162,19 @@</span>\n     }\n     use_moving_average: false\n   }\n<span class=\"gd\">-  fine_tune_checkpoint: \"PATH_TO_BE_CONFIGURED\"\n-  num_steps: 50000\n</span><span class=\"gi\">+  fine_tune_checkpoint: \"/work/test/voc/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/checkpoint/ckpt-0\"\n+  num_steps: 2000\n</span>   startup_delay_steps: 0.0\n   replicas_to_aggregate: 8\n   max_number_of_boxes: 100\n   unpad_groundtruth_tensors: false\n<span class=\"gd\">-  fine_tune_checkpoint_type: \"classification\"\n</span><span class=\"gi\">+  fine_tune_checkpoint_type: \"detection\"\n</span>   fine_tune_checkpoint_version: V2\n }\n train_input_reader {\n<span class=\"gd\">-  label_map_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+  label_map_path: \"/work/test/models/research/object_detection/data/pascal_label_map.pbtxt\"\n</span>   tf_record_input_reader {\n<span class=\"gd\">-    input_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+    input_path: \"/work/test/voc/pascal_train.record\"\n</span>   }\n }\n eval_config {\n<span class=\"p\">@@ -182,10 +182,10 @@</span>\n   use_moving_averages: false\n }\n eval_input_reader {\n<span class=\"gd\">-  label_map_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+  label_map_path: \"/work/test/models/research/object_detection/data/pascal_label_map.pbtxt\"\n</span>   shuffle: false\n   num_epochs: 1\n   tf_record_input_reader {\n<span class=\"gd\">-    input_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+    input_path: \"/work/test/voc/pascal_val.record\"\n</span>   }\n }\n</code></pre></div></div>\n\n<h2 id=\"学習の中断\">学習の中断</h2>\n\n<p>学習処理を中断したい場合は、CTRL+cを入力する。<br />\nただし、中断した時点でのチェックポイントの保存は行われないので、それまでに保存されたチェックポイントが有効。<br />\nデフォルトではチェックポイントの保存は1000回毎なので、1000回未満で中断すると学習してないのと同じ(たぶん)。</p>\n\n<h2 id=\"追加学習学習の再開\">追加学習/学習の再開</h2>\n\n<p>中断した学習を再開したい場合や設定した学習回数では十分ではなかった場合の追加学習を行うには<br />\n<code class=\"language-plaintext highlighter-rouge\">model_main_tf2.py</code>を再度実行すればOK。<br />\nそれまで実行した学習結果の続きを実行してくれます。<br />\n(特に設定ファイル類を変更する必要はないみたい)</p>\n\n<p>追加学習の場合や学習回数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--num_train_steps</code>オプションで新しい学習回数を指定するか、\n<code class=\"language-plaintext highlighter-rouge\">pipeline.config</code>ファイル内の<code class=\"language-plaintext highlighter-rouge\">num_steps</code>の項目を変更します。</p>\n\n<p>また、デフォルトでは学習結果は1000回毎にセーブされるので、学習回数が1000回未満の場合や端数が出る場合、結果がセーブされません。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">--checkpoint_every_n</code>オプションで何回毎にセーブするかを指定する必要があります。</p>\n\n<p>以下に例を示します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python model_main_tf2.py <span class=\"nt\">--pipeline_config_path</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--model_dir</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--alsologtostderr</span> <span class=\"nt\">--checkpoint_every_n</span><span class=\"o\">=</span>100 <span class=\"nt\">--num_train_steps</span><span class=\"o\">=</span>2300\n</code></pre></div></div>\n<h2 id=\"モデルのエクスポート\">モデルのエクスポート</h2>\n\n<p>学習を行った結果をエクスポートしてsaved_modelを作成します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython exporter_main_v2.py <span class=\"nt\">--trained_checkpoint_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--pipeline_config_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--output_directory</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/inference_voc\n<span class=\"c\"># ラベルファイルもコピーしておく</span>\n<span class=\"nb\">cp</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/inference_voc/\n</code></pre></div></div>\n\n<h1 id=\"学習データtf-recordの確認方法\">学習データ(tf-record)の確認方法</h1>\n<h2 id=\"セットアップ\">セットアップ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tfrecord\n<span class=\"nb\">cd</span>  /work/tfrecord\n<span class=\"c\"># 仮想環境の準備</span>\npyenv virtualenv 3.8.9 tfrecord\npyenv <span class=\"nb\">local </span>tfrecord \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n<span class=\"c\"># 必要なモジュールのインストール</span>\npip <span class=\"nb\">install </span><span class=\"nv\">tensorflow</span><span class=\"o\">==</span>2.<span class=\"k\">*</span>\npip <span class=\"nb\">install </span>flask\npip <span class=\"nb\">install </span>pillow\npip <span class=\"nb\">install </span>tqdm\n</code></pre></div></div>\n\n<h2 id=\"リポジトリのclone\">リポジトリのclone</h2>\n\n<p>以下のリポジトリから</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/sulc/tfrecord-viewer.git\n<span class=\"nb\">cd </span>tfrecord-viewer/\n</code></pre></div></div>\n<h2 id=\"viewerの実行\">Viewerの実行</h2>\n\n<p>webサーバを起動する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfviewer.py «tf-recordファイル» \n</code></pre></div></div>\n\n<p>例:</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfviewer.py /work/test/train.record \n</code></pre></div></div>\n\n<p>ブラウザで以下に接続する(ポート番号は実行環境によって変わるかも)<br />\n<code class=\"language-plaintext highlighter-rouge\">http://localhost:5000/</code></p>\n\n<p>表示下部にサムネイルが表示されるので、クリックすると中央に拡大表示される。</p>\n\n<h2 id=\"元画像データの抽出\">元画像データの抽出</h2>\n\n<p>以下のパッチを当てる<br />\n(元のファイル名がディレクトリ名を含んでいるとファイル作成エラーになるので)</p>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tfrecord_to_imfolder.py b/tfrecord_to_imfolder.py\nindex 81bb764..7a0e269 100644\n</span><span class=\"gd\">--- a/tfrecord_to_imfolder.py\n</span><span class=\"gi\">+++ b/tfrecord_to_imfolder.py\n</span><span class=\"p\">@@ -41,6 +41,7 @@</span> def parse_tfrecord(record):\n     feat = example.features.feature\n\n     filename = feat[args.filename_key].bytes_list.value[0].decode(\"utf-8\")\n<span class=\"gi\">+    filename = os.path.basename(filename)\n</span>     img =  feat[args.image_key].bytes_list.value[0]\n     label = feat[args.class_label_key].bytes_list.value[0].decode(\"utf-8\")\n</code></pre></div></div>\n\n<p>以下のコマンドを実行<br />\n<code class=\"language-plaintext highlighter-rouge\">--class-label-key</code> には他にも指定できるものがあるけど、これくらいしか使わないと思う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfrecord_to_imfolder.py <span class=\"se\">\\</span>\n  <span class=\"nt\">--output_path</span> «ファイル出力ディレクトリ» <span class=\"se\">\\</span>\n  <span class=\"nt\">--class-label-key</span> image/object/class/text <span class=\"se\">\\</span>\n  <span class=\"nt\">-v</span> <span class=\"se\">\\</span>\n   «tf-recordファイル»\n</code></pre></div></div>\n\n<p>実行すると、«ファイル出力ディレクトリ»/«クラス名»/の下に画像ファイルが生成される。<br />\n(画像中に複数のクラスが含まれる場合は、一番最初のクラスが使用される)</p>\n\n<p>例:</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfrecord_to_imfolder.py <span class=\"se\">\\</span>\n  <span class=\"nt\">--output_path</span> ./hogehoge <span class=\"se\">\\</span>\n  <span class=\"nt\">--class-label-key</span> image/object/class/text <span class=\"se\">\\</span>\n  <span class=\"nt\">-v</span> <span class=\"se\">\\</span>\n  /work/test/train.record\n</code></pre></div></div>\n\n<h1 id=\"参考になるかもしれないページ\">参考になるかもしれないページ</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8c3197d11f61812546a9?fbclid=IwAR35TFl3mOK9XxXcZChP8wNkxp8cF6HZwnrWiTborZqETz7LJBZ88Dehvvs\">TensorFlowでの物体検出が超手軽にできる「Object Detection Tools」をTensorFlow 2.xに対応しました</a></p>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50?fbclid=IwAR35TFl3mOK9XxXcZChP8wNkxp8cF6HZwnrWiTborZqETz7LJBZ88Dehvvs\">Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Keras on tensorflow2 で SSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>Keras on tensorflow2 で SSD</h1>\n      <p>Tensorflow2上のKerasでSSDを実行を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>※ 2021.05.21 kerasをtensorflow.kerasに変更</p>\n\n<h1 id=\"概要\">概要</h1>\n\n<p>Kerasを使ってSSDを実行してみようと思ったら、Tensorflow1.x上の情報ばかり出てきて、Tensorflow2で実行するのに手間取ったのでメモ。<br />\n(最終的にopenVINOに持っていきたいなぁ、と思って試し始めたんだけど、openVINOにサクッと変換できるのはcaffeだった😅)<br />\nということで、やったけど 続きはないかも。実行遅いし…😩💨</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p><a href=\"https://smilerobo.com/papero/tips_keras_tf_ssd/\" target=\"_blank\">【実験】学習済のSSDを使ってPaPeRo i に複数種類の物体を数えさせる</a>\nを参考に、KerasをTensorflow2で動かしてみる。</p>\n\n<p>Pythonは3.8を使用した(念のため明記しておく)。</p>\n\n<p>Anaconda使ってないし、Paperoじゃないので、そのまんまじゃないけど、<br />\nとりあえずSSDを動かしてみよう。</p>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n\n<p>まずは、python仮想環境の準備をする。<br />\npyenv環境前提。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースディレクトリとpython仮想環境の準備</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/keras2/\n<span class=\"nb\">cd</span> /work/keras2/\npyenv virtualenv 3.8.8 keras2\npyenv <span class=\"nb\">local </span>keras2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># pythonモジュールのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n<span class=\"c\"># kerasはtensorflow内を直接参照にしたので不要  </span>\n<span class=\"c\"># pip install keras</span>\npip <span class=\"nb\">install </span>matplotlib\npip <span class=\"nb\">install </span>imageio\n</code></pre></div></div>\n\n<p>インストールされているpythonモジュールは以下の通り</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.2\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.4.0\ngoogle-auth==1.30.0\ngoogle-auth-oauthlib==0.4.4\ngoogle-pasta==0.2.0\ngrpcio==1.34.1\nh5py==3.1.0\nidna==2.10\nimageio==2.9.0\nkeras-nightly==2.5.0.dev2021032900\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.4.2\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.2.52\nopt-einsum==3.3.0\nPillow==8.2.0\nprotobuf==3.17.0\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nsix==1.15.0\ntensorboard==2.5.0\ntensorboard-data-server==0.6.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.5.0\ntensorflow-estimator==2.5.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==2.0.1\nwrapt==1.12.1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nKeras修正以前の状態は以下</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.1\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.3.3\ngoogle-auth==1.28.0\ngoogle-auth-oauthlib==0.4.3\ngoogle-pasta==0.2.0\ngrpcio==1.32.0\nh5py==2.10.0\nidna==2.10\nimageio==2.9.0\nKeras==2.4.3\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.3.4\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.1.48\nopt-einsum==3.3.0\nPillow==8.1.2\nprotobuf==3.15.6\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nPyYAML==5.4.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nscipy==1.6.1\nsix==1.15.0\ntensorboard==2.4.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.4.1\ntensorflow-estimator==2.4.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==1.0.1\nwrapt==1.12.1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"patchファイルの準備\">patchファイルの準備</h2>\n\n<p>参照先には色々手順が書いてあるが、めんどくさいので パッチファイル用意した(足りない修正もあるし)。<br />\n以下の内容を<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code> <code class=\"language-plaintext highlighter-rouge\">ssd_keras_2.patch</code>のファイル名で保存しておく。</p>\n\n<h3 id=\"ssd_keraspatch\">ssd_keras.patch</h3>\n\n<p>参照先の情報によるpatch</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/ssd.py b/ssd.py\nindex c0049d8..656cd83 100644\n</span><span class=\"gd\">--- a/ssd.py\n</span><span class=\"gi\">+++ b/ssd.py\n</span><span class=\"p\">@@ -2,14 +2,15 @@</span>\n \n import keras.backend as K\n from keras.layers import Activation\n<span class=\"gd\">-from keras.layers import AtrousConvolution2D\n</span><span class=\"gi\">+#from keras.layers import AtrousConvolution2D\n</span> from keras.layers import Convolution2D\n from keras.layers import Dense\n from keras.layers import Flatten\n from keras.layers import GlobalAveragePooling2D\n from keras.layers import Input\n from keras.layers import MaxPooling2D\n<span class=\"gd\">-from keras.layers import merge\n</span><span class=\"gi\">+#from keras.layers import merge\n+from keras.layers.merge import concatenate\n</span> from keras.layers import Reshape\n from keras.layers import ZeroPadding2D\n from keras.models import Model\n<span class=\"p\">@@ -34,109 +35,115 @@</span> def SSD300(input_shape, num_classes=21):\n     input_tensor = input_tensor = Input(shape=input_shape)\n     img_size = (input_shape[1], input_shape[0])\n     net['input'] = input_tensor\n<span class=\"gd\">-    net['conv1_1'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    net['conv1_1'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_1')(net['input'])\n<span class=\"gd\">-    net['conv1_2'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    \n+    net['conv1_2'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_2')(net['conv1_1'])\n<span class=\"gd\">-    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+\n+    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool1')(net['conv1_2'])\n     # Block 2\n<span class=\"gd\">-    net['conv2_1'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+    net['conv2_1'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_1')(net['pool1'])\n<span class=\"gd\">-    net['conv2_2'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+\n+    net['conv2_2'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_2')(net['conv2_1'])\n<span class=\"gd\">-    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool2')(net['conv2_2'])\n<span class=\"gi\">+\n</span>     # Block 3\n<span class=\"gd\">-    net['conv3_1'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_1'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_1')(net['pool2'])\n<span class=\"gd\">-    net['conv3_2'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_2'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_2')(net['conv3_1'])\n<span class=\"gd\">-    net['conv3_3'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_3'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_3')(net['conv3_2'])\n<span class=\"gd\">-    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool3')(net['conv3_3'])\n     # Block 4\n<span class=\"gd\">-    net['conv4_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_1')(net['pool3'])\n<span class=\"gd\">-    net['conv4_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_2')(net['conv4_1'])\n<span class=\"gd\">-    net['conv4_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_3')(net['conv4_2'])\n<span class=\"gd\">-    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool4')(net['conv4_3'])\n<span class=\"gd\">-    # Block 5\n-    net['conv5_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+# Block 5\n+    net['conv5_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_1')(net['pool4'])\n<span class=\"gd\">-    net['conv5_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_2')(net['conv5_1'])\n<span class=\"gd\">-    net['conv5_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_3')(net['conv5_2'])\n<span class=\"gd\">-    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), border_mode='same',\n</span><span class=\"gi\">+    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), padding='same',\n</span>                                 name='pool5')(net['conv5_3'])\n     # FC6\n<span class=\"gd\">-    net['fc6'] = AtrousConvolution2D(1024, 3, 3, atrous_rate=(6, 6),\n-                                     activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['fc6'] = Convolution2D(1024, (3, 3), dilation_rate=(6, 6),\n+                                     activation='relu', padding='same',\n</span>                                      name='fc6')(net['pool5'])\n     # x = Dropout(0.5, name='drop6')(x)\n     # FC7\n<span class=\"gd\">-    net['fc7'] = Convolution2D(1024, 1, 1, activation='relu',\n-                               border_mode='same', name='fc7')(net['fc6'])\n</span><span class=\"gi\">+    net['fc7'] = Convolution2D(1024, (1, 1), activation='relu',\n+                               padding='same', name='fc7')(net['fc6'])\n</span>     # x = Dropout(0.5, name='drop7')(x)\n     # Block 6\n<span class=\"gd\">-    net['conv6_1'] = Convolution2D(256, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv6_1'] = Convolution2D(256, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv6_1')(net['fc7'])\n<span class=\"gd\">-    net['conv6_2'] = Convolution2D(512, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+\n+\n+    net['conv6_2'] = Convolution2D(512, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv6_2')(net['conv6_1'])\n<span class=\"gd\">-    # Block 7\n-    net['conv7_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+        # Block 7\n+    net['conv7_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv7_1')(net['conv6_2'])\n     net['conv7_2'] = ZeroPadding2D()(net['conv7_1'])\n<span class=\"gd\">-    net['conv7_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='valid',\n</span><span class=\"gi\">+    net['conv7_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='valid',\n</span>                                    name='conv7_2')(net['conv7_2'])\n     # Block 8\n<span class=\"gd\">-    net['conv8_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv8_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv8_1')(net['conv7_2'])\n<span class=\"gd\">-    net['conv8_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['conv8_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv8_2')(net['conv8_1'])\n     # Last Pool\n     net['pool6'] = GlobalAveragePooling2D(name='pool6')(net['conv8_2'])\n     # Prediction from conv4_3\n     net['conv4_3_norm'] = Normalize(20, name='conv4_3_norm')(net['conv4_3'])\n     num_priors = 3\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv4_3_norm_mbox_loc')(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_loc'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_loc_flat')\n<span class=\"p\">@@ -144,7 +151,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv4_3_norm_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_conf'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_conf_flat')\n<span class=\"p\">@@ -155,16 +162,16 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv4_3_norm_mbox_priorbox'] = priorbox(net['conv4_3_norm'])\n     # Prediction from fc7\n     num_priors = 6\n<span class=\"gd\">-    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, 3, 3,\n-                                        border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, (3, 3),\n+                                        padding='same',\n</span>                                         name='fc7_mbox_loc')(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_loc_flat')\n     net['fc7_mbox_loc_flat'] = flatten(net['fc7_mbox_loc'])\n     name = 'fc7_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, 3, 3,\n-                                         border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, (3, 3),\n+                                         padding='same',\n</span>                                          name=name)(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_conf_flat')\n     net['fc7_mbox_conf_flat'] = flatten(net['fc7_mbox_conf'])\n<span class=\"p\">@@ -174,7 +181,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['fc7_mbox_priorbox'] = priorbox(net['fc7'])\n     # Prediction from conv6_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv6_2_mbox_loc')(net['conv6_2'])\n     net['conv6_2_mbox_loc'] = x\n     flatten = Flatten(name='conv6_2_mbox_loc_flat')\n<span class=\"p\">@@ -182,7 +189,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv6_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv6_2'])\n     net['conv6_2_mbox_conf'] = x\n     flatten = Flatten(name='conv6_2_mbox_conf_flat')\n<span class=\"p\">@@ -193,7 +200,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv6_2_mbox_priorbox'] = priorbox(net['conv6_2'])\n     # Prediction from conv7_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv7_2_mbox_loc')(net['conv7_2'])\n     net['conv7_2_mbox_loc'] = x\n     flatten = Flatten(name='conv7_2_mbox_loc_flat')\n<span class=\"p\">@@ -201,7 +208,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv7_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv7_2'])\n     net['conv7_2_mbox_conf'] = x\n     flatten = Flatten(name='conv7_2_mbox_conf_flat')\n<span class=\"p\">@@ -212,7 +219,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv7_2_mbox_priorbox'] = priorbox(net['conv7_2'])\n     # Prediction from conv8_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv8_2_mbox_loc')(net['conv8_2'])\n     net['conv8_2_mbox_loc'] = x\n     flatten = Flatten(name='conv8_2_mbox_loc_flat')\n<span class=\"p\">@@ -220,7 +227,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv8_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv8_2'])\n     net['conv8_2_mbox_conf'] = x\n     flatten = Flatten(name='conv8_2_mbox_conf_flat')\n<span class=\"p\">@@ -241,7 +248,7 @@</span> def SSD300(input_shape, num_classes=21):\n     priorbox = PriorBox(img_size, 276.0, max_size=330.0, aspect_ratios=[2, 3],\n                         variances=[0.1, 0.1, 0.2, 0.2],\n                         name='pool6_mbox_priorbox')\n<span class=\"gd\">-    if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+    if K.image_data_format() == 'channels_last':\n</span>         target_shape = (1, 1, 256)\n     else:\n         target_shape = (256, 1, 1)\n<span class=\"p\">@@ -249,42 +256,47 @@</span> def SSD300(input_shape, num_classes=21):\n                                     name='pool6_reshaped')(net['pool6'])\n     net['pool6_mbox_priorbox'] = priorbox(net['pool6_reshaped'])\n     # Gather all predictions\n<span class=\"gd\">-    net['mbox_loc'] = merge([net['conv4_3_norm_mbox_loc_flat'],\n</span><span class=\"gi\">+    net['mbox_loc'] = concatenate([net['conv4_3_norm_mbox_loc_flat'],\n</span>                              net['fc7_mbox_loc_flat'],\n                              net['conv6_2_mbox_loc_flat'],\n                              net['conv7_2_mbox_loc_flat'],\n                              net['conv8_2_mbox_loc_flat'],\n                              net['pool6_mbox_loc_flat']],\n<span class=\"gd\">-                            mode='concat', concat_axis=1, name='mbox_loc')\n-    net['mbox_conf'] = merge([net['conv4_3_norm_mbox_conf_flat'],\n</span><span class=\"gi\">+                            axis=1,\n+                                  name='mbox_loc')\n+    net['mbox_conf'] = concatenate([net['conv4_3_norm_mbox_conf_flat'],\n</span>                               net['fc7_mbox_conf_flat'],\n                               net['conv6_2_mbox_conf_flat'],\n                               net['conv7_2_mbox_conf_flat'],\n                               net['conv8_2_mbox_conf_flat'],\n                               net['pool6_mbox_conf_flat']],\n<span class=\"gd\">-                             mode='concat', concat_axis=1, name='mbox_conf')\n-    net['mbox_priorbox'] = merge([net['conv4_3_norm_mbox_priorbox'],\n</span><span class=\"gi\">+                              axis=1,\n+                              name='mbox_conf')\n+    net['mbox_priorbox'] = concatenate([net['conv4_3_norm_mbox_priorbox'],\n</span>                                   net['fc7_mbox_priorbox'],\n                                   net['conv6_2_mbox_priorbox'],\n                                   net['conv7_2_mbox_priorbox'],\n                                   net['conv8_2_mbox_priorbox'],\n                                   net['pool6_mbox_priorbox']],\n<span class=\"gd\">-                                 mode='concat', concat_axis=1,\n</span><span class=\"gi\">+                                 axis=1,\n</span>                                  name='mbox_priorbox')\n     if hasattr(net['mbox_loc'], '_keras_shape'):\n         num_boxes = net['mbox_loc']._keras_shape[-1] // 4\n     elif hasattr(net['mbox_loc'], 'int_shape'):\n<span class=\"gd\">-        num_boxes = K.int_shape(net['mbox_loc'])[-1] // 4\n</span><span class=\"gi\">+        num_boxes = net['mbox_loc'].int_shape()[-1] // 4\n+    elif hasattr(net['mbox_loc'], 'get_shape'):\n+        num_boxes = net['mbox_loc'].get_shape()[-1] // 4\n</span>     net['mbox_loc'] = Reshape((num_boxes, 4),\n                               name='mbox_loc_final')(net['mbox_loc'])\n     net['mbox_conf'] = Reshape((num_boxes, num_classes),\n                                name='mbox_conf_logits')(net['mbox_conf'])\n     net['mbox_conf'] = Activation('softmax',\n                                   name='mbox_conf_final')(net['mbox_conf'])\n<span class=\"gd\">-    net['predictions'] = merge([net['mbox_loc'],\n</span><span class=\"gi\">+    net['predictions'] = concatenate([net['mbox_loc'],\n</span>                                net['mbox_conf'],\n                                net['mbox_priorbox']],\n<span class=\"gd\">-                               mode='concat', concat_axis=2,\n</span><span class=\"gi\">+                               axis=2,\n+                               #axis = 0,\n</span>                                name='predictions')\n     model = Model(net['input'], net['predictions'])\n     return model\n<span class=\"gh\">diff --git a/ssd_layers.py b/ssd_layers.py\nindex 5e10478..41ee510 100644\n</span><span class=\"gd\">--- a/ssd_layers.py\n</span><span class=\"gi\">+++ b/ssd_layers.py\n</span><span class=\"p\">@@ -29,7 +29,8 @@</span> class Normalize(Layer):\n         Add possibility to have one scale for all features.\n     \"\"\"\n     def __init__(self, scale, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n+\n</span>             self.axis = 3\n         else:\n             self.axis = 1\n<span class=\"p\">@@ -41,7 +42,7 @@</span> class Normalize(Layer):\n         shape = (input_shape[self.axis],)\n         init_gamma = self.scale * np.ones(shape)\n         self.gamma = K.variable(init_gamma, name='{}_gamma'.format(self.name))\n<span class=\"gd\">-        self.trainable_weights = [self.gamma]\n</span><span class=\"gi\">+        self._trainable_weights = [self.gamma]\n</span> \n     def call(self, x, mask=None):\n         output = K.l2_normalize(x, self.axis)\n<span class=\"p\">@@ -81,7 +82,7 @@</span> class PriorBox(Layer):\n     \"\"\"\n     def __init__(self, img_size, min_size, max_size=None, aspect_ratios=None,\n                  flip=True, variances=[0.1], clip=True, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n</span>             self.waxis = 2\n             self.haxis = 1\n         else:\n<span class=\"p\">@@ -108,7 +109,7 @@</span> class PriorBox(Layer):\n         self.clip = True\n         super(PriorBox, self).__init__(**kwargs)\n \n<span class=\"gd\">-    def get_output_shape_for(self, input_shape):\n</span><span class=\"gi\">+    def compute_output_shape(self, input_shape):\n</span>         num_priors_ = len(self.aspect_ratios)\n         layer_width = input_shape[self.waxis]\n         layer_height = input_shape[self.haxis]\n<span class=\"gh\">diff --git a/ssd_utils.py b/ssd_utils.py\nindex 0a9ffb1..4fc7a49 100644\n</span><span class=\"gd\">--- a/ssd_utils.py\n</span><span class=\"gi\">+++ b/ssd_utils.py\n</span><span class=\"p\">@@ -1,7 +1,8 @@</span>\n \"\"\"Some utils for SSD.\"\"\"\n \n import numpy as np\n<span class=\"gd\">-import tensorflow as tf\n</span><span class=\"gi\">+import tensorflow.compat.v1 as tf\n+tf.disable_v2_behavior()\n</span> \n \n class BBoxUtility(object):\n<span class=\"gh\">diff --git a/testing_utils/videotest.py b/testing_utils/videotest.py\nindex 0cbae3c..7b2ff4f 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest.py\n</span><span class=\"p\">@@ -3,13 +3,14 @@</span>\n import cv2\n import keras\n from keras.applications.imagenet_utils import preprocess_input\n<span class=\"gd\">-from keras.backend.tensorflow_backend import set_session\n</span><span class=\"gi\">+# from keras.backend.tensorflow_backend import set_session\n</span> from keras.models import Model\n from keras.preprocessing import image \n import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-from scipy.misc import imread, imresize\n</span><span class=\"gi\">+# from scipy.misc import imread, imresize\n+from imageio import imread\n</span> from timeit import default_timer as timer\n \n import sys\n<span class=\"p\">@@ -84,8 +85,8 @@</span> class VideoTest(object):\n             \"trying to open a webcam, make sure you video_path is an integer!\"))\n         \n         # Compute aspect ratio of video     \n<span class=\"gd\">-        vidw = vid.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)\n-        vidh = vid.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)\n</span><span class=\"gi\">+        vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)\n+        vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)\n</span>         vidar = vidw/vidh\n         \n         # Skip frames until reaching start_frame\n<span class=\"gh\">diff --git a/testing_utils/videotest_example.py b/testing_utils/videotest_example.py\nindex fb4d873..27ec148 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest_example.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest_example.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import os\n+# GPU不使用を設定\n+os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n+\n</span> import keras\n import pickle\n from videotest import VideoTest\n<span class=\"p\">@@ -9,16 +13,38 @@</span> from ssd import SSD300 as SSD\n input_shape = (300,300,3)\n \n # Change this if you run with other classes than VOC\n<span class=\"gd\">-class_names = [\"background\", \"aeroplane\", \"bicycle\", \"bird\", \"boat\", \"bottle\", \"bus\", \"car\", \"cat\", \"chair\", \"cow\", \"diningtable\", \"dog\", \"horse\", \"motorbike\", \"person\", \"pottedplant\", \"sheep\", \"sofa\", \"train\", \"tvmonitor\"];\n</span><span class=\"gi\">+class_names = [ \n+                \"background\", \n+                \"aeroplane\", \n+                \"bicycle\", \n+                \"bird\", \n+                \"boat\", \n+                \"bottle\", \n+                \"bus\", \n+                \"car\", \n+                \"cat\", \n+                \"chair\", \n+                \"cow\", \n+                \"diningtable\", \n+                \"dog\", \n+                \"horse\", \n+                \"motorbike\", \n+                \"person\", \n+                \"pottedplant\", \n+                \"sheep\", \n+                \"sofa\", \n+                \"train\", \n+                \"tvmonitor\"\n+            ];\n</span> NUM_CLASSES = len(class_names)\n \n model = SSD(input_shape, num_classes=NUM_CLASSES)\n \n # Change this path if you want to use your own trained weights\n<span class=\"gd\">-model.load_weights('../weights_SSD300.hdf5') \n</span><span class=\"gi\">+model.load_weights('../../weights_SSD300.hdf5') \n</span>         \n vid_test = VideoTest(class_names, model, input_shape)\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('path/to/your/video.mkv')\n</span><span class=\"gi\">+vid_test.run('../../testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h3 id=\"ssd_keras_2patch\">ssd_keras_2.patch</h3>\n\n<p>keras修正対応</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras_2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd.py ssd_keras.tmp/ssd.py\n</span><span class=\"gd\">--- ssd_keras/ssd.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd.py\t2021-05-21 07:06:44.970000000 +0900\n</span><span class=\"p\">@@ -1,19 +1,17 @@</span>\n \"\"\"Keras implementation of SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.layers import Activation\n-#from keras.layers import AtrousConvolution2D\n-from keras.layers import Convolution2D\n-from keras.layers import Dense\n-from keras.layers import Flatten\n-from keras.layers import GlobalAveragePooling2D\n-from keras.layers import Input\n-from keras.layers import MaxPooling2D\n-#from keras.layers import merge\n-from keras.layers.merge import concatenate\n-from keras.layers import Reshape\n-from keras.layers import ZeroPadding2D\n-from keras.models import Model\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.keras.layers import Activation\n+from tensorflow.keras.layers import Convolution2D\n+from tensorflow.keras.layers import Dense\n+from tensorflow.keras.layers import Flatten\n+from tensorflow.keras.layers import GlobalAveragePooling2D\n+from tensorflow.keras.layers import Input\n+from tensorflow.keras.layers import MaxPooling2D\n+from tensorflow.keras.layers import concatenate\n+from tensorflow.keras.layers import Reshape\n+from tensorflow.keras.layers import ZeroPadding2D\n+from tensorflow.keras.models import Model\n</span> \n from ssd_layers import Normalize\n from ssd_layers import PriorBox\n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd_layers.py ssd_keras.tmp/ssd_layers.py\n</span><span class=\"gd\">--- ssd_keras/ssd_layers.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd_layers.py\t2021-05-21 06:31:11.780000000 +0900\n</span><span class=\"p\">@@ -1,8 +1,8 @@</span>\n \"\"\"Some special pupropse layers for SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.engine.topology import InputSpec\n-from keras.engine.topology import Layer\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.python.keras.engine.input_spec import InputSpec\n+from tensorflow.python.keras.engine.base_layer import Layer\n</span> import numpy as np\n import tensorflow as tf\n \n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest.py ssd_keras.tmp/testing_utils/videotest.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest.py\t2021-05-21 07:08:24.680000000 +0900\n</span><span class=\"p\">@@ -1,15 +1,13 @@</span>\n \"\"\" A class for testing a SSD model on a video file or webcam \"\"\"\n \n import cv2\n<span class=\"gd\">-import keras\n-from keras.applications.imagenet_utils import preprocess_input\n-# from keras.backend.tensorflow_backend import set_session\n-from keras.models import Model\n-from keras.preprocessing import image \n</span><span class=\"gi\">+import tensorflow.keras as keras\n+from tensorflow.keras.applications.imagenet_utils import preprocess_input\n+from tensorflow.keras.models import Model\n+from tensorflow.keras.preprocessing import image \n</span> import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-# from scipy.misc import imread, imresize\n</span> from imageio import imread\n from timeit import default_timer as timer\n \n<span class=\"p\">@@ -179,6 +177,7 @@</span>\n             cv2.putText(to_draw, fps, (3,10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0,0,0), 1)\n             \n             cv2.imshow(\"SSD result\", to_draw)\n<span class=\"gd\">-            cv2.waitKey(10)\n-            \n-        \n</span><span class=\"gi\">+            key = cv2.waitKey(1)\n+            if key == 27:\n+                # ESCキー\n+                break\n</span><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest_example.py ssd_keras.tmp/testing_utils/videotest_example.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest_example.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest_example.py\t2021-05-21 07:04:24.320000000 +0900\n</span><span class=\"p\">@@ -2,7 +2,7 @@</span>\n # GPU不使用を設定\n os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n \n<span class=\"gd\">-import keras\n</span><span class=\"gi\">+import tensorflow.keras as keras\n</span> import pickle\n from videotest import VideoTest\n \n<span class=\"p\">@@ -47,4 +47,4 @@</span>\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('../../testvideo3.mp4')\n</span><span class=\"gi\">+vid_test.run('../../images/testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h2 id=\"学習済み重みファイルのダウンロード\">学習済み重みファイルのダウンロード</h2>\n\n<p>参照先の記載にしたがって、重み学習済み重みファイルをダウンロードする。</p>\n\n<p>wgetでは取得できなかったので、ブラウザで↓ここ から weights_SSD300.hdf5 をダウンロード。<br />\n<a href=\"https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA\" target=\"_blank\">https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA</a><br />\nで、ZIPファイルをカレントディレクトリに解凍しておく。</p>\n\n<h2 id=\"ソースのダウンロードパッチをあてる\">ソースのダウンロード&パッチをあてる</h2>\n\n<p>githubからソースをダウンロードする。<br />\nこのままではエラーになるので、先ほど作成したパッチファイル<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code>でパッチをあてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/rykov8/ssd_keras.git\n<span class=\"nb\">cd </span>ssd_keras\npatch <span class=\"nt\">-p1</span> < ../ssd_keras.patch \n<span class=\"c\"># Keras修正対応パッチ</span>\npatch <span class=\"nt\">-p1</span> < ../ssd_keras_2.patch \n</code></pre></div></div>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>testing_utils/\npython videotest_example.py\n</code></pre></div></div>\n\n<p>おー。<br />\nしかし遅い…. <br />\nKerasは遅いみたい。。。orz…</p>\n\n<h1 id=\"こんなんもある\">こんなんもある</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50\" target=\"_blank\">「Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PyPiからopenVINOをインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>PyPiからopenVINOをインストール</h1>\n      <p>PyPiで配布されているopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>openVINOを使いたいが、SDKをインストールするのは面倒というズボラさんのためのTips😅<br />\nNCS2を使うためのドライバをインストールするにはSDK必要だが(WSLだとそもそもNCS2は使えないけど)、CPUだけでさくっと使いたいときなんかは有効かな?<br />\nあと、SDKインストール済みだけど、別のバージョン試したいときとか。</p>\n\n<p>対象はWindwos(試してないけど)、Ubuntu(x86_64 の 18.04、20.04)。(macOSも対象らしいけど使ったことないのでよーわからん😅)<br />\nPython は3.6、3.7、3.8<br />\nRasoberryPiは現在のところ対象外。</p>\n\n<h1 id=\"pypiのページ\">PyPiのページ</h1>\n\n<p>PyPiは以下にページがある。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino/\" target=\"_blank\">openvino · PyPI</a></li>\n</ul>\n\n<p>ただし、現状はUbuntuでPython3.8を使用する場合は以下を使用(Ubuntu Python3.7は両方用意されているらしい)。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino-ubuntu20/\" target=\"_blank\">openvino-ubuntu20 · PyPI</a></li>\n</ul>\n\n<h1 id=\"pythonモジュールのインストール\">pythonモジュールのインストール</h1>\n<p>上記ページに記載された通りだが、大抵openCVも必要になるので、インストールしておく。 <br />\n最近はopenCVも<code class=\"language-plaintext highlighter-rouge\">pip</code>コマンドイッパツでインストールできるのでラクチン😊</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOのインストール</span>\npip <span class=\"nb\">install </span>openvino\n<span class=\"c\"># またはこちら</span>\n<span class=\"c\"># pip install openvino-ubuntu20</span>\n\n<span class=\"c\"># openCVのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<p>インストールすると、現状、以下のモジュールがインストールされる(ubuntuでpython3.7/3.8の場合)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>numpy==1.20.1\nopencv-python==4.5.1.48\nopenvino==2021.2\ntbb==2020.3.254\n</code></pre></div></div>\n\n<h1 id=\"実行前の準備\">実行前の準備</h1>\n\n<p>openVINOモジュールは<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>の設定が必要なので、\nシステムのpythonを使用するときは上記ページに記載された通りに<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>を設定する。<br />\nただし、pyenvを使用している場合は、以下のように設定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"k\">}</span>:<span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/versions/<span class=\"sb\">`</span>pyenv version-name<span class=\"sb\">`</span>/lib\n</code></pre></div></div>\n\n<p>pyenvで環境を切り替えることを考えると、<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>で設定するより、スクリプト実行ラッパで設定した方が無難かも。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu20.04 on WSL2 で openVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu20.04 on WSL2 で openVINO</h1>\n      <p>WSL2上のUbuntu20.04でopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"環境構築\">環境構築</h1>\n\n<p>WSL環境ではNCS2は使えないが、CPU演算での実行は可能。<br />\n以下インストール~デモ実行までのメモ。</p>\n\n<p>基本は以下を参考に。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></li>\n  <li><a href=\"/memoBlog/2020/10/18/openVINO_ubuntu_3.html\">openVINO フルパッケージ(2021.1)をインストール(追加)</a></li>\n</ul>\n\n<p>WSLのインストールメモはこちら:<a href=\"/memoBlog/2021/03/03/WSL_memo.html\">WSL2 メモ</a><br />\nUbuntuは20.04。<br />\n今回はopenVINO 2021.2を使用した。</p>\n\n<h2 id=\"pyenvの仮想環境を作成\">pyenvの仮想環境を作成</h2>\n<p>まずは、pythonの環境を準備。<br />\n以下ではpythonは3.7.10を使用。(3.8を使えばTensorflow2を使えるらしい(?))</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.10 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n\n<p>ubuntuのライブラリ類をインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev \n<span class=\"c\"># 他にもあるかもしれんけど、とりあえずこれだけ。</span>\n</code></pre></div></div>\n\n<p>WSLでは以下も必要(グラフィック系処理が入ってないので)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgtk-3-0\n</code></pre></div></div>\n<h2 id=\"ダウンロードしたopenvinoアーカイブの展開とインストール\">ダウンロードしたopenVINOアーカイブの展開とインストール</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/mnt/f/Download/</code>にダウンロードしたファイルがあるとして。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\n<span class=\"nb\">tar </span>xzvf /mnt/f/Download/l_openvino_toolkit_p_2021.2.185.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2021.2.185/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n<span class=\"c\"># なぜかXwindow設定しててもテキストベースになる...</span>\n<span class=\"c\"># てきとーに答えていく。</span>\n</code></pre></div></div>\n\n<p>スクリプト終了したら、以下に従い進めていく。<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html</a></p>\n\n<h2 id=\"後半のコマンド一覧と注意事項\">後半のコマンド一覧と注意事項</h2>\n\n<ul>\n  <li>環境変数の設定とpythonモジュールのインストール</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># このコマンド、~/.bashrcにも書いておくこと</span>\n<span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n\n<span class=\"c\"># このコマンド実行すると、pyenvでなくsystemのpipでモジュールがインストールされるので実行しない</span>\n<span class=\"c\"># しかも、systemのpip3が壊れる...すごい罠😡</span>\n<span class=\"c\"># cd /opt/intel/openvino_2021/deployment_tools/model_optimizer/install_prerequisites/</span>\n<span class=\"c\"># sudo -E ./install_prerequisites.sh </span>\n\n<span class=\"c\"># 代わりに以下を実行(上記スクリプトは結局これを実行しているだけなので)</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npython 3.7で実行すると、</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version >= \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われるけど、無視して良い。<br />\nこれはPython3.8未満か以上で異なるバージョンのTensorflowがインストールされるように設定されているため。<br />\nちなみに、python 3.8でやると</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version < \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nもし、<code class=\"language-plaintext highlighter-rouge\">install_prerequisites.sh</code>を実行してしまい、pip3が壊れてしまった場合は\n以下で復旧する(一旦アンインストールしてから再インストール)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove python3-pip \n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip \n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"デモ実行\">デモ実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino_2021/deployment_tools/demo\n<span class=\"nb\">sudo cp</span> /work/.python-version <span class=\"nb\">.</span>\n\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/demo1.log\n\n<span class=\"c\"># このデモはグラフィック表示可能環境で実行する必要がある。  </span>\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/dem2.log\n</code></pre></div></div>\n\n<h1 id=\"別の仮想環境を用意する場合\">別の仮想環境を用意する場合</h1>\n\n<p>別の仮想環境を用意するときは以下で新しい仮想環境下にモジュールをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano に pyenv をインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano に pyenv をインストールする</h1>\n      <p>Jetson nano に pyenvをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>systemのpythonを使うのはちょっと嫌なので、仮想環境を使えるようにしておく。<br />\n<code class=\"language-plaintext highlighter-rouge\">venv</code>でもいいけど、やっぱり使い慣れた<code class=\"language-plaintext highlighter-rouge\">pyenv</code>+<code class=\"language-plaintext highlighter-rouge\">vertualenv</code>で。<br />\n基本的に<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a>と同じだけど、<br />\nJetpackでインストール済みで、<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできないパッケージがあるなど、<br />\nJetson nano 固有の設定等があるので、メモ。</p>\n\n<h1 id=\"手順再掲を含む\">手順(再掲を含む)</h1>\n\n<h2 id=\"pyenvをインストールする\">pyenvをインストールする</h2>\n<ul>\n  <li>必要なパッケージのインストール\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>pyenvとプラグインをダウンロード\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git            <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone git://github.com/pyenv/pyenv-update.git      <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境からJetpackでインストール済みのパッケージを参照できるようにしておく。<br />\n(pipでインストールできないみたいなので、お手軽な方法で解決)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/cv2          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/graphsurgeon <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/tensorrt     <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/uff          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>\n、とやりたいけど、ARM版は非対応らしいので…</p>\n    </blockquote>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>の修正<br />\n以下を追加しておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n<span class=\"c\">#jetson専用のインストール済みパッケージをコピっておく</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHONPATH</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span><span class=\"s2\">/jetson_pythonlib:</span><span class=\"nv\">$PYTHONPATH</span><span class=\"s2\">\"</span>\n</code></pre></div>    </div>\n  </li>\n  <li>ターミナル開きなおし or <code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を再読み込み</li>\n</ul>\n\n<h2 id=\"ベースとなるpythonのインストール\">ベースとなるpythonのインストール</h2>\n<p>バージョンは3.6.xでないとダメっぽい</p>\n\n<h2 id=\"python-のインストール\">python のインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.12\npyenv global 3.6.12\n</code></pre></div></div>\n<p>pip と setuptools のアップデート</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n<h2 id=\"その他\">その他</h2>\n<p>wheelが入ってると仮想環境を変えて同じモジュールをインストールするときに早いので、<br />\nインストールしておきたいが、各仮想環境に逐一インストールするのも面倒なので<br />\n共通に参照できるディレクトリにインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>wheel <span class=\"nt\">-t</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をUSBドライブからブートできるようにする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をUSBドライブからブートできるようにする</h1>\n      <p>Jetson nano をUSBドライブからブートできるようにする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>本稿はJetoack4.4での手順です。<br />\nJetpack4.6のときのメモは<a href=\"/memoBlog/2021/09/14/Jetson_usb_boot.html\" target=\"_blank\">Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</a> にあります。</p>\n\n<h1 id=\"概要\">概要</h1>\n<p>SDカードからブートすると、かなりディスクアクセスが遅いのと、ディスク容量を結構喰うので、<br />\nUSBドライブ(HDD/SSD)からブートできるようにする手順。<br />\n例によって、先人の知恵を借りるだけだけど(パクりとも言う)…(^^ゞ</p>\n\n<p>めんどくさそうだったけど、ほとんどスクリプト化されているので、意外と簡単。</p>\n\n<h1 id=\"参考\">参考</h1>\n<ul>\n  <li><a href=\"https://www.miki-ie.com/nvidiajetsonnano/nvidia-jetson-nano-usb-root/\">NVIDIA Jetson Nano USB ディスクをルート構成</a></li>\n  <li><a href=\"https://qiita.com/sgrowd/items/87d65383c0b74306ea7d\">Jetson Nanoの/をUSBドライブにしてSDカードを長生きさせる</a></li>\n  <li><a href=\"https://www.jetsonhacks.com/2019/09/17/jetson-nano-run-from-usb-drive/\">Jetson Nano – Run From USB Drive</a></li>\n</ul>\n\n<h1 id=\"手順を再掲しとく\">手順を再掲しとく</h1>\n\n<ul>\n  <li>SDカードからブート</li>\n  <li>USBドライブを接続&フォーマット</li>\n  <li>USBドライブをマウント</li>\n  <li>ツールのダウンロード\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/JetsonHacksNano/rootOnUSB.git\n<span class=\"nb\">cd </span>rootOnUSB/\n</code></pre></div>    </div>\n  </li>\n  <li>USBドライブからbootするためのinitrdを作成する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./addUSBToInitramfs.sh\n</code></pre></div>    </div>\n  </li>\n  <li>SDカードからUSBドライブへファイルをコピーする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./copyRootToUSB.sh <span class=\"nt\">-p</span> «コピー先パーティション»\n  <span class=\"c\"># 例: ./copyRootToUSB.sh -p /dev/sda1</span>\n</code></pre></div>    </div>\n  </li>\n  <li>実際にUSBドライブからブートするための設定\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/boot/extlinux/extlinux.conf</code>のバックアップをとっておく\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv</span> /boot/extlinux/extlinux.conf /boot/extlinux/extlinux.conf.org\n</code></pre></div>        </div>\n      </li>\n      <li>USBドライブのUUIDを調べる\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./diskUUID.sh\n</code></pre></div>        </div>\n        <p>→ <code class=\"language-plaintext highlighter-rouge\">XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</code>として得られる。</p>\n      </li>\n      <li><code class=\"language-plaintext highlighter-rouge\">sample-extlinux.conf</code> の <code class=\"language-plaintext highlighter-rouge\">APPEND</code>の行のUUID部分を以下のように変更する\n        <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    APPEND ${cbootargs} root=UUID=dc21871e-9db4-434c-98b4-713f55f807eb rootwait rootfstype=ext4\n                                     ↓↓↓↓↓\n    APPEND ${cbootargs} root=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rootwait rootfstype=ext4\n</code></pre></div>        </div>\n      </li>\n      <li>変更した<code class=\"language-plaintext highlighter-rouge\">sample-extlinux.conf</code>を<code class=\"language-plaintext highlighter-rouge\">/boot/extlinux/extlinux.conf</code>をコピー\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp </span>sample-extlinux.conf /boot/extlinux/extlinux.conf\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>リーブート</li>\n</ul>\n\n<p>リブート完了したらUSBドライブがrootにマウントされていることを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">mount</code>で確認しても良いけど、いっぱい出てきて鬱陶しいので<code class=\"language-plaintext highlighter-rouge\">df</code>で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">df</span> <span class=\"nt\">-h</span> /\n</code></pre></div></div>\n<p>こんな感じで行頭にマウント元が表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Filesystem      Size  Used Avail Use% Mounted on\n/dev/sda1       110G   14G   91G  13% /\n</code></pre></div></div>\n\n<h1 id=\"注意\">注意</h1>\n<p>USBドライブからブートできるようになっても、SDカードは取り外してはいけない。<br />\nu-bootからinitrdをロードするのはSDカードなので。</p>\n\n<p>ということは、<code class=\"language-plaintext highlighter-rouge\">apt update</code>でカーネルアップデートされても古いカーネルが使われちゃうなぁ…<br />\nそれはそのとき考えよう…<br />\nそんなに変わるもんでもないだろう。</p>\n\n<h1 id=\"独り言\">独り言</h1>\n<p>u-bootの環境変数見ると、そのままUSBブート出来そうな感じだったけど、<br />\n実際に<code class=\"language-plaintext highlighter-rouge\">usb start</code>してみたらエラーになる。<br />\nどうやらu-bootにはUSBドライバが入ってないらしい…<br />\nそんな環境変数残しとくな!!</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano のSDカードをバックアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano のSDカードをバックアップする</h1>\n      <p>Jetson nano のSDカードをバックアップする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2020/10/23/Jetson_nano_install.html\">Jetson nano をセットアップする</a> \nでセットアップしたSDカードをバックアップしておけば逐一セットアップ作業を行わなくても環境を復元できます。</p>\n\n<p>ただ、そのままSDカードをイメージファイル化しただけでは復元するSDカードのサイズが微妙に小さい場合などは、復元できなくなってしまいます。<br />\nそこで、バックアップしtイメージファイル内のパーティションサイズを縮小し、イメージファイルを小さくするスクリプトを用意しました。</p>\n\n<p>この作業はubuntu PC上で行います。</p>\n\n<p>この方法、およびスクリプトはRaspberryPi用SDカードでも使用できます。</p>\n\n<h1 id=\"sdカードのバックアップ\">SDカードのバックアップ</h1>\n<blockquote>\n  <p>[!WARNING]\nJetson用SDカードはFATパーティションが存在しないため、<br />\nWindowsPCではバックアップツールがSDカードを認識できず、バックアップできません。</p>\n</blockquote>\n\n<ul>\n  <li>ubuntu PCにバックアップしたいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>SDカードイメージをファイルにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">of</span><span class=\"o\">=</span>«出力ファイル» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n  <li>ubuntu PCからSDカードを抜去</li>\n</ul>\n\n<h1 id=\"ディスクイメージファイルの縮小\">ディスクイメージファイルの縮小</h1>\n\n<p>バックアップしたイメージファイルはSDカード容量と同じサイズになっています。<br />\nディスクイメージを縮小するために <a href=\"/memoBlog/misc/stock/diskimage_shrink.sh\">このスクリプト</a> をダウンロードして実行します。</p>\n\n<p>まず、必要なツールをインストールしておきます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install </span>kpartx\n</code></pre></div></div>\n\n<p>ダウンロードしたスクリプトを実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash diskimage_shrink.sh «入力イメージファイル» «出力イメージファイル» \n</code></pre></div></div>\n<p>出力イメージファイルが既に存在する場合は、上書きするか聞かれますので、yまたはnで指定してください。</p>\n\n<p>最初に入力イメージファイルから出力イメージファイルへコピーを行います。<br />\nコピーが終了すると、<code class=\"language-plaintext highlighter-rouge\">sudo</code>実行するためのパスワードを聞かれますので、入力してください。<br />\n縮小するパーティションサイズを計算した後、\n現在のパーティションサイズと縮小後のパーティションサイズが表示されます。<br />\n各サイズが正しければ、yを入力してパーティションサイズの修正を行いますが、\n一般的に危険な処理なので、「警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?」と再度確認されます。<br />\nyを入力して実行してください。</p>\n\n<p>その後、さらに ファイルサイズを切り詰めます。</p>\n\n<p>処理が終了すると、以下のメッセージが表示されますので、これにしたがって後の処理を行ってください。<br />\nRaspberryPi用SDカードはMBRパーティションなので<code class=\"language-plaintext highlighter-rouge\">gdisk</code>の処理は不要です。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n<p>実行例を以下に示します。<br />\n入力コマンドは<code class=\"language-plaintext highlighter-rouge\"># =========</code>で囲んであります。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># =========================================================================\n/work2$ bash diskimage_shrink.sh jetson_sd_20201022_2.img XXXX.img\n# =========================================================================\nCopy image file...\n>f+++++++++ jetson_sd_20201022_2.img\n 30,953,963,520 100%   26.97MB/s    0:18:14 (xfr#1, to-chk=0/1)\nGet partition info...\n対象パーティション番号 : 1\nImage file mapping...\n[sudo] <<ユーザ>> のパスワード: «パスワードを入力»\nadd map loop18p1 (253:0): 0 60313600 linear 7:18 28672\nadd map loop18p2 (253:1): 0 256 linear 7:18 2048\nadd map loop18p3 (253:2): 0 896 linear 7:18 4096\nadd map loop18p4 (253:3): 0 1152 linear 7:18 6144\nadd map loop18p5 (253:4): 0 128 linear 7:18 8192\nadd map loop18p6 (253:5): 0 384 linear 7:18 10240\nadd map loop18p7 (253:6): 0 768 linear 7:18 12288\nadd map loop18p8 (253:7): 0 128 linear 7:18 14336\nadd map loop18p9 (253:8): 0 896 linear 7:18 16384\nadd map loop18p10 (253:9): 0 896 linear 7:18 18432\nadd map loop18p11 (253:10): 0 1536 linear 7:18 20480\nadd map loop18p12 (253:11): 0 128 linear 7:18 22528\nadd map loop18p13 (253:12): 0 160 linear 7:18 24576\nadd map loop18p14 (253:13): 0 256 linear 7:18 26624\nLOOP device : /dev/mapper/loop18p1\n現在のパーティションサイズ   : 29450MiB\n縮小後のパーティションサイズ : 15637MiB\nパーティションを縮小しますか? [y/N]: y\nPartition shrinking...\ne2fsck 1.44.1 (24-Mar-2018)\nPass 1: Checking iノードs, blocks, and sizes\nPass 2: Checking ディレクトリ structure\nPass 3: Checking ディレクトリ connectivity\nPass 4: Checking reference counts\nPass 5: Checking グループ summary information\n/dev/mapper/loop18p1: 199065/1881264 files (0.2% non-contiguous), 3701166/7539200 blocks\nresize2fs 1.44.1 (24-Mar-2018)\nResizing the filesystem on /dev/mapper/loop18p1 to 4003167 (4k) blocks.\nBegin pass 2 (max = 55)\nRelocating blocks             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nBegin pass 3 (max = 231)\nScanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nThe filesystem on /dev/mapper/loop18p1 is now 4003167 (4k) blocks long.\n\n警告: 管理者権限がありません。パーミッションに注意してください。\n警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?\nはい(Y)/Yes/いいえ(N)/No? y                                               \nTruncate image file size...\nReleas image file mapping...\nloop deleted : /dev/loop18\n******** Done!! ********\n\n\n\n対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\n\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n\n\n\n# =========================================================================\n/work2$ gdisk XXXX.img \n# =========================================================================\nGPT fdisk (gdisk) version 1.0.3\n\nWarning! Disk size is smaller than the main header indicates! Loading\nsecondary header from the last sector of the disk! You should use 'v' to\nverify disk integrity, and perhaps options on the experts' menu to repair\nthe disk.\nCaution: invalid backup GPT header, but valid main header; regenerating\nbackup header from main header.\n\nWarning! Error 25 reading partition table for CRC check!\nWarning! One or more CRCs don't match. You should repair the disk!\n\nPartition table scan:\n  MBR: protective\n  BSD: not present\n  APM: not present\n  GPT: damaged\n\n****************************************************************************\nCaution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\nverification and recovery are STRONGLY recommended.\n****************************************************************************\n\nCommand (? for help): b\nEnter backup filename to save: backup.gpt\nThe operation has completed successfully.\n\nCommand (? for help): r\n\nRecovery/transformation command (? for help): d\n\nRecovery/transformation command (? for help): w\nCaution! Secondary header was placed beyond the disk's limits! Moving the\nheader, but other problems may occur!\n\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\nPARTITIONS!!\n\nDo you want to proceed? (Y/N): y\nOK; writing new GUID partition table (GPT) to XXXX.img.\nWarning: The kernel is still using the old partition table.\nThe new table will be used at the next reboot or after you\nrun partprobe(8) or kpartx(8)\nThe operation has completed successfully.\n\n\n\n# =========================================================================\n/work2$ sudo parted -m XXXX.img unit GiB print\n# =========================================================================\nBYT;\n/work2/XXXX.img:15.3GiB:file:512:512:gpt::;\n2:0.00GiB:0.00GiB:0.00GiB::TBC:;\n3:0.00GiB:0.00GiB:0.00GiB::RP1:;\n4:0.00GiB:0.00GiB:0.00GiB::EBT:;\n5:0.00GiB:0.00GiB:0.00GiB::WB0:;\n6:0.00GiB:0.01GiB:0.00GiB::BPF:;\n7:0.01GiB:0.01GiB:0.00GiB::BPF-DTB:;\n8:0.01GiB:0.01GiB:0.00GiB::FX:;\n9:0.01GiB:0.01GiB:0.00GiB::TOS:;\n10:0.01GiB:0.01GiB:0.00GiB::DTB:;\n11:0.01GiB:0.01GiB:0.00GiB::LNX:;\n12:0.01GiB:0.01GiB:0.00GiB::EKS:;\n13:0.01GiB:0.01GiB:0.00GiB::BMP:;\n14:0.01GiB:0.01GiB:0.00GiB::RP4:;\n1:0.01GiB:15.3GiB:15.3GiB:ext4:APP:;\n\n\n\n# =========================================================================\n/work2$ ls -la jetson_sd_20201022_2.img y.img \n# =========================================================================\n-rw-r--r-- 1 user  user 30953963520 10月 22 15:42 jetson_sd_20201022_2.img\n-rw-r--r-- 1 user  user 16422139904 10月 25 07:00 y.img\n</code></pre></div></div>\n\n<h1 id=\"新しいsdカードにバックアップを復元\">新しいSDカードにバックアップを復元</h1>\n\n<p>イメージファイルからSDカードへのコピーはWindowsマシンで行っても良いですが、ここではubuntu PCで行う方法について記載します。</p>\n\n<ul>\n  <li>ubuntu PCに新しいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>バックアップしたイメージファイルをSDカードにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«入力ファイル» <span class=\"nv\">of</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h1 id=\"新しいsdカードのパーティションを拡張\">新しいSDカードのパーティションを拡張</h1>\n\n<p>バックアップした際にパーティションサイズを縮小してあるため、そのままのSDカードではディスクの残り容量がわずかしかありません。<br />\nそこで、パーティションサイズを拡張して容量を増加させます。</p>\n\n<p>この作業はubuntu PCであらかじめ行うか、またはターゲットマシンでブートした後に行います。</p>\n\n<p>パーティション操作プログラム<code class=\"language-plaintext highlighter-rouge\">gparted</code>を使用します。<br />\nインストールされていない場合は、<code class=\"language-plaintext highlighter-rouge\">sudo apt install gparted</code>でインストールしておいてください。</p>\n\n<ul>\n  <li>gpartedを起動\n    <ul>\n      <li>Libparted Warning ダイアログで”Not all of the space available to ~”と出たらFixをクリック</li>\n      <li>Libparted Warning ダイアログで”The backup GPT table is corrupt, but the primary appears OK, so that will be used.”と出たらOKをクリック<br />\n以降も何度か出るが、以下の操作がすべて終わればbackup GPTが新たに作成されるので問題なし。<br />\n(これは、ディスクイメージを縮小したときにgdiskコマンドを実行しなかった場合に出ます)</li>\n      <li>Gparted→デバイスで<code class=\"language-plaintext highlighter-rouge\">«SDカードデバイス»</code>`を選択</li>\n      <li>図の<code class=\"language-plaintext highlighter-rouge\">«SDカードのパーティション»</code> を右クリック→「リサイズ/移動」をクリック\n        <ul>\n          <li>「新しいサイズ」の欄に上にある「最大サイズ」以下の値を入力</li>\n          <li>「リサイズ」をクリック</li>\n        </ul>\n      </li>\n      <li>「編集(E)」→「保留中の全ての操作を適用する(A)」をクリック\n        <ul>\n          <li>「本当に保留中の操作を適用してもよろしいですか?」と聞かれるので、「適用」をクリック</li>\n        </ul>\n      </li>\n      <li>処理が完了したら「閉じる」をクリック</li>\n    </ul>\n  </li>\n  <li>gpartedを終了</li>\n</ul>\n\n<p>ターゲットマシンで実行している場合は、そのまま使用できます。<br />\nubuntuマシンで実行した場合は、SDカードを取り外してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をセットアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をセットアップする</h1>\n      <p>Jetson nano をセットアップする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>本稿はJetoack4.4での手順です。<br />\nJetpack4.6のときのメモは<a href=\"/memoBlog/2021/09/13/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする(Jetpack4.6)</a> にあります。</p>\n\n<p>Nvidiaの<a href=\"https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/\">Jetson nano</a>をセットアップしたときのメモ</p>\n\n<h1 id=\"参照先\">参照先</h1>\n<ul>\n  <li><a href=\"https://monoist.atmarkit.co.jp/mn/articles/1905/30/news029.html\">「Jetson Nano」の電源を入れて立ち上げる</a>\n    <ul>\n      <li>わりと詳しく書いてある</li>\n    </ul>\n  </li>\n  <li><a href=\"https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit\">Getting Started With Jetson Nano Developer Kit </a>\n    <ul>\n      <li>本家</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"sdカードの作成\">SDカードの作成</h1>\n<p>参照先の通り。</p>\n\n<p>ただし、参照先のSDカードイメージへのリンクは古いので、は以下から最新版をダウンロードする(古いのも下の方を探せば出てくる)</p>\n<ul>\n  <li><a href=\"https://developer.nvidia.com/embedded/downloads\">Jetson Download Center</a></li>\n</ul>\n\n<p>SDカード書き込みは記事に書かれた balenaEtcher でなく WIN32DiskImager でも大丈夫だが、<br />\nbalenaEtcher は zipファイルを解凍せずにSDカードに書き込めるので便利。<br />\nちなみに、<em>balena</em> はイタリア語で <em>鯨</em> の意味らしい…全然関係ないけど…</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストール先のSDカードは32GB必須みたい。<br />\n16GBだとインストールしただけで「残り少ない」と言われてしまう。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSDカードスロットが分かりにくいところにある(開発ボード側ではなく、モジュール側の裏側)。<br />\nシリアルコンソール繋いでるとケーブルが邪魔で特に挿抜しにくい…</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\n一度このイメージを書き込んだSDカードは、以後Windowsから認識されなくなる。<br />\nよって、SDフォーマッタやディスクイメージ書き込みツールから新たに書き込みできなくなってしまう。\nこれは書き込んだSDカードにFATのパーティションが存在しないためのよう。<br />\n(RaspberryPiはbootパーティションとしてFATパーティションを持っているので認識されるようだ)</p>\n\n  <p>コントロールパネル→管理ツール→コンピュータの管理を起動して、<br />\n記憶域の下のディスクの管理からSDカード上の不明なパーティションを解放し、<br />\nそこに新たにFATパーティションを作成すればWindowsから認識されるようになる。<br />\nもちろん、他のUbuntuマシンで書き換えちゃうのもアリだけど。。。</p>\n</blockquote>\n\n<h1 id=\"シリアルコンソールの使用\">シリアルコンソールの使用</h1>\n<p>シリアルコンソールが必要なら接続できる。<br />\n特に設定等は必要ない。  <br />\n接続端子は以下を参照</p>\n<ul>\n  <li><a href=\"https://www.jetsonhacks.com/2019/04/19/jetson-nano-serial-console/\">Jetson Nano – Serial Console</a>\nの 「Wiring」の下の「Jetson Nano B01」を参照。</li>\n</ul>\n\n<p>シリアルポートの設定は115200bps/8bit/none/1bit/none</p>\n\n<blockquote>\n  <p>[!WARNING]\nJ41(RaspberryPi互換の40pinヘッダ)のUART端子はコンソールとして動作していないみたい。<br />\ngettyが動いてないみたいなので。  <br />\nたぶん、<code class=\"language-plaintext highlighter-rouge\">/etc/systemd/nvgetty.sh</code> に<code class=\"language-plaintext highlighter-rouge\">ttyTHS2</code>の設定を追加すればできるようになる感じだけど、試してないので詳細不明。<br />\nJ41のUARTを汎用UARTとして使用するには、以下を参照。</p>\n  <ul>\n    <li><a href=\"https://www.jetsonhacks.com/2019/10/10/jetson-nano-uart/\">Jetson Nano – UART</a></li>\n  </ul>\n</blockquote>\n\n<p>その他、コネクタ類の配置が分かりにくい場合は、\n<a href=\"https://developer.download.nvidia.com/assets/embedded/secure/jetson/Nano/docs/NV_Jetson_Nano_Developer_Kit_User_Guide.pdf?yIbsUqvBKxI1G6r3WW7cOdheZGv2-eSfaFW_kMt3dSgi0NJ7h77OwFHr5b-rquc3IX7Tyrt8FV6IKD4DHqvP4_LzhWt55tb071gqXlNGwBPYCOC5pnEKAla8D-B82bPjhQMykANFyn-EhxZRHC8AIBYWuVwwwXVPWtCOjs34Tg50oBdN0vBNoyUlZMRFXLNJ2to\">JETSON NANO DEVELOPER KIT</a>\nのP22 に<strong>Developer kit module and carrier board: rev B01 top view</strong>として配置図が掲載されているので参照のこと。</p>\n\n<h1 id=\"firstboot\">FirstBoot</h1>\n<p>最初のブートでUbuntuのセットアップを行う。<br />\nこれも参照先の通り。<br />\n終わったら、何はともあれ最新版にアップデート。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ここで一旦リブートしておく。</p>\n\n<p>その他こまごました設定はこちらが参考になるかも。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/05/08/ubuntu_native.html\">UbuntuをNative環境にインストールする(18.04)</a></li>\n</ul>\n\n<p>インストールしたパッケージ\ngnome-tweaks\ndconf-editor\nsamba</p>\n<blockquote>\n  <p>[!NOTE]\nmin/max/closeボタンがウィンドウ右側に移動できない…\nちょっとストレス…</p>\n</blockquote>\n\n<h1 id=\"その他設定\">その他設定</h1>\n<h2 id=\"ウィンドウマネージャをunityからubuntuに変更する\">ウィンドウマネージャをUnityからubuntuに変更する</h2>\n<p>Unityは使いにくくて嫌(個人の見解デス)なので、Ubuntuに変更する(変更しなくても良い)。\n自動ログインしている場合は、一旦ログアウトして、<br />\n再ログインする際に、「サインイン」ボタンの左にある歯車アイコンをクリック→Ubuntuを選択してから<br />\nログインすると、ウィンドウマネージャがUbuntuに変更されている。<br />\n次回ログイン(自動ログインでも)は何もしなくても前回のウィンドウマネージャが選択される。</p>\n<blockquote>\n  <p>[!NOTE]\nUbuntuに変えると min/max/closeボタンがウィンドウ右側に移動できてる。<br />\n結果オーライ😅</p>\n</blockquote>\n\n<h2 id=\"sshでの接続\">SSHでの接続</h2>\n<p>特に設定などは必要ない。<br />\nTeraTermなどで接続すれば良い。\nUbuntuではmDNSが動いているので、«マシン名».localでアクセスできる。</p>\n\n<p>コマンドは以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\"C:\\Program Files (x86)\\teraterm\\ttermpro.exe\" /auth=password /user=«ユーザ名» /passwd=«パスワード» «JetsonのIPアドレス or マシン名.local»\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nSSHやmDNSは立ち上がるまで少し時間がかかるみたいなので、<br />\n起動後数十秒程度待ってから接続した方が良い。</p>\n</blockquote>\n\n<h3 id=\"ssh接続がタイムアウトする対策\">SSH接続がタイムアウトする対策</h3>\n<p>SSH接続したターミナルを触らずにしばらく置いておくと、タイムアウトしてクローズされてしまう。\nこれを防ぐにはクライアント側からkeep-aliveパケットを定期的に送信してやれば良いらしい。</p>\n\n<p>Teratermの場合、「設定」→「SSH」→「ハートビート(keep-alive)」を「8」とかに設定し、保存。\n次回接続時はこの保存した設定ファイルを読み込む</p>\n\n<h3 id=\"シリアルコンソールssh接続でguiウィンドウを表示できるようにする\">シリアルコンソール/SSH接続でGUIウィンドウを表示できるようにする</h3>\n<p>シリアルコンソール/SSH接続でGUIウィンドウを表示できるようにするには、\nWindowsPCなどでX-Serverを動作させておき、<br />\nそこに出力するようにすればよい。<br />\nJetson側は<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加しておく。<br />\nここのIPアドレスはX-Serverが動作しているマシンのIPアドレスに変更すること。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XX.XX:0.0\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"リモートデスクトップの設定\">リモートデスクトップの設定</h1>\n<p>TigerVNC はちょっと動作があやしいので、やめておいて、Desktop Sharing(Vino)を使うことにする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f#%E6%96%B9%E6%B3%952-desktop-sharingvino%E3%82%92%E4%BD%BF%E3%81%86\">Jetson Nanoにリモートデスクトップ(VNC)環境を用意する</a></li>\n  <li><a href=\"https://www.hackster.io/news/getting-started-with-the-nvidia-jetson-nano-developer-kit-43aa7c298797\">Getting Started with the NVIDIA Jetson Nano Developer Kit</a> の 「Enabling Desktop Sharing」</li>\n</ul>\n\n<p>この手順はウィンドウマネージャがUnityで実行しています。 ウィンドウマネージャをUbuntuに変更していると少し手順が違うかもしれませんので、\nウィンドウマネージャをUbuntuに変更している場合はUnityに戻してから設定してください。<br />\n設定完了後はUbuntuに再変更しても問題ありません。</p>\n\n<p>以下手順の再掲。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml</code>に以下のパッチを当てる</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- org.gnome.Vino.gschema.xml.org      2020-10-19 06:21:32.034728957 +0900\n</span><span class=\"gi\">+++ org.gnome.Vino.gschema.xml  2020-10-19 06:22:30.887994965 +0900\n</span><span class=\"p\">@@ -154,5 +154,14 @@</span>\n       </description>\n       <default>true</default>\n     </key>\n<span class=\"gi\">+    <key name='enabled' type='b'>\n+      <summary>Enable remote access to the desktop</summary>\n+        <description>\n+          If true, allows remote access to the desktop via the RFB\n+          protocol. Users on remote machines may then connect to the\n+          desktop using a VNC viewer.\n+        </description>\n+      <default>false</default>\n+    </key>\n</span>   </schema>\n </schemalist>\n</code></pre></div></div>\n<ul>\n  <li>以下のコマンドを実行(これで「システム設定」に「デスクトップの共有」アイコンが表示されるようになる)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>glib-compile-schemas /usr/share/glib-2.0/schemas\n</code></pre></div>    </div>\n  </li>\n  <li>GUI画面から「システム設定」→「デスクトップの共有」(ユーザ向けカテゴリの中にある)\n    <ul>\n      <li>「Sharing」カテゴリ\n        <ul>\n          <li>「Allow other users to view your desktop」にチェックを<em>入れる</em></li>\n          <li>「Allow other users to control your desktop」にチェックを<em>入れる</em></li>\n        </ul>\n      </li>\n      <li>「セキュリティ」カテゴリ\n        <ul>\n          <li>「You must confirm each access to this machine」のチェックを<em>はずす</em></li>\n          <li>「Requwire the user to enter this password」にチェックを<em>入れて</em>パスワード設定</li>\n          <li>「Automatically configure UPnP router to open and forward ports」のチェックを<em>はずす</em></li>\n        </ul>\n      </li>\n      <li>「Show Notification Area Icon」カテゴリ\n        <ul>\n          <li>「Only when someone is connected」を選択\n            <blockquote>\n              <p>[!NOTE]\nウィンドウマネージャがUbuntuの時は「設定」で設定する。\n左側の「共有」カテゴリを選択、「画面共有」をクリック</p>\n              <ul>\n                <li>「このスクリーンの操作する接続を許可する」をチェック</li>\n                <li>「アクセスオプション」で「パスワードを要求する」を選択し、パスワード設定</li>\n                <li>「ネットワーク」で「有線接続1」のスライドスイッチで「オン」を選択\n左上のスライドスイッチで「オン」を選択\nで出来ると思うけど、出来なかったらUnityで上の方法で設定した後、再度Ubuntuに切り替えてちょ。</li>\n              </ul>\n            </blockquote>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>「自動起動するアプリケーション」を起動\n    <blockquote>\n      <p>[!NOTE]\n「コンピュータを検索」で「自動」または「session」と入力すると出てくる\n日本語環境だと「startup」で出てこないみたい…</p>\n    </blockquote>\n    <ul>\n      <li>「追加」ボタンをクリック\n        <ul>\n          <li>名前に「Vino」</li>\n          <li>コマンドに「/usr/lib/vino/vino-server」</li>\n          <li>説明に「VNC server」\nー と入力して「追加」をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>以下のコマンドを実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.Vino prompt-enabled <span class=\"nb\">false</span>\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\nこれはVinoの暗号化方式がWindowsと互換性がないための措置で、<br />\n暗号化を無効化しているらしい。<br />\ndconf-editorでも設定できる。</p>\n    </blockquote>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nVNC使う場合は自動ログインをONしておかないといけない<br />\n設定箇所はぐぐってちゃぶだい…😅</p>\n</blockquote>\n\n<ul>\n  <li>リブートする</li>\n  <li>ホストPCからRealVNCのVNC ViewerやUltraVNC viewerなどで接続する</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nVNCは反応速度が鈍いので、ちょっと使いにくい。<br />\n普段はSSHとsambaとホスト側のX-Serverで動かすのが良いかも…</p>\n</blockquote>\n\n<h1 id=\"追加情報\">追加情報</h1>\n<p>ipv6を無効にしたい(ネットワーク環境によっては無効にした方が良い)場合は、<br />\n<a href=\"/memoBlog/2020/05/26/ubuntu_koneta.html\">ubuntu 小ネタ集</a>の\n「ubuntu 18.04 で IPv6を無効にする方法」 にしたがって設定する。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージ(2021.1)をインストール(追加)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージ(2021.1)をインストール(追加)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2021.1対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a>で\nubuntuへopenVINO 2020.3のインストールしたが、今回は 2021.1 を追加インストールしたのでメモ。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>前に登録したときに通知されたURLから「Choose Version」でバージョン選んでダウンロードできる。<br />\n新しく登録しなても大丈夫(登録方法は<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>参照)。</p>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>これは前回と同じ。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫だが、<br />\ncmakeは<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたバージョンだと古くてNGといわれてしまうので、<br />\n別途本家からダウンロードしてインストールする(ubuntu 18.04の場合。20.04だとたぶん<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたので大丈夫)。</p>\n\n<ul>\n  <li>既に<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストール済みの場合は、アンインストールする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt purge <span class=\"nt\">--auto-remove</span> cmake\n</code></pre></div>    </div>\n  </li>\n  <li>本家からダウンロードして展開\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/Kitware/CMake/releases/download/v3.18.4/cmake-3.18.4-Linux-x86_64.tar.gz  \n<span class=\"nb\">tar </span>xzvf cmake-3.18.4-Linux-x86_64.tar.gz \n</code></pre></div>    </div>\n  </li>\n  <li>/opt ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv </span>cmake-3.18.4-Linux-x86_64 /opt/\n</code></pre></div>    </div>\n  </li>\n  <li>/usr/bin ディレクトリにシンボリックリンク作成\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /opt/cmake-3.18.4-Linux-x86_64/bin/<span class=\"k\">*</span> /usr/bin/\n</code></pre></div>    </div>\n  </li>\n  <li>バージョン確認\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">--version</span> \n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>インストール手順も<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫。</p>\n\n<p>完了したらこれが表示されるページのURLは以下に変更されている。<br />\n<a href=\"https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<p>2020.3インストール済みだと端折っても大丈夫かと思ったけど、微妙にパッケージ増えてたりするので、再度やった方が良い。<br />\n環境変数の設定のために、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に記述する処理は以下に変更(<code class=\"language-plaintext highlighter-rouge\">openvino</code>→<code class=\"language-plaintext highlighter-rouge\">openvino_2021</code>)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\n<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を実行すると、再度<code class=\"language-plaintext highlighter-rouge\">apt</code>で<code class=\"language-plaintext highlighter-rouge\">cmake</code>がインストールされてしまいます。<br />\nopenVINOのインストール完了後であれば<code class=\"language-plaintext highlighter-rouge\">cmake</code>のバージョンが古くても大丈夫ですが、<br />\n気になるなら、再度アンインストールとシンボリックリンクの作成を行います。<br />\n(実行前に<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を編集してcmake消しておいても良いけど)</p>\n</blockquote>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>これは2020.3インストール済みだと端折ってもOK。<br />\n初めてインストールなら<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>を参照。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その6</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その6</h1>\n      <p>tensorflow lite で色々なSSDモデルを使う手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はソースが大半なので、githubにリポジトリ作った。<br />\n内容は各ディレクトリのREADME.mdを見てチョ。<br />\n<a href=\"https://github.com/ippei8jp/tflite_trial\">https://github.com/ippei8jp/tflite_trial</a></p>\n\n<p>順序は <code class=\"language-plaintext highlighter-rouge\">download_models</code> → <code class=\"language-plaintext highlighter-rouge\">mk_tflite_ssd</code> → <code class=\"language-plaintext highlighter-rouge\">images</code> → <code class=\"language-plaintext highlighter-rouge\">ssd</code> が良いと思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール(改訂版)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2020.3対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a>で\nubuntuへのインストール手順を書いたが、今読み返すと結構分かりにくかったので改訂版を書いとく。<br />\n今回はNCS2をubuntuで使えるようにしたので、その手順も追加。<br />\nついでに、今日(2020/06/16)現在の最新版Ver.2020.3での手順確認したので、反映しておく。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<p>参考 :<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">AIを始めよう!OpenVINOのインストールからデモの実行まで[R4対応]</a></p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>何やら登録しないとダウンロードさせてくれないらしい。</p>\n<ul>\n  <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download.html\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a> <br />\nLinux* (supports Ubuntu, CentOS, and Yocto Project)を選択\n    <ul>\n      <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download/linux.html\">Free Download</a>  <br />\n<span style=\"border: 1px solid;\">Register & Download</span>をクリック\n        <ul>\n          <li><a href=\"https://software.seek.intel.com/openvino-toolkit?os=linux\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a><br />\n必要事項を記入して<span style=\"border: 1px solid;\">Submit</span>をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>openVINO用のpython環境を用意しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work1/\npyenv virtualenv 3.7.7 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p>あとで「入ってない」って言われるので先にインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev\n</code></pre></div></div>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>ダウンロードしたファイルを展開してインストールスクリプトを実行する。<br />\n今回はバージョン 2020.3 で確認した。<br />\n最新版は <a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html</a> を参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf l_openvino_toolkit_p_<version>.tgz\n<span class=\"nb\">cd </span>l_openvino_toolkit_p_<version>/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n<p>GUIで次へを押していく。</p>\n\n<p>完了したらこれが表示されるので、したがって進める。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<h3 id=\"install-external-software-dependencies\">Install External Software Dependencies</h3>\n<p>依存パッケージのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh \n</code></pre></div></div>\n\n<h3 id=\"set-the-environment-variables\">Set the Environment Variables</h3>\n<p>環境変数の設定<br />\n~/.bashrc に以下の一文を追加。これでこの後開くコンソールでは環境変数が設定される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>source /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<p>現在のターミナルでも使えるように以下のコマンドを実行しておく。コンソール開きなおしてもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<h3 id=\"configure-the-model-optimizer\">Configure the Model Optimizer</h3>\n<p>モデルオプティマイザのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh \n</code></pre></div></div>\n\n<p>上記スクリプトではsystemのpython3にpipモジュールがインストールされてしまうので、<br />\npyenv環境にも必要なpipモジュールをインストールしておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell openVINO                       <span class=\"c\"># python環境を固定したいので</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\npyenv shell <span class=\"nt\">--unset</span>                        <span class=\"c\"># python環境を戻しておく</span>\n</code></pre></div></div>\n\n<h3 id=\"run-the-verification-scripts-to-verify-installation\">Run the Verification Scripts to Verify Installation</h3>\n<p>デモ実行<br />\n「Verify Installation」って書いてあるけど、実行必須。</p>\n\n<ul>\n  <li>デモ用ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo/\n</code></pre></div>    </div>\n  </li>\n  <li>sudoでpyenvが使えないので、代わりに <code class=\"language-plaintext highlighter-rouge\">/work1</code>  で作成した <code class=\"language-plaintext highlighter-rouge\">.python-version</code>をコピーしておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /work1/.python-version <span class=\"nb\">.</span>\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境にデモ環境で必要なpipモジュールをインストールしておく 。Systemのpython使うときは↓のスクリプト実行時にインストールされる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その1\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/demo1.log\n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その2\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/dem2.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"steps-for-intel-processor-graphics-gpu\">Steps for Intel® Processor Graphics (GPU)</h3>\n<p>今回はGPUを使わないのでスキップ</p>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>NCS2の準備<br />\n色々書いてあるけど、これ一発でOK。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n中ではこんなことをやってます。<br />\nグループusersに自分を追加<br />\n(ログアウト & 再ログインするまで追加は反映されません)<br />\nudevルールの作成と再ロード</p>\n</blockquote>\n\n<p>NCS2をUSBポートにブッ挿すして認識したか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下があったら認識できてる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ID 03e7:2485\n</code></pre></div></div>\n\n<h3 id=\"steps-for-intel-vision-accelerator-design-with-intel-movidius-vpus\">Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPUs</h3>\n<p>今回はVPUを使わないのでスキップ</p>\n\n<p>デモプログラムの実行で動作確認</p>\n\n<p>で、Run a Sample Application に行く前に、ログアウト&再ログインでいいはずだけど、念のためリブート。</p>\n\n<h3 id=\"run-a-sample-application\">Run a Sample Application</h3>\n<p>リブートして開いてたページが分からなくなるといけないので、念のためURL貼っとく。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample</a></p>\n\n<ul>\n  <li>デモ実行ディレクトリに移動。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~/inference_engine_samples_build/intel64/Release\n</code></pre></div>    </div>\n  </li>\n  <li>CPUでデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> CPU\n</code></pre></div>    </div>\n  </li>\n  <li>NCS2でデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> MYRIAD\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>このページの手順はここでおしまい。</p>\n\n<h1 id=\"他のサンプルも試してみよう\">他のサンプルも試してみよう。</h1>\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n<h3 id=\"前準備\">前準備</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work1/NCS/sample <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work1/NCS/sample/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release /opt/intel/openvino_2020.3.194/deployment_tools/inference_engine/samples/cpp/\n</code></pre></div></div>\n\n<h3 id=\"ssdを試してみよう\">SSDを試してみよう</h3>\n<h4 id=\"build\">build</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">-j2</span> object_detection_sample_ssd\n</code></pre></div></div>\n<h4 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R4/20200117_150000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n</code></pre></div></div>\n\n<h4 id=\"実行\">実行</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./intel64/Release/object_detection_sample_ssd <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> /work/data/data2/z_20141013051441.jpg \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nコマンド実行時の<code class=\"language-plaintext highlighter-rouge\">-i</code>オプションは入力画像ファイル。<br />\n人の顔が写っているjpegファイルを指定しましょう。 \n顔が写ってなければ顔検出できません(^^ゞ</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[ INFO ] Execution successful</code>と表示されたら実行成功だと思う。</p>\n\n<h4 id=\"結果画像を表示してみる\">結果画像を表示してみる。</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>eog out_0.bmp \n</code></pre></div></div>\n\n<h4 id=\"おーーーー\"><strong><em>おーーーー</em></strong></h4>\n\n<h1 id=\"ここまでの作業でインストールしたpipパッケージ一覧\">ここまでの作業でインストールしたpipパッケージ一覧</h1>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.9.0\nastor==0.8.1\ncertifi==2020.4.5.2\nchardet==3.0.4\ndecorator==4.4.2\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.2.0\ngraphviz==0.8.4\ngrpcio==1.29.0\nh5py==2.10.0\nidna==2.9\nimportlib-metadata==1.6.1\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.2\nMarkdown==3.2.2\nmxnet==1.5.1\nnetworkx==2.4\nnumpy==1.18.5\nonnx==1.7.0\nopt-einsum==3.2.1\nprotobuf==3.6.1\nPyYAML==5.3.1\nrequests==2.23.0\nsix==1.15.0\ntensorboard==1.15.0\ntensorflow==1.15.3\ntensorflow-estimator==1.15.1\ntermcolor==1.1.0\ntyping-extensions==3.7.4.2\nurllib3==1.25.9\nWerkzeug==1.0.1\nwrapt==1.12.1\nzipp==3.1.0\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その5</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その5</h1>\n      <p>Tensorflow v1.15のインストールとソースからのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はUbuntuだけ。</p>\n\n<h1 id=\"tensorflow-115-のインストール\">Tensorflow 1.15 のインストール</h1>\n\n<p>Tensorflow1系でないと動かない環境とかサンプルとかあるので、<br />\nTensorflow v1.15をインストールする。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_1.15.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_1.15.0\n<span class=\"nb\">cd</span> /work/tf_1.15.0\npyenv <span class=\"nb\">local </span>tf_1.15.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"tensorflow-115-ライブラリのインストール\">Tensorflow 1.15 ライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>1.15\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nGPU使わないので-cpu付きパッケージを選択する</p>\n</blockquote>\n\n<h1 id=\"tensorflow-115-のbuild\">Tensorflow 1.15 のbuild</h1>\n\n<p>Tensorflowのpythonライブラリは<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできるが、\nソースからbuildしないと使えないツールもあるのでbuild環境を整える。</p>\n\n<p>参考: <a href=\"https://www.tensorflow.org/install/source?hl=ja\">ソースからのビルド | Tensorflow</a></p>\n\n<h2 id=\"bazelのインストール\">Bazelのインストール</h2>\n\n<p>Tensorflow をソースからbuildするには<code class=\"language-plaintext highlighter-rouge\">bazel</code>が必要なので、インストールしておく。</p>\n<blockquote>\n  <p>[!NOTE]\nBazelはVer.0.26.1 以下 を使用しないといけない<br />\nVer. 0.26.1はaptでインストールできない</p>\n</blockquote>\n\n<p>参考: <a href=\"https://docs.bazel.build/versions/0.26.0/install-ubuntu.html\">Installing Bazel on Ubuntu</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/bazelbuild/bazel/releases/download/0.26.1/bazel-0.26.1-installer-linux-x86_64.sh\n<span class=\"nb\">chmod</span> +x bazel-0.26.1-installer-linux-x86_64.sh\n./bazel-0.26.1-installer-linux-x86_64.sh <span class=\"nt\">--user</span>\n</code></pre></div></div>\n\n<p>実行ファイルは、<code class=\"language-plaintext highlighter-rouge\">~/bin/bazel</code> になるので、pathが~/binに通ってない場合は、一旦 ログアウトして 再ログイン\n(pathが通ってない場合、configureでエラーになる)</p>\n\n<h2 id=\"必要なpipパッケージのインストール\">必要なpipパッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>six numpy wheel mock <span class=\"s1\">'future>=0.17.1'</span>\npip <span class=\"nb\">install </span>keras_applications <span class=\"nt\">--no-deps</span>\npip <span class=\"nb\">install </span>keras_preprocessing <span class=\"nt\">--no-deps</span>\n</code></pre></div></div>\n\n<h2 id=\"tennsorflowのソースを取得\">tennsorflowのソースを取得</h2>\n\n<p>githubからcloneして V1.15.3 をチェックアウトしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/\ngit clone https://github.com/tensorflow/tensorflow.git\n<span class=\"nb\">cd </span>tensorflow\ngit checkout <span class=\"nt\">-b</span> v1.15.3 refs/tags/v1.15.3\n</code></pre></div></div>\n\n<h1 id=\"buildの設定\">buildの設定</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\n./configure\n<span class=\"c\"># いくつか質問されるので、すべてデフォルト(リターン)を入力</span>\n</code></pre></div></div>\n\n<h1 id=\"buildの実行\">buildの実行</h1>\n<h2 id=\"実行のひな形\">実行のひな形</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build //《対象ディレクトリ》:《ターゲット》\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n※ 対象ディレクトリはカレントディレクトリからの相対パス<br />\n※ ターゲットは対象ディレクトリのBUILDファイルで確認</p>\n</blockquote>\n\n<h2 id=\"例えばこんな感じ\">例えばこんな感じ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel build //tensorflow/lite/toco:toco\nbazel build //tensorflow/python/tools:freeze_graph\nbazel build //tensorflow/tools/graph_transforms:summarize_graph\nbazel build //tensorflow/tools/graph_transforms:transform_graph\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRAMは4GB以上必要かな?<br />\nオプション<code class=\"language-plaintext highlighter-rouge\">--local_ram_resources=2048</code>を指定すると使用するRAMを2GBに限定できる(指定する数値はMB単位)。<br />\n使用するPCのスペックによってかかる時間はマチマチ。<br />\nNativeなUbuntuで4コア8スレッドでも3~4時間程度かかる。<br />\nVirtualboxで1コア使用だと24時間とかかかることも。</p>\n</blockquote>\n\n<h2 id=\"buildしたファイルの実行\">buildしたファイルの実行</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">bazel run</code> で実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nオプションをbazelではなく実行するコマンドに渡すため、<code class=\"language-plaintext highlighter-rouge\">--</code> を入れる必要がある。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel run //tensorflow/lite/toco:toco <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:summarize_graph <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:transform_graph <span class=\"nt\">--</span> «オプション»\n</code></pre></div></div>\n\n<p>絶対パスで実行するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph «オプション»\n</code></pre></div></div>\n\n<p>パスが長いので、以下を設定しておくと便利。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">alias            </span><span class=\"nv\">toco</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">summarize_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">transform_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph'</span>\n</code></pre></div></div>\n\n<h2 id=\"おまけ\">おまけ</h2>\n\n<p>フツーはこっちがメインだが…(^^ゞ<br />\npipでインストールすれば必要ないが、Tensorflowのpipパッケージを作成するにはこちら。<br />\n(オプション変更したいときとか)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build <span class=\"nt\">--config</span><span class=\"o\">=</span>v1 //tensorflow/tools/pip_package:build_pip_package\n./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg\npip <span class=\"nb\">install</span> /tmp/tensorflow_pkg/tensorflow-1.15.3-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その4</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その4</h1>\n      <p>tensorflowのモデルファイル(*.pbや*.tflite)の可視化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>tensorflowのモデルファイル( <code class=\"language-plaintext highlighter-rouge\">*.pb</code> や <code class=\"language-plaintext highlighter-rouge\">*.tflite</code> )を可視化する方法について。<br />\n<code class=\"language-plaintext highlighter-rouge\">tensorboard</code> を使う方法などもあるが、最もお手軽と思われる <code class=\"language-plaintext highlighter-rouge\">netron</code> を使用する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれやらなくても、<a href=\"https://lutzroeder.github.io/netron/\">https://lutzroeder.github.io/netron/</a> にアクセスすれば使える。</p>\n</blockquote>\n\n<h1 id=\"netron-の-インストール\">netron の インストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code>をインストールする。<br />\n<code class=\"language-plaintext highlighter-rouge\">netron</code> はtensorflowのバージョンに依存しない(そもそもtensorflow自体に依存してない)のでTensorflow1系、Tenorflow2系 どちらの環境にインストールしてもよい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>netron\n</code></pre></div></div>\n\n<h1 id=\"netron-の-実行\">netron の 実行</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code> を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>netron <span class=\"nt\">--host</span> 0.0.0.0 <span class=\"o\">[</span><span class=\"nt\">--port</span> xxxx]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--host</code> オプションを指定しないとlocalhostからしか接続できないので、他のマシンから接続するときは指定する。<br />\n<code class=\"language-plaintext highlighter-rouge\">--port</code> オプションのデフォルトは8080なので、変更したいときは指定する。</p>\n\n<h1 id=\"モデルファイルの表示\">モデルファイルの表示</h1>\n\n<p>ブラウザ(Winマシンからで可)で実行したマシンのポート8008(またはオプションで指定したxxxx)に接続。<br />\n例:<code class=\"language-plaintext highlighter-rouge\">http://ncc-1701u.local:8080/</code></p>\n\n<p>表示された画面でOpen Model…をクリックして表示するモデルファイルを選ぶ。<br />\nしばらく待つと表示される。<br />\nモデルファイルはブラウザからアップロードするので、ブラウザから参照できる場所になければならない(サーバ側にあってもダメ)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">*.pb</code> ファイルが大きいとうまく表示できないみたい。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その3</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その3</h1>\n      <p>Tensorflow 2.2.0をインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Edge-TPUを直接操作するわけではないが、Tensorflowで作成されたモデルファイルをtflite用に変換する準備として<br />\ntensorflowをインストールする。<br />\nここではVersion 2.2.0を使用する。</p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<p>coral環境に追加インストールでも良いが、今回は別の環境を用意する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_2.2.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_2.2.0\n<span class=\"nb\">cd</span> /work/tf_2.2.0\npyenv <span class=\"nb\">local </span>tf_2.2.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"tensorflow-220-のインストール\">tensorflow 2.2.0 のインストール</h1>\n\n<p>インストールするパッケージはGPUを使わないので-cpu付きパッケージを選択する。<br />\nTensorflowはバージョンによって機能差が激しいので、インストールするバージョンを指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>2.2.0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その2</h1>\n      <p>Google Coral USB Accelerator で SSD(Single Shot MultiBox Detector)を実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n一部を除き、基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<h1 id=\"tflite-の-モデルファイルをedgetpu使用モデルに変換する方法\">tflite の モデルファイルをEdgeTPU使用モデルに変換する方法</h1>\n<p>通常のtfliteのモデルファイルはCPUのみ(またはCPU+GPU)を使用するように構成されていて、\nそのまま実行してもEdge-TPUは使用されない。<br />\nそこで、Edge-TPU使用モデルに変換するため、edgetpu_compilerを使用する必要がある。<br />\n(ただし、Ubuntuのみ。RasPi不可。)</p>\n\n<h2 id=\"edgetpu_compiler-のインストール\">edgetpu_compiler のインストール</h2>\n\n<p>CPU使用モデルからEdge-TPU使用モデルに変換するツール<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code>をインストールする。<br />\naptリポジトリの登録はTPUライブラリインストール時に行っているので不要(以下ではコメントアウトしてある)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -</span>\n<span class=\"c\"># echo \"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list</span>\n<span class=\"c\"># sudo apt update</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>edgetpu-compiler\n</code></pre></div></div>\n\n<h2 id=\"使用方法\">使用方法</h2>\n<p>基本的に以下。<br />\ntfliteファイルを喰わせるとファイル名に<code class=\"language-plaintext highlighter-rouge\">_edgetpu</code>を付加したファイルが作成される。<br />\nこれがEdge-TPU使用するモデルファイル。<br />\n詳細は<a href=\"https://coral.ai/docs/edgetpu/compiler/\">Edge TPU Compiler</a> を参照。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>edgetpu_compiler [options] model...\n</code></pre></div></div>\n\n<h1 id=\"事前準備\">事前準備</h1>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n\n<p>openCVをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"ssdを実行してみる\">SSDを実行してみる</h1>\n\n<h2 id=\"作業用ディレクトリの作成移動\">作業用ディレクトリの作成&移動</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral/ssd/\n<span class=\"nb\">cd</span> /work/coral/ssd/\n</code></pre></div></div>\n\n<h2 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h2>\n\n<p>用意されているSSDのモデルをダウンロードし、Edge-TPU使用モデルを作成する。<br />\n実行が終了すると、<code class=\"language-plaintext highlighter-rouge\">models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite</code> ができる。</p>\n\n<ul>\n  <li>ダウンロード元: <a href=\"https://www.tensorflow.org/lite/models/object_detection/overview\">Object detection</a>\nの 「Get Started」の「Download starter model and labels」</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl <span class=\"nt\">-O</span> https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip\nunzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip \n<span class=\"nb\">mv </span>detect.tflite coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># リネームしなくてもいいけど、後でわからなくならないようにリネームしておく</span>\n<span class=\"nb\">mv </span>labelmap.txt coco_ssd_mobilenet_v1_1.0_quant.labels   <span class=\"c\"># 同上</span>\nedgetpu_compiler coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># EdgeTPU使用モデルに変換</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"テスト用画像の準備\">テスト用画像の準備</h2>\n\n<p>適当な画像を<code class=\"language-plaintext highlighter-rouge\">image</code>ディレクトリに用意しておく。<br />\n使用できるファイル形式は<code class=\"language-plaintext highlighter-rouge\">jpg</code>と<code class=\"language-plaintext highlighter-rouge\">mp4</code></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>images\n<span class=\"nb\">cd </span>images/\n<span class=\"c\"># 適当な画像ファイルをダウンロードする</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"ssdのプログラムソース\">SSDのプログラムソース</h2>\n\n<p>以下の内容を<code class=\"language-plaintext highlighter-rouge\">object_detection_demo_ssd.py</code>として保存しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">tflite_runtime.interpreter</span> <span class=\"k\">as</span> <span class=\"n\">tflite</span>\n\n<span class=\"c1\"># shared library\n</span><span class=\"n\">EDGETPU_SHARED_LIB</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n  <span class=\"s\">'Linux'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.so.1'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Darwin'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.1.dylib'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Windows'</span><span class=\"p\">:</span> <span class=\"s\">'edgetpu.dll'</span>\n<span class=\"p\">}[</span><span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">system</span><span class=\"p\">()]</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># interpreter の生成\n</span><span class=\"k\">def</span> <span class=\"nf\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">):</span>\n    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"o\">=</span><span class=\"n\">model_file</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span>\n                <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">model_file</span><span class=\"p\">,</span>\n                <span class=\"n\">experimental_delegates</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n                    <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">load_delegate</span><span class=\"p\">(</span><span class=\"n\">EDGETPU_SHARED_LIB</span><span class=\"p\">)</span>\n                <span class=\"p\">])</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    \n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">output_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_output_details</span><span class=\"p\">()</span>\n    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n\n    <span class=\"n\">tflite_results1</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Locations (Top, Left, Bottom, Right)\n</span>    <span class=\"n\">tflite_results2</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Classes (0=Person)\n</span>    <span class=\"n\">tflite_results3</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Scores\n</span>    <span class=\"n\">tflite_results4</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Number of detections\n</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">tflite_results4</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])):</span>\n        <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        \n        <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>        <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n\n        <span class=\"n\">prob</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results3</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">prob</span> <span class=\"o\">>=</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'Class=</span><span class=\"si\">{</span><span class=\"n\">class_name</span><span class=\"si\">:</span><span class=\"mi\">15</span><span class=\"si\">}</span><span class=\"s\">    Probability=</span><span class=\"si\">{</span><span class=\"n\">prob</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    Location=(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)-(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n            <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span>    <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span>   <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span>  <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 表示色\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 対象物の枠とラベルの描画\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"n\">bottom</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">20</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"o\">+</span><span class=\"mi\">160</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"s\">\"{} ({:.3f})\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">class_name</span><span class=\"p\">,</span> <span class=\"n\">prob</span><span class=\"p\">),</span>\n                        <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># interpreterの構築\n</span>    <span class=\"n\">interpreter</span> <span class=\"o\">=</span> <span class=\"n\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">allocate_tensors</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">input_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()</span>\n    \n    <span class=\"c1\"># 入力データ\n</span>    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">org_frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>                 <span class=\"c1\"># オリジナルのフレームレート\n</span>    <span class=\"n\">org_frame_time</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span> <span class=\"o\">/</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>                <span class=\"c1\"># オリジナルのフレーム時間\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">org_frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルの読み込み\n</span>        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルがない場合\n</span>        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># フレーム数\n</span>    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 実行時間測定用変数の初期化\n</span>    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n    <span class=\"c1\"># フレーム測定用タイマ\n</span>    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># モデルの入力サイズ\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># 画像の前処理 =============================================================================\n</span>        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                          <span class=\"c1\"># 前処理開始時刻\n</span>        \n        <span class=\"c1\"># 画像の読み込み\n</span>        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレームを作成\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># モデル入力用にリサイズ\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>   <span class=\"c1\"># input size of coco ssd mobilenet?\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">]]</span>                          <span class=\"c1\"># BGR -> RGB\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">in_frame</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>                 <span class=\"c1\"># 3D -> 4D\n</span>        \n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>     <span class=\"c1\"># 前処理にかかった時間\n</span>        \n        <span class=\"c1\"># 推論実行 =============================================================================\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"c1\"># 推論本体\n</span>        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">set_tensor</span><span class=\"p\">(</span><span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">],</span> <span class=\"n\">in_frame</span><span class=\"p\">)</span>\n        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">invoke</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>                          <span class=\"c1\"># 推論処理にかかった時間\n</span>        \n        <span class=\"c1\"># 検出結果の解析 =============================================================================\n</span>        <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                               <span class=\"c1\"># 解析処理開始時刻\n</span>        <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n        <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>                    <span class=\"c1\"># 解析処理にかかった時間\n</span>        \n        <span class=\"c1\"># 結果の表示 =============================================================================\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 表示処理開始時刻\n</span>        \n        <span class=\"c1\"># 測定データの表示\n</span>        <span class=\"n\">frame_number_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'frame_number   : </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span>\n        <span class=\"k\">if</span> <span class=\"n\">frame_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span>  <span class=\"s\">'Frame time     : ---'</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Frame time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms    </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> fps'</span>\n        <span class=\"n\">inf_time_message</span>        <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Inference time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">render_time_message</span>     <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Rendering time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">parsing_time_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'parse time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        \n        <span class=\"c1\"># 結果の書き込み\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_number_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>     <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>   <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像の保存\n</span>        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>                 <span class=\"c1\"># 表示処理にかかった時間\n</span>        \n        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"c1\"># フレーム処理終了 =============================================================================\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_key_code</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"make_interpretermodel_file\">make_interpreter(model_file)</h3>\n\n<p>interpreter(認識エンジン)を構築する処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>モデルファイル内に<code class=\"language-plaintext highlighter-rouge\">\"edgetpu-custom-op\"</code>という文字列が含まれていたらTPU使用モデルと判定してTPU使用のための共有ライブラリをダウンロードして初期化する。<br />\nそうでなければCPUのみ使用モデルなので、 共有ライブラリなしで初期化する。</p>\n\n<p>もっと単純にモデルファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>が含まれていたらTPU使用モデルと判定しても良いかもしれない(<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code> は出力ファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>を付加するので)。</p>\n\n<h3 id=\"parse_resultinterpreter-frame-labels_map-args\">parse_result(interpreter, frame, labels_map, args)</h3>\n\n<p>認識結果の解析と結果の表示(検出枠とラベルの描画)</p>\n\n<p>認識結果から検出した座標、クラスID、スコアを取得し、出力画像に描画している。</p>\n\n<p>出力データの構成は<a href=\"https://www.tensorflow.org/lite/models/object_detection/overview#output\">ここ</a>を参照。</p>\n\n<p>どうやらこのモデルは検出個数が10個に設定されているようだ。</p>\n\n<h3 id=\"main\">main()</h3>\n\n<p>メインルーチン</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>タイミング調整部分は、認識処理が速かった場合に結果表示画像の表示時間を実際の入力画像の表示時間に合わせるため、ちょっと小細工を入れてある。</p>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--help</span>\nusage: object_detection_demo_ssd.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT <span class=\"o\">[</span><span class=\"nt\">-l</span> LABELS]\n                                    <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> LABELS, <span class=\"nt\">--labels</span> LABELS\n                        Optional. Labels mapping file\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合edge-tpu使用\">静止画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合edge-tpu使用\">動画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n再生が終了するか、画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n<h2 id=\"静止画の場合cpuのみ\">静止画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合cpuのみ\">動画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その1</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その1</h1>\n      <p>Google Coral USB Acceleratorのインストールメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<p>参考サイト:\n<a href=\"https://qiita.com/rhene/items/7b34f60b73645d430789\">RaspberryPi 4でCoral USB TPU Accelerator(EdgeTPU)をとりあえず使う</a></p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<h2 id=\"edgetpu用ライブラリのインストール\">EdgeTPU用ライブラリのインストール</h2>\n\n<p>下記コマンドを実行して、EdgeTPU用ライブラリ(ドライバ類)をインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/coral-edgetpu.list\ncurl https://packages.cloud.google.com/apt/doc/apt-key.gpg | <span class=\"nb\">sudo </span>apt-key add -\n\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># 通常版をインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libedgetpu1-std\n<span class=\"c\"># または、最大クロック版</span>\n<span class=\"c\"># sudo apt install libedgetpu1-max</span>\n</code></pre></div></div>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 coral\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral\n<span class=\"nb\">cd</span> /work/coral\npyenv <span class=\"nb\">local </span>coral \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<p>numpyのinstallで失敗するので、以下を実行しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n</code></pre></div></div>\n\n<h2 id=\"tfliteモジュールのインストール\">TFLiteモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install  </span>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nどれをインストールするかは<a href=\"https://www.tensorflow.org/lite/guide/python\">Python quickstart</a>で確認<br />\n========= 例えば、ubuntu/raspbianのときはpythonのバージョンに応じて以下のどれかを指定 ==============</p>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (x86-64)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl</td>\n      </tr>\n    </tbody>\n  </table>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (ARM 32)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl</td>\n      </tr>\n    </tbody>\n  </table>\n</blockquote>\n\n<h2 id=\"coral-usb-acceleratorの接続と確認\">Coral USB Acceleratorの接続と確認</h2>\n\n<p>USBポートに Coral USB Accelerator を接続する</p>\n\n<p>認識されたことを確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下の表示があったら正常に認識されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>«省略»\nBus XXX Device YYY: ID 1a6e:089a Global Unichip Corp. \n«省略»\n</code></pre></div></div>\n\n<h1 id=\"動作確認サンプルプログラム\">動作確認(サンプルプログラム)</h1>\n\n<h2 id=\"サンプルソースのインストール\">サンプルソースのインストール</h2>\n\n<p>Githubからソースをダウンロードする</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/\ngit<span class=\"k\">**</span> clone https://github.com/google-coral/tflite.git\n</code></pre></div></div>\n\n<h2 id=\"サンプルプログラムの実行その1-classification\">サンプルプログラムの実行(その1) classification</h2>\n\n<h3 id=\"プログラムディレクトリへの移動\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/classification/\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh \n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py \n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n<p>結果の例は以下。<br />\n結果は「Ara macao(コンゴウインコ)」と表示されている。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference on Edge TPU is slow because it includes loading the model into Edge TPU memory.\n12.4ms\n4.2ms\n4.1ms\n4.2ms\n4.2ms\n-------RESULTS--------\nAra macao (Scarlet Macaw): 0.77734\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n\n<p><a id=\"CPUonlydiff\"> </a></p>\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合もCoral USB Acceleratorを接続しておかないとエラーになる。<br />\n接続しなくても実行できるようにするには以下のパッチを適用し、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">-cpu</code>オプションを指定する。</p>\n\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/python/examples/classification/classify_image.py b/python/examples/classification/\n</span><span class=\"gi\">> classify_image.py\n</span><span class=\"gh\">index 75f1d76..44fb798 100644\n</span><span class=\"gd\">--- a/python/examples/classification/classify_image.py\n</span><span class=\"gi\">+++ b/python/examples/classification/classify_image.py\n</span><span class=\"p\">@@ -12,7 +12,7 @@</span>\n<span class=\"err\">#</span> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n # See the License for the specific language governing permissions and\n # limitations under the License.\n<span class=\"gd\">-r\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span><span class=\"gi\">+\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span>\n    To run this code, you must attach an Edge TPU attached to the host and\n    install the Edge TPU runtime (`libedgetpu.so`) and `tflite_runtime`. For\n<span class=\"p\">@@ -64,9 +64,12 @@</span> def load_labels(path, encoding='utf-8'):\n       return {index: line.strip() for index, line in enumerate(lines)}\n\n\n<span class=\"gd\">-def make_interpreter(model_file):\n</span><span class=\"gi\">+def make_interpreter(model_file, cpu=False):\n</span>   model_file, *device = model_file.split('@')\n<span class=\"gd\">-  return tflite.Interpreter(\n</span><span class=\"gi\">+  if cpu :\n+    return tflite.Interpreter(model_path=model_file)\n+  else :\n+    return tflite.Interpreter(\n</span>       model_path=model_file,\n       experimental_delegates=[\n           tflite.load_delegate(EDGETPU_SHARED_LIB,\n<span class=\"p\">@@ -92,11 +95,19 @@</span> def main():\n   parser.add_argument(\n       '-c', '--count', type=int, default=5,\n       help='Number of times to run inference')\n<span class=\"gi\">+  parser.add_argument(\n+      '--cpu', action='store_true',\n+      help='use cpu only(default:use with TPU)')\n</span>   args = parser.parse_args()\n\n+  if args.cpu :\n<span class=\"gi\">+    print('**** USE CPU ONLY!! ****')\n+  else :\n+    print('**** USE WITH TPU ****')\n+\n</span>   labels = load_labels(args.labels) if args.labels else {}\n\n-  interpreter = make_interpreter(args.model)\n<span class=\"gi\">+  interpreter = make_interpreter(args.model, args.cpu)\n</span>   interpreter.allocate_tensors()\n\n   size = classify.input_size(interpreter)\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"サンプルプログラムの実行その2-detection\">サンプルプログラムの実行(その2) detection</h2>\n\n<h3 id=\"プログラムディレクトリへの移動-1\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/detection\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール-1\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh\n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行-1\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<p>結果の例は以下。<br />\n以下の表示と同時に認識結果の画像が別ウィンドウで表示される。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference is slow because it includes loading the model into Edge TPU memory.\n27.90 ms\n11.59 ms\n11.36 ms\n11.89 ms\n11.10 ms\n-------RESULTS--------\ntie\n  id:     31\n  score:  0.83984375\n  bbox:   BBox(xmin=226, ymin=417, xmax=290, ymax=539)\nperson\n  id:     0\n  score:  0.83984375\n  bbox:   BBox(xmin=2, ymin=5, xmax=507, ymax=590)\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行-1\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションを指定すると、結果画像を保存するとともに、表示を行う。<br />\n指定しなければ認識だけ行う(結果の画像表示もしない)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションによる出力ファイルの形式は指定した拡張子で決定される。jpgやbmpなど。<br />\nrawデータで出力した場合(拡張子rgb)は、以下のコマンドでjpgやbmpに変換できる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.jpg\n</code></pre></div>  </div>\n\n  <p>または</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.bmp\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合でCoral USB Acceleratorを接続していなくてエラーになる場合は<br />\n<a href=\"#CPUonlydiff\">こちら</a>を参照</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD(その2)</h1>\n      <p>openVINOのSSDのサンプルプログラムのモデルデータを変更してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> でSSDを動かしてみたが、\n検出できるオブジェクトの種類が少なくてちょっと寂しかったので、別のモデルがないか探してみた。</p>\n\n<p>で、調べてみると、openCVのopen_model_zoo以外にもTensorFlowの公式モデルなどをダウンロードして変換するスクリプトが用意されていた。<br />\nで、以下手順。</p>\n\n<h1 id=\"モデルのダウンロードモデルのirへの変換\">モデルのダウンロード&モデルのIRへの変換</h1>\n\n<h4 id=\"テンポラリディレクトリの作成移動\">テンポラリディレクトリの作成&移動</h4>\n\n<p>とりあえず作業用のディレクトリを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/temp\n<span class=\"nb\">cd</span> /work/temp\n</code></pre></div></div>\n\n<h3 id=\"使用できるモデルの一覧を表示\">使用できるモデルの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py  <span class=\"nt\">--print_all</span>\n</code></pre></div></div>\n\n<p>ちなみに、モデル毎の設定は以下にあるので、雰囲気で解読してちょ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>${INTEL_OPENVINO_DIR}/deployment_tools/open_model_zoo/models/public/${modelname}/model.yml\n</code></pre></div></div>\n\n<h3 id=\"このへんのモデルを使ってみる\">このへんのモデルを使ってみる</h3>\n\n<p>なんとなく、mobilenetが小さそうなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssd_mobilenet_v2_coco\n</code></pre></div></div>\n\n<p>または</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssdlite_mobilenet_v2\n</code></pre></div></div>\n\n<p>ssdlightの方がモデルデータが小さい。その分精度は落ちるらしい。<br />\n検出できるオブジェクトの種類は同じ。<br />\n出力は90種類だが、途中欠番があるみたいなので実質80種類くらい。<br />\n変わったところでは「テディベア」なんてのもある。試してみたらちゃんと認識した(あたりまえか…)。<br />\ncocoデータセット<a href=\"http://cocodataset.org/#home\">http://cocodataset.org/#home</a>なので、有名どころですね。<br />\nあ、「80 object categories 91 stuff categories」ってちゃんと書いてある…</p>\n\n<h3 id=\"ダウンロード\">ダウンロード</h3>\n\n<p>まずはダウンロード。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/</code>にモデルがダウンロードされる。</p>\n\n<h3 id=\"モデルデータをirファイルへ変換\">モデルデータをIRファイルへ変換</h3>\n\n<p>もとのモデルデータはTensorFlowで使用するProtocolBuffer形式なので、openVINOで使用できるIR形式に変換する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/converter.py <span class=\"nt\">--precisions</span> FP16 <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/FP16/</code>にIRモデルが出来る。</p>\n\n<h3 id=\"そのままの場所で使用しても良いが他のモデルとまとめておく\">そのままの場所で使用しても良いが、他のモデルとまとめておく</h3>\n\n<p>モデルがあちこちにあると管理しずらくなるので、他のモデルと同じところに置いておく。<br />\n必要なのはxmlとbin。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>public/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>/FP16/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>.<span class=\"o\">{</span>xml,bin<span class=\"o\">}</span> /work/NCS2/openvino_models/FP16/\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">.{xml,bin}</code>のところにスペースなどを入れてしまうとうまく動かないので注意。<br />\n結構「あとで読みやすいように」と入れてしまいがち(特にスクリプト書くとき)なので注意。</p>\n\n<h3 id=\"ラベルファイルの作成\">ラベルファイルの作成</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/work/NCS2/openvino_models/FP16/${modelname}.labels</code>にラベルデータを作成しておく。<br />\nなくても可。<br />\n作り方は後述。</p>\n\n<h3 id=\"実行\">実行</h3>\n\n<p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> の「デモ実行」と同じ手順で\nモデルファイルを差し替えて(<code class=\"language-plaintext highlighter-rouge\">--model</code>オプション)実行すれば良い。</p>\n\n<h1 id=\"ラベルファイルの作成方法\">ラベルファイルの作成方法</h1>\n\n<p>ラベルデータはモデルデータには含まれていないようなので、作成する方法を検討してみた。</p>\n\n<h3 id=\"tensorflowのmodelsモジュールをダウンロード\">tensorflowのmodelsモジュールをダウンロード</h3>\n\n<p>まず、モデルデータの作成情報のあるモジュールをダウンロードしておく。<br />\ngitでなくてもzipをダウンロードして展開しておいても可(ちょっとデカいので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git models_tf\n</code></pre></div></div>\n\n<h3 id=\"作業ディレクトリに移動\">作業ディレクトリに移動</h3>\n\n<p>あとでpythonプログラムを作成するときに色々面倒がないので、作業ディレクトリはココで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models_tf/research\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">object_detection/samples/configs</code>から対応するconfigファイルを探して(なんとなく雰囲気で探せ!)表示<br />\n<code class=\"language-plaintext highlighter-rouge\">label_map_path</code>に記載されたファイルがlabel_mapファイル<br />\nこのとき、PATH_TO_BE_CONFIGURED は <code class=\"language-plaintext highlighter-rouge\">object_detection/data</code> に読み替えること</p>\n\n<p>ssd_mobilenet_v2_cocoの場合は以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/samples/configs/ssd_mobilenet_v2_coco.config\n</code></pre></div></div>\n\n<p>上記ファイルの場合、label_mapは以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/data/mscoco_label_map.pbtxt\"\n</code></pre></div></div>\n\n<p>こにファイルにIDとラベルが定義されているが、そのままラベルファイルとしては認識できない。<br />\nIDには途中抜けがあるので注意(そのままgrepで抜き出してはダメ)</p>\n\n<h2 id=\"ラベルデータ変換プログラムを作成する\">ラベルデータ変換プログラムを作成する</h2>\n\n<p>label_map.pbtxtからラベル一覧を取得するのを手作業で行うのは大変なので、プログラムを作成する。</p>\n\n<h3 id=\"protocのインストール\">protocのインストール</h3>\n\n<p>まずは必要なモジュールのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n</code></pre></div></div>\n\n<h3 id=\"protoファイルからpythonモジュールを作成する\">protoファイルからpythonモジュールを作成する</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>protoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"変換プログラムのソース\">変換プログラムのソース</h3>\n\n<p>label_mapからテーブルを作成するスクリプト(labelmap2labels.py)をカレントディレクトリに作成する。<br />\nやっつけ仕事なので、かなりテキトー(笑)、、、</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">object_detection.utils</span> <span class=\"kn\">import</span> <span class=\"n\">label_map_util</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"==== USAGE ====\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"    python </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> label_map_file\"</span><span class=\"p\">)</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># パラメータが1個でない\n</span>    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_map_file = \"object_detection/data/mscoco_complete_label_map.pbtxt\"\n</span><span class=\"n\">label_map_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># 第一パラメータのファイルが存在しない\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"error: '</span><span class=\"si\">{</span><span class=\"n\">label_map_file</span><span class=\"si\">}</span><span class=\"s\">' not exist</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_mapからカテゴリインデックスを作成\n</span><span class=\"n\">category_index</span> <span class=\"o\">=</span> <span class=\"n\">label_map_util</span><span class=\"p\">.</span><span class=\"n\">create_category_index_from_labelmap</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span>\n\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># print(i)\n</span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">category_index</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">\"name\"</span><span class=\"p\">]</span>\n    <span class=\"k\">except</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'{name}\\t# {i}')\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n    \n<span class=\"c1\"># 個数確認のためにダミーを出力\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スクリプトの実行\">スクリプトの実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.py label_map_file\n</code></pre></div></div>\n\n<p>結果は標準出力へ出力されるので、ファイルにcastして使用する</p>\n\n<p>例:</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.pyobject_detection/data/mscoco_complete_label_map.pbtxt <span class=\"o\">></span> mscoco_complete.labels\n</code></pre></div></div>\n\n<p>出来上がったlabelsファイルを必要なところへコピーして使ってちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO で顔検出(特定人物識別)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO で顔検出(特定人物識別)</h1>\n      <p>openVINOの顔検出(特定人物識別)のサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOで顔検出(特定人物識別)するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"ソースをワークディレクトリにコピー\">ソースをワークディレクトリにコピー</h1>\n\n<p>ファイルのオーナがrootなので、編集しやすいようにワークディレクトリにソースをコピーし、そこで作業する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>face_recognition_demo/\n</code></pre></div></div>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p>いくつかのモデルデータが必要になるので、ダウンロードする。<br />\nワイルドカードでファイル指定したかったので、wgetでなくcurlを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/landmarks-regression-retail-0009/FP16/landmarks-regression-retail-0009.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-reidentification-retail-0095/FP16/face-reidentification-retail-0095.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\n<span class=\"nb\">cd</span> ..\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ncurlは「カレントディレクトリにターゲットと同じファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-O</code> と 「任意のファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-o</code>オプションしかなく、\nwgetの「ターゲットと同じファイル名で保存先ディレクトリを指定して保存」の<code class=\"language-plaintext highlighter-rouge\">-P</code>に相当するオプションがないので、\nカレントディレクトリを保存先に移動してから<code class=\"language-plaintext highlighter-rouge\">-O</code> オプションでコマンドを実行する。</p>\n</blockquote>\n\n<h1 id=\"足りないモジュールのインストール\">足りないモジュールのインストール</h1>\n\n<p>使用するモジュールでこれまでのお試しで未インストールのモジュールがあるのでインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>scipy\n</code></pre></div></div>\n\n<h1 id=\"ソースの修正\">ソースの修正</h1>\n\n<p>ソースはそのままで問題ないが、ちょっと修正しておく。</p>\n\n<p>主な変更内容は以下の通り。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code> オプションの追加と関連処理</li>\n  <li>Unknownと識別できた場合で検出枠の色を変える</li>\n  <li>入力ファイルを絶対パスに変換(不具合対策)</li>\n  <li>出力ファイルのフォーマットのmp4対応を追加(オリジナルはaviのみ対応)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur face_recognition_demo.org/face_recognition_demo.py face_recognition_demo/face_recognition_demo.py\n</span><span class=\"gd\">--- face_recognition_demo.org/face_recognition_demo.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/face_recognition_demo.py\t2019-11-27 06:29:07.507574900 +0900\n</span><span class=\"p\">@@ -62,6 +62,10 @@</span>\n     gallery.add_argument('--run_detector', action='store_true',\n                          help=\"(optional) Use Face Detection model to find faces\" \\\n                          \" on the face images, otherwise use full images.\")\n<span class=\"gi\">+    gallery.add_argument('--run_detector_no_save', action='store_true',\n+                         help=\"(optional) Use Face Detection model to find faces\" \\\n+                         \" on the face images, otherwise use full images.\" \\\n+                         \" not save detected face image.\")\n</span> \n     models = parser.add_argument_group('Models')\n     models.add_argument('-m_fd', metavar=\"PATH\", default=\"\", required=True,\n<span class=\"p\">@@ -142,7 +146,7 @@</span>\n         log.info(\"Building faces database using images from '%s'\" % (args.fg))\n         self.faces_database = FacesDatabase(args.fg, self.face_identifier,\n                                             self.landmarks_detector,\n<span class=\"gd\">-                                            self.face_detector if args.run_detector else None, args.no_show)\n</span><span class=\"gi\">+                                            self.face_detector if args.run_detector or args.run_detector_no_save else None, args.no_show, args.run_detector_no_save)\n</span>         self.face_identifier.set_faces_database(self.faces_database)\n         log.info(\"Database is built, registered %s identities\" % \\\n             (len(self.faces_database)))\n<span class=\"p\">@@ -261,9 +265,8 @@</span>\n             .face_identifier.get_identity_label(identity.id)\n \n         # Draw face ROI border\n<span class=\"gd\">-        cv2.rectangle(frame,\n-                      tuple(roi.position), tuple(roi.position + roi.size),\n-                      (0, 220, 0), 2)\n</span><span class=\"gi\">+        color1 = (0, 220, 0) if identity.id == FaceIdentifier.UNKNOWN_ID else (0, 0, 220)\n+        cv2.rectangle(frame, tuple(roi.position), tuple(roi.position + roi.size), color1, 2)\n</span> \n         # Draw identity label\n         text_scale = 0.5\n<span class=\"p\">@@ -398,19 +401,17 @@</span>\n         try:\n             stream = int(path)\n         except ValueError:\n<span class=\"gd\">-            pass\n</span><span class=\"gi\">+            # 数字でなければ絶対パスに変換\n+            stream = osp.abspath(path)\n</span>         return cv2.VideoCapture(stream)\n \n     @staticmethod\n     def open_output_stream(path, fps, frame_size):\n         output_stream = None\n         if path != \"\":\n<span class=\"gd\">-            if not path.endswith('.avi'):\n-                log.warning(\"Output file extension is not 'avi'. \" \\\n-                        \"Some issues with output can occur, check logs.\")\n</span><span class=\"gi\">+            forcc = cv2.VideoWriter.fourcc(*'mp4v') if path.endswith('.mp4') else cv2.VideoWriter.fourcc(*'MJPG')\n</span>             log.info(\"Writing output to '%s'\" % (path))\n<span class=\"gd\">-            output_stream = cv2.VideoWriter(path,\n-                                            cv2.VideoWriter.fourcc(*'MJPG'), fps, frame_size)\n</span><span class=\"gi\">+            output_stream = cv2.VideoWriter(path, forcc, fps, frame_size)\n</span>         return output_stream\n \n \n<span class=\"gh\">diff -ur face_recognition_demo.org/faces_database.py face_recognition_demo/faces_database.py\n</span><span class=\"gd\">--- face_recognition_demo.org/faces_database.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/faces_database.py\t2019-11-20 06:31:13.481819754 +0900\n</span><span class=\"p\">@@ -36,10 +36,11 @@</span>\n         def cosine_dist(x, y):\n             return cosine(x, y) * 0.5\n \n<span class=\"gd\">-    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False):\n</span><span class=\"gi\">+    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False, no_db_save=False):\n</span>         path = osp.abspath(path)\n         self.fg_path = path\n         self.no_show = no_show\n<span class=\"gi\">+        self.no_db_save = no_db_save\n</span>         paths = []\n         if osp.isdir(path):\n             paths = [osp.join(path, f) for f in os.listdir(path) \\\n<span class=\"p\">@@ -96,7 +97,7 @@</span>\n                     self.add_item(descriptor, label)\n \n     def ask_to_save(self, image):\n<span class=\"gd\">-        if self.no_show:\n</span><span class=\"gi\">+        if self.no_show or self.no_db_save:\n</span>             return None\n         save = False\n         label = None\n<span class=\"p\">@@ -209,12 +210,14 @@</span>\n             match = len(self.database)-1\n         else:\n             filename = \"{}-{}.jpg\".format(label, len(self.database[match].descriptors)-1)\n<span class=\"gd\">-        filename = osp.join(self.fg_path, filename)\n-\n-        log.debug(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n-        if osp.exists(filename):\n-            log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n-        cv2.imwrite(filename, image)\n</span><span class=\"gi\">+        \n+        if name :\n+            filename = osp.join(self.fg_path, filename)\n+            log.info(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n+            if osp.exists(filename):\n+                log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n+            else :\n+                cv2.imwrite(filename, image)\n</span>         return match\n \n     def add_item(self, desc, label):\n</code></pre></div></div>\n\n<h1 id=\"前準備\">前準備</h1>\n\n<p>識別したい顔の画像を適当なディレクトリに保存しておく。ファイル形式はjpgまたはpng。<br />\n一人ずつ1画像で顔部分のみ切り出しておく。<br />\n複数の人の顔を識別したい場合はそれぞれ別々に保存しておく。</p>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"実行用スクリプトの作成\">実行用スクリプトの作成</h2>\n\n<p>実行コマンドが長ったらしくて入力が面倒なので、以下のスクリプト(demo.sh)を作成しておく。<br />\nUbuntuとRaspberrypiを識別して自動でコマンドオプションを変更するようにしてある。 \n作成したら実行属性を付与しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/bin/bash</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"face_recognition_demo.py\"</span>\n\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"       -m_fd models/face-detection-retail-0004.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_lm models/landmarks-regression-retail-0009.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_reid models/face-reidentification-retail-0095.xml\"</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"o\">==</span> <span class=\"s2\">\"armv7l\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Raspberry Pi\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_fd MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_lm MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_reid MYRIAD\"</span>\n<span class=\"k\">else\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Ubuntu\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> --cpu_lib /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so\"</span>\n<span class=\"k\">fi\n\n\nif</span> <span class=\"o\">[</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 0 <span class=\"nt\">-o</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 1 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n\t<span class=\"c\"># パラメータなし/1個はエラー</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\n</span><span class=\"s2\">==== usage ====\"</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"nv\">$0</span><span class=\"s2\"> database_dir input_file [other option(s)]</span><span class=\"se\">\\n\\n\\n</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">exit </span>1\n<span class=\"k\">else\n    </span><span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -fg </span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\"> --input </span><span class=\"k\">${</span><span class=\"nv\">2</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    <span class=\"c\"># 3番目以降すべてのパラメータを追加</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"p\">@</span>:3:<span class=\"p\">(</span><span class=\"nv\">$#-2</span><span class=\"p\">)</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi\n</span><span class=\"nb\">echo</span> <span class=\"s2\">\"python </span><span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\npython <span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n\n<p>第1パラメータに識別子する顔画像を保存したディレクトリ、第2パラメータに入力ビデオファイル名を指定する。<br />\nこれらのパラメータは省略不可。<br />\n追加でオプションを指定したい場合は第3パラメータ以降に指定する。<br />\nたとえば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo.sh data data/video.mp4  <span class=\"nt\">--output</span> result.mp4\n</code></pre></div></div>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python face_recognition_demo.py <span class=\"nt\">-h</span>\nusage: face_recognition_demo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-i</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-o</span> PATH] <span class=\"o\">[</span><span class=\"nt\">--no_show</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-tl</span><span class=\"o\">]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-cw</span> CROP_WIDTH] <span class=\"o\">[</span><span class=\"nt\">-ch</span> CROP_HEIGHT] <span class=\"nt\">-fg</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">--run_detector</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--run_detector_no_save</span><span class=\"o\">]</span>\n                                <span class=\"nt\">-m_fd</span> PATH <span class=\"nt\">-m_lm</span> PATH <span class=\"nt\">-m_reid</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-l</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-c</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]]\n                                <span class=\"o\">[</span><span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]] <span class=\"o\">[</span><span class=\"nt\">-exp_r_fd</span> NUMBER]\n                                <span class=\"o\">[</span><span class=\"nt\">--allow_grow</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit\n\n</span>General:\n  <span class=\"nt\">-i</span> PATH, <span class=\"nt\">--input</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to the input video <span class=\"o\">(</span><span class=\"s1\">'0'</span> <span class=\"k\">for </span>the\n                        camera, default<span class=\"o\">)</span>\n  <span class=\"nt\">-o</span> PATH, <span class=\"nt\">--output</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to save the output video to\n  <span class=\"nt\">--no_show</span>             <span class=\"o\">(</span>optional<span class=\"o\">)</span> Do not display output\n  <span class=\"nt\">-tl</span>, <span class=\"nt\">--timelapse</span>      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Auto-pause after each frame\n  <span class=\"nt\">-cw</span> CROP_WIDTH, <span class=\"nt\">--crop_width</span> CROP_WIDTH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this width\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n  <span class=\"nt\">-ch</span> CROP_HEIGHT, <span class=\"nt\">--crop_height</span> CROP_HEIGHT\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this height\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n\nFaces database:\n  <span class=\"nt\">-fg</span> PATH              Path to the face images directory\n  <span class=\"nt\">--run_detector</span>        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images.\n  <span class=\"nt\">--run_detector_no_save</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images. not save\n                        detected face image.\n\nModels:\n  <span class=\"nt\">-m_fd</span> PATH            Path to the Face Detection model XML file\n  <span class=\"nt\">-m_lm</span> PATH            Path to the Facial Landmarks Regression model XML file\n  <span class=\"nt\">-m_reid</span> PATH          Path to the Face Reidentification model XML file\n\nInference options:\n  <span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Detection model\n                        <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Facial Landmarks\n                        Regression model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Reidentification\n                        model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> PATH, <span class=\"nt\">--cpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For MKLDNN <span class=\"o\">(</span>CPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to a shared library with custom layers\n                        implementations\n  <span class=\"nt\">-c</span> PATH, <span class=\"nt\">--gpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For clDNN <span class=\"o\">(</span>GPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to the XML file with descriptions of the\n                        kernels\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> Be more verbose\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_stats</span>     <span class=\"o\">(</span>optional<span class=\"o\">)</span> Output detailed per-layer performance stats\n  <span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Probability threshold <span class=\"k\">for </span>face\n                        detections<span class=\"o\">(</span>default: 0.6<span class=\"o\">)</span>\n  <span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Cosine distance threshold between two\n                        vectors <span class=\"k\">for </span>face identification <span class=\"o\">(</span>default: 0.3<span class=\"o\">)</span>\n  <span class=\"nt\">-exp_r_fd</span> NUMBER      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Scaling ratio <span class=\"k\">for </span>bboxes passed to face\n                        recognition <span class=\"o\">(</span>default: 1.15<span class=\"o\">)</span>\n  <span class=\"nt\">--allow_grow</span>          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Allow to grow faces gallery and to dump on\n                        disk. Available only <span class=\"k\">if</span> <span class=\"nt\">--no_show</span> option is off.\n</code></pre></div></div>\n\n<p>主なオプションの意味は以下の通り。</p>\n\n<h3 id=\"-m_fd\"><code class=\"language-plaintext highlighter-rouge\">-m_fd</code></h3>\n\n<p>必須。<br />\n顔位置検出モデルファイル</p>\n\n<h3 id=\"ーm_lm\"><code class=\"language-plaintext highlighter-rouge\">ーm_lm</code></h3>\n\n<p>必須。<br />\n顔特徴点検出モデルファイル</p>\n\n<h3 id=\"-m_reid\"><code class=\"language-plaintext highlighter-rouge\">-m_reid</code></h3>\n\n<p>必須。<br />\n顔識別モデルファイル</p>\n\n<h3 id=\"-d_fd\"><code class=\"language-plaintext highlighter-rouge\">-d_fd</code></h3>\n\n<p>顔位置検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_lm\"><code class=\"language-plaintext highlighter-rouge\">-d_lm</code></h3>\n\n<p>顔特徴点検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_reid\"><code class=\"language-plaintext highlighter-rouge\">-d_reid</code></h3>\n\n<p>顔識別に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"--cpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--cpu_lib</code></h3>\n\n<p>CPU用カスタムレイヤライブラリ(?)ファイル</p>\n\n<h3 id=\"--gpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--gpu_lib</code></h3>\n\n<p>GPU用カスタムレイヤライブラリ(?)ファイル(使ったことないからワカラン)</p>\n\n<h3 id=\"-fg\"><code class=\"language-plaintext highlighter-rouge\">-fg</code></h3>\n\n<p>必須。<br />\n識別する顔画像を格納したディレクトリ<br />\nこのディレクトリ内のjpg、pngファイルのみ抽出してくれるので、他のファイルが混在しても大丈夫。</p>\n\n<h3 id=\"--input\"><code class=\"language-plaintext highlighter-rouge\">--input</code></h3>\n\n<p>必須。<br />\n入力ファイル(動画ファイル)を指定する。 <br />\n静止画でもエラーにならないが、一瞬で消えるので、オプション –timelapse でキー入力待ちにするか、\nオプション –outputでファイル出力すると確認できる。<br />\n省略時はカメラが指定される。</p>\n\n<h3 id=\"--output\"><code class=\"language-plaintext highlighter-rouge\">--output</code></h3>\n\n<p>認識結果をファイルに出力する。<br />\n指定しなければファイルは作成されない(表示のみ)。 \n拡張子がmp4のときはMP4(追加した処理)。<br />\nそれ以外はMJPEGで保存(aviにするのが望ましい。それ以外だとffmpegがなんか言うがファイルはできてるっぽい)。</p>\n\n<h3 id=\"--no_show\"><code class=\"language-plaintext highlighter-rouge\">--no_show</code></h3>\n\n<p>画像表示しない。<br />\n通常は–outputと組み合わせて使う。</p>\n\n<h3 id=\"--timelapse\"><code class=\"language-plaintext highlighter-rouge\">--timelapse</code></h3>\n\n<p>1フレーム表示するごとにキー入力待ちになる。</p>\n\n<h3 id=\"--crop_width--crop_height\"><code class=\"language-plaintext highlighter-rouge\">--crop_width</code>、<code class=\"language-plaintext highlighter-rouge\">--crop_height</code></h3>\n\n<p>入力画像を指定したサイズに切り取る。切り取る場所は元画像の中心。<br />\n両方指定しないと無効。</p>\n\n<h3 id=\"--run_detector\"><code class=\"language-plaintext highlighter-rouge\">--run_detector</code></h3>\n\n<p>オプションを指定するとデータベース作成時に顔検出して新たに顔画像を作成してくれる。<br />\nデータベースファイルが全身画像だったり、複数人数が一緒に写っていてもOK。<br />\n1回指定すれば画像が残っているので以降は指定しなくても良い。</p>\n\n<h3 id=\"--run_detector_no_save\"><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code></h3>\n\n<p>追加したオプション<br />\n指定するとデータベース作成時に顔検出するが、顔画像の保存はしない。</p>\n\n<h3 id=\"--verbose\"><code class=\"language-plaintext highlighter-rouge\">--verbose</code></h3>\n\n<p>指定するとloglevelがDEBUGになる</p>\n\n<h3 id=\"--perf_stats\"><code class=\"language-plaintext highlighter-rouge\">--perf_stats</code></h3>\n\n<p>指定するとフレーム毎にパフォーマンスステータスを表示する</p>\n\n<h3 id=\"-t_fd\"><code class=\"language-plaintext highlighter-rouge\">-t_fd</code></h3>\n\n<p>顔位置検出に使用する閾値。省略時は0.6。</p>\n\n<h3 id=\"-t_reid\"><code class=\"language-plaintext highlighter-rouge\">-t_reid</code></h3>\n\n<p>顔識別に使用する閾値。省略時は0.3。</p>\n\n<h3 id=\"-exp_r_fd\"><code class=\"language-plaintext highlighter-rouge\">-exp_r_fd</code></h3>\n\n<p>顔位置検出した枠のサイズを何倍にするか。ギリギリだとうまく行かないから?省略時は1.15</p>\n\n<h3 id=\"--allow_grow\"><code class=\"language-plaintext highlighter-rouge\">--allow_grow</code></h3>\n\n<p>認識画像で知らない顔が出てきたらその都度登録するか確認する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でYOLO(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でYOLO(その2)</h1>\n      <p>openVINOのYOLOのプログラムをちょこっと改変</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> のソースを\n<a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> のソースと形状を合わせたもの。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">math</span> <span class=\"kn\">import</span> <span class=\"n\">exp</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-iout\"</span><span class=\"p\">,</span> <span class=\"s\">\"--iou_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Intersection over union threshold for overlapping \"</span>\n                                                       <span class=\"s\">\"detections filtering\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-ni\"</span><span class=\"p\">,</span> <span class=\"s\">\"--number_iter\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Number of inference iterations\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pc\"</span><span class=\"p\">,</span> <span class=\"s\">\"--perf_counts\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Report performance counters\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span>\n                      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-r\"</span><span class=\"p\">,</span> <span class=\"s\">\"--raw_output_message\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Output inference results raw values showing\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">YoloParams</span><span class=\"p\">:</span>\n    <span class=\"c1\"># ------------------------------------------- Extracting layer parameters ------------------------------------------\n</span>    <span class=\"c1\"># Magic numbers are copied from yolo samples\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">param</span><span class=\"p\">,</span> <span class=\"n\">side</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"mi\">3</span> <span class=\"k\">if</span> <span class=\"s\">'num'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'num'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">=</span> <span class=\"mi\">4</span> <span class=\"k\">if</span> <span class=\"s\">'coords'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'coords'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">classes</span> <span class=\"o\">=</span> <span class=\"mi\">80</span> <span class=\"k\">if</span> <span class=\"s\">'classes'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'classes'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">10.0</span><span class=\"p\">,</span> <span class=\"mf\">13.0</span><span class=\"p\">,</span> <span class=\"mf\">16.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">33.0</span><span class=\"p\">,</span> <span class=\"mf\">23.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">61.0</span><span class=\"p\">,</span> <span class=\"mf\">62.0</span><span class=\"p\">,</span> <span class=\"mf\">45.0</span><span class=\"p\">,</span> <span class=\"mf\">59.0</span><span class=\"p\">,</span> <span class=\"mf\">119.0</span><span class=\"p\">,</span> <span class=\"mf\">116.0</span><span class=\"p\">,</span> <span class=\"mf\">90.0</span><span class=\"p\">,</span> <span class=\"mf\">156.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">198.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">373.0</span><span class=\"p\">,</span> <span class=\"mf\">326.0</span><span class=\"p\">]</span> <span class=\"k\">if</span> <span class=\"s\">'anchors'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"p\">[</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">a</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'anchors'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n\n        <span class=\"k\">if</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">:</span>\n            <span class=\"n\">mask</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">idx</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'mask'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">mask</span><span class=\"p\">)</span>\n\n            <span class=\"n\">maskedAnchors</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n            <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">mask</span><span class=\"p\">:</span>\n                <span class=\"n\">maskedAnchors</span> <span class=\"o\">+=</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"n\">maskedAnchors</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">=</span> <span class=\"n\">side</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"o\">=</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span>  <span class=\"c1\"># Weak way to determine but the only one.\n</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">log_params</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># params_to_print = {'classes': self.classes, 'num': self.num, 'coords': self.coords, 'anchors': self.anchors}\n</span>        <span class=\"c1\"># [log.info(\"         {:8}: {}\".format(param_name, param)) for param_name, param in params_to_print.items()]\n</span>        <span class=\"k\">pass</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">entry_index</span><span class=\"p\">(</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">coord</span><span class=\"p\">,</span> <span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">location</span><span class=\"p\">,</span> <span class=\"n\">entry</span><span class=\"p\">):</span>\n    <span class=\"n\">side_power_2</span> <span class=\"o\">=</span> <span class=\"n\">side</span> <span class=\"o\">**</span> <span class=\"mi\">2</span>\n    <span class=\"n\">n</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">//</span> <span class=\"n\">side_power_2</span>\n    <span class=\"n\">loc</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">%</span> <span class=\"n\">side_power_2</span>\n    <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">side_power_2</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">coord</span> <span class=\"o\">+</span> <span class=\"n\">classes</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">entry</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">loc</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"p\">,</span> <span class=\"n\">h_scale</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"p\">):</span>\n    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">w</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">y</span> <span class=\"o\">-</span> <span class=\"n\">h</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">w</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">+</span> <span class=\"n\">h</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"nb\">dict</span><span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"o\">=</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"o\">=</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"o\">=</span><span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"o\">=</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">blob</span><span class=\"p\">,</span> <span class=\"n\">resized_image_shape</span><span class=\"p\">,</span> <span class=\"n\">original_im_shape</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">threshold</span><span class=\"p\">):</span>\n    <span class=\"c1\"># ------------------------------------------ Validating output parameters ------------------------------------------\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    <span class=\"k\">assert</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">==</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"s\">\"Invalid size of output blob. It sould be in NCHW layout and height should \"</span> \\\n                                     <span class=\"s\">\"be equal to width. Current height = {}, current width = {}\"</span> \\\n                                     <span class=\"s\">\"\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ------------------------------------------ Extracting layer parameters -------------------------------------------\n</span>    <span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">orig_im_w</span> <span class=\"o\">=</span> <span class=\"n\">original_im_shape</span>\n    <span class=\"n\">resized_image_h</span><span class=\"p\">,</span> <span class=\"n\">resized_image_w</span> <span class=\"o\">=</span> <span class=\"n\">resized_image_shape</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">predictions</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">flatten</span><span class=\"p\">()</span>\n    <span class=\"n\">side_square</span> <span class=\"o\">=</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n\n    <span class=\"c1\"># ------------------------------------------- Parsing YOLO Region output -------------------------------------------\n</span>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">side_square</span><span class=\"p\">):</span>\n        <span class=\"n\">row</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">//</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"n\">col</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">%</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"k\">for</span> <span class=\"n\">n</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">num</span><span class=\"p\">):</span>\n            <span class=\"n\">obj_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">)</span>\n            <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">scale</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"n\">box_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n            <span class=\"c1\"># Network produces location predictions in absolute coordinates of feature maps.\n</span>            <span class=\"c1\"># Scale it to relative coordinates.\n</span>            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">col</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">0</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">row</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"c1\"># Value for exp is very big number in some cases so following construction is using here\n</span>            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">w_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n                <span class=\"n\">h_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">3</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n            <span class=\"k\">except</span> <span class=\"nb\">OverflowError</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"c1\"># Depends on topology we need to normalize sizes by feature maps (up to YOLOv3) or by input shape (YOLOv3)\n</span>            <span class=\"n\">w</span> <span class=\"o\">=</span> <span class=\"n\">w_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_w</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"n\">h</span> <span class=\"o\">=</span> <span class=\"n\">h_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_h</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">):</span>\n                <span class=\"n\">class_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span>\n                                          <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">+</span> <span class=\"n\">j</span><span class=\"p\">)</span>\n                <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"n\">scale</span> <span class=\"o\">*</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">class_index</span><span class=\"p\">]</span>\n                <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                    <span class=\"k\">continue</span>\n                <span class=\"n\">objects</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">=</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">=</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"o\">=</span><span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"o\">=</span><span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">j</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">,</span>\n                                          <span class=\"n\">h_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_w</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"n\">objects</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n    <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">height_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span>\n    <span class=\"k\">if</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">height_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">*</span> <span class=\"n\">height_of_overlap_area</span>\n    <span class=\"n\">box_1_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">box_2_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">area_of_union</span> <span class=\"o\">=</span> <span class=\"n\">box_1_area</span> <span class=\"o\">+</span> <span class=\"n\">box_2_area</span> <span class=\"o\">-</span> <span class=\"n\">area_of_overlap</span>\n    <span class=\"k\">if</span> <span class=\"n\">area_of_union</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"mi\">0</span>\n    <span class=\"k\">return</span> <span class=\"n\">area_of_overlap</span> <span class=\"o\">/</span> <span class=\"n\">area_of_union</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>                 <span class=\"c1\"># 冒頭でinputは一つでなければエラーになってるので決め打ちで[0]\n</span>    <span class=\"n\">in_frame_shape</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">:]</span>       <span class=\"c1\"># HWC→BCHWに変更してあるので、height/widthはshape[2:]で取得\n</span>    <span class=\"k\">for</span> <span class=\"n\">layer_name</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">.</span><span class=\"n\">items</span><span class=\"p\">():</span>\n        <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">parents</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]].</span><span class=\"n\">shape</span><span class=\"p\">)</span>\n        <span class=\"n\">layer_params</span> <span class=\"o\">=</span> <span class=\"n\">YoloParams</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n        <span class=\"c1\"># log.info(\"Layer {} parameters: \".format(layer_name))\n</span>        <span class=\"n\">layer_params</span><span class=\"p\">.</span><span class=\"n\">log_params</span><span class=\"p\">()</span>\n        <span class=\"n\">objects</span> <span class=\"o\">+=</span> <span class=\"n\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">out_blob</span><span class=\"p\">,</span> \n                                        <span class=\"n\">in_frame_shape</span><span class=\"p\">,</span>\n                                        <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">],</span> \n                                        <span class=\"n\">layer_params</span><span class=\"p\">,</span>\n                                        <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Filtering overlapping boxes with respect to the --iou_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">sorted</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">,</span> <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"k\">lambda</span> <span class=\"n\">obj</span> <span class=\"p\">:</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">reverse</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">iou_threshold</span><span class=\"p\">:</span>\n                <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># Drawing objects with respect to the --prob_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">obj</span> <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span> <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">Detected boxes for batch {}:\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">))</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\" Class ID | Confidence | XMIN | YMIN | XMAX | YMAX | COLOR \"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">origin_im_size</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Validation bbox of detected object\n</span>        <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"c1\"># color = (int(min(obj['class_id'] * 12.5, 255)),\n</span>        <span class=\"c1\">#          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span>        <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n        <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]]</span> <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"ow\">and</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">>=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]</span> <span class=\"k\">else</span> \\\n            <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">])</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span>\n                <span class=\"s\">\"{:^9} | {:10f} | {:4} | {:4} | {:4} | {:4} | {} \"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">det_label</span><span class=\"p\">,</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">color</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]),</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span>\n                    <span class=\"s\">\"#\"</span> <span class=\"o\">+</span> <span class=\"n\">det_label</span> <span class=\"o\">+</span> <span class=\"s\">' '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"s\">' %'</span><span class=\"p\">,</span>\n                    <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.6</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"c1\"># YOLOのoutputsは1ではない\n</span>    \n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Sample supports only YOLO V3 based single input topologies\"</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>     <span class=\"c1\"># inputは一つだけなので決め打ちで[0]\n</span>    \n    <span class=\"c1\">#  Defaulf batch_size is 1\n</span>    <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n    \n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n        \n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span> <span class=\"o\">=</span>      <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span> <span class=\"o\">=</span>   <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span>  <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_yolov3_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                             <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                             <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                             <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-iout</span> IOU_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-ni</span> NUMBER_ITER] <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-r</span><span class=\"o\">]</span>\n                                             <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG]\n                                             <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n  <span class=\"nt\">-iout</span> IOU_THRESHOLD, <span class=\"nt\">--iou_threshold</span> IOU_THRESHOLD\n                        Optional. Intersection over union threshold <span class=\"k\">for\n                        </span>overlapping detections filtering\n  <span class=\"nt\">-ni</span> NUMBER_ITER, <span class=\"nt\">--number_iter</span> NUMBER_ITER\n                        Optional. Number of inference iterations\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_counts</span>    Optional. Report performance counters\n  <span class=\"nt\">-r</span>, <span class=\"nt\">--raw_output_message</span>\n                        Optional. Output inference results raw values showing\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD</h1>\n      <p>openVINOのSSDのサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>YOLOとは別のアルゴリズムSSDで物体認識するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_ssd_async</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">models.list</code>によると、以下のモデルデータが使用できるらしい。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>face-detection-adas-????\nface-detection-adas-binary-????\nface-detection-retail-????\npedestrian-and-vehicle-detector-adas-????\npedestrian-detection-adas-????\npedestrian-detection-adas-binary-????\nperson-detection-retail-????\nvehicle-detection-adas-????\nvehicle-detection-adas-binary-????\nvehicle-license-plate-detection-barrier-????\n</code></pre></div></div>\n\n<p>ここでは、vehicle-detection-adas-binary-????を使ってみることにする。</p>\n\n<p>以下の手順でモデルデータをダウンロードする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/pedestrian-and-vehicle-detector-adas-0001/FP16/pedestrian-and-vehicle-detector-adas-0001\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>ラベルデータは用意されていないので、ラベルデータを以下の内容で、<code class=\"language-plaintext highlighter-rouge\">${models_diir}/pedestrian-and-vehicle-detector-adas-0001.labels</code>のファイル名で作成する。<br />\nオリジナルでは<code class=\"language-plaintext highlighter-rouge\">--label</code>オプションでラベルデータファイルを指定するようになっているが、\nモデルデータファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものをデフォルトのラベルデータファイルとして認識するように変更しておいた。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>UNKNOWN\nvehicles\npedestrians\nUNKNOWN\n</code></pre></div></div>\n\n<p>どのIDが何を示すか書いてる場所を見つけられなかったんだよなぁ~。<br />\nとりあえず、結果表示から推測するしかないか。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<p>ちょっとのつもりで改造してたら、結構たくさんの変更になったので、ソース全体を掲載しておく。<br />\n(RaspberryPiにはソース入ってないし)<br />\nおもな変更点は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--save</code> <code class=\"language-plaintext highlighter-rouge\">--log</code> <code class=\"language-plaintext highlighter-rouge\">--sync</code> <code class=\"language-plaintext highlighter-rouge\">--no_disp</code> オプションの追加</li>\n  <li>結果解析部分の関数化(後でYOLOと比較しやすいように)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># print(res[out_blob].shape)\n</span>    <span class=\"c1\">#  -> (1, 1, 200, 7)        200:バウンディングボックスの数\n</span>    <span class=\"c1\"># データ構成は\n</span>    <span class=\"c1\"># https://docs.openvinotoolkit.org/2019_R1/_pedestrian_and_vehicle_detector_adas_0001_description_pedestrian_and_vehicle_detector_adas_0001.html\n</span>    <span class=\"c1\"># の「outputs」を参照\n</span>    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"n\">out_blob</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]:</span>     <span class=\"c1\"># このループは200回まわる\n</span>        <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>                       <span class=\"c1\"># confidence for the predicted class(スコア)\n</span>        <span class=\"k\">if</span> <span class=\"n\">conf</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">:</span>      <span class=\"c1\"># 閾値より大きいものだけ処理\n</span>            <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n            <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 表示色\n</span>            <span class=\"c1\"># color = (min(class_id * 12.5, 255), min(class_id * 7, 255), min(class_id * 5, 255))\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>            <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># バウンディングボックスとラベル、スコアを表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">det_label</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">conf</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">%\"</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Demo supports only single output topologies\"</span>\n\n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"c1\"># SSDのinputsは1とは限らないのでスキャンする\n</span>    <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">for</span> <span class=\"n\">blob_name</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">:</span>\n        <span class=\"c1\"># print(f'{blob_name}   {net.inputs[blob_name].shape}')\n</span>        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">4</span><span class=\"p\">:</span>\n            <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">2</span><span class=\"p\">:</span>\n            <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"nb\">RuntimeError</span><span class=\"p\">(</span><span class=\"s\">\"Unsupported {}D input layer '{}'. Only 2D and 4D input layers are supported\"</span>\n                               <span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">),</span> <span class=\"n\">blob_name</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    <span class=\"k\">if</span> <span class=\"n\">img_info_input_blob</span><span class=\"p\">:</span>\n        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">img_info_input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n\n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span>     <span class=\"o\">=</span> <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span>  <span class=\"o\">=</span> <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span> <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_ssd_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                          <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                          <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO(C++版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO(C++版)</h1>\n      <p>tinyYOLOのC++版デモプログラムのbuildと実行</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nのpythonで実行したデモプログラムのC++版をbuild&実行してみる。</p>\n\n<h1 id=\"ubuntu環境での実行\">ubuntu環境での実行</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h2 id=\"デモのソースプログラム\">デモのソースプログラム</h2>\n\n<p>ドライバのインストール先 <code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/deployment_tools/open_model_zoo/demos</code> にあるので、そのまま参照しても良いが、\nソース修正に備えて、ソースをコピっておく(オーナーも変更)と何かと便利。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++/openvino_demo <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos <span class=\"nb\">.</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> demos/\n</code></pre></div></div>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>出力文字列のサイズと位置を調整</li>\n  <li>-saveオプションの追加と認識結果画像ファイルの保存処理の追加</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.hpp.org\t2019-10-31 14:39:14.757039048 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.hpp\t2019-10-31 06:16:49.178945707 +0900\n</span><span class=\"p\">@@ -93,6 +93,7 @@</span>\n /// \\brief Define a flag to disable showing processed video<br>\n /// It is an optional parameter\n DEFINE_bool(no_show, false, no_show_processed_video);\n<span class=\"gi\">+DEFINE_bool(save, false, \"Optional. save image file.\");\n</span> \n /**\n * \\brief This function shows a help message\n<span class=\"p\">@@ -115,4 +116,5 @@</span>\n     std::cout << \"    -iou_t                    \" << iou_thresh_output_message << std::endl;\n     std::cout << \"    -auto_resize              \" << input_resizable_message << std::endl;\n     std::cout << \"    -no_show                  \" << no_show_processed_video << std::endl;\n<span class=\"gi\">+    std::cout << \"    -save                     \" << \"Optional. save image file.\" << std::endl;\n</span> }\n</code></pre></div></div>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.org\t2019-10-31 05:46:38.515000000 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"p\">@@ -197,6 +197,21 @@</span>\n         }\n         // -----------------------------------------------------------------------------------------------------\n \n<span class=\"gi\">+        // =====================================================================================\n+        // 動画ファイルを書き出すためのオブジェクトを宣言する\n+        cv::VideoWriter writer;\n+        // =====================================================================================\n+        // =====================================================================================\n+        if (FLAGS_save) {\n+            double fps    = cap.get(cv::CAP_PROP_FPS);\t\t\t\t// フレームレートを取得\n+            int fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v');\t\t// MP4形式を指定\n+            // * エンコード形式 \"XVID\" = AVI, \"MP4V\" = MPEG4, \"WMV1\" = WMV\n+\n+            // 動画ファイルを書き出すためのファイルをオープンする\n+            writer.open(\"result.mp4\", fourcc, fps, cv::Size(width, height));\n+        }\n+        // =====================================================================================\n+\n</span>         // --------------------------- 1. Load inference engine -------------------------------------\n         slog::info << \"Loading Inference Engine\" << slog::endl;\n         Core ie;\n<span class=\"p\">@@ -356,17 +371,17 @@</span>\n                 std::ostringstream out;\n                 out << \"OpenCV cap/render time: \" << std::fixed << std::setprecision(2)\n                     << (ocv_decode_time + ocv_render_time) << \" ms\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 25), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 255, 0));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 15), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 255, 0));\n</span>                 out.str(\"\");\n                 out << \"Wallclock time \" << (isAsyncMode ? \"(TRUE ASYNC):      \" : \"(SYNC, press Tab): \");\n                 out << std::fixed << std::setprecision(2) << wall.count() << \" ms (\" << 1000.f / wall.count() << \" fps)\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 50), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 0, 255));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 30), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 0, 255));\n</span>                 if (!isAsyncMode) {  // In the true async mode, there is no way to measure detection time directly\n                     out.str(\"\");\n                     out << \"Detection time  : \" << std::fixed << std::setprecision(2) << detection.count()\n                         << \" ms (\"\n                         << 1000.f / detection.count() << \" fps)\";\n<span class=\"gd\">-                    cv::putText(frame, out.str(), cv::Point2f(0, 75), cv::FONT_HERSHEY_TRIPLEX, 0.6,\n</span><span class=\"gi\">+                    cv::putText(frame, out.str(), cv::Point2f(0, 45), cv::FONT_HERSHEY_TRIPLEX, 0.4,\n</span>                                 cv::Scalar(255, 0, 0));\n                 }\n \n<span class=\"p\">@@ -410,7 +425,7 @@</span>\n                         cv::putText(frame,\n                                 (label < static_cast<int>(labels.size()) ?\n                                         labels[label] : std::string(\"label #\") + std::to_string(label)) + conf.str(),\n<span class=\"gd\">-                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 1,\n</span><span class=\"gi\">+                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.4,\n</span>                                     cv::Scalar(0, 0, 255));\n                         cv::rectangle(frame, cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin)),\n                                       cv::Point2f(static_cast<float>(object.xmax), static_cast<float>(object.ymax)), cv::Scalar(0, 0, 255));\n<span class=\"p\">@@ -420,6 +435,11 @@</span>\n             if (!FLAGS_no_show) {\n                 cv::imshow(\"Detection results\", frame);\n             }\n<span class=\"gi\">+            // =====================================================================================\n+            if (FLAGS_save) {\n+                writer << frame;\n+            }\n+            // =====================================================================================\n</span> \n             t1 = std::chrono::high_resolution_clock::now();\n             ocv_render_time = std::chrono::duration_cast<ms>(t1 - t0).count();\n<span class=\"p\">@@ -457,6 +477,11 @@</span>\n         if (FLAGS_pc) {\n             printPerformanceCounts(*async_infer_request_curr, std::cout, getFullDeviceName(ie, FLAGS_d));\n         }\n<span class=\"gi\">+        // =====================================================================================\n+        if (FLAGS_save) {\n+            writer.release();\n+        }\n+        // =====================================================================================\n</span>     }\n     catch (const std::exception& error) {\n         std::cerr << \"[ ERROR ] \" << error.what() << std::endl;\n\n</code></pre></div></div>\n\n<h2 id=\"buildディレクトリの作成とbuild\">buildディレクトリの作成とbuild</h2>\n\n<p>cmakeの実行とbuild</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<p>ちょっと時間がかかる。</p>\n\n<h2 id=\"モデルデータ\">モデルデータ</h2>\n\n<p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nで作成したモデルデータをそのまま使用する。<br />\nラベルデータファイルのファイル名はモデルデータのxmlファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものに固定だが、モデルデータ作成時にコピー済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./intel64/Release/</code>に作成される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./intel64/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-l</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> ../../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>-save オプションを指定すると、認識結果の動画をresult.mp4(ファイル名は固定)に保存する。</p>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>デモプログラムはRasspberryPiでも動作させることができる。<br />\nソースはRaspberryPi側にはないので、ubuntuからコピーする。</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>ubuntuで作成した /work/NCS2/c++/openvino_demo/demos ディレクトリと/work/NCS2/openvino_models ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"buildディレクトリの作成とbuild-1\">buildディレクトリの作成とbuild</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a -Wno-psabi\"</span> ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./armv7l/Release/</code>に作成される。<br />\n入力ファイル(-i オプション)はフルパスで指定すること。相対パスだとファイルが見つからないと怒られる。<br />\n※ 下のパッチを当てると相対パスでも大丈夫になる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./armv7l/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-d</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> /work/NCS2/data/testvideo3.mp4 \n</code></pre></div></div>\n\n<p>なぜか-saveオプションが効かない。。。</p>\n\n<h2 id=\"入力ファイル名に相対パスを使用できるようにするためのパッチ\">入力ファイル名に相対パスを使用できるようにするためのパッチ</h2>\n\n<p>入力ファイル名をrealpath()で絶対パスに変換して使用することで対応。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.1\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-11-01 11:25:29.720856218 +0900\n</span><span class=\"p\">@@ -30,6 +30,9 @@</span>\n #include <ext_list.hpp>\n #endif\n \n<span class=\"gi\">+#include <limits.h>\n+#include <unistd.h>\n+\n</span> using namespace InferenceEngine;\n \n bool ParseAndCheckCommandLine(int argc, char *argv[]) {\n<span class=\"p\">@@ -180,7 +183,23 @@</span>\n \n         slog::info << \"Reading input\" << slog::endl;\n         cv::VideoCapture cap;\n<span class=\"gd\">-        if (!((FLAGS_i == \"cam\") ? cap.open(0) : cap.open(FLAGS_i.c_str()))) {\n</span><span class=\"gi\">+\n+        bool open_status;\n+        if (FLAGS_i == \"cam\") {\n+            open_status = cap.open(0);\n+        }\n+        else {\n+            std::string input_filename;\n+            char input_filename_char[PATH_MAX+1];\n+            if (!realpath(FLAGS_i.c_str(), input_filename_char)) {\n+                throw std::logic_error(\"Cannot get realpath\");\n+            }\n+            input_filename = input_filename_char;\n+            slog::info << \"input filename :\" + input_filename << slog::endl;\n+            open_status = cap.open(input_filename.c_str());\n+\n+        }\n+        if (!open_status) {\n</span>             throw std::logic_error(\"Cannot open input file or camera: \" + FLAGS_i);\n         }\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO</h1>\n      <p>darknetのモデルデータをopenVINOのモデルデータに変換し、tinyYOLOで画像認識を行う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOの2019 R3.1 がリリー(2019.10.29現在、ubuntu用のみ)スされ、YOLOのサンプルプログラムが用意されていたので、tinyYOLOを実行してみた。</p>\n\n<p>参考:<a href=\"https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html\">https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html</a></p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"darknetのモデルデータをopenvinoのモデルデータに変換\">darknetのモデルデータをopenVINOのモデルデータに変換</h1>\n\n<p>上記参考サイトの手順に従って、darknetのtinyYOLOモデルデータをopenVINOのモデルデータに変換する。</p>\n\n<h2 id=\"darknet--tensorflow-変換のためのプログラム取得\">darknet → tensorflow 変換のためのプログラム取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2\ngit clone https://github.com/mystic123/tensorflow-yolo-v3.git\n<span class=\"nb\">cd </span>tensorflow-yolo-v3/\ngit checkout ed60b90\n</code></pre></div></div>\n\n<h2 id=\"darknet-tinyyoloモデルデータ取得\">darknet tinyYOLOモデルデータ取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://raw.githubusercontent.com/pjreddie/darknet/master/data/coco.names\nwget https://pjreddie.com/media/files/yolov3-tiny.weights\n</code></pre></div></div>\n\n<h1 id=\"darknet--tensorflow-モデルデータ変換\">darknet → tensorflow モデルデータ変換</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python convert_weights_pb.py <span class=\"nt\">--class_names</span> coco.names <span class=\"nt\">--data_format</span> NHWC <span class=\"nt\">--weights_file</span> yolov3-tiny.weights <span class=\"nt\">--tiny</span>\n<span class=\"nb\">mv </span>frozen_darknet_yolov3_model.pb yolo_v3_tiny.pb\n</code></pre></div></div>\n\n<h2 id=\"モデルデータを変換\">モデルデータを変換</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP16 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div></div>\n\n<p>/work/NCS2/openvino_models/FP16ディレクトリに yolo_v3_tiny.bin yolo_v3_tiny.mapping yolo_v3_tiny.xml の3つが出来る</p>\n\n<blockquote>\n  <p>[!NOTE]\nFP32で計算する場合はこちら<br />\nNCStick使用時はFP16のみサポートなので、FP16で作っておくと使い回しできて楽。<br />\nそんなに認識精度が変わるわけでもなさそうだし。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP32\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP32 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"ラベルデータもコピー\">ラベルデータもコピー</h2>\n\n<p>pbファイルにはラベルデータが入っているはずだが、この後の変換でラベルデータは欠落するらしい。<br />\n後のプログラムのためにファイル名変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>coco.names <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels\n</code></pre></div></div>\n\n<h2 id=\"デモプログラムをコピー\">デモプログラムをコピー</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ..\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_yolov3_async <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>object_detection_demo_yolov3_async/\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>MP4ファイルのパスが絶対パスでないと正常にオープンできない対策(ubuntuではやらなくても大丈夫)</li>\n  <li>1フレームあたりの処理時間の計測と表示処理を追加</li>\n  <li>認識枠の表示色変更(ちょっと見難かったので)</li>\n  <li>計測データ表示処理の並べ替え(ソースが見難かったので。フレーム時間の追加以外の動作は変更なし)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py.org\t2019-10-29 05:08:34.982999999 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"p\">@@ -210,7 +210,8 @@</span>\n     else:\n         labels_map = None\n \n<span class=\"gd\">-    input_stream = 0 if args.input == \"cam\" else args.input\n</span><span class=\"gi\">+    # input_stream = 0 if args.input == \"cam\" else args.input\n+    input_stream = 0 if args.input == \"cam\" else os.path.abspath(args.input)\n</span> \n     is_async_mode = True\n     cap = cv2.VideoCapture(input_stream)\n<span class=\"p\">@@ -234,6 +235,8 @@</span>\n     next_request_id = 1\n     render_time = 0\n     parsing_time = 0\n<span class=\"gi\">+    frame_time = 0\n+    prev_time = time()\n</span> \n     # ----------------------------------------------- 6. Doing inference -----------------------------------------------\n     log.info(\"Starting inference...\")\n<span class=\"p\">@@ -263,6 +266,8 @@</span>\n \n         # Start inference\n         start_time = time()\n<span class=\"gi\">+        frame_time = start_time - prev_time         # 1フレームの処理時間\n+        prev_time = start_time\n</span>         exec_net.start_async(request_id=request_id, inputs={input_blob: in_frame})\n         det_time = time() - start_time\n \n<span class=\"p\">@@ -303,8 +308,9 @@</span>\n             # Validation bbox of detected object\n             if obj['xmax'] > origin_im_size[1] or obj['ymax'] > origin_im_size[0] or obj['xmin'] < 0 or obj['ymin'] < 0:\n                 continue\n<span class=\"gd\">-            color = (int(min(obj['class_id'] * 12.5, 255)),\n-                     min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span><span class=\"gi\">+            # color = (int(min(obj['class_id'] * 12.5, 255)),\n+            #          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n+            color = (255, 128, 128)\n</span>             det_label = labels_map[obj['class_id']] if labels_map and len(labels_map) >= obj['class_id'] else \\\n                 str(obj['class_id'])\n \n<span class=\"p\">@@ -322,16 +328,17 @@</span>\n         # Draw performance stats over frame\n         inf_time_message = \"Inference time: N\\A for async mode\" if is_async_mode else \\\n             \"Inference time: {:.3f} ms\".format(det_time * 1e3)\n<span class=\"gi\">+        frame_time_message = \"Frame time: {:.3f} ms\".format(frame_time * 1e3)\n</span>         render_time_message = \"OpenCV rendering time: {:.3f} ms\".format(render_time * 1e3)\n         async_mode_message = \"Async mode is on. Processing request {}\".format(cur_request_id) if is_async_mode else \\\n             \"Async mode is off. Processing request {}\".format(cur_request_id)\n         parsing_message = \"YOLO parsing time is {:.3f}\".format(parsing_time * 1e3)\n \n<span class=\"gd\">-        cv2.putText(frame, inf_time_message, (15, 15), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200, 10, 10), 1)\n-        cv2.putText(frame, render_time_message, (15, 45), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n-        cv2.putText(frame, async_mode_message, (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5,\n-                    (10, 10, 200), 1)\n-        cv2.putText(frame, parsing_message, (15, 30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n</span><span class=\"gi\">+        cv2.putText(frame, inf_time_message,    (15, 15),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, parsing_message,     (15, 30),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, render_time_message, (15, 45),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, frame_time_message,  (10, int(origin_im_size[0] - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, async_mode_message,  (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n</span> \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n</code></pre></div></div>\n\n<p>上のパッチ内容をa.patchとして保存したとして、以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch object_detection_demo_yolov3_async.py a.patch \n\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\n入力ファイルをmp4に変えるだけ。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしいが、カメラないので未確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>RaspberryPi用はopenVINO 2019R3のまま(2019.10.29現在、R3.1はリリースされていない)だけど、問題なし。</p>\n\n<p>ubuntuで作成した object_detection_demo_yolov3_async ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"静止画の場合-1\">静止画の場合</h2>\n\n<p>実行コマンドは以下。  ubuntuの実行コマンドと比べて、以下の変更がある。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--device MYRIAD</code>を追加</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">--cpu_extension</code>を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合-1\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\nこちらも入力ファイルをmp4に変えるだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p>openCVではMP4ファイルを保存することができる。<br />\nobject_detection_demo_yolov3_async.py に以下の変更を加えることで、認識結果をMP4ファイルに保存することができる。</p>\n\n<p>以下の修正ファイルは簡易的に保存する処理を追加したため、保存ファイル名は決め打ち。 <br />\n汎用的にするなら、オプションで指定できるようにしてもいいかもね。</p>\n\n<p>ただし、実際に保存するタイミングとMP4ファイルのタイムインデックスが一致するわけではないので、\n処理時の見た目と保存ファイルを再生したときの見た目は異なるので注意が必要。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"gi\">+++ record.py\t2019-10-29 11:35:37.296005608 +0900\n</span><span class=\"p\">@@ -218,6 +218,18 @@</span>\n     number_input_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n     number_input_frames = 1 if number_input_frames != -1 and number_input_frames < 0 else number_input_frames\n \n<span class=\"gi\">+    # =====================================================================================\n+    # 幅と高さを取得\n+    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n+    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n+    size = (width, height)\n+    # フレームレート(1フレームの時間単位はミリ秒)の取得\n+    frame_rate = int(cap.get(cv2.CAP_PROP_FPS))\n+    # フォーマット\n+    fmt = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')\n+    writer = cv2.VideoWriter('./outtest.mp4', fmt, frame_rate, size)\n+    # =====================================================================================\n+\n</span>     wait_key_code = 1\n \n     # Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n<span class=\"p\">@@ -342,6 +354,9 @@</span>\n \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n<span class=\"gi\">+        # =====================================================================================\n+        writer.write(frame)\n+        # =====================================================================================\n</span>         render_time = time() - start_time\n \n         if is_async_mode:\n<span class=\"p\">@@ -359,6 +374,10 @@</span>\n             is_async_mode = not is_async_mode\n             log.info(\"Switched to {} mode\".format(\"async\" if is_async_mode else \"sync\"))\n \n<span class=\"gi\">+    # =====================================================================================\n+    writer.release()\n+    # =====================================================================================\n+\n</span>     cv2.destroyAllWindows()\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>改訂版はこちら→<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></p>\n\n<p>caffeモデルなどをopenVINOへ変換するには、フルパッケージが必要らしい。<br />\nでもって、フルパッケージはRaspberryPiでは使用できなくて、WindowsやLinux、macOSが必要。<br />\nということで、openVINO フルパッケージをubuntu 18.04にインストールする。 <br />\n(16.04でも大丈夫かもしれないけど、今回は18.04を使う。LTSじゃないのはやめといた方が良さそう)</p>\n\n<h1 id=\"ダウンロード--インストール前半\">ダウンロード & インストール前半</h1>\n\n<p>ダウンロードはこの辺を参考に。。。<br />\n<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758</a><br />\nなにやら登録しないといけないらしい。</p>\n\n<p>ダウンロードしたら、てきとーなところに展開して、インストーラを実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\n2910.10 「2019 R3.1」がリリースされた。ファイル名は「l_openvino_toolkit_p_2019.3.376.tgz」</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf /Share/l_openvino_toolkit_p_2019.3.334.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2019.3.334\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n\n<p>nextをクリックしていけば大丈夫(Agreeするとこはあるけど)。<br />\nあとで色々インストールしろと言われるけど、あとでやるので無視して大丈夫<br />\n・・・・しばらく待つ・・・・<br />\nいったんFinishするとブラウザが表示される<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h1 id=\"インストール後半--動作確認\">インストール後半 & 動作確認</h1>\n\n<h2 id=\"install-external-software-dependenciesとな\">「Install External Software Dependencies」とな?</h2>\n\n<p>なんか実行してインストールしろってことらしい。<br />\nroot権限で実行しないとエラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh\n</code></pre></div></div>\n\n<p>なんか色々インストールされるっぽい。<br />\n中身はOSのディストリビューションとバージョンでインストールパッケージを切り替えてインストールしてるらしい。</p>\n\n<h2 id=\"set-the-environment-variablesとな\">「Set the Environment Variables」とな?</h2>\n\n<p>環境変数の設定らしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<p>~/.bashrcに追加しておくと良いとのことなので、そうする。</p>\n\n<h2 id=\"configure-the-model-optimizerとな\">「Configure the Model Optimizer」とな?</h2>\n\n<p>モデルオプティマイザの設定。<br />\nこれが欲しかったのよ。</p>\n\n<p>必要なpipモジュールをインストールするらしい。<br />\n必要なものだけインストールすることもできるけど、一括でインストールしといた方が手間がかからないでしょう。</p>\n\n<p>pyenvを使ってると、<code class=\"language-plaintext highlighter-rouge\">sudo pip3</code>されると、systemのpip3が動いてしまい、pyenv環境にモジュールがインストールされない。<br />\nスクリプトの中で必要なコマンドだけ実行する(随分スッキリしちゃったなぁ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\n</code></pre></div></div>\n\n<p>バージョン不一致とか言われたら、適宜バージョン合わせてアップグレードorダウングレードしてちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nsetuptoolsは<code class=\"language-plaintext highlighter-rouge\">pip install -U setuptools</code>でOKなはず。<br />\nnumpyは<code class=\"language-plaintext highlighter-rouge\">mxnet 1.3.1 has requirement numpy<1.15.0,>=1.8.2, but you'll have numpy 1.17.3 which is incompatible.</code>と言われるのだけど、tensorflow 1.15.0だとnumpy 1.16.0以上を要求する。<br />\nとりあえず、tenssorflowを1.13.1にしてnumpyを1.14.6にしてみて様子見。<br />\n現状のバージョン一覧は以下。これを<code class=\"language-plaintext highlighter-rouge\">requirements.txt</code>として保存し、<code class=\"language-plaintext highlighter-rouge\">pip install -r requirements.txt</code>するとこのバージョンでそろえてくれるはず。</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.8.1\nastor==0.8.0\ncertifi==2019.9.11\nchardet==3.0.4\ndecorator==4.4.0\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.1.7\ngraphviz==0.8.4\ngrpcio==1.24.3\nh5py==2.10.0\nidna==2.8\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.0\nMarkdown==3.1.1\nmock==3.0.5\nmxnet==1.3.1\nnetworkx==2.3\nnumpy==1.14.6\nonnx==1.6.0\nopt-einsum==3.1.0\npipdeptree==0.13.2\nprotobuf==3.6.1\nrequests==2.22.0\nsix==1.12.0\ntensorboard==1.13.1\ntensorflow==1.13.1\ntensorflow-estimator==1.13.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4\nurllib3==1.25.6\nWerkzeug==0.16.0\nwrapt==1.11.2\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nオリジナルの方法はこちら</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"run-the-verification-scripts-to-verify-installationとな\">「Run the Verification Scripts to Verify Installation」とな?</h2>\n\n<p>なになに、実行必須?たしかにapt installが実行される。<br />\nなら、タイトルに “to Verify Installation” とか書くなよ!</p>\n\n<p>build前に<code class=\"language-plaintext highlighter-rouge\">apt install</code> と <code class=\"language-plaintext highlighter-rouge\">pip install</code>が走る。</p>\n\n<p>こっちもpyenv使ってるとpipで悲しいことになるので、先にpipだけ実行しておく。<br />\nスクリプト側でもpipが走ってsystemのモジュールが追加されるが、悪影響はないと思うので、そのままにしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div></div>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n./demo_squeezenet_download_convert_run.sh\n</code></pre></div></div>\n\n<p>・・・・こんなことをやってるらしい・・・・</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">target_precision</code> は FP16 になっている</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">apt install</code> で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pip install</code>で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/open_model_zoo/tools/downloaderdownloader.py</code>でモデルのダウンロードを行う\n    <ul>\n      <li>ダウンロード済みならスキップ»</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/model_optimizer/mo.py</code>でモデル変換を行う\n    <ul>\n      <li>変換済みならスキップ»</li>\n    </ul>\n  </li>\n  <li>サンプルプログラムのbuild</li>\n  <li>サンプルプログラム(classification_sample_async)の実行<br />\n  実行結果はこんな感じ</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./classification_sample_async -d CPU -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/openvino_models/ir/FP16//public/squeezenet1.1/squeezenet1.1.xml \n\n[ INFO ] InferenceEngine: \n\tAPI version ............ 2.1\n\tBuild .................. custom_releases/2019/R3_cb6cad9663aea3d282e0e8b3e0bf359df665d5d0\n\tDescription ....... API\n[ INFO ] Parsing input parameters\n[ INFO ] Parsing input parameters\n[ INFO ] Files were added: 1\n[ INFO ]     /opt/intel/openvino/deployment_tools/demo/car.png\n[ INFO ] Creating Inference Engine\n\tCPU\n\tMKLDNNPlugin version ......... 2.1\n\tBuild ........... 30677\n\n[ INFO ] Loading network files\n[ INFO ] Preparing input blobs\n[ WARNING ] Image is resized from (787, 259) to (227, 227)\n[ INFO ] Batch size is 1\n[ INFO ] Loading model to the device\n[ INFO ] Create infer request\n[ INFO ] Start inference (10 asynchronous executions)\n[ INFO ] Completed 1 async request execution\n[ INFO ] Completed 2 async request execution\n[ INFO ] Completed 3 async request execution\n[ INFO ] Completed 4 async request execution\n[ INFO ] Completed 5 async request execution\n[ INFO ] Completed 6 async request execution\n[ INFO ] Completed 7 async request execution\n[ INFO ] Completed 8 async request execution\n[ INFO ] Completed 9 async request execution\n[ INFO ] Completed 10 async request execution\n[ INFO ] Processing output blobs\n\nTop 10 results:\n\nImage /opt/intel/openvino/deployment_tools/demo/car.png\n\nclassid probability label\n------- ----------- -----\n817     0.8364176   sports car, sport car\n511     0.0945683   convertible\n479     0.0419195   car wheel\n751     0.0091233   racer, race car, racing car\n436     0.0068038   beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon\n656     0.0037315   minivan\n586     0.0025940   half track\n717     0.0016044   pickup, pickup truck\n864     0.0012045   tow truck, tow car, wrecker\n581     0.0005833   grille, radiator grille\n\n[ INFO ] Execution successful\n\n[ INFO ] This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool\n</code></pre></div></div>\n\n<ul>\n  <li>終了</li>\n</ul>\n\n<p>もういっちょでも実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh\n</code></pre></div></div>\n\n<p>やってることは前のと同じ。<br />\nこっちはopenVINOのモデルをダウンロードするので、モデル変換はない。<br />\n最終的に実行しているデモプログラムはこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./security_barrier_camera_demo -d CPU -d_va CPU -d_lpr CPU -i /opt/intel/openvino/deployment_tools/demo/car_1.bmp -m ~/openvino_models/ir/FP16/intel/vehicle-license-plate-detection-barrier-0106/FP16/vehicle-license-plate-detection-barrier-0106.xml -m_lpr ~/openvino_models/ir/FP16/intel/license-plate-recognition-barrier-0001/FP16/license-plate-recognition-barrier-0001.xml -m_va ~/openvino_models/ir/FP16/intel/vehicle-attributes-recognition-barrier-0039/FP16/vehicle-attributes-recognition-barrier-0039.xml \n</code></pre></div></div>\n\n<h2 id=\"gpuやncstick使わないから以下スキップ\">GPUやNCStick使わないから以下スキップ</h2>\n\n<!--\n## 「Run a Sample Application」\n\nNCStickなどVPUベースの環境で実行するにはFP16モデルが必要\nデフォルトはFP32\n\nFP16: 16bit浮動小数点\nFP32: 32bit浮動小数点\n====\nmkdir ~/squeezenet1.1_FP16\ncd ~/squeezenet1.1_FP16\npython3 /opt/intel/openvino/deployment_tools/model_optimizer/mo.py --input_model ~/openvino_models/models/FP32/classification/squeezenet/1.1/caffe/squeezenet1.1.caffemodel --data_type FP16 --output_dir .\n\n====\n\n\n\n\n./classification_sample_async -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/squeezenet1.1_FP16/squeezenet1.1.xml -d CPU\n-->\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PythonでIntel NCStick2</title>\n  </head>\n  <body>\n    <header>\n      <h1>PythonでIntel NCStick2</h1>\n      <p>PythonでIntel NCStick2を操作する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"事前準備\">事前準備</h1>\n<p>何はなくともPythonが必要。<br />\n実際には3.7.4を使用して動作確認。</p>\n\n<p>Pythonはpyenvでインストールしておくのが便利。インストール方法は \n<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a> を参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\npyenvとの相性が悪いらしく、pyenvで3.7.xがインストールされていると\n(python3.7コマンド自体は存在するので;実行自体はエラーで返ってくるが)、\nsetupvars.shでPYTHONPATHにpython3.7用pathが設定されてしまう。\nプログラム中で<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>でpathを追加しても、sys.pathの末尾に追加されてしまい、\n先に設定された3.7用モジュールがインポートされてしまう。\nもし、他のバージョンのpythonで実行する場合は<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">sys.path.insert</code>で\npathの先頭に追加するようにしないといけないようだ(試してないけど)。</p>\n\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n    <span class=\"err\">↓</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>ということで、下のプログラムソースの<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>の行は不要。</p>\n</blockquote>\n\n<h2 id=\"モジュールのインストール\">モジュールのインストール</h2>\n\n<p>必要なモジュール類をインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgfortran-6-dev\npip <span class=\"nb\">install </span>numpy\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h2 id=\"ワークディレクトリ\">ワークディレクトリ</h2>\n\n<p>色々共通で使いたいサイズのでっかいファイルがあるので、ワークディレクトリを以下の構成で作成しておく。<br />\n以降のopenVINO関連の投稿もこのディレクトリ構成を使うようにする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># C++プログラム湯尾</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++\n<span class=\"c\"># pythonプログラム用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/python\n<span class=\"c\"># モデルデータ用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP16\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP32\n</code></pre></div></div>\n\n<h1 id=\"参考\">参考</h1>\n\n<p><del>パクった</del> 参考にしたのは以下のあたり<br />\n解説や実行方法などはこっちを参照してちょ(相変わらずの他力本願ぶり…))</p>\n\n<ul>\n  <li><a href=\"http://jellyware.jp/openvino/\">JELLYWARE ゼロから学ぶディープラーニング推論</a>\n    <ul>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c07_ie_emotion.html\">Inference Engineを学んで感情分類</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c08_face_detection.html\">リアルタイム顔検出</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c09_emotion_app.html\">リアルタイム感情分析アプリ</a></li>\n    </ul>\n  </li>\n</ul>\n\n<p>顔検出+感情分類の参照元はカメラキャプチャした画像を処理しているけど、手元に適当なカメラがなかったので、JPEGファイルで実行するようにしてある(こっちの方が余計な処理なくて分かりやすいかな、と思ったのもある)。</p>\n\n<h1 id=\"感情分類\">感情分類</h1>\n\n<p>感情分類のプログラムを試す。</p>\n\n<h3 id=\"準備\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/emotions-recognition-retail-0003/FP16/emotions-recognition-retail-0003\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する顔画像(顔部分のみ切り出し)をPHOTO/face.jpgとして保存しておく。</p>\n\n<h3 id=\"プログラム\">プログラム</h3>\n\n<p>試したソースはこちら。<br />\nPCのubuntuで実行するための処理も追加済み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/face.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 結果取り出し\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>\n<span class=\"c1\"># 結果の最大値を持つインデックスを取得\n</span><span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 結果表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">結果'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">index_max</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"c1\"># 結果の詳細表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">詳細'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'スコア:</span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出\">顔検出</h1>\n\n<p>顔検出のプログラムを試す。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-1\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-1\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n\n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-1\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_detect.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_detect.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_detect.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出感情分類\">顔検出+感情分類</h1>\n\n<p>上の2つを合体させ、顔検出した結果に感情分類を実行する。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-2\">準備</h3>\n\n<p>モデルデータは上の2つをそのまま使用。</p>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-2\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出 + 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n# 日本語表示にはPillow使うとかしないといけないので、英語で。\n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# バウンティングボックスとラベルを表示する関数\n</span><span class=\"k\">def</span> <span class=\"nf\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ラベル領域サイズ\n</span>    <span class=\"n\">LABEL_W</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">12</span>    <span class=\"c1\"># 等幅フォントじゃないので正確ではないけど、大体こんな感じ\n</span>    <span class=\"n\">LABEL_H</span> <span class=\"o\">=</span> <span class=\"mi\">14</span>                <span class=\"c1\"># こっちもトライアンドエラーで微調整\n</span>    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">IMAGE_W</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">IMAGE_H</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># バウンディングボックス表示 \n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ラベル表示位置(X)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">IMAGE_W</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">IMAGE_W</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_W</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">xmin</span>\n    \n    <span class=\"c1\"># ラベル表示位置(Y)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span>\n    \n    <span class=\"c1\"># 文字列背景描画(塗りつぶし)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">label_x</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 文字列描画(座標は文字の左下)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX_SMALL</span><span class=\"p\">,</span> <span class=\"mf\">0.8</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n    \n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。特にminは補正しないとエラーになる\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 顔領域のみ切り出し \n</span>    <span class=\"n\">frame_face</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">[</span> <span class=\"n\">ymin</span><span class=\"p\">:</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">:</span><span class=\"n\">xmax</span> <span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 入力データフォーマットへ変換 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame_face</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span>   <span class=\"c1\"># サイズ変更 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">img_face</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img_face</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>    \n    <span class=\"c1\"># 推論実行 \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img_face</span><span class=\"p\">})</span>\n    \n    <span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>    \n    <span class=\"c1\"># 出力値が最大のインデックスを得る \n</span>    <span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"c1\"># print(list_emotion[index_max])\n</span>    <span class=\"n\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-2\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<h1 id=\"考察\">考察</h1>\n\n<p>基本パターンはこんな感じ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># モジュールのロード\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># 初期化\n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"s\">\"MYRIAD\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み\n</span><span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"s\">'xmlファイル'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"s\">'binファイル'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 推論実行 \n# imgは入力データ、Numpy配列 ndarray型\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># outが出力データ、Numpy配列 ndarray型\n</span>\n</code></pre></div></div>\n\n<p>入出力データの並びは読み込んだモデルに依存する。<br />\n入力データのサイズやRGB並び順などを合わせる。<br />\n(モデルに入力する際にリサイズすれば、元の画像ファイルのサイズは任意で良い。)<br />\n出力データはそのままでは「何のこっちゃ?」なので、きちんと整形してやる必要がある。</p>\n\n<p>ここに学習済みデータが色々登録されているらしい。<br />\n<a href=\"https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html\">https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html</a></p>\n\n<p>TensorflowやCaffeで作成した学習済みデータを変換することもできるらしいが、やり方はこれから調査。</p>\n\n<h1 id=\"参考情報\">参考情報</h1>\n<p><a href=\"https://software.intel.com/en-us/articles/OpenVINO-RelNotes\">openVINO toolkit リリースノート</a><br />\n<a href=\"https://git.uni-paderborn.de/rnagle/dldt/tree/noctua_plugin_develop\">openVINO toolkit リポジトリ</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick2用動作環境の構築</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick2用動作環境の構築</h1>\n      <p>Intel NCStick2用動作環境の構築</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Dセンセの悪魔の囁きに踊らされ、Intel NCStick2をポチってしまった。<br />\nで、動作環境を構築したときのメモを残しておく。</p>\n\n<p>ホストマシンは、RaspberryPi3 model B+ で Raspbian Buster を使用。</p>\n\n<p>Raspbian Busterのインストールは、\n<a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\">Raspbian Busterのインストール</a>\nの手順で行った。</p>\n\n<p><a href=\"http://jellyware.jp/openvino/\">JellyWare:ゼロから学ぶディープラーニング推論</a> \n → <a href=\"http://jellyware.jp/kurage/openvino/c03_setting.html\">ゼロから始めるインストール</a> をマネしただけだが、\nダウンロード先の<strong>URLが微妙に変更</strong>されてたり、\nこのページの説明が<strong>細かすぎてちょっとイラっとした</strong>ので、\n以下に手順の要約を書いておく。</p>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2\n<span class=\"nb\">cd</span> /work/NCS2/\n</code></pre></div></div>\n\n<h2 id=\"openvino-の取得とインストール\">openVINO の取得とインストール</h2>\n\n<p>アーカイブファイル落としてきて、展開するだけ。<br />\nR3がリリースされているようなので、これを使う。(2019/10/01現在)\nちょくちょくリリースされるみたいなので、<a href=\"https://download.01.org/opencv/2019/openvinotoolkit/\">https://download.01.org/opencv/2019/openvinotoolkit/</a>をチェックしてね。<br />\n2020年になったら、~download.01.org/opencv/2020/~ なのかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R3/l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz\n\n<span class=\"c\"># インストール先ディレクトリの作成 & オーナー変更(あとあとめんどくさいので)</span>\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span>  <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n\n<span class=\"c\"># 展開</span>\n<span class=\"nb\">tar </span>xzvf l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span> <span class=\"nt\">--strip-components</span><span class=\"o\">=</span>1\n<span class=\"nb\">sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以下以前の情報</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R2/l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz\n\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo tar</span> <span class=\"nt\">-xf</span> l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz <span class=\"nt\">--strip</span> 1 <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h2 id=\"cmakeのインストール\">cmakeのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n</code></pre></div></div>\n\n<p>他にもmakeとかbuild-essentialとか要るけど、<a href=\"/memoBlog/2019/06/27/pyenv.html\">ここ</a>\nでインストールしたやつがあれば大丈夫っぽい。</p>\n\n<h2 id=\"初期化スクリプトの変更\">初期化スクリプトの変更</h2>\n\n<p>~/.bashrc の最後に以下を追加。<br />\nここでは<code class=\"language-plaintext highlighter-rouge\">${VINO_DIR_TMP}</code>使っちゃダメよ~。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOの設定</span>\n<span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<h2 id=\"初期化スクリプトの変更を反映\">初期化スクリプトの変更を反映</h2>\n\n<p>シリアルコンソールやSSHでlog inしてる場合は、ここで一旦log offして再log in。<br />\nX使ってるならターミナル開きなおす。<br />\nもちろん、<code class=\"language-plaintext highlighter-rouge\">source</code>するだけでも良いけど。<br />\nいちお、.bashrcにちゃんと書けてるか確認の意味で一旦log off or ターミナル開きなおしするのがいいかな。  <br />\n(.bashrcの変更だけなので、再起動までは必要ない) <br />\nlog in時 or 新しいターミナルを開いた時に <code class=\"language-plaintext highlighter-rouge\">[setupvars.sh] OpenVINO environment initialized</code> と表示されることを確認。</p>\n\n<h2 id=\"グループの追加\">グループの追加</h2>\n\n<p>ユーザがグループusersを持っているか確認。(デフォルトなら持ってるハズ) 持ってなかったら追加。<br />\n次のコマンドで追加してくれるっぽいけど。。。</p>\n\n<h2 id=\"udevルールの追加\">udevルールの追加</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sh <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n\n<h2 id=\"いよいよncstick2の登場だ\">いよいよNCStick2の登場だ~~~</h2>\n\n<p>NCStick2をUSBポートにぶっ挿す。<br />\nデカくて他のポートに干渉するので、必要なら延長ケーブルを使ってちょ。</p>\n\n<p>で、認識されたか確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n<span class=\"c\"># こんな感じで表示されるハズ。XXX部分は ぶっ挿したUSBポートで変わる。</span>\n・・・\nBus XXX Device XXX: ID 03e7:2485 Intel Movidius MyriadX\n・・・\n</code></pre></div></div>\n\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n\n<p>とりあえず、ワークディレクトリは<code class=\"language-plaintext highlighter-rouge\">/work/NCS2/</code>を使ってる。<br />\nhome に色々ぶち込むの嫌いなので。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">/work</code>は作成済みで<code class=\"language-plaintext highlighter-rouge\">chown</code>済みとする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ワークディレクトリの作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/sample\n<span class=\"nb\">cd</span> /work/NCS2/sample\n\n<span class=\"c\"># cmakeの実行</span>\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a\"</span> <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/deployment_tools/inference_engine/samples\n\n<span class=\"c\"># makeの実行</span>\nmake <span class=\"nt\">-j2</span> object_detection_sample_ssd\n\n<span class=\"c\"># ネットワークデータの取得</span>\n<span class=\"c\"># shell変数の設定時はスペース入れちゃダメだよ~</span>\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R2/20190716_170000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n\n<span class=\"c\"># 入力ファイルをどっかから持ってきて、<<入力ファイル>>.jpgとしてカレントディレクトリに保存しておく</span>\n<span class=\"c\"># 顔検出のデモなので、人物が何人か写ってる画像を用意してね。</span>\n\n<span class=\"c\"># サンプル実行</span>\n./armv7l/Release/object_detection_sample_ssd  <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> <<入力ファイル>>.jpg\n\n<span class=\"c\"># out_0.bmpができる</span>\n</code></pre></div></div>\n\n<h2 id=\"結果の確認\">結果の確認</h2>\n\n<p>out_0.bmpをテキトーに表示。<br />\n人物の顔が四角で囲まれていることを確認。</p>\n\n<h2 id=\"インストールと動作確認完了\">インストールと動作確認完了</h2>\n\n<p>めでたしめでたし。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Intel NCStick用TinyYOLOの<a href=\"https://github.com/movidius/ncappzoo/blob/ncsdk2/caffe/TinyYolo/run.py\">ソース</a>のコピー</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#! /usr/bin/env python3\n</span>\n<span class=\"c1\"># Copyright(c) 2017 Intel Corporation. \n# License: MIT See LICENSE file in root directory.\n</span>\n<span class=\"kn\">from</span> <span class=\"nn\">mvnc</span> <span class=\"kn\">import</span> <span class=\"n\">mvncapi</span> <span class=\"k\">as</span> <span class=\"n\">mvnc</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n\n\n<span class=\"c1\"># Assume running in examples/caffe/TinyYolo and graph file is in current directory.\n</span><span class=\"n\">input_image_file</span><span class=\"o\">=</span> <span class=\"s\">'../../data/images/nps_chair.png'</span>\n<span class=\"n\">tiny_yolo_graph_file</span><span class=\"o\">=</span> <span class=\"s\">'./graph'</span>\n\n<span class=\"c1\"># Tiny Yolo assumes input images are these dimensions.\n</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n<span class=\"n\">NETWORK_IMAGE_HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n\n\n<span class=\"c1\"># Interpret the output from a single inference of TinyYolo (GetResult)\n# and filter out objects/boxes with low probabilities.\n# output is the array of floats returned from the API GetResult but converted\n# to float32 format.\n# input_image_width is the width of the input image\n# input_image_height is the height of the input image\n# Returns a list of lists. each of the inner lists represent one found object and contain\n# the following 6 values:\n#    string that is network classification ie 'cat', or 'chair' etc\n#    float value for box center X pixel location within source image\n#    float value for box center Y pixel location within source image\n#    float value for box width in pixels within source image\n#    float value for box height in pixels within source image\n#    float value that is the probability for the network classification.\n</span><span class=\"k\">def</span> <span class=\"nf\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># the raw number of floats returned from the inference (GetResult())\n</span>    <span class=\"n\">num_inference_results</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># the 20 classes this network was trained on\n</span>    <span class=\"n\">network_classifications</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">\"aeroplane\"</span><span class=\"p\">,</span> <span class=\"s\">\"bicycle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bird\"</span><span class=\"p\">,</span> <span class=\"s\">\"boat\"</span><span class=\"p\">,</span> <span class=\"s\">\"bottle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bus\"</span><span class=\"p\">,</span> <span class=\"s\">\"car\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"cat\"</span><span class=\"p\">,</span> <span class=\"s\">\"chair\"</span><span class=\"p\">,</span> <span class=\"s\">\"cow\"</span><span class=\"p\">,</span> <span class=\"s\">\"diningtable\"</span><span class=\"p\">,</span> <span class=\"s\">\"dog\"</span><span class=\"p\">,</span> <span class=\"s\">\"horse\"</span><span class=\"p\">,</span> <span class=\"s\">\"motorbike\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"person\"</span><span class=\"p\">,</span> <span class=\"s\">\"pottedplant\"</span><span class=\"p\">,</span> <span class=\"s\">\"sheep\"</span><span class=\"p\">,</span> <span class=\"s\">\"sofa\"</span><span class=\"p\">,</span> <span class=\"s\">\"train\"</span><span class=\"p\">,</span><span class=\"s\">\"tvmonitor\"</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># only keep boxes with probabilities greater than this\n</span>    <span class=\"n\">probability_threshold</span> <span class=\"o\">=</span> <span class=\"mf\">0.07</span>\n\n    <span class=\"n\">num_classifications</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">network_classifications</span><span class=\"p\">)</span> <span class=\"c1\"># should be 20\n</span>    <span class=\"n\">grid_size</span> <span class=\"o\">=</span> <span class=\"mi\">7</span> <span class=\"c1\"># the image is a 7x7 grid.  Each box in the grid is 64x64 pixels\n</span>    <span class=\"n\">boxes_per_grid_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span> <span class=\"c1\"># the number of boxes returned for each grid cell\n</span>\n    <span class=\"c1\"># grid_size is 7 (grid is 7x7)\n</span>    <span class=\"c1\"># num classifications is 20\n</span>    <span class=\"c1\"># boxes per grid cell is 2\n</span>    <span class=\"n\">all_probabilities</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># classification_probabilities  contains a probability for each classification for\n</span>    <span class=\"c1\"># each 64x64 pixel square of the grid.  The source image contains\n</span>    <span class=\"c1\"># 7x7 of these 64x64 pixel squares and there are 20 possible classifications\n</span>    <span class=\"n\">classification_probabilities</span> <span class=\"o\">=</span> \\\n        <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">980</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n    <span class=\"n\">num_of_class_probs</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># The probability scale factor for each box\n</span>    <span class=\"n\">box_prob_scale_factor</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">980</span><span class=\"p\">:</span><span class=\"mi\">1078</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># get the boxes from the results and adjust to be pixel units\n</span>    <span class=\"n\">all_boxes</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">1078</span><span class=\"p\">:],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n    <span class=\"n\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">all_boxes</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># adjust the probabilities with the scaling factor\n</span>    <span class=\"k\">for</span> <span class=\"n\">box_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">):</span> <span class=\"c1\"># loop over boxes\n</span>        <span class=\"k\">for</span> <span class=\"n\">class_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">):</span> <span class=\"c1\"># loop over classifications\n</span>            <span class=\"n\">all_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">,</span><span class=\"n\">class_index</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">class_index</span><span class=\"p\">],</span><span class=\"n\">box_prob_scale_factor</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">])</span>\n\n\n    <span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"o\">>=</span><span class=\"n\">probability_threshold</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">nonzero</span><span class=\"p\">(</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">)</span>\n    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># sort the boxes from highest probability to lowest and then\n</span>    <span class=\"c1\"># sort the probabilities and classifications to match\n</span>    <span class=\"n\">argsort</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argsort</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">))[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n\n\n    <span class=\"c1\"># get mask for boxes that seem to be the same object\n</span>    <span class=\"n\">duplicate_box_mask</span> <span class=\"o\">=</span> <span class=\"n\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># update the boxes, probabilities and classifications removing duplicates.\n</span>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n\n    <span class=\"n\">classes_boxes_and_probs</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)):</span>\n        <span class=\"n\">classes_boxes_and_probs</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">([</span><span class=\"n\">network_classifications</span><span class=\"p\">[</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]])</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">classes_boxes_and_probs</span>\n\n<span class=\"c1\"># creates a mask to remove duplicate objects (boxes) and their related probabilities and classifications\n# that should be considered the same object.  This is determined by how similar the boxes are\n# based on the intersection-over-union metric.\n# box_list is as list of boxes (4 floats for centerX, centerY and Length and Width)\n</span><span class=\"k\">def</span> <span class=\"nf\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">):</span>\n    <span class=\"c1\"># The intersection-over-union threshold to use when determining duplicates.\n</span>    <span class=\"c1\"># objects/boxes found that are over this threshold will be\n</span>    <span class=\"c1\"># considered the same object\n</span>    <span class=\"n\">max_iou</span> <span class=\"o\">=</span> <span class=\"mf\">0.35</span>\n\n    <span class=\"n\">box_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">ones</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">))</span>\n\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">max_iou</span><span class=\"p\">:</span>\n                <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span>\n\n    <span class=\"n\">filter_iou_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">box_mask</span> <span class=\"o\">></span> <span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">filter_iou_mask</span>\n\n<span class=\"c1\"># Converts the boxes in box list to pixel units\n# assumes box_list is the output from the box output from\n# the tiny yolo network and is [grid_size x grid_size x 2 x 4].\n</span><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># number of boxes per grid cell\n</span>    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n\n    <span class=\"c1\"># setup some offset values to map boxes to pixels\n</span>    <span class=\"c1\"># box_offset will be [[ [0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6]] ...repeated for 7 ]\n</span>    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">)),(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)),(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># adjust the box center\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">box_offset</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">box_offset</span><span class=\"p\">,(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># adjust the lengths and widths\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n\n    <span class=\"c1\">#scale the boxes to the image size in pixels\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n\n\n<span class=\"c1\"># Evaluate the intersection-over-union for two boxes\n# The intersection-over-union metric determines how close\n# two boxes are to being the same box.  The closer the boxes\n# are to being the same, the closer the metric will be to 1.0\n# box_1 and box_2 are arrays of 4 numbers which are the (x, y)\n# points that define the center of the box and the length and width of\n# the box.\n# Returns the intersection-over-union (between 0.0 and 1.0)\n# for the two boxes specified.\n</span><span class=\"k\">def</span> <span class=\"nf\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># one diminsion of the intersecting box\n</span>    <span class=\"n\">intersection_dim_1</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># the other dimension of the intersecting box\n</span>    <span class=\"n\">intersection_dim_2</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">intersection_dim_1</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">intersection_dim_2</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># no intersection area\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># intersection area is product of intersection dimensions\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span>  <span class=\"n\">intersection_dim_1</span><span class=\"o\">*</span><span class=\"n\">intersection_dim_2</span>\n\n    <span class=\"c1\"># calculate the union area which is the area of each box added\n</span>    <span class=\"c1\"># and then we need to subtract out the intersection area since\n</span>    <span class=\"c1\"># it is counted twice (by definition it is in each box)\n</span>    <span class=\"n\">union_area</span> <span class=\"o\">=</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">intersection_area</span><span class=\"p\">;</span>\n\n    <span class=\"c1\"># now we can return the intersection over union\n</span>    <span class=\"n\">iou</span> <span class=\"o\">=</span> <span class=\"n\">intersection_area</span> <span class=\"o\">/</span> <span class=\"n\">union_area</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">iou</span>\n\n<span class=\"c1\"># Displays a gui window with an image that contains\n# boxes and lables for found objects.  will not return until\n# user presses a key.\n# source_image is the original image for the inference before it was resized or otherwise changed.\n# filtered_objects is a list of lists (as returned from filter_objects()\n# each of the inner lists represent one found object and contain\n# the following 6 values:\n#    string that is network classification ie 'cat', or 'chair' etc\n#    float value for box center X pixel location within source image\n#    float value for box center Y pixel location within source image\n#    float value for box width in pixels within source image\n#    float value for box height in pixels within source image\n#    float value that is the probability for the network classification.\n</span><span class=\"k\">def</span> <span class=\"nf\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">source_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objects</span><span class=\"p\">):</span>\n    <span class=\"c1\"># copy image so we can draw on it. Could just draw directly on source image if not concerned about that.\n</span>    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n    <span class=\"n\">source_image_width</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">source_image_height</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"n\">x_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_width</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_WIDTH</span>\n    <span class=\"n\">y_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_height</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span>\n\n    <span class=\"c1\"># loop through each box and draw it on the image along with a classification label\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Found this many objects in the image: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)))</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)):</span>\n        <span class=\"n\">center_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span> \n        <span class=\"n\">center_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span>\n        <span class=\"n\">half_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n        <span class=\"n\">half_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n\n        <span class=\"c1\"># calculate box (left, top) and (right, bottom) coordinates\n</span>        <span class=\"n\">box_left</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">-</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_top</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">-</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_right</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">+</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"n\">source_image_width</span><span class=\"p\">)</span>\n        <span class=\"n\">box_bottom</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">+</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"n\">source_image_height</span><span class=\"p\">)</span>\n\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'box at index '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj_index</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">' is... left: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', top: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_top</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', right: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_right</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', bottom: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_bottom</span><span class=\"p\">))</span>  \n\n        <span class=\"c1\">#draw the rectangle on the image.  This is hopefully around the object\n</span>        <span class=\"n\">box_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>  <span class=\"c1\"># green box\n</span>        <span class=\"n\">box_thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span> <span class=\"n\">box_bottom</span><span class=\"p\">),</span> <span class=\"n\">box_color</span><span class=\"p\">,</span> <span class=\"n\">box_thickness</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># draw the classification label string just above and to the left of the rectangle\n</span>        <span class=\"n\">label_background_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">70</span><span class=\"p\">,</span> <span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">70</span><span class=\"p\">)</span> <span class=\"c1\"># greyish green background for text\n</span>        <span class=\"n\">label_text_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>   <span class=\"c1\"># white text\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">20</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"p\">),</span> <span class=\"n\">label_background_color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">' : %.2f'</span> <span class=\"o\">%</span> <span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">5</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"o\">+</span><span class=\"mi\">5</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"n\">label_text_color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n    <span class=\"n\">window_name</span> <span class=\"o\">=</span> <span class=\"s\">'TinyYolo (hit key to exit)'</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">display_image</span><span class=\"p\">)</span>\n\n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"n\">raw_key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># check if the window is visible, this means the user hasn't closed\n</span>        <span class=\"c1\"># the window via the X button (may only work with opencv 3.x\n</span>        <span class=\"n\">prop_val</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">getWindowProperty</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">WND_PROP_ASPECT_RATIO</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">raw_key</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"n\">prop_val</span> <span class=\"o\"><</span> <span class=\"mf\">0.0</span><span class=\"p\">)):</span>\n            <span class=\"c1\"># the user hit a key or closed the window (in that order)\n</span>            <span class=\"k\">break</span>\n\n\n<span class=\"c1\"># This function is called from the entry point to do\n# all the work.\n</span><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Running NCS Caffe TinyYolo example'</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Set logging level to only log errors\n</span>    <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">global_set_option</span><span class=\"p\">(</span><span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">GlobalOption</span><span class=\"p\">.</span><span class=\"n\">RW_LOG_LEVEL</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"n\">devices</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">enumerate_devices</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'No devices found'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"mi\">1</span>\n    <span class=\"n\">device</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Device</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"nb\">open</span><span class=\"p\">()</span>\n\n    <span class=\"c1\">#Load graph from disk and allocate graph via API\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tiny_yolo_graph_file</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'rb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">graph_from_disk</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Graph</span><span class=\"p\">(</span><span class=\"s\">\"Tiny Yolo Graph\"</span><span class=\"p\">)</span>\n    <span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span> <span class=\"o\">=</span> <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">allocate_with_fifos</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"n\">graph_from_disk</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Read image from file, resize it to network width and height\n</span>    <span class=\"c1\"># save a copy in display_image for display, then convert to float32, normalize (divide by 255),\n</span>    <span class=\"c1\"># and finally convert to convert to float16 to pass to LoadTensor as input for an inference\n</span>    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">input_image_file</span><span class=\"p\">)</span>\n    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span><span class=\"p\">,</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">INTER_LINEAR</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">divide</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"mf\">255.0</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>  <span class=\"c1\"># convert to RGB\n</span>\n    <span class=\"c1\"># Load tensor and get result.  This executes the inference on the NCS\n</span>    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">queue_inference_with_fifo_elem</span><span class=\"p\">(</span><span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span><span class=\"p\">,</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">output</span><span class=\"p\">,</span> <span class=\"n\">userobj</span> <span class=\"o\">=</span> <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">read_elem</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># filter out all the objects/boxes that don't meet thresholds\n</span>    <span class=\"n\">filtered_objs</span> <span class=\"o\">=</span> <span class=\"n\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">output</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Displaying image with objects detected in GUI'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Click in the GUI window and hit any key to exit'</span><span class=\"p\">)</span>\n    <span class=\"c1\">#display the filtered objects/boxes in a GUI window\n</span>    <span class=\"n\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objs</span><span class=\"p\">)</span>\n\n    <span class=\"n\">fifo_in</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Finished'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># main entry point for program. we'll call main() to do what needs to be done.\n</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その5)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その5)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"認識結果の表示ルーチンdisplay_objects_in_gui\">認識結果の表示ルーチン(display_objects_in_gui)</h1>\n\n<p>203行目<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">source_image</code>:入力画像(表示画像)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects</code>:整理された認識結果</li>\n</ul>\n\n<p><code class=\"language-plaintext highlighter-rouge\">filtered_objects</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">source_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objects</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>205行目<br />\n入力画像を表示用に<code class=\"language-plaintext highlighter-rouge\">display_image</code>にコピーする。(もともと入力された<code class=\"language-plaintext highlighter-rouge\">source_image</code>は汚さない。)<br />\n<code class=\"language-plaintext highlighter-rouge\">source_image_width</code>、<code class=\"language-plaintext highlighter-rouge\">source_image_height</code>は入力画像の幅と高さ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n    <span class=\"n\">source_image_width</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">source_image_height</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>209行目<br />\n<code class=\"language-plaintext highlighter-rouge\">NETWORK_IMAGE_WIDTH</code>と<code class=\"language-plaintext highlighter-rouge\">NETWORK_IMAGE_HEIGHT</code> は ニューラルネットに入力した画像サイズ(グローバル変数)。<br />\nどうせなら関数パラメータで渡した方がスマートだと思うが…<br />\n<code class=\"language-plaintext highlighter-rouge\">filtered_objects</code>の各データはこのサイズで定義されているので、表示用に変換するための比率を<code class=\"language-plaintext highlighter-rouge\">x_ratio</code>、<code class=\"language-plaintext highlighter-rouge\">y_ratio</code>として得る。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">x_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_width</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_WIDTH</span>\n    <span class=\"n\">y_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_height</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span>\n</code></pre></div></div>\n\n<p>213行目<br />\nそれぞれのバウンティングボックスに対してのループ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Found this many objects in the image: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)))</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)):</span>\n</code></pre></div></div>\n\n<p>215行目<br />\n認識結果のX座標(中心)、Y座標(中心)、幅、高さを表示用画像のサイズに変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">center_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span> \n        <span class=\"n\">center_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span>\n        <span class=\"n\">half_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n        <span class=\"n\">half_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n</code></pre></div></div>\n\n<p>221行目<br />\nX座標(中心)、Y座標(中心)、幅、高さからX座標(左端)、Y座標(上端)、X座標(右端)、Y座標(右端)に変換。<br />\n表示画像の範囲からはみ出ないように制限処理を付けてある。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">box_left</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">-</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_top</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">-</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_right</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">+</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"n\">source_image_width</span><span class=\"p\">)</span>\n        <span class=\"n\">box_bottom</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">+</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"n\">source_image_height</span><span class=\"p\">)</span>\n\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'box at index '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj_index</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">' is... left: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', top: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_top</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', right: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_right</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', bottom: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_bottom</span><span class=\"p\">))</span>  \n</code></pre></div></div>\n\n<p>229行目<br />\n表示画像にバウンティングボックスの四角を描く。<br />\n色は緑、線幅は2。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">box_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>  <span class=\"c1\"># green box\n</span>        <span class=\"n\">box_thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span> <span class=\"n\">box_bottom</span><span class=\"p\">),</span> <span class=\"n\">box_color</span><span class=\"p\">,</span> <span class=\"n\">box_thickness</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>234行目<br />\n表示画像に認識結果の名称とスコアを書く。<br />\n背景は暗い緑。文字色は白。<br />\n表示位置はバウンティングボックスの上20ピクセルの場所。<br />\nサイズは縦20ピクセル、横バウンティングボックスと同サイズ。<br />\n(バウンティングボックスの上端が20未満の時大丈夫なんだろか?表示が切れるだけ?)<br />\n(バウンティングボックスの右端より認識結果文字列が長いときも?)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">label_background_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">70</span><span class=\"p\">,</span> <span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">70</span><span class=\"p\">)</span> <span class=\"c1\"># greyish green background for text\n</span>        <span class=\"n\">label_text_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>   <span class=\"c1\"># white text\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">20</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"p\">),</span> <span class=\"n\">label_background_color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">' : %.2f'</span> <span class=\"o\">%</span> <span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">5</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"o\">+</span><span class=\"mi\">5</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"n\">label_text_color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>ループはここまで。</p>\n\n<p>239行目<br />\n画像の表示</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">window_name</span> <span class=\"o\">=</span> <span class=\"s\">'TinyYolo (hit key to exit)'</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">display_image</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>242行目<br />\nキー入力待ち。待ち時間は1msec。<br />\n待ち時間内にキーが押されなければ-1が返ってくる。<br />\nキー入力はGUIで表示されたウィンドウにフォーカスが当たっているときのみ有効で、コンソール(ターミナルなど)で入力してもダメ。<br />\n64bitマシンでは、キーコードを使用する場合は値を<code class=\"language-plaintext highlighter-rouge\">& 0xff</code>する必要があるが、入力なしを検出するだけなのでそのままでOK。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"n\">raw_key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>247行目<br />\nウィンドウパラメータの取得。<br />\nウィンドウが閉じられていれば-1.0が返る。表示状態ならウィンドウのアクセプト比が返る。<br />\n×ボタンでウィンドウを閉じたときの対策。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">prop_val</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">getWindowProperty</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">WND_PROP_ASPECT_RATIO</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>247行目<br />\nキー入力があった、または、×ボタンでウィンドウが閉じられたら終了。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">raw_key</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"n\">prop_val</span> <span class=\"o\"><</span> <span class=\"mf\">0.0</span><span class=\"p\">)):</span>\n            <span class=\"c1\"># the user hit a key or closed the window (in that order)\n</span>            <span class=\"k\">break</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その4)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その4)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"バウンティングボックス情報の単位変換boxes_to_pixel_units\">バウンティングボックス情報の単位変換(boxes_to_pixel_units)</h1>\n\n<p>129行目<br />\n各バウンティングボックスの座標/サイズ情報配列内のデータは各グリッド内の相対位置/相対サイズなので、画像内の座標に変換する。</p>\n\n<p>パラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_list   </code> : 各バウンティングボックスの座標/サイズ情報配列、</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">image_width</code> : 入力画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">image_height</code> : 入力画像高(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">grid_size  </code> : グリッドサイズ(7)<br />\n<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n [\n   [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n   [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n ]\n ・・・\n 同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>変換後の<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>132行目<br />\n定義されたバウンティングボックスの数。<br />\nGraphファイルに紐づいた値と考えられるので、トップレベルで定義しておいた方が分かりやすいと思うのだが。。。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n</code></pre></div></div>\n\n<p>136行目<br />\nグリッド内オフセットから画像内オフセットに変換するための作業用配列を作成。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">)),(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)),(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>う~ん、まとめて書いてあって分かり難いので、分解してみる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">aa</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span>\n    <span class=\"n\">bb</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">aa</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n    <span class=\"n\">cc</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">bb</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">))</span>\n    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">cc</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>としたとき、</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>aa = [\n       [0, 1, 2, 3, 4, 5, 6]\n     ]\nbb = [\n       [0, 1, 2, 3, 4, 5, 6],\n       ・・・\n       同じものがあと13組(合計14組)\n     ]\ncc = [\n       [\n         [0, 1, 2, 3, 4, 5, 6],\n         ・・・\n         同じものがあと6組(合計7組)\n       ],\n       ・・・\n       同じものがあと1組(合計2組)\n     ]\nbox_offset = [\n               [\n                 [0, 0],\n                 [1, 1],\n                 [2, 2],\n                 [3, 3],\n                 [4, 4],\n                 [5, 5],\n                 [6, 6]\n               ],\n               ・・・\n               同じものがあと6組(合計7組)\n             ]\n</code></pre></div></div>\n<p>となる。</p>\n\n<p>139行目<br />\n各グリッドのX座標データにグリッド番号を加算する(画像内絶対位置になる。単位:グリッド)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">box_offset</span>\n</code></pre></div></div>\n\n<p>140行目<br />\n各グリッドのY座標データにグリッド番号を加算する(画像内絶対位置になる。単位:グリッド)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">box_offset</span><span class=\"p\">,(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>141行目<br />\n各グリッドのX座標とY座標データをグリッド数で割る(画像内相対位置になる)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># adjust the lengths and widths\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n</code></pre></div></div>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\">#scale the boxes to the image size in pixels\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n</code></pre></div></div>\n\n<h2 id=\"処理を書き換えてみる\">処理を書き換えてみる</h2>\n<p>なにやら小難しいことをやっているので、実行速度を考えずに分かりやすく書き換えると以下のようになる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units_alt</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>                               <span class=\"c1\"># 定義されたバウンティングボックス数  \n</span>    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>                     <span class=\"c1\"># グリッド縦方向ループ\n</span>        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>                 <span class=\"c1\"># グリッド横方向ループ\n</span>            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>        <span class=\"c1\"># バウンティングボックスループ\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">gx</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span>        <span class=\"c1\"># box_x\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">gy</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span>       <span class=\"c1\"># box_y\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">**</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span>                             <span class=\"c1\"># box_widtn\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">**</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span>                            <span class=\"c1\"># box_height\n</span></code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その3)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その3)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"重なったボックス情報を削除するためのマスク情報配列を取得get_duplicate_box_mask\">重なったボックス情報を削除するためのマスク情報配列を取得(get_duplicate_box_mask)</h1>\n\n<p>109行目<br />\n重なったボックス情報を削除するためのマスク情報配列を取得する。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_list</code> : バウンティングボックスの座標/サイズ情報のセットの配列<br />\n<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [X座標, Y座標, 幅, 高さ],\n  [X座標, Y座標, 幅, 高さ],\n  ・・・\n]\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>出力は<br />\n重なったボックス情報を削除するためのマスク情報配列。<br />\n閾値を超えたスコアの数 の dtype.bool型の1次元配列。<br />\n出力の配列の構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ True, True, False, False, True, ・・・]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>113行目<br />\n重なっていると判断する重なり比率の閾値</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">max_iou</span> <span class=\"o\">=</span> <span class=\"mf\">0.35</span>\n</code></pre></div></div>\n\n<p>115行目<br />\n重なり判断済みフラグを1で初期化<br />\ndtype=’bool’ で良い気がするが…そうすれば最後のboolへの変換処理が不要になるのに…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">ones</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>117行目<br />\n総当たりチェックを行うためのループ処理<br />\n重なり判断済みフラグが0なら既に重なりBOXとして削除済みなのでスキップ</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n</code></pre></div></div>\n\n<p>120行目<br />\n2つのBOXの重なり比率を計算し、<code class=\"language-plaintext highlighter-rouge\">max_iou</code>より大きければ重なっていると判断する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"k\">if</span> <span class=\"n\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">max_iou</span><span class=\"p\">:</span>\n                <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span>\n</code></pre></div></div>\n<p>123行目<br />\n重なり判断済みフラグをbool型に変換したものを返す</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">filter_iou_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">box_mask</span> <span class=\"o\">></span> <span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">filter_iou_mask</span>\n</code></pre></div></div>\n\n<h1 id=\"2つのboxの重なり比率を計算get_intersection_over_union\">2つのBOXの重なり比率を計算(get_intersection_over_union)</h1>\n\n<p>163行目<br />\nパラメータで与えられる2つのBOXの重なり比率を計算する</p>\n\n<p>パラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_1</code> : ボックス1の座標/サイズ情報</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_2</code> : ボックス2の座標/サイズ情報</li>\n</ul>\n\n<p>各パラメータの配列構成は</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[0]</code> : ボックスのX座標(中心, pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[1]</code> : ボックスのY座標(中心, pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[2]</code> : ボックスの幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[3]</code> : ボックスの高さ(pixel単位)</li>\n</ul>\n\n<p>なお、座標系は  X座標は左端が原点、Y座標は上端が原点</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>166行目<br />\nbox_1 の右端座標 と box_2 の 右端座標 の小さい方 の座標 から<br />\nbox_1 の左端座標 と box_2 の 左端座標 の大きい方 の座標を引く<br />\n    ⇒ 重なっている部分の幅</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">intersection_dim_1</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n</code></pre></div></div>\n\n<p>170行目<br />\nbox_1 の下端座標 と box_2 の下端座標 の小さい方 の座標 から<br />\nbox_1 の上端座標 と box_2 の上端座標 の大きい方 の座標を引く<br />\n    ⇒ 重なっている部分の高さ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">intersection_dim_2</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>173行目<br />\n重なっている部分の幅と高さのどちらかが負数<br />\n    ⇒ 重なっている部分はないので、その面積は0</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">if</span> <span class=\"n\">intersection_dim_1</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">intersection_dim_2</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># no intersection area\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n</code></pre></div></div>\n\n<p>176行目<br />\n重なっている部分の幅と高さのどちらかが正数<br />\n    ⇒ 重なっている部分の面積を計算</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># intersection area is product of intersection dimensions\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span>  <span class=\"n\">intersection_dim_1</span><span class=\"o\">*</span><span class=\"n\">intersection_dim_2</span>\n</code></pre></div></div>\n\n<p>183行目<br />\nbox_1とbox_2の合計面積を計算(box_1の面積 + box_2の面積 - 重なっている部分の面積)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">union_area</span> <span class=\"o\">=</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">intersection_area</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<p>186行目<br />\nbox_1とbox_2の合計面積のうち、重なっている部分の比率を返す。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">iou</span> <span class=\"o\">=</span> <span class=\"n\">intersection_area</span> <span class=\"o\">/</span> <span class=\"n\">union_area</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">iou</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その2)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ncstickの出力を整理する処理ルーチンfilter_objects\">NCStickの出力を整理する処理ルーチン(filter_objects)</h1>\n\n<p>35行目<br />\nNCStickの生の出力を整理して、各Gridが何と認識したのか整理して出力する。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">inference_result  </code> : NCStickの出力をfloat32にキャストした配列(1次元×要素数1470)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image_width </code> : 画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image_height</code> : 画像高(448)</li>\n</ul>\n\n<p>出力は</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs</code> : 整理された認識結果</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<h2 id=\"各パラメータのサイズ\">各パラメータのサイズ</h2>\n\n<p>37行目<br />\nこのサイズはニューラルネット構築の際に決定された値。<br />\nGraphファイルに紐づいた値と考えられる。<br />\nなので、グローバル変数で定義しておいてパラメータで渡す方が良さそうだが。。。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">num_inference_results </code> :  NCStickの出力のサイズ(1470 : 未使用)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">network_classifications</code> : 各クラスのラベル(認識結果の名称)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">num_classifications  </code> :  その個数(20)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">grid_size             </code> :  画像のGrid分割数(7)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_per_grid_cell   </code> :  各グリッドに割り当てられたバウンティングボックス数(2)</li>\n</ul>\n\n<p>以下は認識結果を整理するためのパラメータ。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">probability_threshold </code> :  認識結果の確率の閾値。これ以下の確率は無視する。</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># the raw number of floats returned from the inference (GetResult())\n</span>    <span class=\"n\">num_inference_results</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># the 20 classes this network was trained on\n</span>    <span class=\"n\">network_classifications</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">\"aeroplane\"</span><span class=\"p\">,</span> <span class=\"s\">\"bicycle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bird\"</span><span class=\"p\">,</span> <span class=\"s\">\"boat\"</span><span class=\"p\">,</span> <span class=\"s\">\"bottle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bus\"</span><span class=\"p\">,</span> <span class=\"s\">\"car\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"cat\"</span><span class=\"p\">,</span> <span class=\"s\">\"chair\"</span><span class=\"p\">,</span> <span class=\"s\">\"cow\"</span><span class=\"p\">,</span> <span class=\"s\">\"diningtable\"</span><span class=\"p\">,</span> <span class=\"s\">\"dog\"</span><span class=\"p\">,</span> <span class=\"s\">\"horse\"</span><span class=\"p\">,</span> <span class=\"s\">\"motorbike\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"person\"</span><span class=\"p\">,</span> <span class=\"s\">\"pottedplant\"</span><span class=\"p\">,</span> <span class=\"s\">\"sheep\"</span><span class=\"p\">,</span> <span class=\"s\">\"sofa\"</span><span class=\"p\">,</span> <span class=\"s\">\"train\"</span><span class=\"p\">,</span><span class=\"s\">\"tvmonitor\"</span><span class=\"p\">]</span>\n\n    <span class=\"n\">probability_threshold</span> <span class=\"o\">=</span> <span class=\"mf\">0.07</span>\n\n    <span class=\"n\">num_classifications</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">network_classifications</span><span class=\"p\">)</span> <span class=\"c1\"># should be 20\n</span>\n    <span class=\"n\">grid_size</span> <span class=\"o\">=</span> <span class=\"mi\">7</span> <span class=\"c1\"># the image is a 7x7 grid.  Each box in the grid is 64x64 pixels\n</span>    <span class=\"n\">boxes_per_grid_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span> <span class=\"c1\"># the number of boxes returned for each grid cell\n</span></code></pre></div></div>\n\n<h2 id=\"すべての確率配列\">すべての確率配列</h2>\n\n<p>55行目<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)×クラス数(20) で、一旦0クリアしておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">all_probabilities</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<h2 id=\"各クラスの確率配列\">各クラスの確率配列</h2>\n\n<p>60行目<br />\n<code class=\"language-plaintext highlighter-rouge\">classification_probabilities</code> : NCStickの出力から各クラスの確率配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×クラス数(20)<br />\n入力側は1次元配列なので、要素 0 ~ 979 (980個 = 7×7×20)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classification_probabilities</span> <span class=\"o\">=</span> \\\n        <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">980</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n    <span class=\"n\">num_of_class_probs</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"各バウンティングボックスの確率配列\">各バウンティングボックスの確率配列</h2>\n\n<p>65行目<br />\n<code class=\"language-plaintext highlighter-rouge\">box_prob_scale_factor</code> : NCStickの出力から各バウンティングボックスの確率配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)<br />\n入力側は1次元配列なので、要素 980 ~ 1077 (98個 = 7×7×2)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_prob_scale_factor</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">980</span><span class=\"p\">:</span><span class=\"mi\">1078</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<h2 id=\"各バウンティングボックスの座標サイズ情報配列\">各バウンティングボックスの座標/サイズ情報配列</h2>\n\n<p>68行目<br />\nNCStickの出力から各バウンティングボックスの座標/サイズ情報配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)×XY幅高さ(4)<br />\n入力側は1次元配列なので、要素 1078 ~ 1469 (392個 = 7×7×2×4)<br />\n<code class=\"language-plaintext highlighter-rouge\">all_boxes</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n      [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n<p>幅と高さがイメージサイズに対する比率の平方根な理由は謎。。。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># get the boxes from the results and adjust to be pixel units\n</span>    <span class=\"n\">all_boxes</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">1078</span><span class=\"p\">:],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>69行目<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_to_pixel_units</code>(129行目)で<br />\n各バウンティングボックスの座標/サイズ情報配列を、入力画像幅(448)、入力画像高(448)、グリッドサイズ(7)からピクセル単位に変換</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">all_boxes</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">boxes_to_pixel_units</code> 実行後の <code class=\"language-plaintext highlighter-rouge\">all_boxes</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n\n<p>これらの配列の再配列のイメージはこんな感じ。<br />\n<img src=\"/memoBlog/misc/TinyYOLO_2_1.png\" alt=\"結果の再配列のイメージ\" /></p>\n\n<p>72行目<br />\n各グリッドに対する各クラスの確率と各バウンティングボックスの確率を乗じてすべての確率配列を生成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities</code> は Grid_Y × Grid_X × BBox × NumClass の4次元配列。<br />\nデータはバウンティングボックスごとの各クラスのスコアを示している。<br />\n(バウンティングボックスの確率 × クラスの確率)<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [     0.5488,     0.7152,     0.6028,     0.5449,     0.4237,     0.6459, ]\n      [     0.4376,     0.8918,     0.9637,     0.3834,     0.7917,     0.5289, ]\n    ]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">for</span> <span class=\"n\">box_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">):</span> <span class=\"c1\"># loop over boxes\n</span>        <span class=\"k\">for</span> <span class=\"n\">class_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">):</span> <span class=\"c1\"># loop over classifications\n</span>            <span class=\"n\">all_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">,</span><span class=\"n\">class_index</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">class_index</span><span class=\"p\">],</span><span class=\"n\">box_prob_scale_factor</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>77行目<br />\nすべての確率のマスク配列<code class=\"language-plaintext highlighter-rouge\">probability_threshold_mask</code>を生成する。<br />\nデータはall_probabilitiesの要素の値がprobability_threshold以上であればTrue、未満ならFalseが入っている。<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [ True, True, True, True, False, True, ]\n      [ False, True, True, False, True, True, ]\n    ]\n    ・・・・\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"o\">>=</span><span class=\"n\">probability_threshold</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">),</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">probability_threshold</span>\n</code></pre></div></div>\n\n<p>78行目<br />\n<code class=\"language-plaintext highlighter-rouge\">box_threshold_mask</code> は 4 × 閾値を超えたスコアの数 の 2次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_boxes</code>、<code class=\"language-plaintext highlighter-rouge\">all_probabilities</code>から有効なデータを取り出すためのマスクデータ。<br />\n<code class=\"language-plaintext highlighter-rouge\">probability_threshold_mask</code>で要素が<code class=\"language-plaintext highlighter-rouge\">true</code>のもの(=ゼロでないもの)のインデックス一覧をに格納する。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[0][n]</code> : n番目の閾値を超えたスコアを持つY方向のグリッド番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[1][n]</code> : n番目の閾値を超えたスコアを持つX方向のグリッド番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[2][n]</code> : n番目の閾値を超えたスコアを持つバウンティングボックス番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[3][n]</code> : n番目の閾値を超えたスコアを持つクラス番号</li>\n</ul>\n\n<p>つまり、<br />\n    <code class=\"language-plaintext highlighter-rouge\">all_boxes[box_threshold_mask[0][n]][box_threshold_mask[1][n]][box_threshold_mask[2][n]]</code><br />\n    <code class=\"language-plaintext highlighter-rouge\">all_probabilities[box_threshold_mask[0][n]][box_threshold_mask[1][n]][box_threshold_mask[2][n]][0または1]</code><br />\nがそれぞれn番目の閾値を超えたスコアを持つバウンティングボックスの座標/大きさ情報とスコア(バウンティングボックスごとのペア)を持つ</p>\n\n<p>データ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [ 0, 0, 0, 0, 0, 0, ・・・・\n  [ 0, 0, 0, 0, 0, 0, ・・・・]\n  [ 0, 0, 0, 0, 0, 1, ・・・・]\n  [ 0, 1, 2, 3, 5, 1, ・・・・]\n]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">nonzero</span><span class=\"p\">(</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">gx_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">gy_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">bb_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">cls_list</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n                        <span class=\"n\">gy_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">gy_list</span><span class=\"p\">,</span>  <span class=\"n\">gy</span><span class=\"p\">)</span>\n                        <span class=\"n\">gx_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">gx_list</span><span class=\"p\">,</span>  <span class=\"n\">gx</span><span class=\"p\">)</span>\n                        <span class=\"n\">bb_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">bb_list</span><span class=\"p\">,</span>  <span class=\"n\">bb</span><span class=\"p\">)</span>\n                        <span class=\"n\">cls_list</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">cls_list</span><span class=\"p\">,</span> <span class=\"n\">cls</span><span class=\"p\">)</span>\n    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">gy_list</span><span class=\"p\">,</span> <span class=\"n\">gx_list</span><span class=\"p\">,</span> <span class=\"n\">bb_list</span><span class=\"p\">,</span> <span class=\"n\">cls_list</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>79行目<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 閾値を超えたスコアの数 × 4 の 2次元配列</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n]</code>    : n番目の閾値を超えたスコアを持つバウンティングボックスの座標/サイズ情報のセット\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][0]</code> : X座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][1]</code> : Y座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][2]</code> : 幅(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][3]</code> : 高さ(pixel単位)</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">((</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">),</span> <span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i0</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span> <span class=\"p\">:</span>\n        <span class=\"n\">box_info</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]]</span>\n        <span class=\"n\">box_info</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">box_info</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n        <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">,</span> <span class=\"n\">box_info</span><span class=\"p\">,</span> <span class=\"n\">axis</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>80行目<br />\n・・・  う~ん ・・・</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p>なんか複雑な式なのでちょっと分割してみる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tmp_data</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">tmp_data</code> は Grid_Y × Grid_X × BBox の3次元配列<br />\nデータは各グリッドにBBoxずつ定義されたバウンティングボックスの各クラスに対するスコアの中から最大値を持つ要素のインデックス(=クラス番号)</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">np.argmax()</code>は配列要素の最大値を取るメソッド。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities[GY][GX][BB][CLS]</code>の4次元配列に対してaxis=3を指定して実行していて、<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities[gy][gx][bb][0~NumCls]</code>の最大値を持つ要素のインデックスを <code class=\"language-plaintext highlighter-rouge\">tmp_data[gy][gx][bb]</code>に格納する</p>\n\n<p>データ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [ 1, 2, ]\n    [ 1, 2, ]\n    [ 3, 1, ]\n    [ 2, 0, ]\n    [ 4, 2, ]\n    [ 2, 4, ]\n    [ 0, 5, ]\n  ]\n  ・・・\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code> は 閾値を超えたスコアの数 の 1次元配列<br />\nデータは各グリッドのスコアが最大のクラス番号を格納した1次元配列\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ 1, 1, 1, 1, ・・・\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tmp_data</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_cell</span><span class=\"p\">),</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">].</span><span class=\"n\">tolist</span><span class=\"p\">()</span>\n                <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">a</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">))</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span>  <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i0</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span> <span class=\"p\">:</span>\n        <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">,</span> <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]])</span>\n</code></pre></div></div>\n\n<p>81行目<br />\n<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code> は 閾値を超えたスコアの数 の 1次元配列。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold[n]</code>    : n番目の閾値を超えたスコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probabilities_above_threshold</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'float'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n                        <span class=\"n\">probabilities_above_threshold</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">,</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>この時点でスコアが閾値を超えたグリッドの情報が</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code></li>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code></li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code></li>\n</ul>\n\n<p>に格納される。これらは 一対一対一 の関係になっている。<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 2次元配列だが、X, Y, WIDTH, HEIGHT のペアの配列と考えればわかりやすい。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above[n]</code>  : n番目の閾値を超えたスコアを持つクラス番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold[n]</code>    : n番目の閾値を超えたスコア</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n]</code>            : n番目の閾値を超えたスコアを持つバウンティングボックスの座標/サイズ情報のセット\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][0]</code>       : X座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][1]</code>       : Y座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][2]</code>       : 幅(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][3]</code>       : 高さ(pixel単位)</li>\n    </ul>\n  </li>\n</ul>\n\n<p>85行目<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort</code> は <code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code> の各要素を降順に並べた際のインデックス番号を取り出した1次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort(~)</code> は 指定された配列 の各要素を昇順に並べた際のインデックス番号を取り出した配列を得るメソッド。<br />\n<code class=\"language-plaintext highlighter-rouge\">[::-1]</code>を付けてあるので降順になる。<br />\nそのままだと<code class=\"language-plaintext highlighter-rouge\">list</code>型になってしまうので、<code class=\"language-plaintext highlighter-rouge\">np.array()</code>で<code class=\"language-plaintext highlighter-rouge\">np.ndarray</code>型に変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">argsort</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argsort</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">))[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>86行目<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort</code>  を使って\n<code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code>、<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code>、<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> から <code class=\"language-plaintext highlighter-rouge\">argsort</code>で示されたインデックスで示された順に取り出す。<br />\n⇒ スコアの降順にそれぞれを並べ変える。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>書き換えるほどでもないので、ま、いっか。</p>\n\n<p>92行目<br />\n<code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code> は <code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> を検索して重なったボックス情報を削除するためのマスク情報配列。<br />\n閾値を超えたスコアの数 の dtype.bool型の1次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">get_duplicate_box_mask()</code> は <a href=\"TinyYOLO_3\">別ページ</a>参照。<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ True, True, False, False, True, ・・・]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 既にスコアの高い順に並べ替えられているので、先頭から検索していって最初の出てきたボックスを優先すれば良い。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">duplicate_box_mask</span> <span class=\"o\">=</span> <span class=\"n\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>95行目<br />\n<code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code>  を使ってそれぞれの配列からダブったデータを削除する。<br />\n<code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code>、<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code>、<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> から <code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code>でTrueの要素だけ取り出す。<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code>は ダブっていない結果の数(最終認識結果の数) × 4 の 2次元配列<br />\nそれ以外は ダブっていない結果の数(最終認識結果の数)の 1次元配列</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>99行目<br />\n最終認識結果をlistにまとめなおしてリターンする。<br />\n<code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classes_boxes_and_probs</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)):</span>\n        <span class=\"n\">classes_boxes_and_probs</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">([</span><span class=\"n\">network_classifications</span><span class=\"p\">[</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]])</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">classes_boxes_and_probs</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その1)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その1)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Intel NCStick用TinyYOLOの<a href=\"http://jellyware.jp/kurage/movidius/c13_tinyyolo_run.html\">解説記事</a>を見かけた。<br />\n<a href=\"https://github.com/movidius/ncappzoo/blob/ncsdk2/caffe/TinyYolo/run.py\">ソース</a>を読んでみたが、\n結構難解で(特にnumpy回り)、自分の鶏頭でも思い出せるように調べた結果をメモしてみた。<br />\nNCStick持ってないから実際に動かしてないけど。。。</p>\n\n<p>リポジトリは <a href=\"https://github.com/movidius/ncappzoo\">https://github.com/movidius/ncappzoo</a> だが、このソースはmasterブランチには存在しない。必ずncsdk2ブランチを選択すること。<br />\n<code class=\"language-plaintext highlighter-rouge\">git clone</code> する場合は要注意。</p>\n\n<p>どっか行っちゃうといけないので、ソースのコピーを<a href=\"TinyYOLO_src\">ここ</a>にも置いておく。</p>\n\n<h1 id=\"モジュールのインポート\">モジュールのインポート</h1>\n\n<p>特に難しいことはしてない。mvncがNCStickのドライバ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">mvnc</span> <span class=\"kn\">import</span> <span class=\"n\">mvncapi</span> <span class=\"k\">as</span> <span class=\"n\">mvnc</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n</code></pre></div></div>\n\n<h1 id=\"ファイル名定義\">ファイル名定義</h1>\n\n<p>13行目<br />\n<code class=\"language-plaintext highlighter-rouge\">input_image_file</code> : ここに書かれたファイルを読み込んで認識する。<br />\n<code class=\"language-plaintext highlighter-rouge\">tiny_yolo_graph_file</code> : ニューラルネットのネットリスト(?)  ニューロンの接続情報と重みが入っていると思われる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">input_image_file</span><span class=\"o\">=</span> <span class=\"s\">'../../data/images/nps_chair.png'</span>\n<span class=\"n\">tiny_yolo_graph_file</span><span class=\"o\">=</span> <span class=\"s\">'./graph'</span>\n</code></pre></div></div>\n\n<h1 id=\"認識用の画像サイズ定義\">認識用の画像サイズ定義</h1>\n\n<p>17行目<br />\nニューラルネットに入力する画像サイズ。任意のサイズの画像をこのサイズにリサイズしてから入力する。<br />\nこのサイズはニューラルネット構築の際に決定された値。Graphファイルに紐づいた値と考えられる。</p>\n\n<p>Grid分割数が7×7で、1Grid当たりの画像サイズが64pixelなので、7×64 = 448 でおのずと決まる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">NETWORK_IMAGE_WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n<span class=\"n\">NETWORK_IMAGE_HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n</code></pre></div></div>\n\n<h1 id=\"ncstickの出力を整理する処理ルーチンfilter_objects\">NCStickの出力を整理する処理ルーチン(filter_objects)</h1>\n\n<p>35行目<br />\n<a href=\"TinyYOLO_2\">別ページ</a></p>\n\n<h1 id=\"重なったボックス情報を削除するためのマスク情報配列を取得get_duplicate_box_mask\">重なったボックス情報を削除するためのマスク情報配列を取得(get_duplicate_box_mask)</h1>\n\n<p>109行目<br />\n<a href=\"TinyYOLO_3\">別ページ</a></p>\n\n<h1 id=\"バウンティングボックス情報の単位変換boxes_to_pixel_units\">バウンティングボックス情報の単位変換(boxes_to_pixel_units)</h1>\n\n<p>129行目<br />\n<a href=\"TinyYOLO_4\">別ページ</a></p>\n\n<h1 id=\"2つのboxの重なり比率を計算get_intersection_over_union\">2つのBOXの重なり比率を計算(get_intersection_over_union)</h1>\n\n<p>163行目<br />\n<a href=\"TinyYOLO_3\">別ページ</a></p>\n\n<h1 id=\"認識結果の表示ルーチンdisplay_objects_in_gui\">認識結果の表示ルーチン(display_objects_in_gui)</h1>\n\n<p>203行目<br />\n<a href=\"TinyYOLO_5\">別ページ</a></p>\n\n<h1 id=\"mainルーチン\">mainルーチン</h1>\n\n<h3 id=\"関数の先頭とオープニングメッセージ\">関数の先頭とオープニングメッセージ</h3>\n\n<p>255行目</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Running NCS Caffe TinyYolo example'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickドライバのオプション設定\">NCStickドライバのオプション設定</h3>\n<p>258行目</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Set logging level to only log errors\n</span>    <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">global_set_option</span><span class=\"p\">(</span><span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">GlobalOption</span><span class=\"p\">.</span><span class=\"n\">RW_LOG_LEVEL</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickの検出とオープン\">NCStickの検出とオープン</h3>\n\n<p>260行目<br />\nなかったらエラー終了。<br />\n複数見つかった場合は最初のものをオープンする。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">devices</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">enumerate_devices</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'No devices found'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"mi\">1</span>\n    <span class=\"n\">device</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Device</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"nb\">open</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h3 id=\"graphファイルの読み込み\">Graphファイルの読み込み</h3>\n\n<p>267行目<br />\n14行目で設定したGraphファイルを読み込んで、NCStickドライバに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\">#Load graph from disk and allocate graph via API\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tiny_yolo_graph_file</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'rb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">graph_from_disk</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Graph</span><span class=\"p\">(</span><span class=\"s\">\"Tiny Yolo Graph\"</span><span class=\"p\">)</span>\n    <span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span> <span class=\"o\">=</span> <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">allocate_with_fifos</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"n\">graph_from_disk</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"入力画像の読み込みと前処理\">入力画像の読み込みと前処理</h3>\n\n<p>276行目</p>\n<ul>\n  <li>13行目で設定した画像ファイルを読み込んむ(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>結果表示用にオリジナルサイズのままコピーを取っておく(<code class=\"language-plaintext highlighter-rouge\">display_image</code>)</li>\n  <li>NCStickに入力する画像サイズにリサイズ(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>各画素の値をfloat32型に変換(<code class=\"language-plaintext highlighter-rouge\">input_image</code>  元データは<code class=\"language-plaintext highlighter-rouge\">int</code>)</li>\n  <li>さらに各画素の値を0.0~1.0に正規化(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>色並びをBGRからRGBに再配列(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">input_image_file</span><span class=\"p\">)</span>\n    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span><span class=\"p\">,</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">INTER_LINEAR</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">divide</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"mf\">255.0</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>  <span class=\"c1\"># convert to RGB\n</span></code></pre></div></div>\n\n<h3 id=\"ncstick-による処理\">NCStick による処理</h3>\n\n<p>284行目<br />\nNCStickに前処理した画像を入力し、計算結果を得る。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">input_image</code>の各要素はfloat32型に変換して入力する。(既に変換済みな気もするが…)<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">input_image</code>そのものの型は <code class=\"language-plaintext highlighter-rouge\">numpy.ndarray</code>。<br />\nニューラルネットの処理本体の処理は実質この2行だけ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Load tensor and get result.  This executes the inference on the NCS\n</span>    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">queue_inference_with_fifo_elem</span><span class=\"p\">(</span><span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span><span class=\"p\">,</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">output</span><span class=\"p\">,</span> <span class=\"n\">userobj</span> <span class=\"o\">=</span> <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">read_elem</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickの出力を整理する\">NCStickの出力を整理する</h3>\n\n<p>288行目<br />\n<code class=\"language-plaintext highlighter-rouge\">filter_objects</code>(35行目)で  NCStickの出力を整理する。<br />\n<a href=\"TinyYOLO_2\">別ページ</a>を参照。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">output.astype(np.float32)</code> : NCStickの出力をfloat32にキャストした配列(1次元)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image.shape[1]     </code> : 画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image.shape[0]     </code> : 画像高(448)</li>\n</ul>\n\n<p>得られるデータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> : 整理された認識結果</li>\n</ul>\n\n<p><code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">filtered_objs</span> <span class=\"o\">=</span> <span class=\"n\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">output</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<h3 id=\"認識結果の表示\">認識結果の表示</h3>\n\n<p>290行目<br />\n<code class=\"language-plaintext highlighter-rouge\">display_objects_in_gui</code> (203行目)で 表示用イメージと整理された認識結果を表示。<br />\n<a href=\"TinyYOLO_5\">別ページ</a>を参照。<br />\nパラメータは<br />\n<code class=\"language-plaintext highlighter-rouge\">display_image</code> : 表示用画像\n<code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> : 整理された認識結果</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Displaying image with objects detected in GUI'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Click in the GUI window and hit any key to exit'</span><span class=\"p\">)</span>\n    <span class=\"c1\">#display the filtered objects/boxes in a GUI window\n</span>    <span class=\"n\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"後片付け\">後片付け</h3>\n\n<p>295行目<br />\n各クローズ処理。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">fifo_in</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Finished'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"mainルーチン呼び出し\">mainルーチン呼び出し</h1>\n\n<p>お約束の処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "TinyYOLO": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(プログラムソース)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Intel NCStick用TinyYOLOの<a href=\"https://github.com/movidius/ncappzoo/blob/ncsdk2/caffe/TinyYolo/run.py\">ソース</a>のコピー</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#! /usr/bin/env python3\n</span>\n<span class=\"c1\"># Copyright(c) 2017 Intel Corporation. \n# License: MIT See LICENSE file in root directory.\n</span>\n<span class=\"kn\">from</span> <span class=\"nn\">mvnc</span> <span class=\"kn\">import</span> <span class=\"n\">mvncapi</span> <span class=\"k\">as</span> <span class=\"n\">mvnc</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n\n\n<span class=\"c1\"># Assume running in examples/caffe/TinyYolo and graph file is in current directory.\n</span><span class=\"n\">input_image_file</span><span class=\"o\">=</span> <span class=\"s\">'../../data/images/nps_chair.png'</span>\n<span class=\"n\">tiny_yolo_graph_file</span><span class=\"o\">=</span> <span class=\"s\">'./graph'</span>\n\n<span class=\"c1\"># Tiny Yolo assumes input images are these dimensions.\n</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n<span class=\"n\">NETWORK_IMAGE_HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n\n\n<span class=\"c1\"># Interpret the output from a single inference of TinyYolo (GetResult)\n# and filter out objects/boxes with low probabilities.\n# output is the array of floats returned from the API GetResult but converted\n# to float32 format.\n# input_image_width is the width of the input image\n# input_image_height is the height of the input image\n# Returns a list of lists. each of the inner lists represent one found object and contain\n# the following 6 values:\n#    string that is network classification ie 'cat', or 'chair' etc\n#    float value for box center X pixel location within source image\n#    float value for box center Y pixel location within source image\n#    float value for box width in pixels within source image\n#    float value for box height in pixels within source image\n#    float value that is the probability for the network classification.\n</span><span class=\"k\">def</span> <span class=\"nf\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># the raw number of floats returned from the inference (GetResult())\n</span>    <span class=\"n\">num_inference_results</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># the 20 classes this network was trained on\n</span>    <span class=\"n\">network_classifications</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">\"aeroplane\"</span><span class=\"p\">,</span> <span class=\"s\">\"bicycle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bird\"</span><span class=\"p\">,</span> <span class=\"s\">\"boat\"</span><span class=\"p\">,</span> <span class=\"s\">\"bottle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bus\"</span><span class=\"p\">,</span> <span class=\"s\">\"car\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"cat\"</span><span class=\"p\">,</span> <span class=\"s\">\"chair\"</span><span class=\"p\">,</span> <span class=\"s\">\"cow\"</span><span class=\"p\">,</span> <span class=\"s\">\"diningtable\"</span><span class=\"p\">,</span> <span class=\"s\">\"dog\"</span><span class=\"p\">,</span> <span class=\"s\">\"horse\"</span><span class=\"p\">,</span> <span class=\"s\">\"motorbike\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"person\"</span><span class=\"p\">,</span> <span class=\"s\">\"pottedplant\"</span><span class=\"p\">,</span> <span class=\"s\">\"sheep\"</span><span class=\"p\">,</span> <span class=\"s\">\"sofa\"</span><span class=\"p\">,</span> <span class=\"s\">\"train\"</span><span class=\"p\">,</span><span class=\"s\">\"tvmonitor\"</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># only keep boxes with probabilities greater than this\n</span>    <span class=\"n\">probability_threshold</span> <span class=\"o\">=</span> <span class=\"mf\">0.07</span>\n\n    <span class=\"n\">num_classifications</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">network_classifications</span><span class=\"p\">)</span> <span class=\"c1\"># should be 20\n</span>    <span class=\"n\">grid_size</span> <span class=\"o\">=</span> <span class=\"mi\">7</span> <span class=\"c1\"># the image is a 7x7 grid.  Each box in the grid is 64x64 pixels\n</span>    <span class=\"n\">boxes_per_grid_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span> <span class=\"c1\"># the number of boxes returned for each grid cell\n</span>\n    <span class=\"c1\"># grid_size is 7 (grid is 7x7)\n</span>    <span class=\"c1\"># num classifications is 20\n</span>    <span class=\"c1\"># boxes per grid cell is 2\n</span>    <span class=\"n\">all_probabilities</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># classification_probabilities  contains a probability for each classification for\n</span>    <span class=\"c1\"># each 64x64 pixel square of the grid.  The source image contains\n</span>    <span class=\"c1\"># 7x7 of these 64x64 pixel squares and there are 20 possible classifications\n</span>    <span class=\"n\">classification_probabilities</span> <span class=\"o\">=</span> \\\n        <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">980</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n    <span class=\"n\">num_of_class_probs</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># The probability scale factor for each box\n</span>    <span class=\"n\">box_prob_scale_factor</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">980</span><span class=\"p\">:</span><span class=\"mi\">1078</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># get the boxes from the results and adjust to be pixel units\n</span>    <span class=\"n\">all_boxes</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">1078</span><span class=\"p\">:],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n    <span class=\"n\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">all_boxes</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># adjust the probabilities with the scaling factor\n</span>    <span class=\"k\">for</span> <span class=\"n\">box_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">):</span> <span class=\"c1\"># loop over boxes\n</span>        <span class=\"k\">for</span> <span class=\"n\">class_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">):</span> <span class=\"c1\"># loop over classifications\n</span>            <span class=\"n\">all_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">,</span><span class=\"n\">class_index</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">class_index</span><span class=\"p\">],</span><span class=\"n\">box_prob_scale_factor</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">])</span>\n\n\n    <span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"o\">>=</span><span class=\"n\">probability_threshold</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">nonzero</span><span class=\"p\">(</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">)</span>\n    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># sort the boxes from highest probability to lowest and then\n</span>    <span class=\"c1\"># sort the probabilities and classifications to match\n</span>    <span class=\"n\">argsort</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argsort</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">))[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n\n\n    <span class=\"c1\"># get mask for boxes that seem to be the same object\n</span>    <span class=\"n\">duplicate_box_mask</span> <span class=\"o\">=</span> <span class=\"n\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># update the boxes, probabilities and classifications removing duplicates.\n</span>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n\n    <span class=\"n\">classes_boxes_and_probs</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)):</span>\n        <span class=\"n\">classes_boxes_and_probs</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">([</span><span class=\"n\">network_classifications</span><span class=\"p\">[</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]])</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">classes_boxes_and_probs</span>\n\n<span class=\"c1\"># creates a mask to remove duplicate objects (boxes) and their related probabilities and classifications\n# that should be considered the same object.  This is determined by how similar the boxes are\n# based on the intersection-over-union metric.\n# box_list is as list of boxes (4 floats for centerX, centerY and Length and Width)\n</span><span class=\"k\">def</span> <span class=\"nf\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">):</span>\n    <span class=\"c1\"># The intersection-over-union threshold to use when determining duplicates.\n</span>    <span class=\"c1\"># objects/boxes found that are over this threshold will be\n</span>    <span class=\"c1\"># considered the same object\n</span>    <span class=\"n\">max_iou</span> <span class=\"o\">=</span> <span class=\"mf\">0.35</span>\n\n    <span class=\"n\">box_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">ones</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">))</span>\n\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">max_iou</span><span class=\"p\">:</span>\n                <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span>\n\n    <span class=\"n\">filter_iou_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">box_mask</span> <span class=\"o\">></span> <span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">filter_iou_mask</span>\n\n<span class=\"c1\"># Converts the boxes in box list to pixel units\n# assumes box_list is the output from the box output from\n# the tiny yolo network and is [grid_size x grid_size x 2 x 4].\n</span><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># number of boxes per grid cell\n</span>    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n\n    <span class=\"c1\"># setup some offset values to map boxes to pixels\n</span>    <span class=\"c1\"># box_offset will be [[ [0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6]] ...repeated for 7 ]\n</span>    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">)),(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)),(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n\n    <span class=\"c1\"># adjust the box center\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">box_offset</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">box_offset</span><span class=\"p\">,(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># adjust the lengths and widths\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n\n    <span class=\"c1\">#scale the boxes to the image size in pixels\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n\n\n<span class=\"c1\"># Evaluate the intersection-over-union for two boxes\n# The intersection-over-union metric determines how close\n# two boxes are to being the same box.  The closer the boxes\n# are to being the same, the closer the metric will be to 1.0\n# box_1 and box_2 are arrays of 4 numbers which are the (x, y)\n# points that define the center of the box and the length and width of\n# the box.\n# Returns the intersection-over-union (between 0.0 and 1.0)\n# for the two boxes specified.\n</span><span class=\"k\">def</span> <span class=\"nf\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># one diminsion of the intersecting box\n</span>    <span class=\"n\">intersection_dim_1</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># the other dimension of the intersecting box\n</span>    <span class=\"n\">intersection_dim_2</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">intersection_dim_1</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">intersection_dim_2</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># no intersection area\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># intersection area is product of intersection dimensions\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span>  <span class=\"n\">intersection_dim_1</span><span class=\"o\">*</span><span class=\"n\">intersection_dim_2</span>\n\n    <span class=\"c1\"># calculate the union area which is the area of each box added\n</span>    <span class=\"c1\"># and then we need to subtract out the intersection area since\n</span>    <span class=\"c1\"># it is counted twice (by definition it is in each box)\n</span>    <span class=\"n\">union_area</span> <span class=\"o\">=</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">intersection_area</span><span class=\"p\">;</span>\n\n    <span class=\"c1\"># now we can return the intersection over union\n</span>    <span class=\"n\">iou</span> <span class=\"o\">=</span> <span class=\"n\">intersection_area</span> <span class=\"o\">/</span> <span class=\"n\">union_area</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">iou</span>\n\n<span class=\"c1\"># Displays a gui window with an image that contains\n# boxes and lables for found objects.  will not return until\n# user presses a key.\n# source_image is the original image for the inference before it was resized or otherwise changed.\n# filtered_objects is a list of lists (as returned from filter_objects()\n# each of the inner lists represent one found object and contain\n# the following 6 values:\n#    string that is network classification ie 'cat', or 'chair' etc\n#    float value for box center X pixel location within source image\n#    float value for box center Y pixel location within source image\n#    float value for box width in pixels within source image\n#    float value for box height in pixels within source image\n#    float value that is the probability for the network classification.\n</span><span class=\"k\">def</span> <span class=\"nf\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">source_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objects</span><span class=\"p\">):</span>\n    <span class=\"c1\"># copy image so we can draw on it. Could just draw directly on source image if not concerned about that.\n</span>    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n    <span class=\"n\">source_image_width</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">source_image_height</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"n\">x_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_width</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_WIDTH</span>\n    <span class=\"n\">y_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_height</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span>\n\n    <span class=\"c1\"># loop through each box and draw it on the image along with a classification label\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Found this many objects in the image: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)))</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)):</span>\n        <span class=\"n\">center_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span> \n        <span class=\"n\">center_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span>\n        <span class=\"n\">half_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n        <span class=\"n\">half_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n\n        <span class=\"c1\"># calculate box (left, top) and (right, bottom) coordinates\n</span>        <span class=\"n\">box_left</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">-</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_top</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">-</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_right</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">+</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"n\">source_image_width</span><span class=\"p\">)</span>\n        <span class=\"n\">box_bottom</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">+</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"n\">source_image_height</span><span class=\"p\">)</span>\n\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'box at index '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj_index</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">' is... left: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', top: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_top</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', right: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_right</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', bottom: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_bottom</span><span class=\"p\">))</span>  \n\n        <span class=\"c1\">#draw the rectangle on the image.  This is hopefully around the object\n</span>        <span class=\"n\">box_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>  <span class=\"c1\"># green box\n</span>        <span class=\"n\">box_thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span> <span class=\"n\">box_bottom</span><span class=\"p\">),</span> <span class=\"n\">box_color</span><span class=\"p\">,</span> <span class=\"n\">box_thickness</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># draw the classification label string just above and to the left of the rectangle\n</span>        <span class=\"n\">label_background_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">70</span><span class=\"p\">,</span> <span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">70</span><span class=\"p\">)</span> <span class=\"c1\"># greyish green background for text\n</span>        <span class=\"n\">label_text_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>   <span class=\"c1\"># white text\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">20</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"p\">),</span> <span class=\"n\">label_background_color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">' : %.2f'</span> <span class=\"o\">%</span> <span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">5</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"o\">+</span><span class=\"mi\">5</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"n\">label_text_color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n    <span class=\"n\">window_name</span> <span class=\"o\">=</span> <span class=\"s\">'TinyYolo (hit key to exit)'</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">display_image</span><span class=\"p\">)</span>\n\n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"n\">raw_key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># check if the window is visible, this means the user hasn't closed\n</span>        <span class=\"c1\"># the window via the X button (may only work with opencv 3.x\n</span>        <span class=\"n\">prop_val</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">getWindowProperty</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">WND_PROP_ASPECT_RATIO</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">raw_key</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"n\">prop_val</span> <span class=\"o\"><</span> <span class=\"mf\">0.0</span><span class=\"p\">)):</span>\n            <span class=\"c1\"># the user hit a key or closed the window (in that order)\n</span>            <span class=\"k\">break</span>\n\n\n<span class=\"c1\"># This function is called from the entry point to do\n# all the work.\n</span><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Running NCS Caffe TinyYolo example'</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Set logging level to only log errors\n</span>    <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">global_set_option</span><span class=\"p\">(</span><span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">GlobalOption</span><span class=\"p\">.</span><span class=\"n\">RW_LOG_LEVEL</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"n\">devices</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">enumerate_devices</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'No devices found'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"mi\">1</span>\n    <span class=\"n\">device</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Device</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"nb\">open</span><span class=\"p\">()</span>\n\n    <span class=\"c1\">#Load graph from disk and allocate graph via API\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tiny_yolo_graph_file</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'rb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">graph_from_disk</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Graph</span><span class=\"p\">(</span><span class=\"s\">\"Tiny Yolo Graph\"</span><span class=\"p\">)</span>\n    <span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span> <span class=\"o\">=</span> <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">allocate_with_fifos</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"n\">graph_from_disk</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Read image from file, resize it to network width and height\n</span>    <span class=\"c1\"># save a copy in display_image for display, then convert to float32, normalize (divide by 255),\n</span>    <span class=\"c1\"># and finally convert to convert to float16 to pass to LoadTensor as input for an inference\n</span>    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">input_image_file</span><span class=\"p\">)</span>\n    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span><span class=\"p\">,</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">INTER_LINEAR</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">divide</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"mf\">255.0</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>  <span class=\"c1\"># convert to RGB\n</span>\n    <span class=\"c1\"># Load tensor and get result.  This executes the inference on the NCS\n</span>    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">queue_inference_with_fifo_elem</span><span class=\"p\">(</span><span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span><span class=\"p\">,</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">output</span><span class=\"p\">,</span> <span class=\"n\">userobj</span> <span class=\"o\">=</span> <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">read_elem</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># filter out all the objects/boxes that don't meet thresholds\n</span>    <span class=\"n\">filtered_objs</span> <span class=\"o\">=</span> <span class=\"n\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">output</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Displaying image with objects detected in GUI'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Click in the GUI window and hit any key to exit'</span><span class=\"p\">)</span>\n    <span class=\"c1\">#display the filtered objects/boxes in a GUI window\n</span>    <span class=\"n\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objs</span><span class=\"p\">)</span>\n\n    <span class=\"n\">fifo_in</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Finished'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># main entry point for program. we'll call main() to do what needs to be done.\n</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その5)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その5)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"認識結果の表示ルーチンdisplay_objects_in_gui\">認識結果の表示ルーチン(display_objects_in_gui)</h1>\n\n<p>203行目<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">source_image</code>:入力画像(表示画像)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects</code>:整理された認識結果</li>\n</ul>\n\n<p><code class=\"language-plaintext highlighter-rouge\">filtered_objects</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objects[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">source_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objects</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>205行目<br />\n入力画像を表示用に<code class=\"language-plaintext highlighter-rouge\">display_image</code>にコピーする。(もともと入力された<code class=\"language-plaintext highlighter-rouge\">source_image</code>は汚さない。)<br />\n<code class=\"language-plaintext highlighter-rouge\">source_image_width</code>、<code class=\"language-plaintext highlighter-rouge\">source_image_height</code>は入力画像の幅と高さ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n    <span class=\"n\">source_image_width</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">source_image_height</span> <span class=\"o\">=</span> <span class=\"n\">source_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>209行目<br />\n<code class=\"language-plaintext highlighter-rouge\">NETWORK_IMAGE_WIDTH</code>と<code class=\"language-plaintext highlighter-rouge\">NETWORK_IMAGE_HEIGHT</code> は ニューラルネットに入力した画像サイズ(グローバル変数)。<br />\nどうせなら関数パラメータで渡した方がスマートだと思うが…<br />\n<code class=\"language-plaintext highlighter-rouge\">filtered_objects</code>の各データはこのサイズで定義されているので、表示用に変換するための比率を<code class=\"language-plaintext highlighter-rouge\">x_ratio</code>、<code class=\"language-plaintext highlighter-rouge\">y_ratio</code>として得る。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">x_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_width</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_WIDTH</span>\n    <span class=\"n\">y_ratio</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">source_image_height</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span>\n</code></pre></div></div>\n\n<p>213行目<br />\nそれぞれのバウンティングボックスに対してのループ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Found this many objects in the image: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)))</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">)):</span>\n</code></pre></div></div>\n\n<p>215行目<br />\n認識結果のX座標(中心)、Y座標(中心)、幅、高さを表示用画像のサイズに変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">center_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span> \n        <span class=\"n\">center_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span>\n        <span class=\"n\">half_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">x_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n        <span class=\"n\">half_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">y_ratio</span><span class=\"p\">)</span><span class=\"o\">//</span><span class=\"mi\">2</span>\n</code></pre></div></div>\n\n<p>221行目<br />\nX座標(中心)、Y座標(中心)、幅、高さからX座標(左端)、Y座標(上端)、X座標(右端)、Y座標(右端)に変換。<br />\n表示画像の範囲からはみ出ないように制限処理を付けてある。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">box_left</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">-</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_top</span> <span class=\"o\">=</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">-</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"n\">box_right</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_x</span> <span class=\"o\">+</span> <span class=\"n\">half_width</span><span class=\"p\">,</span> <span class=\"n\">source_image_width</span><span class=\"p\">)</span>\n        <span class=\"n\">box_bottom</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">center_y</span> <span class=\"o\">+</span> <span class=\"n\">half_height</span><span class=\"p\">,</span> <span class=\"n\">source_image_height</span><span class=\"p\">)</span>\n\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'box at index '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj_index</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">' is... left: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', top: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_top</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', right: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_right</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s\">', bottom: '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">box_bottom</span><span class=\"p\">))</span>  \n</code></pre></div></div>\n\n<p>229行目<br />\n表示画像にバウンティングボックスの四角を描く。<br />\n色は緑、線幅は2。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">box_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>  <span class=\"c1\"># green box\n</span>        <span class=\"n\">box_thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span> <span class=\"n\">box_bottom</span><span class=\"p\">),</span> <span class=\"n\">box_color</span><span class=\"p\">,</span> <span class=\"n\">box_thickness</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>234行目<br />\n表示画像に認識結果の名称とスコアを書く。<br />\n背景は暗い緑。文字色は白。<br />\n表示位置はバウンティングボックスの上20ピクセルの場所。<br />\nサイズは縦20ピクセル、横バウンティングボックスと同サイズ。<br />\n(バウンティングボックスの上端が20未満の時大丈夫なんだろか?表示が切れるだけ?)<br />\n(バウンティングボックスの右端より認識結果文字列が長いときも?)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">label_background_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">70</span><span class=\"p\">,</span> <span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">70</span><span class=\"p\">)</span> <span class=\"c1\"># greyish green background for text\n</span>        <span class=\"n\">label_text_color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>   <span class=\"c1\"># white text\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,(</span><span class=\"n\">box_left</span><span class=\"p\">,</span> <span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">20</span><span class=\"p\">),(</span><span class=\"n\">box_right</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"p\">),</span> <span class=\"n\">label_background_color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span><span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">' : %.2f'</span> <span class=\"o\">%</span> <span class=\"n\">filtered_objects</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">][</span><span class=\"mi\">5</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">box_left</span><span class=\"o\">+</span><span class=\"mi\">5</span><span class=\"p\">,</span><span class=\"n\">box_top</span><span class=\"o\">-</span><span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"n\">label_text_color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>ループはここまで。</p>\n\n<p>239行目<br />\n画像の表示</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">window_name</span> <span class=\"o\">=</span> <span class=\"s\">'TinyYolo (hit key to exit)'</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">display_image</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>242行目<br />\nキー入力待ち。待ち時間は1msec。<br />\n待ち時間内にキーが押されなければ-1が返ってくる。<br />\nキー入力はGUIで表示されたウィンドウにフォーカスが当たっているときのみ有効で、コンソール(ターミナルなど)で入力してもダメ。<br />\n64bitマシンでは、キーコードを使用する場合は値を<code class=\"language-plaintext highlighter-rouge\">& 0xff</code>する必要があるが、入力なしを検出するだけなのでそのままでOK。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"n\">raw_key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>247行目<br />\nウィンドウパラメータの取得。<br />\nウィンドウが閉じられていれば-1.0が返る。表示状態ならウィンドウのアクセプト比が返る。<br />\n×ボタンでウィンドウを閉じたときの対策。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">prop_val</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">getWindowProperty</span><span class=\"p\">(</span><span class=\"n\">window_name</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">WND_PROP_ASPECT_RATIO</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>247行目<br />\nキー入力があった、または、×ボタンでウィンドウが閉じられたら終了。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">raw_key</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"n\">prop_val</span> <span class=\"o\"><</span> <span class=\"mf\">0.0</span><span class=\"p\">)):</span>\n            <span class=\"c1\"># the user hit a key or closed the window (in that order)\n</span>            <span class=\"k\">break</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その4)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その4)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"バウンティングボックス情報の単位変換boxes_to_pixel_units\">バウンティングボックス情報の単位変換(boxes_to_pixel_units)</h1>\n\n<p>129行目<br />\n各バウンティングボックスの座標/サイズ情報配列内のデータは各グリッド内の相対位置/相対サイズなので、画像内の座標に変換する。</p>\n\n<p>パラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_list   </code> : 各バウンティングボックスの座標/サイズ情報配列、</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">image_width</code> : 入力画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">image_height</code> : 入力画像高(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">grid_size  </code> : グリッドサイズ(7)<br />\n<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n [\n   [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n   [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n ]\n ・・・\n 同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>変換後の<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>132行目<br />\n定義されたバウンティングボックスの数。<br />\nGraphファイルに紐づいた値と考えられるので、トップレベルで定義しておいた方が分かりやすいと思うのだが。。。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n</code></pre></div></div>\n\n<p>136行目<br />\nグリッド内オフセットから画像内オフセットに変換するための作業用配列を作成。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">)),(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)),(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>う~ん、まとめて書いてあって分かり難いので、分解してみる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">aa</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)]</span>\n    <span class=\"n\">bb</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">aa</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"o\">*</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n    <span class=\"n\">cc</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">bb</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">,</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">))</span>\n    <span class=\"n\">box_offset</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">cc</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>としたとき、</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>aa = [\n       [0, 1, 2, 3, 4, 5, 6]\n     ]\nbb = [\n       [0, 1, 2, 3, 4, 5, 6],\n       ・・・\n       同じものがあと13組(合計14組)\n     ]\ncc = [\n       [\n         [0, 1, 2, 3, 4, 5, 6],\n         ・・・\n         同じものがあと6組(合計7組)\n       ],\n       ・・・\n       同じものがあと1組(合計2組)\n     ]\nbox_offset = [\n               [\n                 [0, 0],\n                 [1, 1],\n                 [2, 2],\n                 [3, 3],\n                 [4, 4],\n                 [5, 5],\n                 [6, 6]\n               ],\n               ・・・\n               同じものがあと6組(合計7組)\n             ]\n</code></pre></div></div>\n<p>となる。</p>\n\n<p>139行目<br />\n各グリッドのX座標データにグリッド番号を加算する(画像内絶対位置になる。単位:グリッド)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">box_offset</span>\n</code></pre></div></div>\n\n<p>140行目<br />\n各グリッドのY座標データにグリッド番号を加算する(画像内絶対位置になる。単位:グリッド)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">(</span><span class=\"n\">box_offset</span><span class=\"p\">,(</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>141行目<br />\n各グリッドのX座標とY座標データをグリッド数で割る(画像内相対位置になる)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># adjust the lengths and widths\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n</code></pre></div></div>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\">#scale the boxes to the image size in pixels\n</span>    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_width</span>\n    <span class=\"n\">box_list</span><span class=\"p\">[:,:,:,</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*=</span> <span class=\"n\">image_height</span>\n</code></pre></div></div>\n\n<h2 id=\"処理を書き換えてみる\">処理を書き換えてみる</h2>\n<p>なにやら小難しいことをやっているので、実行速度を考えずに分かりやすく書き換えると以下のようになる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">boxes_to_pixel_units_alt</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">):</span>\n    <span class=\"n\">boxes_per_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>                               <span class=\"c1\"># 定義されたバウンティングボックス数  \n</span>    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>                     <span class=\"c1\"># グリッド縦方向ループ\n</span>        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>                 <span class=\"c1\"># グリッド横方向ループ\n</span>            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>        <span class=\"c1\"># バウンティングボックスループ\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">gx</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span>        <span class=\"c1\"># box_x\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">gy</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span> <span class=\"o\">*</span> <span class=\"mf\">1.0</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span>       <span class=\"c1\"># box_y\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">**</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span>                             <span class=\"c1\"># box_widtn\n</span>                <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">**</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span>                            <span class=\"c1\"># box_height\n</span></code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その3)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その3)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"重なったボックス情報を削除するためのマスク情報配列を取得get_duplicate_box_mask\">重なったボックス情報を削除するためのマスク情報配列を取得(get_duplicate_box_mask)</h1>\n\n<p>109行目<br />\n重なったボックス情報を削除するためのマスク情報配列を取得する。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_list</code> : バウンティングボックスの座標/サイズ情報のセットの配列<br />\n<code class=\"language-plaintext highlighter-rouge\">box_list</code>の配列構成はこんな感じ。\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [X座標, Y座標, 幅, 高さ],\n  [X座標, Y座標, 幅, 高さ],\n  ・・・\n]\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>出力は<br />\n重なったボックス情報を削除するためのマスク情報配列。<br />\n閾値を超えたスコアの数 の dtype.bool型の1次元配列。<br />\n出力の配列の構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ True, True, False, False, True, ・・・]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>113行目<br />\n重なっていると判断する重なり比率の閾値</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">max_iou</span> <span class=\"o\">=</span> <span class=\"mf\">0.35</span>\n</code></pre></div></div>\n\n<p>115行目<br />\n重なり判断済みフラグを1で初期化<br />\ndtype=’bool’ で良い気がするが…そうすれば最後のboolへの変換処理が不要になるのに…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">ones</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>117行目<br />\n総当たりチェックを行うためのループ処理<br />\n重なり判断済みフラグが0なら既に重なりBOXとして削除済みなのでスキップ</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">)):</span>\n</code></pre></div></div>\n\n<p>120行目<br />\n2つのBOXの重なり比率を計算し、<code class=\"language-plaintext highlighter-rouge\">max_iou</code>より大きければ重なっていると判断する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"k\">if</span> <span class=\"n\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">box_list</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">max_iou</span><span class=\"p\">:</span>\n                <span class=\"n\">box_mask</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span>\n</code></pre></div></div>\n<p>123行目<br />\n重なり判断済みフラグをbool型に変換したものを返す</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">filter_iou_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">box_mask</span> <span class=\"o\">></span> <span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">filter_iou_mask</span>\n</code></pre></div></div>\n\n<h1 id=\"2つのboxの重なり比率を計算get_intersection_over_union\">2つのBOXの重なり比率を計算(get_intersection_over_union)</h1>\n\n<p>163行目<br />\nパラメータで与えられる2つのBOXの重なり比率を計算する</p>\n\n<p>パラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_1</code> : ボックス1の座標/サイズ情報</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_2</code> : ボックス2の座標/サイズ情報</li>\n</ul>\n\n<p>各パラメータの配列構成は</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[0]</code> : ボックスのX座標(中心, pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[1]</code> : ボックスのY座標(中心, pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[2]</code> : ボックスの幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box[3]</code> : ボックスの高さ(pixel単位)</li>\n</ul>\n\n<p>なお、座標系は  X座標は左端が原点、Y座標は上端が原点</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">get_intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>166行目<br />\nbox_1 の右端座標 と box_2 の 右端座標 の小さい方 の座標 から<br />\nbox_1 の左端座標 と box_2 の 左端座標 の大きい方 の座標を引く<br />\n    ⇒ 重なっている部分の幅</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">intersection_dim_1</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n</code></pre></div></div>\n\n<p>170行目<br />\nbox_1 の下端座標 と box_2 の下端座標 の小さい方 の座標 から<br />\nbox_1 の上端座標 と box_2 の上端座標 の大きい方 の座標を引く<br />\n    ⇒ 重なっている部分の高さ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">intersection_dim_2</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span><span class=\"o\">-</span>\\\n                         <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">-</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>173行目<br />\n重なっている部分の幅と高さのどちらかが負数<br />\n    ⇒ 重なっている部分はないので、その面積は0</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">if</span> <span class=\"n\">intersection_dim_1</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">intersection_dim_2</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># no intersection area\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n</code></pre></div></div>\n\n<p>176行目<br />\n重なっている部分の幅と高さのどちらかが正数<br />\n    ⇒ 重なっている部分の面積を計算</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># intersection area is product of intersection dimensions\n</span>        <span class=\"n\">intersection_area</span> <span class=\"o\">=</span>  <span class=\"n\">intersection_dim_1</span><span class=\"o\">*</span><span class=\"n\">intersection_dim_2</span>\n</code></pre></div></div>\n\n<p>183行目<br />\nbox_1とbox_2の合計面積を計算(box_1の面積 + box_2の面積 - 重なっている部分の面積)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">union_area</span> <span class=\"o\">=</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">*</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">intersection_area</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<p>186行目<br />\nbox_1とbox_2の合計面積のうち、重なっている部分の比率を返す。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">iou</span> <span class=\"o\">=</span> <span class=\"n\">intersection_area</span> <span class=\"o\">/</span> <span class=\"n\">union_area</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">iou</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その2)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ncstickの出力を整理する処理ルーチンfilter_objects\">NCStickの出力を整理する処理ルーチン(filter_objects)</h1>\n\n<p>35行目<br />\nNCStickの生の出力を整理して、各Gridが何と認識したのか整理して出力する。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">inference_result  </code> : NCStickの出力をfloat32にキャストした配列(1次元×要素数1470)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image_width </code> : 画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image_height</code> : 画像高(448)</li>\n</ul>\n\n<p>出力は</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs</code> : 整理された認識結果</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<h2 id=\"各パラメータのサイズ\">各パラメータのサイズ</h2>\n\n<p>37行目<br />\nこのサイズはニューラルネット構築の際に決定された値。<br />\nGraphファイルに紐づいた値と考えられる。<br />\nなので、グローバル変数で定義しておいてパラメータで渡す方が良さそうだが。。。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">num_inference_results </code> :  NCStickの出力のサイズ(1470 : 未使用)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">network_classifications</code> : 各クラスのラベル(認識結果の名称)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">num_classifications  </code> :  その個数(20)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">grid_size             </code> :  画像のGrid分割数(7)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_per_grid_cell   </code> :  各グリッドに割り当てられたバウンティングボックス数(2)</li>\n</ul>\n\n<p>以下は認識結果を整理するためのパラメータ。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">probability_threshold </code> :  認識結果の確率の閾値。これ以下の確率は無視する。</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># the raw number of floats returned from the inference (GetResult())\n</span>    <span class=\"n\">num_inference_results</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># the 20 classes this network was trained on\n</span>    <span class=\"n\">network_classifications</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">\"aeroplane\"</span><span class=\"p\">,</span> <span class=\"s\">\"bicycle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bird\"</span><span class=\"p\">,</span> <span class=\"s\">\"boat\"</span><span class=\"p\">,</span> <span class=\"s\">\"bottle\"</span><span class=\"p\">,</span> <span class=\"s\">\"bus\"</span><span class=\"p\">,</span> <span class=\"s\">\"car\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"cat\"</span><span class=\"p\">,</span> <span class=\"s\">\"chair\"</span><span class=\"p\">,</span> <span class=\"s\">\"cow\"</span><span class=\"p\">,</span> <span class=\"s\">\"diningtable\"</span><span class=\"p\">,</span> <span class=\"s\">\"dog\"</span><span class=\"p\">,</span> <span class=\"s\">\"horse\"</span><span class=\"p\">,</span> <span class=\"s\">\"motorbike\"</span><span class=\"p\">,</span>\n                               <span class=\"s\">\"person\"</span><span class=\"p\">,</span> <span class=\"s\">\"pottedplant\"</span><span class=\"p\">,</span> <span class=\"s\">\"sheep\"</span><span class=\"p\">,</span> <span class=\"s\">\"sofa\"</span><span class=\"p\">,</span> <span class=\"s\">\"train\"</span><span class=\"p\">,</span><span class=\"s\">\"tvmonitor\"</span><span class=\"p\">]</span>\n\n    <span class=\"n\">probability_threshold</span> <span class=\"o\">=</span> <span class=\"mf\">0.07</span>\n\n    <span class=\"n\">num_classifications</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">network_classifications</span><span class=\"p\">)</span> <span class=\"c1\"># should be 20\n</span>\n    <span class=\"n\">grid_size</span> <span class=\"o\">=</span> <span class=\"mi\">7</span> <span class=\"c1\"># the image is a 7x7 grid.  Each box in the grid is 64x64 pixels\n</span>    <span class=\"n\">boxes_per_grid_cell</span> <span class=\"o\">=</span> <span class=\"mi\">2</span> <span class=\"c1\"># the number of boxes returned for each grid cell\n</span></code></pre></div></div>\n\n<h2 id=\"すべての確率配列\">すべての確率配列</h2>\n\n<p>55行目<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)×クラス数(20) で、一旦0クリアしておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">all_probabilities</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<h2 id=\"各クラスの確率配列\">各クラスの確率配列</h2>\n\n<p>60行目<br />\n<code class=\"language-plaintext highlighter-rouge\">classification_probabilities</code> : NCStickの出力から各クラスの確率配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×クラス数(20)<br />\n入力側は1次元配列なので、要素 0 ~ 979 (980個 = 7×7×20)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classification_probabilities</span> <span class=\"o\">=</span> \\\n        <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">980</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">num_classifications</span><span class=\"p\">))</span>\n    <span class=\"n\">num_of_class_probs</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"各バウンティングボックスの確率配列\">各バウンティングボックスの確率配列</h2>\n\n<p>65行目<br />\n<code class=\"language-plaintext highlighter-rouge\">box_prob_scale_factor</code> : NCStickの出力から各バウンティングボックスの確率配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)<br />\n入力側は1次元配列なので、要素 980 ~ 1077 (98個 = 7×7×2)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_prob_scale_factor</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">980</span><span class=\"p\">:</span><span class=\"mi\">1078</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<h2 id=\"各バウンティングボックスの座標サイズ情報配列\">各バウンティングボックスの座標/サイズ情報配列</h2>\n\n<p>68行目<br />\nNCStickの出力から各バウンティングボックスの座標/サイズ情報配列を取り出す。<br />\nサイズはグリッド分割数(7)×グリッド分割数(7)×バウンティングボックス数(2)×XY幅高さ(4)<br />\n入力側は1次元配列なので、要素 1078 ~ 1469 (392個 = 7×7×2×4)<br />\n<code class=\"language-plaintext highlighter-rouge\">all_boxes</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n      [X座標(グリッド内相対位置), Y座標(グリッド内相対位置), 幅(イメージサイズ比の平方根), 高さ(イメージサイズ比の平方根)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n<p>幅と高さがイメージサイズに対する比率の平方根な理由は謎。。。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># get the boxes from the results and adjust to be pixel units\n</span>    <span class=\"n\">all_boxes</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">inference_result</span><span class=\"p\">[</span><span class=\"mi\">1078</span><span class=\"p\">:],</span> <span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n</code></pre></div></div>\n\n<p>69行目<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_to_pixel_units</code>(129行目)で<br />\n各バウンティングボックスの座標/サイズ情報配列を、入力画像幅(448)、入力画像高(448)、グリッドサイズ(7)からピクセル単位に変換</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_to_pixel_units</span><span class=\"p\">(</span><span class=\"n\">all_boxes</span><span class=\"p\">,</span> <span class=\"n\">input_image_width</span><span class=\"p\">,</span> <span class=\"n\">input_image_height</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">boxes_to_pixel_units</code> 実行後の <code class=\"language-plaintext highlighter-rouge\">all_boxes</code>の配列構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n      [X座標(pixel単位), Y座標(pixel単位), 幅(pixel単位), 高さ(pixel単位)],\n    ]\n    ・・・\n    同じものがあと6組(合計7組)\n  ]\n  ・・・\n  同じものがあと6組(合計7組)\n]\n</code></pre></div></div>\n\n<p>これらの配列の再配列のイメージはこんな感じ。<br />\n<img src=\"/memoBlog/misc/TinyYOLO_2_1.png\" alt=\"結果の再配列のイメージ\" /></p>\n\n<p>72行目<br />\n各グリッドに対する各クラスの確率と各バウンティングボックスの確率を乗じてすべての確率配列を生成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities</code> は Grid_Y × Grid_X × BBox × NumClass の4次元配列。<br />\nデータはバウンティングボックスごとの各クラスのスコアを示している。<br />\n(バウンティングボックスの確率 × クラスの確率)<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [     0.5488,     0.7152,     0.6028,     0.5449,     0.4237,     0.6459, ]\n      [     0.4376,     0.8918,     0.9637,     0.3834,     0.7917,     0.5289, ]\n    ]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">for</span> <span class=\"n\">box_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_grid_cell</span><span class=\"p\">):</span> <span class=\"c1\"># loop over boxes\n</span>        <span class=\"k\">for</span> <span class=\"n\">class_index</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">):</span> <span class=\"c1\"># loop over classifications\n</span>            <span class=\"n\">all_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">,</span><span class=\"n\">class_index</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">multiply</span><span class=\"p\">(</span><span class=\"n\">classification_probabilities</span><span class=\"p\">[:,:,</span><span class=\"n\">class_index</span><span class=\"p\">],</span><span class=\"n\">box_prob_scale_factor</span><span class=\"p\">[:,:,</span><span class=\"n\">box_index</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>77行目<br />\nすべての確率のマスク配列<code class=\"language-plaintext highlighter-rouge\">probability_threshold_mask</code>を生成する。<br />\nデータはall_probabilitiesの要素の値がprobability_threshold以上であればTrue、未満ならFalseが入っている。<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [\n      [ True, True, True, True, False, True, ]\n      [ False, True, True, False, True, True, ]\n    ]\n    ・・・・\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"o\">>=</span><span class=\"n\">probability_threshold</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">probability_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">),</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'bool'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">probability_threshold</span>\n</code></pre></div></div>\n\n<p>78行目<br />\n<code class=\"language-plaintext highlighter-rouge\">box_threshold_mask</code> は 4 × 閾値を超えたスコアの数 の 2次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_boxes</code>、<code class=\"language-plaintext highlighter-rouge\">all_probabilities</code>から有効なデータを取り出すためのマスクデータ。<br />\n<code class=\"language-plaintext highlighter-rouge\">probability_threshold_mask</code>で要素が<code class=\"language-plaintext highlighter-rouge\">true</code>のもの(=ゼロでないもの)のインデックス一覧をに格納する。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[0][n]</code> : n番目の閾値を超えたスコアを持つY方向のグリッド番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[1][n]</code> : n番目の閾値を超えたスコアを持つX方向のグリッド番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[2][n]</code> : n番目の閾値を超えたスコアを持つバウンティングボックス番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">box_threshold_mask[3][n]</code> : n番目の閾値を超えたスコアを持つクラス番号</li>\n</ul>\n\n<p>つまり、<br />\n    <code class=\"language-plaintext highlighter-rouge\">all_boxes[box_threshold_mask[0][n]][box_threshold_mask[1][n]][box_threshold_mask[2][n]]</code><br />\n    <code class=\"language-plaintext highlighter-rouge\">all_probabilities[box_threshold_mask[0][n]][box_threshold_mask[1][n]][box_threshold_mask[2][n]][0または1]</code><br />\nがそれぞれn番目の閾値を超えたスコアを持つバウンティングボックスの座標/大きさ情報とスコア(バウンティングボックスごとのペア)を持つ</p>\n\n<p>データ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [ 0, 0, 0, 0, 0, 0, ・・・・\n  [ 0, 0, 0, 0, 0, 0, ・・・・]\n  [ 0, 0, 0, 0, 0, 1, ・・・・]\n  [ 0, 1, 2, 3, 5, 1, ・・・・]\n]\n</code></pre></div></div>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">nonzero</span><span class=\"p\">(</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">gx_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">gy_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">bb_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"n\">cls_list</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n                        <span class=\"n\">gy_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">gy_list</span><span class=\"p\">,</span>  <span class=\"n\">gy</span><span class=\"p\">)</span>\n                        <span class=\"n\">gx_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">gx_list</span><span class=\"p\">,</span>  <span class=\"n\">gx</span><span class=\"p\">)</span>\n                        <span class=\"n\">bb_list</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">bb_list</span><span class=\"p\">,</span>  <span class=\"n\">bb</span><span class=\"p\">)</span>\n                        <span class=\"n\">cls_list</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">cls_list</span><span class=\"p\">,</span> <span class=\"n\">cls</span><span class=\"p\">)</span>\n    <span class=\"n\">box_threshold_mask</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">gy_list</span><span class=\"p\">,</span> <span class=\"n\">gx_list</span><span class=\"p\">,</span> <span class=\"n\">bb_list</span><span class=\"p\">,</span> <span class=\"n\">cls_list</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>79行目<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 閾値を超えたスコアの数 × 4 の 2次元配列</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n]</code>    : n番目の閾値を超えたスコアを持つバウンティングボックスの座標/サイズ情報のセット\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][0]</code> : X座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][1]</code> : Y座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][2]</code> : 幅(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][3]</code> : 高さ(pixel単位)</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">((</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">),</span> <span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i0</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span> <span class=\"p\">:</span>\n        <span class=\"n\">box_info</span> <span class=\"o\">=</span> <span class=\"n\">all_boxes</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]]</span>\n        <span class=\"n\">box_info</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">box_info</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">))</span>\n        <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">,</span> <span class=\"n\">box_info</span><span class=\"p\">,</span> <span class=\"n\">axis</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>80行目<br />\n・・・  う~ん ・・・</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p>なんか複雑な式なのでちょっと分割してみる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tmp_data</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">all_probabilities</span><span class=\"p\">,</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">tmp_data</code> は Grid_Y × Grid_X × BBox の3次元配列<br />\nデータは各グリッドにBBoxずつ定義されたバウンティングボックスの各クラスに対するスコアの中から最大値を持つ要素のインデックス(=クラス番号)</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">np.argmax()</code>は配列要素の最大値を取るメソッド。<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities[GY][GX][BB][CLS]</code>の4次元配列に対してaxis=3を指定して実行していて、<br />\n<code class=\"language-plaintext highlighter-rouge\">all_probabilities[gy][gx][bb][0~NumCls]</code>の最大値を持つ要素のインデックスを <code class=\"language-plaintext highlighter-rouge\">tmp_data[gy][gx][bb]</code>に格納する</p>\n\n<p>データ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n  [\n    [ 1, 2, ]\n    [ 1, 2, ]\n    [ 3, 1, ]\n    [ 2, 0, ]\n    [ 4, 2, ]\n    [ 2, 4, ]\n    [ 0, 5, ]\n  ]\n  ・・・\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code> は 閾値を超えたスコアの数 の 1次元配列<br />\nデータは各グリッドのスコアが最大のクラス番号を格納した1次元配列\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ 1, 1, 1, 1, ・・・\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tmp_data</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">empty</span><span class=\"p\">((</span><span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">grid_size</span><span class=\"p\">,</span> <span class=\"n\">boxes_per_cell</span><span class=\"p\">),</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">].</span><span class=\"n\">tolist</span><span class=\"p\">()</span>\n                <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">a</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">))</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span>  <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'int'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i0</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span> <span class=\"p\">:</span>\n        <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">,</span> <span class=\"n\">tmp_data</span><span class=\"p\">[</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]][</span><span class=\"n\">box_threshold_mask</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"n\">i0</span><span class=\"p\">]])</span>\n</code></pre></div></div>\n\n<p>81行目<br />\n<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code> は 閾値を超えたスコアの数 の 1次元配列。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold[n]</code>    : n番目の閾値を超えたスコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">probability_threshold_mask</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>上の処理を書き換えるとこんな感じ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">probabilities_above_threshold</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([],</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s\">'float'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">gy</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">gx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">grid_size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">bb</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">boxes_per_cell</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">cls</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">num_classifications</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">probability_threshold_mask</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n                        <span class=\"n\">probabilities_above_threshold</span>  <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">,</span> <span class=\"n\">all_probabilities</span><span class=\"p\">[</span><span class=\"n\">gy</span><span class=\"p\">][</span><span class=\"n\">gx</span><span class=\"p\">][</span><span class=\"n\">bb</span><span class=\"p\">][</span><span class=\"n\">cls</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<p>この時点でスコアが閾値を超えたグリッドの情報が</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code></li>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code></li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code></li>\n</ul>\n\n<p>に格納される。これらは 一対一対一 の関係になっている。<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 2次元配列だが、X, Y, WIDTH, HEIGHT のペアの配列と考えればわかりやすい。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above[n]</code>  : n番目の閾値を超えたスコアを持つクラス番号</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold[n]</code>    : n番目の閾値を超えたスコア</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n]</code>            : n番目の閾値を超えたスコアを持つバウンティングボックスの座標/サイズ情報のセット\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][0]</code>       : X座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][1]</code>       : Y座標(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][2]</code>       : 幅(pixel単位)</li>\n      <li><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold[n][3]</code>       : 高さ(pixel単位)</li>\n    </ul>\n  </li>\n</ul>\n\n<p>85行目<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort</code> は <code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code> の各要素を降順に並べた際のインデックス番号を取り出した1次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort(~)</code> は 指定された配列 の各要素を昇順に並べた際のインデックス番号を取り出した配列を得るメソッド。<br />\n<code class=\"language-plaintext highlighter-rouge\">[::-1]</code>を付けてあるので降順になる。<br />\nそのままだと<code class=\"language-plaintext highlighter-rouge\">list</code>型になってしまうので、<code class=\"language-plaintext highlighter-rouge\">np.array()</code>で<code class=\"language-plaintext highlighter-rouge\">np.ndarray</code>型に変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">argsort</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argsort</span><span class=\"p\">(</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">))[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>86行目<br />\n<code class=\"language-plaintext highlighter-rouge\">argsort</code>  を使って\n<code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code>、<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code>、<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> から <code class=\"language-plaintext highlighter-rouge\">argsort</code>で示されたインデックスで示された順に取り出す。<br />\n⇒ スコアの降順にそれぞれを並べ変える。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">argsort</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>書き換えるほどでもないので、ま、いっか。</p>\n\n<p>92行目<br />\n<code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code> は <code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> を検索して重なったボックス情報を削除するためのマスク情報配列。<br />\n閾値を超えたスコアの数 の dtype.bool型の1次元配列。<br />\n<code class=\"language-plaintext highlighter-rouge\">get_duplicate_box_mask()</code> は <a href=\"TinyYOLO_3\">別ページ</a>参照。<br />\nデータ構成はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[ True, True, False, False, True, ・・・]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> は 既にスコアの高い順に並べ替えられているので、先頭から検索していって最初の出てきたボックスを優先すれば良い。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">duplicate_box_mask</span> <span class=\"o\">=</span> <span class=\"n\">get_duplicate_box_mask</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>95行目<br />\n<code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code>  を使ってそれぞれの配列からダブったデータを削除する。<br />\n<code class=\"language-plaintext highlighter-rouge\">classifications_for_boxes_above</code>、<code class=\"language-plaintext highlighter-rouge\">probabilities_above_threshold</code>、<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code> から <code class=\"language-plaintext highlighter-rouge\">duplicate_box_mask</code>でTrueの要素だけ取り出す。<br />\n<code class=\"language-plaintext highlighter-rouge\">boxes_above_threshold</code>は ダブっていない結果の数(最終認識結果の数) × 4 の 2次元配列<br />\nそれ以外は ダブっていない結果の数(最終認識結果の数)の 1次元配列</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">boxes_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">classifications_for_boxes_above</span> <span class=\"o\">=</span> <span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n    <span class=\"n\">probabilities_above_threshold</span> <span class=\"o\">=</span> <span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">duplicate_box_mask</span><span class=\"p\">]</span>\n</code></pre></div></div>\n\n<p>99行目<br />\n最終認識結果をlistにまとめなおしてリターンする。<br />\n<code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">classes_boxes_and_probs[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">classes_boxes_and_probs</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">)):</span>\n        <span class=\"n\">classes_boxes_and_probs</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">([</span><span class=\"n\">network_classifications</span><span class=\"p\">[</span><span class=\"n\">classifications_for_boxes_above</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">],</span><span class=\"n\">boxes_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">],</span><span class=\"n\">probabilities_above_threshold</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]])</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">classes_boxes_and_probs</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick用TinyYOLOのソース読んでみた(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick用TinyYOLOのソース読んでみた(その1)</h1>\n      <p>Intel NCStick用TinyYOLOのソース読んでみた(その1)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Intel NCStick用TinyYOLOの<a href=\"http://jellyware.jp/kurage/movidius/c13_tinyyolo_run.html\">解説記事</a>を見かけた。<br />\n<a href=\"https://github.com/movidius/ncappzoo/blob/ncsdk2/caffe/TinyYolo/run.py\">ソース</a>を読んでみたが、\n結構難解で(特にnumpy回り)、自分の鶏頭でも思い出せるように調べた結果をメモしてみた。<br />\nNCStick持ってないから実際に動かしてないけど。。。</p>\n\n<p>リポジトリは <a href=\"https://github.com/movidius/ncappzoo\">https://github.com/movidius/ncappzoo</a> だが、このソースはmasterブランチには存在しない。必ずncsdk2ブランチを選択すること。<br />\n<code class=\"language-plaintext highlighter-rouge\">git clone</code> する場合は要注意。</p>\n\n<p>どっか行っちゃうといけないので、ソースのコピーを<a href=\"TinyYOLO_src\">ここ</a>にも置いておく。</p>\n\n<h1 id=\"モジュールのインポート\">モジュールのインポート</h1>\n\n<p>特に難しいことはしてない。mvncがNCStickのドライバ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">mvnc</span> <span class=\"kn\">import</span> <span class=\"n\">mvncapi</span> <span class=\"k\">as</span> <span class=\"n\">mvnc</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n</code></pre></div></div>\n\n<h1 id=\"ファイル名定義\">ファイル名定義</h1>\n\n<p>13行目<br />\n<code class=\"language-plaintext highlighter-rouge\">input_image_file</code> : ここに書かれたファイルを読み込んで認識する。<br />\n<code class=\"language-plaintext highlighter-rouge\">tiny_yolo_graph_file</code> : ニューラルネットのネットリスト(?)  ニューロンの接続情報と重みが入っていると思われる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">input_image_file</span><span class=\"o\">=</span> <span class=\"s\">'../../data/images/nps_chair.png'</span>\n<span class=\"n\">tiny_yolo_graph_file</span><span class=\"o\">=</span> <span class=\"s\">'./graph'</span>\n</code></pre></div></div>\n\n<h1 id=\"認識用の画像サイズ定義\">認識用の画像サイズ定義</h1>\n\n<p>17行目<br />\nニューラルネットに入力する画像サイズ。任意のサイズの画像をこのサイズにリサイズしてから入力する。<br />\nこのサイズはニューラルネット構築の際に決定された値。Graphファイルに紐づいた値と考えられる。</p>\n\n<p>Grid分割数が7×7で、1Grid当たりの画像サイズが64pixelなので、7×64 = 448 でおのずと決まる。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">NETWORK_IMAGE_WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n<span class=\"n\">NETWORK_IMAGE_HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">448</span>\n</code></pre></div></div>\n\n<h1 id=\"ncstickの出力を整理する処理ルーチンfilter_objects\">NCStickの出力を整理する処理ルーチン(filter_objects)</h1>\n\n<p>35行目<br />\n<a href=\"TinyYOLO_2\">別ページ</a></p>\n\n<h1 id=\"重なったボックス情報を削除するためのマスク情報配列を取得get_duplicate_box_mask\">重なったボックス情報を削除するためのマスク情報配列を取得(get_duplicate_box_mask)</h1>\n\n<p>109行目<br />\n<a href=\"TinyYOLO_3\">別ページ</a></p>\n\n<h1 id=\"バウンティングボックス情報の単位変換boxes_to_pixel_units\">バウンティングボックス情報の単位変換(boxes_to_pixel_units)</h1>\n\n<p>129行目<br />\n<a href=\"TinyYOLO_4\">別ページ</a></p>\n\n<h1 id=\"2つのboxの重なり比率を計算get_intersection_over_union\">2つのBOXの重なり比率を計算(get_intersection_over_union)</h1>\n\n<p>163行目<br />\n<a href=\"TinyYOLO_3\">別ページ</a></p>\n\n<h1 id=\"認識結果の表示ルーチンdisplay_objects_in_gui\">認識結果の表示ルーチン(display_objects_in_gui)</h1>\n\n<p>203行目<br />\n<a href=\"TinyYOLO_5\">別ページ</a></p>\n\n<h1 id=\"mainルーチン\">mainルーチン</h1>\n\n<h3 id=\"関数の先頭とオープニングメッセージ\">関数の先頭とオープニングメッセージ</h3>\n\n<p>255行目</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Running NCS Caffe TinyYolo example'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickドライバのオプション設定\">NCStickドライバのオプション設定</h3>\n<p>258行目</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Set logging level to only log errors\n</span>    <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">global_set_option</span><span class=\"p\">(</span><span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">GlobalOption</span><span class=\"p\">.</span><span class=\"n\">RW_LOG_LEVEL</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickの検出とオープン\">NCStickの検出とオープン</h3>\n\n<p>260行目<br />\nなかったらエラー終了。<br />\n複数見つかった場合は最初のものをオープンする。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">devices</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">enumerate_devices</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'No devices found'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"mi\">1</span>\n    <span class=\"n\">device</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Device</span><span class=\"p\">(</span><span class=\"n\">devices</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"nb\">open</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h3 id=\"graphファイルの読み込み\">Graphファイルの読み込み</h3>\n\n<p>267行目<br />\n14行目で設定したGraphファイルを読み込んで、NCStickドライバに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\">#Load graph from disk and allocate graph via API\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tiny_yolo_graph_file</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'rb'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">graph_from_disk</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span> <span class=\"o\">=</span> <span class=\"n\">mvnc</span><span class=\"p\">.</span><span class=\"n\">Graph</span><span class=\"p\">(</span><span class=\"s\">\"Tiny Yolo Graph\"</span><span class=\"p\">)</span>\n    <span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span> <span class=\"o\">=</span> <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">allocate_with_fifos</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"n\">graph_from_disk</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"入力画像の読み込みと前処理\">入力画像の読み込みと前処理</h3>\n\n<p>276行目</p>\n<ul>\n  <li>13行目で設定した画像ファイルを読み込んむ(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>結果表示用にオリジナルサイズのままコピーを取っておく(<code class=\"language-plaintext highlighter-rouge\">display_image</code>)</li>\n  <li>NCStickに入力する画像サイズにリサイズ(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>各画素の値をfloat32型に変換(<code class=\"language-plaintext highlighter-rouge\">input_image</code>  元データは<code class=\"language-plaintext highlighter-rouge\">int</code>)</li>\n  <li>さらに各画素の値を0.0~1.0に正規化(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n  <li>色並びをBGRからRGBに再配列(<code class=\"language-plaintext highlighter-rouge\">input_image</code>)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">input_image_file</span><span class=\"p\">)</span>\n    <span class=\"n\">display_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">NETWORK_IMAGE_WIDTH</span><span class=\"p\">,</span> <span class=\"n\">NETWORK_IMAGE_HEIGHT</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">INTER_LINEAR</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">divide</span><span class=\"p\">(</span><span class=\"n\">input_image</span><span class=\"p\">,</span> <span class=\"mf\">255.0</span><span class=\"p\">)</span>\n    <span class=\"n\">input_image</span> <span class=\"o\">=</span> <span class=\"n\">input_image</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>  <span class=\"c1\"># convert to RGB\n</span></code></pre></div></div>\n\n<h3 id=\"ncstick-による処理\">NCStick による処理</h3>\n\n<p>284行目<br />\nNCStickに前処理した画像を入力し、計算結果を得る。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">input_image</code>の各要素はfloat32型に変換して入力する。(既に変換済みな気もするが…)<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">input_image</code>そのものの型は <code class=\"language-plaintext highlighter-rouge\">numpy.ndarray</code>。<br />\nニューラルネットの処理本体の処理は実質この2行だけ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Load tensor and get result.  This executes the inference on the NCS\n</span>    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">queue_inference_with_fifo_elem</span><span class=\"p\">(</span><span class=\"n\">fifo_in</span><span class=\"p\">,</span> <span class=\"n\">fifo_out</span><span class=\"p\">,</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">output</span><span class=\"p\">,</span> <span class=\"n\">userobj</span> <span class=\"o\">=</span> <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">read_elem</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h3 id=\"ncstickの出力を整理する\">NCStickの出力を整理する</h3>\n\n<p>288行目<br />\n<code class=\"language-plaintext highlighter-rouge\">filter_objects</code>(35行目)で  NCStickの出力を整理する。<br />\n<a href=\"TinyYOLO_2\">別ページ</a>を参照。<br />\nパラメータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">output.astype(np.float32)</code> : NCStickの出力をfloat32にキャストした配列(1次元)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image.shape[1]     </code> : 画像幅(448)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">input_image.shape[0]     </code> : 画像高(448)</li>\n</ul>\n\n<p>得られるデータは</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> : 整理された認識結果</li>\n</ul>\n\n<p><code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> は 最終認識結果数 × 6 の 2次元配列(list)<br />\nデータ構成はこんな感じ。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][0]</code> : クラスのラベル(認識結果の名称; 文字列)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][1]</code> : X座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][2]</code> : Y座標(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][3]</code> : 幅(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][4]</code> : 高さ(pixel単位)</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">filtered_objs[n][5]</code> : スコア</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">filtered_objs</span> <span class=\"o\">=</span> <span class=\"n\">filter_objects</span><span class=\"p\">(</span><span class=\"n\">output</span><span class=\"p\">.</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">float32</span><span class=\"p\">),</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">input_image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<h3 id=\"認識結果の表示\">認識結果の表示</h3>\n\n<p>290行目<br />\n<code class=\"language-plaintext highlighter-rouge\">display_objects_in_gui</code> (203行目)で 表示用イメージと整理された認識結果を表示。<br />\n<a href=\"TinyYOLO_5\">別ページ</a>を参照。<br />\nパラメータは<br />\n<code class=\"language-plaintext highlighter-rouge\">display_image</code> : 表示用画像\n<code class=\"language-plaintext highlighter-rouge\">filtered_objs</code> : 整理された認識結果</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Displaying image with objects detected in GUI'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Click in the GUI window and hit any key to exit'</span><span class=\"p\">)</span>\n    <span class=\"c1\">#display the filtered objects/boxes in a GUI window\n</span>    <span class=\"n\">display_objects_in_gui</span><span class=\"p\">(</span><span class=\"n\">display_image</span><span class=\"p\">,</span> <span class=\"n\">filtered_objs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"後片付け\">後片付け</h3>\n\n<p>295行目<br />\n各クローズ処理。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">fifo_in</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">fifo_out</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">graph</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">device</span><span class=\"p\">.</span><span class=\"n\">destroy</span><span class=\"p\">()</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Finished'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"mainルーチン呼び出し\">mainルーチン呼び出し</h1>\n\n<p>お約束の処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "NCStick2": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</h1>\n      <p>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使うためのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1ではpypiからモジュールインストールするだけで使えるようになったのだけれど(python使用時)、<br />\nNCS2を使用しようとすると以下のようなエラーが発生します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>RuntimeError: Cannot load library 'libopenvino_intel_myriad_plugin.so: libopenvino_intel_myriad_plugin.so: cannot open shared object file: No such file or directory\n</code></pre></div></div>\n\n<p>どうやらNCS2(myriad)用のshared libraryがないらしい。<br />\nインストールミスか?と思ったけど、pypiのインストールファイル確認してみたけど、やっぱり入っていない。</p>\n<blockquote>\n  <p>[!NOTE]\nwhlファイルの拡張子をzipに変更するとファイルの中身を確認できる</p>\n</blockquote>\n\n<p>そこで、ソースからNCS2用のshared libraryをbuildしてみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p>参考: <a href=\"https://github.com/openvinotoolkit/openvino/wiki/BuildingForLinux\" target=\"_blank\">BuildingForLinux</a></p>\n\n<p>今回はWSL2の仮想マシンでbuildしてみることにする。<br />\nまた、NCS2用のshared libraryだけが目的なので、pythonモジュールとかはbuildしていない。<br />\nたぶん、ちゃんとCMAKEのオプション設定すればbuild時間が短くなるかもしれないけど、そこはお手軽最優先で。</p>\n\n<blockquote>\n  <p>[!NOTE]\n色々とbuildのために``apt install`するので、WSL2上のcloneした仮想マシンで実行した。<br />\nNCS2はWSL2上で使えないけど、buildするだけなら大丈夫みたい。<br />\n仮想マシンはUbuntu22.04を使用。 たぶん、20.04でも同様と思われる。<br />\nまぁ、Docker使えという説もある…</p>\n</blockquote>\n\n<h2 id=\"ソース取得\">ソース取得</h2>\n\n<p>openVINOのリポジトリからソース取得。<br />\n例によって<code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけてディスク容量&通信時間節約。<br />\n今回はcontribは使わない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> /work  clone  <span class=\"nt\">-b</span> 2022.1.0 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> /work/openvino submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n<span class=\"nb\">cd</span> /work/openvino\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこれ書いてる時点で2022.1.1がリリースされているけど、-bオプション変えればOKでしょう。\nたぶん。。。</p>\n</blockquote>\n\n<h2 id=\"必要なモジュールのインストール\">必要なモジュールのインストール</h2>\n\n<p>必要なモジュールはスクリプトファイルにまとめられているので、それを実行するだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash install_build_dependencies.sh \n</code></pre></div></div>\n\n<p>cmakeのバージョン3.17以上が必要なので、cmakeがそれ以下だとcmakeをソースからbuildしてくれる。<br />\nUbuntu22.04のデフォルト状態だとcmakeのバージョンは3.16なのでbuildが実行される。<br />\nちょっと時間がかかるけど、気長にお待ちください。</p>\n\n<h1 id=\"build\">build</h1>\n\n<p>準備ができたので、buildを実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>make.log\n</code></pre></div></div>\n\n<p>あとはひたすら待つ。<br />\n(うちの環境では1時間くらいだったかな)</p>\n\n<h1 id=\"ターゲットマシンにコピー\">ターゲットマシンにコピー</h1>\n\n<p>makeが終わると、以下のファイルが出来ているはず。<br />\nこの2つをNCS2を使用するターゲットマシンにコピーする。</p>\n\n<ul>\n  <li>openvino/bin/intel64/Release/lib/libopenvino_intel_myriad_plugin.so</li>\n  <li>openvino/bin/intel64/Release/lib/usb-ma2x8x.mvcmd</li>\n</ul>\n\n<p>ターゲットマシンのコピー先はopenVINOモジュールのインストール先の<code class=\"language-plaintext highlighter-rouge\">openvino/libs/</code>ディレクトリの下。<br />\n<code class=\"language-plaintext highlighter-rouge\">libopenvino.so</code>など、soファイルが並んでいるはず。</p>\n\n<p>なお、openVINOモジュールのインストール先は以下のようなコマンドで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"^openvino\"</span>\n</code></pre></div></div>\n\n<p>コピーの方法はエクスプローラでもrcpでも何でもよい。 \nエクスプローラなど、Windows経由でコピーすると実行属性が落ちてしまうけど、<br />\nそもそも実行属性必要ないので気にしなくて良いです。</p>\n\n<h1 id=\"テスト\">テスト</h1>\n<p>NCS2を使用してプログラム実行してみて、エラーにならずに実行できればOK。</p>\n\n<h1 id=\"つぶやき\">つぶやき</h1>\n<p>でも、なんでNCS2用のライブラリ入ってないんだろ?<br />\n単なる入れ忘れ? サポート終了目前?</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージ(2021.1)をインストール(追加)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージ(2021.1)をインストール(追加)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2021.1対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a>で\nubuntuへopenVINO 2020.3のインストールしたが、今回は 2021.1 を追加インストールしたのでメモ。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>前に登録したときに通知されたURLから「Choose Version」でバージョン選んでダウンロードできる。<br />\n新しく登録しなても大丈夫(登録方法は<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>参照)。</p>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>これは前回と同じ。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫だが、<br />\ncmakeは<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたバージョンだと古くてNGといわれてしまうので、<br />\n別途本家からダウンロードしてインストールする(ubuntu 18.04の場合。20.04だとたぶん<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたので大丈夫)。</p>\n\n<ul>\n  <li>既に<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストール済みの場合は、アンインストールする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt purge <span class=\"nt\">--auto-remove</span> cmake\n</code></pre></div>    </div>\n  </li>\n  <li>本家からダウンロードして展開\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/Kitware/CMake/releases/download/v3.18.4/cmake-3.18.4-Linux-x86_64.tar.gz  \n<span class=\"nb\">tar </span>xzvf cmake-3.18.4-Linux-x86_64.tar.gz \n</code></pre></div>    </div>\n  </li>\n  <li>/opt ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv </span>cmake-3.18.4-Linux-x86_64 /opt/\n</code></pre></div>    </div>\n  </li>\n  <li>/usr/bin ディレクトリにシンボリックリンク作成\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /opt/cmake-3.18.4-Linux-x86_64/bin/<span class=\"k\">*</span> /usr/bin/\n</code></pre></div>    </div>\n  </li>\n  <li>バージョン確認\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">--version</span> \n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>インストール手順も<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫。</p>\n\n<p>完了したらこれが表示されるページのURLは以下に変更されている。<br />\n<a href=\"https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<p>2020.3インストール済みだと端折っても大丈夫かと思ったけど、微妙にパッケージ増えてたりするので、再度やった方が良い。<br />\n環境変数の設定のために、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に記述する処理は以下に変更(<code class=\"language-plaintext highlighter-rouge\">openvino</code>→<code class=\"language-plaintext highlighter-rouge\">openvino_2021</code>)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\n<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を実行すると、再度<code class=\"language-plaintext highlighter-rouge\">apt</code>で<code class=\"language-plaintext highlighter-rouge\">cmake</code>がインストールされてしまいます。<br />\nopenVINOのインストール完了後であれば<code class=\"language-plaintext highlighter-rouge\">cmake</code>のバージョンが古くても大丈夫ですが、<br />\n気になるなら、再度アンインストールとシンボリックリンクの作成を行います。<br />\n(実行前に<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を編集してcmake消しておいても良いけど)</p>\n</blockquote>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>これは2020.3インストール済みだと端折ってもOK。<br />\n初めてインストールなら<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>を参照。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール(改訂版)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2020.3対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a>で\nubuntuへのインストール手順を書いたが、今読み返すと結構分かりにくかったので改訂版を書いとく。<br />\n今回はNCS2をubuntuで使えるようにしたので、その手順も追加。<br />\nついでに、今日(2020/06/16)現在の最新版Ver.2020.3での手順確認したので、反映しておく。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<p>参考 :<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">AIを始めよう!OpenVINOのインストールからデモの実行まで[R4対応]</a></p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>何やら登録しないとダウンロードさせてくれないらしい。</p>\n<ul>\n  <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download.html\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a> <br />\nLinux* (supports Ubuntu, CentOS, and Yocto Project)を選択\n    <ul>\n      <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download/linux.html\">Free Download</a>  <br />\n<span style=\"border: 1px solid;\">Register & Download</span>をクリック\n        <ul>\n          <li><a href=\"https://software.seek.intel.com/openvino-toolkit?os=linux\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a><br />\n必要事項を記入して<span style=\"border: 1px solid;\">Submit</span>をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>openVINO用のpython環境を用意しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work1/\npyenv virtualenv 3.7.7 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p>あとで「入ってない」って言われるので先にインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev\n</code></pre></div></div>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>ダウンロードしたファイルを展開してインストールスクリプトを実行する。<br />\n今回はバージョン 2020.3 で確認した。<br />\n最新版は <a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html</a> を参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf l_openvino_toolkit_p_<version>.tgz\n<span class=\"nb\">cd </span>l_openvino_toolkit_p_<version>/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n<p>GUIで次へを押していく。</p>\n\n<p>完了したらこれが表示されるので、したがって進める。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<h3 id=\"install-external-software-dependencies\">Install External Software Dependencies</h3>\n<p>依存パッケージのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh \n</code></pre></div></div>\n\n<h3 id=\"set-the-environment-variables\">Set the Environment Variables</h3>\n<p>環境変数の設定<br />\n~/.bashrc に以下の一文を追加。これでこの後開くコンソールでは環境変数が設定される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>source /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<p>現在のターミナルでも使えるように以下のコマンドを実行しておく。コンソール開きなおしてもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<h3 id=\"configure-the-model-optimizer\">Configure the Model Optimizer</h3>\n<p>モデルオプティマイザのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh \n</code></pre></div></div>\n\n<p>上記スクリプトではsystemのpython3にpipモジュールがインストールされてしまうので、<br />\npyenv環境にも必要なpipモジュールをインストールしておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell openVINO                       <span class=\"c\"># python環境を固定したいので</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\npyenv shell <span class=\"nt\">--unset</span>                        <span class=\"c\"># python環境を戻しておく</span>\n</code></pre></div></div>\n\n<h3 id=\"run-the-verification-scripts-to-verify-installation\">Run the Verification Scripts to Verify Installation</h3>\n<p>デモ実行<br />\n「Verify Installation」って書いてあるけど、実行必須。</p>\n\n<ul>\n  <li>デモ用ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo/\n</code></pre></div>    </div>\n  </li>\n  <li>sudoでpyenvが使えないので、代わりに <code class=\"language-plaintext highlighter-rouge\">/work1</code>  で作成した <code class=\"language-plaintext highlighter-rouge\">.python-version</code>をコピーしておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /work1/.python-version <span class=\"nb\">.</span>\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境にデモ環境で必要なpipモジュールをインストールしておく 。Systemのpython使うときは↓のスクリプト実行時にインストールされる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その1\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/demo1.log\n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その2\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/dem2.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"steps-for-intel-processor-graphics-gpu\">Steps for Intel® Processor Graphics (GPU)</h3>\n<p>今回はGPUを使わないのでスキップ</p>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>NCS2の準備<br />\n色々書いてあるけど、これ一発でOK。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n中ではこんなことをやってます。<br />\nグループusersに自分を追加<br />\n(ログアウト & 再ログインするまで追加は反映されません)<br />\nudevルールの作成と再ロード</p>\n</blockquote>\n\n<p>NCS2をUSBポートにブッ挿すして認識したか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下があったら認識できてる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ID 03e7:2485\n</code></pre></div></div>\n\n<h3 id=\"steps-for-intel-vision-accelerator-design-with-intel-movidius-vpus\">Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPUs</h3>\n<p>今回はVPUを使わないのでスキップ</p>\n\n<p>デモプログラムの実行で動作確認</p>\n\n<p>で、Run a Sample Application に行く前に、ログアウト&再ログインでいいはずだけど、念のためリブート。</p>\n\n<h3 id=\"run-a-sample-application\">Run a Sample Application</h3>\n<p>リブートして開いてたページが分からなくなるといけないので、念のためURL貼っとく。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample</a></p>\n\n<ul>\n  <li>デモ実行ディレクトリに移動。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~/inference_engine_samples_build/intel64/Release\n</code></pre></div>    </div>\n  </li>\n  <li>CPUでデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> CPU\n</code></pre></div>    </div>\n  </li>\n  <li>NCS2でデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> MYRIAD\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>このページの手順はここでおしまい。</p>\n\n<h1 id=\"他のサンプルも試してみよう\">他のサンプルも試してみよう。</h1>\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n<h3 id=\"前準備\">前準備</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work1/NCS/sample <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work1/NCS/sample/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release /opt/intel/openvino_2020.3.194/deployment_tools/inference_engine/samples/cpp/\n</code></pre></div></div>\n\n<h3 id=\"ssdを試してみよう\">SSDを試してみよう</h3>\n<h4 id=\"build\">build</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">-j2</span> object_detection_sample_ssd\n</code></pre></div></div>\n<h4 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R4/20200117_150000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n</code></pre></div></div>\n\n<h4 id=\"実行\">実行</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./intel64/Release/object_detection_sample_ssd <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> /work/data/data2/z_20141013051441.jpg \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nコマンド実行時の<code class=\"language-plaintext highlighter-rouge\">-i</code>オプションは入力画像ファイル。<br />\n人の顔が写っているjpegファイルを指定しましょう。 \n顔が写ってなければ顔検出できません(^^ゞ</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[ INFO ] Execution successful</code>と表示されたら実行成功だと思う。</p>\n\n<h4 id=\"結果画像を表示してみる\">結果画像を表示してみる。</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>eog out_0.bmp \n</code></pre></div></div>\n\n<h4 id=\"おーーーー\"><strong><em>おーーーー</em></strong></h4>\n\n<h1 id=\"ここまでの作業でインストールしたpipパッケージ一覧\">ここまでの作業でインストールしたpipパッケージ一覧</h1>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.9.0\nastor==0.8.1\ncertifi==2020.4.5.2\nchardet==3.0.4\ndecorator==4.4.2\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.2.0\ngraphviz==0.8.4\ngrpcio==1.29.0\nh5py==2.10.0\nidna==2.9\nimportlib-metadata==1.6.1\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.2\nMarkdown==3.2.2\nmxnet==1.5.1\nnetworkx==2.4\nnumpy==1.18.5\nonnx==1.7.0\nopt-einsum==3.2.1\nprotobuf==3.6.1\nPyYAML==5.3.1\nrequests==2.23.0\nsix==1.15.0\ntensorboard==1.15.0\ntensorflow==1.15.3\ntensorflow-estimator==1.15.1\ntermcolor==1.1.0\ntyping-extensions==3.7.4.2\nurllib3==1.25.9\nWerkzeug==1.0.1\nwrapt==1.12.1\nzipp==3.1.0\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PythonでIntel NCStick2</title>\n  </head>\n  <body>\n    <header>\n      <h1>PythonでIntel NCStick2</h1>\n      <p>PythonでIntel NCStick2を操作する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"事前準備\">事前準備</h1>\n<p>何はなくともPythonが必要。<br />\n実際には3.7.4を使用して動作確認。</p>\n\n<p>Pythonはpyenvでインストールしておくのが便利。インストール方法は \n<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a> を参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\npyenvとの相性が悪いらしく、pyenvで3.7.xがインストールされていると\n(python3.7コマンド自体は存在するので;実行自体はエラーで返ってくるが)、\nsetupvars.shでPYTHONPATHにpython3.7用pathが設定されてしまう。\nプログラム中で<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>でpathを追加しても、sys.pathの末尾に追加されてしまい、\n先に設定された3.7用モジュールがインポートされてしまう。\nもし、他のバージョンのpythonで実行する場合は<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">sys.path.insert</code>で\npathの先頭に追加するようにしないといけないようだ(試してないけど)。</p>\n\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n    <span class=\"err\">↓</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>ということで、下のプログラムソースの<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>の行は不要。</p>\n</blockquote>\n\n<h2 id=\"モジュールのインストール\">モジュールのインストール</h2>\n\n<p>必要なモジュール類をインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgfortran-6-dev\npip <span class=\"nb\">install </span>numpy\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h2 id=\"ワークディレクトリ\">ワークディレクトリ</h2>\n\n<p>色々共通で使いたいサイズのでっかいファイルがあるので、ワークディレクトリを以下の構成で作成しておく。<br />\n以降のopenVINO関連の投稿もこのディレクトリ構成を使うようにする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># C++プログラム湯尾</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++\n<span class=\"c\"># pythonプログラム用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/python\n<span class=\"c\"># モデルデータ用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP16\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP32\n</code></pre></div></div>\n\n<h1 id=\"参考\">参考</h1>\n\n<p><del>パクった</del> 参考にしたのは以下のあたり<br />\n解説や実行方法などはこっちを参照してちょ(相変わらずの他力本願ぶり…))</p>\n\n<ul>\n  <li><a href=\"http://jellyware.jp/openvino/\">JELLYWARE ゼロから学ぶディープラーニング推論</a>\n    <ul>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c07_ie_emotion.html\">Inference Engineを学んで感情分類</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c08_face_detection.html\">リアルタイム顔検出</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c09_emotion_app.html\">リアルタイム感情分析アプリ</a></li>\n    </ul>\n  </li>\n</ul>\n\n<p>顔検出+感情分類の参照元はカメラキャプチャした画像を処理しているけど、手元に適当なカメラがなかったので、JPEGファイルで実行するようにしてある(こっちの方が余計な処理なくて分かりやすいかな、と思ったのもある)。</p>\n\n<h1 id=\"感情分類\">感情分類</h1>\n\n<p>感情分類のプログラムを試す。</p>\n\n<h3 id=\"準備\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/emotions-recognition-retail-0003/FP16/emotions-recognition-retail-0003\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する顔画像(顔部分のみ切り出し)をPHOTO/face.jpgとして保存しておく。</p>\n\n<h3 id=\"プログラム\">プログラム</h3>\n\n<p>試したソースはこちら。<br />\nPCのubuntuで実行するための処理も追加済み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/face.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 結果取り出し\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>\n<span class=\"c1\"># 結果の最大値を持つインデックスを取得\n</span><span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 結果表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">結果'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">index_max</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"c1\"># 結果の詳細表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">詳細'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'スコア:</span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出\">顔検出</h1>\n\n<p>顔検出のプログラムを試す。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-1\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-1\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n\n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-1\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_detect.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_detect.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_detect.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出感情分類\">顔検出+感情分類</h1>\n\n<p>上の2つを合体させ、顔検出した結果に感情分類を実行する。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-2\">準備</h3>\n\n<p>モデルデータは上の2つをそのまま使用。</p>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-2\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出 + 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n# 日本語表示にはPillow使うとかしないといけないので、英語で。\n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# バウンティングボックスとラベルを表示する関数\n</span><span class=\"k\">def</span> <span class=\"nf\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ラベル領域サイズ\n</span>    <span class=\"n\">LABEL_W</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">12</span>    <span class=\"c1\"># 等幅フォントじゃないので正確ではないけど、大体こんな感じ\n</span>    <span class=\"n\">LABEL_H</span> <span class=\"o\">=</span> <span class=\"mi\">14</span>                <span class=\"c1\"># こっちもトライアンドエラーで微調整\n</span>    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">IMAGE_W</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">IMAGE_H</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># バウンディングボックス表示 \n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ラベル表示位置(X)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">IMAGE_W</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">IMAGE_W</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_W</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">xmin</span>\n    \n    <span class=\"c1\"># ラベル表示位置(Y)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span>\n    \n    <span class=\"c1\"># 文字列背景描画(塗りつぶし)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">label_x</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 文字列描画(座標は文字の左下)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX_SMALL</span><span class=\"p\">,</span> <span class=\"mf\">0.8</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n    \n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。特にminは補正しないとエラーになる\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 顔領域のみ切り出し \n</span>    <span class=\"n\">frame_face</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">[</span> <span class=\"n\">ymin</span><span class=\"p\">:</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">:</span><span class=\"n\">xmax</span> <span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 入力データフォーマットへ変換 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame_face</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span>   <span class=\"c1\"># サイズ変更 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">img_face</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img_face</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>    \n    <span class=\"c1\"># 推論実行 \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img_face</span><span class=\"p\">})</span>\n    \n    <span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>    \n    <span class=\"c1\"># 出力値が最大のインデックスを得る \n</span>    <span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"c1\"># print(list_emotion[index_max])\n</span>    <span class=\"n\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-2\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<h1 id=\"考察\">考察</h1>\n\n<p>基本パターンはこんな感じ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># モジュールのロード\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># 初期化\n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"s\">\"MYRIAD\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み\n</span><span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"s\">'xmlファイル'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"s\">'binファイル'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 推論実行 \n# imgは入力データ、Numpy配列 ndarray型\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># outが出力データ、Numpy配列 ndarray型\n</span>\n</code></pre></div></div>\n\n<p>入出力データの並びは読み込んだモデルに依存する。<br />\n入力データのサイズやRGB並び順などを合わせる。<br />\n(モデルに入力する際にリサイズすれば、元の画像ファイルのサイズは任意で良い。)<br />\n出力データはそのままでは「何のこっちゃ?」なので、きちんと整形してやる必要がある。</p>\n\n<p>ここに学習済みデータが色々登録されているらしい。<br />\n<a href=\"https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html\">https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html</a></p>\n\n<p>TensorflowやCaffeで作成した学習済みデータを変換することもできるらしいが、やり方はこれから調査。</p>\n\n<h1 id=\"参考情報\">参考情報</h1>\n<p><a href=\"https://software.intel.com/en-us/articles/OpenVINO-RelNotes\">openVINO toolkit リリースノート</a><br />\n<a href=\"https://git.uni-paderborn.de/rnagle/dldt/tree/noctua_plugin_develop\">openVINO toolkit リポジトリ</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick2用動作環境の構築</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick2用動作環境の構築</h1>\n      <p>Intel NCStick2用動作環境の構築</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Dセンセの悪魔の囁きに踊らされ、Intel NCStick2をポチってしまった。<br />\nで、動作環境を構築したときのメモを残しておく。</p>\n\n<p>ホストマシンは、RaspberryPi3 model B+ で Raspbian Buster を使用。</p>\n\n<p>Raspbian Busterのインストールは、\n<a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\">Raspbian Busterのインストール</a>\nの手順で行った。</p>\n\n<p><a href=\"http://jellyware.jp/openvino/\">JellyWare:ゼロから学ぶディープラーニング推論</a> \n → <a href=\"http://jellyware.jp/kurage/openvino/c03_setting.html\">ゼロから始めるインストール</a> をマネしただけだが、\nダウンロード先の<strong>URLが微妙に変更</strong>されてたり、\nこのページの説明が<strong>細かすぎてちょっとイラっとした</strong>ので、\n以下に手順の要約を書いておく。</p>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2\n<span class=\"nb\">cd</span> /work/NCS2/\n</code></pre></div></div>\n\n<h2 id=\"openvino-の取得とインストール\">openVINO の取得とインストール</h2>\n\n<p>アーカイブファイル落としてきて、展開するだけ。<br />\nR3がリリースされているようなので、これを使う。(2019/10/01現在)\nちょくちょくリリースされるみたいなので、<a href=\"https://download.01.org/opencv/2019/openvinotoolkit/\">https://download.01.org/opencv/2019/openvinotoolkit/</a>をチェックしてね。<br />\n2020年になったら、~download.01.org/opencv/2020/~ なのかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R3/l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz\n\n<span class=\"c\"># インストール先ディレクトリの作成 & オーナー変更(あとあとめんどくさいので)</span>\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span>  <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n\n<span class=\"c\"># 展開</span>\n<span class=\"nb\">tar </span>xzvf l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span> <span class=\"nt\">--strip-components</span><span class=\"o\">=</span>1\n<span class=\"nb\">sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以下以前の情報</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R2/l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz\n\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo tar</span> <span class=\"nt\">-xf</span> l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz <span class=\"nt\">--strip</span> 1 <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h2 id=\"cmakeのインストール\">cmakeのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n</code></pre></div></div>\n\n<p>他にもmakeとかbuild-essentialとか要るけど、<a href=\"/memoBlog/2019/06/27/pyenv.html\">ここ</a>\nでインストールしたやつがあれば大丈夫っぽい。</p>\n\n<h2 id=\"初期化スクリプトの変更\">初期化スクリプトの変更</h2>\n\n<p>~/.bashrc の最後に以下を追加。<br />\nここでは<code class=\"language-plaintext highlighter-rouge\">${VINO_DIR_TMP}</code>使っちゃダメよ~。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOの設定</span>\n<span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<h2 id=\"初期化スクリプトの変更を反映\">初期化スクリプトの変更を反映</h2>\n\n<p>シリアルコンソールやSSHでlog inしてる場合は、ここで一旦log offして再log in。<br />\nX使ってるならターミナル開きなおす。<br />\nもちろん、<code class=\"language-plaintext highlighter-rouge\">source</code>するだけでも良いけど。<br />\nいちお、.bashrcにちゃんと書けてるか確認の意味で一旦log off or ターミナル開きなおしするのがいいかな。  <br />\n(.bashrcの変更だけなので、再起動までは必要ない) <br />\nlog in時 or 新しいターミナルを開いた時に <code class=\"language-plaintext highlighter-rouge\">[setupvars.sh] OpenVINO environment initialized</code> と表示されることを確認。</p>\n\n<h2 id=\"グループの追加\">グループの追加</h2>\n\n<p>ユーザがグループusersを持っているか確認。(デフォルトなら持ってるハズ) 持ってなかったら追加。<br />\n次のコマンドで追加してくれるっぽいけど。。。</p>\n\n<h2 id=\"udevルールの追加\">udevルールの追加</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sh <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n\n<h2 id=\"いよいよncstick2の登場だ\">いよいよNCStick2の登場だ~~~</h2>\n\n<p>NCStick2をUSBポートにぶっ挿す。<br />\nデカくて他のポートに干渉するので、必要なら延長ケーブルを使ってちょ。</p>\n\n<p>で、認識されたか確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n<span class=\"c\"># こんな感じで表示されるハズ。XXX部分は ぶっ挿したUSBポートで変わる。</span>\n・・・\nBus XXX Device XXX: ID 03e7:2485 Intel Movidius MyriadX\n・・・\n</code></pre></div></div>\n\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n\n<p>とりあえず、ワークディレクトリは<code class=\"language-plaintext highlighter-rouge\">/work/NCS2/</code>を使ってる。<br />\nhome に色々ぶち込むの嫌いなので。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">/work</code>は作成済みで<code class=\"language-plaintext highlighter-rouge\">chown</code>済みとする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ワークディレクトリの作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/sample\n<span class=\"nb\">cd</span> /work/NCS2/sample\n\n<span class=\"c\"># cmakeの実行</span>\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a\"</span> <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/deployment_tools/inference_engine/samples\n\n<span class=\"c\"># makeの実行</span>\nmake <span class=\"nt\">-j2</span> object_detection_sample_ssd\n\n<span class=\"c\"># ネットワークデータの取得</span>\n<span class=\"c\"># shell変数の設定時はスペース入れちゃダメだよ~</span>\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R2/20190716_170000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n\n<span class=\"c\"># 入力ファイルをどっかから持ってきて、<<入力ファイル>>.jpgとしてカレントディレクトリに保存しておく</span>\n<span class=\"c\"># 顔検出のデモなので、人物が何人か写ってる画像を用意してね。</span>\n\n<span class=\"c\"># サンプル実行</span>\n./armv7l/Release/object_detection_sample_ssd  <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> <<入力ファイル>>.jpg\n\n<span class=\"c\"># out_0.bmpができる</span>\n</code></pre></div></div>\n\n<h2 id=\"結果の確認\">結果の確認</h2>\n\n<p>out_0.bmpをテキトーに表示。<br />\n人物の顔が四角で囲まれていることを確認。</p>\n\n<h2 id=\"インストールと動作確認完了\">インストールと動作確認完了</h2>\n\n<p>めでたしめでたし。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "openVINO": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINO 2022.1のbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1はRaspberry Pi OS(64bit)向けのバイナリがリリースされていないので、自力でbuildしてみます。</p>\n\n<p>今回もUbuntu上のDockerコンテナを使用しましたが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思います。</p>\n\n<p>前回はPythonを諦めてクロスコンパイルする方法とbuild時間を諦めてセルフコンパイル(エミュレーション)する方法を使いましたが、<br />\n今回はPython以外をクロスコンパイル、Python関連部をセルフコンパイル(エミュレーション)して生成物をマージする方法をとってみます。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_2022.1_pi64 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_2022.1_pi64\n</code></pre></div></div>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>workディレクトリを作成し、openvino と openvino_contrib のリポジトリをcloneします。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 2022.1.1 <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib checkout 1a28b530ab40d2ad79ab29021dfddfbbc7d2db0b\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の2022.1だと一部のノードが未対応とエラーになるため、対応済みのcommitを使用します。<br />\ntagが振られていないので、commit IDを指定してcheckoutします。<br />\nこれ以降のcommitではopenvinoのバージョン2022.2が必要になります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ntagやbranchが設定されていない場合はcloneでcheckoutするバージョンを指定できないため、\n一旦cloneしてからcommit IDを指定してcheckoutします。<br />\nsubmoluleのcheckoutは対象のバージョンをcheckoutしてから行います。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の最新commit(試した時点ではcommit ID <code class=\"language-plaintext highlighter-rouge\">fd2ac364435757d23a9b3e91d67235b5e6555bf9</code>)を使用する場合は\nopenvinoのバージョン2022.2を使用する必要がありますが、試した時点で <code class=\"language-plaintext highlighter-rouge\">2022.2.0.dev20220829</code> がリリースされているので\nこれを使用します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0.dev20220829  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit -C ./work/openvino_contrib checkout fd2ac364435757d23a9b3e91d67235b5e6555bf9\ngit -C ./work/openvino_contrib submodule update --init --recursive --depth 1\n</code></pre></div>  </div>\n  <blockquote>\n    <p>2022.2.0正式リリース後はこんな感じになるのかな?</p>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  -b 2022.2    --recursive --depth 1 https://github.com/openvinotoolkit/openvino_contrib.git\n</code></pre></div>    </div>\n  </blockquote>\n\n  <p>この場合、NVIDIA GPUのpluginのbuildでエラーになるため、以下のcmakeのオプションに以下のオプションを追加します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      -D BUILD_nvidia_plugin=OFF\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h1 id=\"openvinoのbuildクロスコンパイル\">openVINOのBuild(クロスコンパイル)</h1>\n\n<p>クロスコンパイルでpython関連以外の部分をbuildします。</p>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir cross</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">cross/Dockerfile</code>を作成します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cross/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates:arm64 <span class=\"se\">\\\n</span>    libboost-regex-dev:arm64 <span class=\"se\">\\\n</span>    libgtk2.0-dev:arm64 <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev:arm64 <span class=\"se\">\\\n</span>    libcairo2-dev:arm64 <span class=\"se\">\\\n</span>    libpango1.0-dev:arm64 <span class=\"se\">\\\n</span>    libglib2.0-dev:arm64 <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev:arm64 <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗します</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeは新しめのをインストールしておきたいので、3.23.2をbuildして使用しています。<br />\nもしかすると、<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたものをそのまま使っても大丈夫かもしれませんが。</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_cross cross\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\ncacheを使わずimage buildしたい場合は<code class=\"language-plaintext highlighter-rouge\">--no-cache</code>オプションを追加します。<br />\n以前に作ったイメージのキャッシュを使って<code class=\"language-plaintext highlighter-rouge\">apt install</code>がエラーになったことがあったので。<br />\n(デフォルトのリポジトリに変更があったらしい)</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_cross_2 ov_2022.1_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_cross_2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_2022.1_pi64_cross_2 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/cmake/arm64.toolchain.cmake <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_BEH_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLDNN</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_FUNCTIONAL_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">THREADING</span><span class=\"o\">=</span>SEQ <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">CONTRIB_TOP</span><span class=\"k\">}</span>/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span> 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=${WORK_DIR}/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"クロスコンパイル終了\">クロスコンパイル終了</h3>\n<p>クロスコンパイルはここまでなので、コンテナから抜ける。</p>\n\n<h1 id=\"openvinoのbuildセルフコンパイル\">openVINOのBuild(セルフコンパイル)</h1>\n\n<p>セルフコンパイルでpython関連部分をbuildします。<br />\ncythonを使うときにクロスコンパイルする方法が分からないので、セルフコンパイルで。</p>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir emu</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">emu/Dockerfile</code>を作成します。</p>\n\n<p>python部だけなので、こんなにライブラリとか要らない気もしますが、全部セルフコンパイルするときのことも考えて\n全部入りのイメージを作っておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  emu/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates <span class=\"se\">\\\n</span>    libboost-regex-dev <span class=\"se\">\\\n</span>    libgtk2.0-dev <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev <span class=\"se\">\\\n</span>    libcairo2-dev <span class=\"se\">\\\n</span>    libpango1.0-dev <span class=\"se\">\\\n</span>    libglib2.0-dev <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_emu emu\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_emu_2 ov_2022.1_pi64_emu /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_emu_2\n</code></pre></div></div>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成-1\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build_python <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build_python\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">InferenceEngineDeveloperPackage_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/build <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/src/bindings/python 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">CMAKE_INSTALL_PREFIX</code>の設定はクロスコンパイルのときと同じ設定にしてください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npyenvでインストールしたpythonなど、デフォルトでないpythonを使用する場合に指定します。<br />\n(以下の設定値はubuntu 22.04の標準インストールの場合のパスなのであまり参考にならないかも)</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  -D PYTHON_EXECUTABLE=/usr/bin/python3.8 \\\n  -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.8.so \\\n  -D PYTHON_INCLUDE_DIR=/usr/include/python3.8 \\\n  -D PYTHON_MODULE_EXTENSION=\".so\" \\\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"make-1\">make</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。</p>\n\n<h3 id=\"セルフコンパイル終了\">セルフコンパイル終了</h3>\n<p>セルフコンパイルはここまでなので、コンテナから抜けます。</p>\n\n<h1 id=\"インストール媒体の作成\">インストール媒体の作成</h1>\n\n<p>ホスト側の<code class=\"language-plaintext highlighter-rouge\">work</code>ディレクトリ内を見ると、<code class=\"language-plaintext highlighter-rouge\">intel</code>ディレクトリが出来ているので、ここをtarなどで固めておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>work\n<span class=\"nb\">tar </span>czvf ov1.tar.gz intel/\n</code></pre></div></div>\n\n<p>この<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiにコピーして展開します。</p>\n\n<h1 id=\"raspberrypiへのインストール\">RaspberryPiへのインストール</h1>\n\n<h2 id=\"インストール\">インストール</h2>\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiの適当なディレクトリに展開します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/proj</code>ディレクトリに展開しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /proj/\n<span class=\"nb\">tar </span>xzvf ov1.tar.gz \n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<p>これで<code class=\"language-plaintext highlighter-rouge\">/proj/intel/openvino</code>ディレクトリにインストールされました。</p>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n<p>環境変数の設定のため、以下を実行します。<br />\nshell起動の度に実行が必要なので<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>などに書いておくと良いです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/intel/openvino/setupvars.sh \n</code></pre></div></div>\n\n<h2 id=\"udevルールの設定\">udevルールの設定</h2>\n<p>以下のスクリプトを実行すればNCS2を挿せば認識されるようになります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/proj/intel/openvino/install_dependencies/install_NCS_udev_rules.sh \n</code></pre></div></div>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n<p>openCVの必要になるので、インストールしておきます。<br />\n今回はお手軽にpipでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認用のプログラムは<a href=\"https://github.com/ippei8jp/ov_trial_2022.1\" target=\"_blank\">https://github.com/ippei8jp/ov_trial_2022.1</a> とかにあります。<br />\nでもモデルのダウンロード/コンバートはRaspberryPiではできないので、UbuntuやWondowsで実行したものをコピーして使用してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使う</h1>\n      <p>openVINO 2022.1 (Ubuntu 20.04)でNCS2を使うためのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1ではpypiからモジュールインストールするだけで使えるようになったのだけれど(python使用時)、<br />\nNCS2を使用しようとすると以下のようなエラーが発生します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>RuntimeError: Cannot load library 'libopenvino_intel_myriad_plugin.so: libopenvino_intel_myriad_plugin.so: cannot open shared object file: No such file or directory\n</code></pre></div></div>\n\n<p>どうやらNCS2(myriad)用のshared libraryがないらしい。<br />\nインストールミスか?と思ったけど、pypiのインストールファイル確認してみたけど、やっぱり入っていない。</p>\n<blockquote>\n  <p>[!NOTE]\nwhlファイルの拡張子をzipに変更するとファイルの中身を確認できる</p>\n</blockquote>\n\n<p>そこで、ソースからNCS2用のshared libraryをbuildしてみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p>参考: <a href=\"https://github.com/openvinotoolkit/openvino/wiki/BuildingForLinux\" target=\"_blank\">BuildingForLinux</a></p>\n\n<p>今回はWSL2の仮想マシンでbuildしてみることにする。<br />\nまた、NCS2用のshared libraryだけが目的なので、pythonモジュールとかはbuildしていない。<br />\nたぶん、ちゃんとCMAKEのオプション設定すればbuild時間が短くなるかもしれないけど、そこはお手軽最優先で。</p>\n\n<blockquote>\n  <p>[!NOTE]\n色々とbuildのために``apt install`するので、WSL2上のcloneした仮想マシンで実行した。<br />\nNCS2はWSL2上で使えないけど、buildするだけなら大丈夫みたい。<br />\n仮想マシンはUbuntu22.04を使用。 たぶん、20.04でも同様と思われる。<br />\nまぁ、Docker使えという説もある…</p>\n</blockquote>\n\n<h2 id=\"ソース取得\">ソース取得</h2>\n\n<p>openVINOのリポジトリからソース取得。<br />\n例によって<code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけてディスク容量&通信時間節約。<br />\n今回はcontribは使わない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> /work  clone  <span class=\"nt\">-b</span> 2022.1.0 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> /work/openvino submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n<span class=\"nb\">cd</span> /work/openvino\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこれ書いてる時点で2022.1.1がリリースされているけど、-bオプション変えればOKでしょう。\nたぶん。。。</p>\n</blockquote>\n\n<h2 id=\"必要なモジュールのインストール\">必要なモジュールのインストール</h2>\n\n<p>必要なモジュールはスクリプトファイルにまとめられているので、それを実行するだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash install_build_dependencies.sh \n</code></pre></div></div>\n\n<p>cmakeのバージョン3.17以上が必要なので、cmakeがそれ以下だとcmakeをソースからbuildしてくれる。<br />\nUbuntu22.04のデフォルト状態だとcmakeのバージョンは3.16なのでbuildが実行される。<br />\nちょっと時間がかかるけど、気長にお待ちください。</p>\n\n<h1 id=\"build\">build</h1>\n\n<p>準備ができたので、buildを実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>make.log\n</code></pre></div></div>\n\n<p>あとはひたすら待つ。<br />\n(うちの環境では1時間くらいだったかな)</p>\n\n<h1 id=\"ターゲットマシンにコピー\">ターゲットマシンにコピー</h1>\n\n<p>makeが終わると、以下のファイルが出来ているはず。<br />\nこの2つをNCS2を使用するターゲットマシンにコピーする。</p>\n\n<ul>\n  <li>openvino/bin/intel64/Release/lib/libopenvino_intel_myriad_plugin.so</li>\n  <li>openvino/bin/intel64/Release/lib/usb-ma2x8x.mvcmd</li>\n</ul>\n\n<p>ターゲットマシンのコピー先はopenVINOモジュールのインストール先の<code class=\"language-plaintext highlighter-rouge\">openvino/libs/</code>ディレクトリの下。<br />\n<code class=\"language-plaintext highlighter-rouge\">libopenvino.so</code>など、soファイルが並んでいるはず。</p>\n\n<p>なお、openVINOモジュールのインストール先は以下のようなコマンドで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"^openvino\"</span>\n</code></pre></div></div>\n\n<p>コピーの方法はエクスプローラでもrcpでも何でもよい。 \nエクスプローラなど、Windows経由でコピーすると実行属性が落ちてしまうけど、<br />\nそもそも実行属性必要ないので気にしなくて良いです。</p>\n\n<h1 id=\"テスト\">テスト</h1>\n<p>NCS2を使用してプログラム実行してみて、エラーにならずに実行できればOK。</p>\n\n<h1 id=\"つぶやき\">つぶやき</h1>\n<p>でも、なんでNCS2用のライブラリ入ってないんだろ?<br />\n単なる入れ忘れ? サポート終了目前?</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINOのクロスコンパイル</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINOのクロスコンパイル</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild(クロスコンパイル環境)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi OS(64bit)向けにopenVINOをクロスコンパイルする方法についてまとめた。<br />\nセルフコンパイル(Docker使用)については『<a href=\"/memoBlog/2022/03/07/openVINO_build_2.html\" target=\"_blank\">openVINO(Raspberry Pi OS(64bit)向け)のbuild</a>』を参照。<br />\nただ、クロスコンパイルだとセルフコンパイルの10倍くらい速い(環境によるけど)ので、クロスコンパイルがおススメ。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_cross <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_cross\n</code></pre></div></div>\n\n<h2 id=\"ソースの取得\">ソースの取得</h2>\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h3>\n<p>以下の1つのpatchファイルを作成する。<br />\nサンプル(テスト?)プログラムのBuildを抑制してコンパイル時間の短縮を計っている。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"opencv-の-gitリポジトリを-clone\">openCV の gitリポジトリを clone</h3>\n<p>opencv のリポジトリをcloneする(opencvのBuildを行わない場合は不要)。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libgtk-3-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_cross <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_cross_1 ov_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_cross_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_cross_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n<p>ここからコンテナ内</p>\n\n<h2 id=\"buildディレクトリの作成\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openvino/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/openvino/build\n</code></pre></div></div>\n\n<h2 id=\"cmake実行\">cmake実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm64.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_SAMPLES</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLANG_FORMAT</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_OPENCV</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n    .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>サンプルはBuildしないので、ENABLE_SAMPLES=OFF を設定</li>\n    <li>ソースをいじるわけではないので、ENABLE_CLANG_FORMAT=OFF を設定</li>\n    <li>openCVインストールされていないので、ENABLE_OPENCV=OFF を設定<br />\n(サンプルのBuildしないのでopenCVなくても大丈夫)</li>\n  </ul>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nログには いくつかWarningがあるが、とくに問題はなさそう</p>\n</blockquote>\n\n<h2 id=\"make\">make</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h2 id=\"その他細々したところ\">その他細々したところ</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"c\"># クロスコンパイルを反映したファイル名になっていないので修正</span>\n<span class=\"nb\">mv</span> /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-x86_64-linux-gnu.so /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-aarch64-linux-gnu.so\n\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>CPU Extentionは<code class=\"language-plaintext highlighter-rouge\">make install</code>でコピーされないので手動でインストールする。</li>\n    <li>バイナリリリースに<code class=\"language-plaintext highlighter-rouge\">inference_engine</code>のシンボリックリンクがあるので同様に作成しておく。</li>\n    <li>ngraphのライブラリファイルのファイル名がx86_64(ホスト環境の名前)になっているので、aarch64に修正。<br />\nバイナリ自体はaarch64になっているので、ファイル名のリネームだけでOK。<br />\n本来はファイル名決めてるところで対処するのが良いのだろうけど、とりあえず力技で。</li>\n  </ul>\n</blockquote>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<p>openCVのBuild方法についてもメモっておく。<br />\npythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。<br />\nその場合は、ここはスキップしても大丈夫。<br />\nopenVINOをBuildしたDockerコンテナで引き続き作業を行う</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk-3-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libjpeg-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libpng-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev:arm64\n</code></pre></div></div>\n<h2 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n</code></pre></div></div>\n<h2 id=\"cmakeの実行\">cmakeの実行</h2>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PKG_CONFIG_LIBDIR</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_ENABLE_PKG_CONFIG</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_FIND_ROOT_PATH</span><span class=\"o\">=</span>/ <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span>/work/opencv/platforms/linux/aarch64-gnu.toolchain.cmake <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_NUMPY_INCLUDE_DIRS</span><span class=\"o\">=</span>/usr/lib/python3/dist-packages/numpy/core/include <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n       .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあらかじめ環境変数<code class=\"language-plaintext highlighter-rouge\">PKG_CONFIG_LIBDIR</code>を設定して<code class=\"language-plaintext highlighter-rouge\">pkg-config</code>でaarch64のライブラリとNativeのツール類を参照するように設定しておく。<br />\nこれをやらないと、libjpegとかをインストールしてあることを検出できない</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeのオプションに <code class=\"language-plaintext highlighter-rouge\">-D CMAKE_FIND_DEBUG_MODE=1</code>を追加すると\ncmake中の<code class=\"language-plaintext highlighter-rouge\">find_xxx</code>の動作のログが出力されるので、パッケージのサーチなどの検索パスの確認などが容易になる。</p>\n</blockquote>\n\n<h2 id=\"make-1\">make</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install-1\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino/opencv</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/opencv</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-D CMAKE_INSTALL_PREFIX=/work/opt/intel/openvino/opencv</code>の部分を変更すれば良いけど、ここはopenVINOのインストール先と合わせておかないとうまく動かない。</p>\n\n<h1 id=\"実機へのインストール\">実機へのインストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">opt</code>ディレクトリ以下を丸ごとアーカイブする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<p>作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>をRaspberryPiの適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"コンテナから出る\">コンテナから出る</h1>\n<p>Dockerコンテナは作業終了したら終了しておく。<br />\nCTRL-D でshell終了</p>\n\n<h1 id=\"補足\">補足</h1>\n<p>コンテナにインストールされているパッケージは以下の通り。<br />\nバージョン違いで動かなくなることもあるかもしれんので、念のため。</p>\n\n<p>こんな感じで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span> | <span class=\"nb\">grep</span> <span class=\"nt\">-v</span> automatic\n</code></pre></div></div>\n\n<p>で、こんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>build-essential/stable,now 12.9 amd64 [installed]\ncmake/stable,now 3.18.4-2+deb11u1 amd64 [installed]\ncrossbuild-essential-arm64/stable,stable,now 12.9 all [installed]\ncython3/stable,now 0.29.21-3+b1 amd64 [installed]\ngit/stable,now 1:2.30.2-1 amd64 [installed]\nlibavcodec-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibavformat-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibgstreamer-plugins-base1.0-dev/stable,now 1.18.4-2 arm64 [installed]\nlibgstreamer1.0-dev/stable,now 1.18.4-2.1 arm64 [installed]\nlibgtk-3-dev/stable,now 3.24.24-4 arm64 [installed]\nlibjpeg-dev/stable,now 1:2.0.6-4 arm64 [installed]\nlibpng-dev/stable,now 1.6.37-3 arm64 [installed]\nlibprotobuf-dev/stable,now 3.12.4-1 arm64 [installed]\nlibprotoc-dev/stable,now 3.12.4-1 arm64 [installed]\nlibpython3-dev/stable,now 3.9.2-3 arm64 [installed]\nlibswscale-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibtiff-dev/stable,now 4.2.0-1 arm64 [installed]\nlibusb-1.0-0-dev/stable,now 2:1.0.24-3 arm64 [installed]\nlibwebp-dev/stable,now 0.6.1-2.1 arm64 [installed]\nprotobuf-compiler/stable,now 3.12.4-1 amd64 [installed]\npython3-minimal/stable,now 3.9.2-3 amd64 [installed]\npython3-numpy/stable,now 1:1.19.5-1 amd64 [installed]\npython3-pip/stable,stable,now 20.3.4-4 all [installed]\nscons/stable,stable,now 4.0.1+dfsg-2 all [installed]\nwget/stable,now 1.21-1+deb11u1 amd64 [installed]\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>aspberry Pi OS(64bit)がリリースされたが、openVINOのBuild済みモジュールはまだこれに対応していない。<br />\nそのうち対応されると思うけど、とりあえず自前でBuildする方法を調べてみた。<br />\nついでにCPU Extensionも作成しておく。<br />\nなお、Raspberry Pi OS(32bit Buster)向けのBuild手順については、\n『<a href=\"/memoBlog/2021/10/28/openVINO_build.html\" target=\"_blank\">openVINO(Raspberry Pi向け)のbuild</a>』を参照。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<p>今回もARM版Dockerコンテナを使用してセルフコンパイルする方法で行う。<br />\n手順そのものは特殊なことはないので、Raspberry Pi上のNative環境でもBuildできそうだけど、\nディスク容量とかスワップ領域とか気にしないといけないかもしれないので試してない。<br />\n(今回はクロスコンパイル環境はなし。cythonの出力モジュールも使いたかったので)</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_emu\n</code></pre></div></div>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h2 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h2>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n32bit版との差分はこんな感じ。<br />\nあれ?32bit版の<code class=\"language-plaintext highlighter-rouge\">python-minimal</code>って間違ってる?<br />\n<code class=\"language-plaintext highlighter-rouge\">python3-numpy</code>で依存モジュールとしてインストールされて事なきを得たのか?<br />\n実質、ベースイメージを変更してるだけだな。</p>\n\n  <div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- Dockerfile.old\t2022-03-01 07:26:28.774187231 +0900\n</span><span class=\"gi\">+++ Dockerfile\t2022-03-01 07:19:45.668393598 +0900\n</span><span class=\"p\">@@ -1,4 +1,4 @@</span>\n<span class=\"gd\">-FROM arm32v7/debian:buster\n</span><span class=\"gi\">+FROM arm64v8/debian:bullseye\n</span> \n USER root\n \n<span class=\"p\">@@ -18,7 +18,7 @@</span>\n     libprotobuf-dev libprotoc-dev protobuf-compiler \\\n     cmake \\\n     python3-pip \\\n<span class=\"gd\">-    python-minimal \\\n</span><span class=\"gi\">+    python3-minimal \\\n</span>     python3-numpy cython3 scons\n \n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_emu_1 ov_pi64_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<p>数時間レベルでかかるので、のんびり待ちましょう。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"その他細々したところ\">その他細々したところ</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コメント\">コメント</h3>\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール\">実機へのインストール</h2>\n\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>を適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>ついでにopenCVのBuild方法についてもメモっておく。</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>openCVのリポジトリをcloneしておく。<br />\n指定するタグは適宜変更してください。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n<p>新しいDockerコンテナ作っても良いけど、別にその必要もないので上記のコンテナをそのまま使用する。</p>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n  <h2 id=\"本番-1\">本番</h2>\n</blockquote>\n\n<h3 id=\"準備-2\">準備</h3>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk2.0-dev  libjpeg-dev libpng-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev\n</code></pre></div></div>\n\n<h3 id=\"build\">Build</h3>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n\n<span class=\"c\"># インストール</span>\nmake <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf opencv.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コンテナから出る-1\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール-1\">実機へのインストール</h2>\n<p>openVINOをBuildしたコンテナで続けてBuildした場合は<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>にopenVINO、openCVがインストールされている。<br />\nこれを適当なディレクトリに展開して環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば良い。</p>\n\n<p>別のコンテナを使用したり、openVINOのBuild結果を削除していた場合は、<br />\n最終的に作成した<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>をopenVINOをインストールしたディレクトリに展開する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi向け)のbuild</h1>\n      <p>Raspberry Pi向けopenVINOのbuild(特にCPU extension)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi用 openVINO は デフォルト状態ではCPUで実行できない(NCS2必須)。<br />\nそこで、オープンソース版openVINOを使用してCPU extensionを作成してみる。<br />\nとはいえ、CPU extension だけサクっと作成できなくて、openVINO全体を作成するハメに…</p>\n\n<p>Raspberry Pi 実機でbuildすると、ディスク容量がバカにならないし、<br />\nあまり実環境を弄りたくなかったので、<br />\nUbuntuマシン上のDockerコンテナで実行する方法を試してみる(Docker Desktop for Windowsでもできると思う)</p>\n\n<h1 id=\"arm版dockerコンテナを使用したセルフコンパイル\">ARM版Dockerコンテナを使用したセルフコンパイル</h1>\n\n<p>Dockerコンテナ全体をQEMU上でARMエミュレーションしてくれるので、特に難しいことを考えずに<br />\nネイティブ環境と変わりなくあつかえる。<br />\nでも、かなり遅い(実機よりちょっと速い?同じくらい?)。<br />\n試した環境では、x86_64な環境でクロスコンパイルした場合の15倍くらいかかった。  <br />\n(M1 Mac上でACVMを使うとかなり早いという噂も…M1 Mac持ってない😢  <a href=\"https://qiita.com/kose3/items/af9edc9c40c9ae8fc5c3\" target=\"_blank\">参考</a>  )</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h3 id=\"qemuのインストール\">qemuのインストール</h3>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_emu\n</code></pre></div></div>\n\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm32v7/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成\">patchファイルを作成</h3>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_emu_1 ov_pi_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n以下のオプションを追加すると少しは速くなるかと思ったが、あまり変わらない。</p>\n  <ul>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_OPENCV=OFF</code></li>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_SAMPLES=OFF</code></li>\n  </ul>\n</blockquote>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。</p>\n\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./inference_engine</code> がない\n    <ul>\n      <li>実体は <code class=\"language-plaintext highlighter-rouge\">deployment_tools/inference_engine</code> なので、シンボリックリンクを作れば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/opencv/</code>からコピーすれば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>opencvのpythonモジュールがない\n        <ul>\n          <li>どこから持ってくれば良いんだろう?</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h3 id=\"実機へのインストール\">実機へのインストール</h3>\n<p>CPU extensionだけなら<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l/</code><br />\nへコピーするだけで良い。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれはmake install してもこれはコピーされないらしい。</p>\n</blockquote>\n\n<p>openVINO全体のインストールなら<code class=\"language-plaintext highlighter-rouge\">work/opt/intel/openvino</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/</code>にコピーすれば良いのだけど、opencvのpythonインタフェースがないので注意。<br />\nということで、実際に試していない…</p>\n\n<blockquote>\n  <p>[!NOTE]\n※※※※ メモ ※※※※ <br />\nopenCVはここでbuildするのではなく、<br />\n<a href=\"https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/\" target=\"_blank\">https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/</a> \nからbuild済みモジュールをダウンロードして<br />\n<code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/</code><br />\nに展開している。</p>\n</blockquote>\n\n<h1 id=\"i386版32bit-x86dockerコンテナを使用したクロスコンパイル\">i386版(32bit x86)Dockerコンテナを使用したクロスコンパイル</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>セルフコンパイルは時間がかかりすぎるので、クロスコンパイルで試してみた。<br />\nかなり早くなったが、一部使えないモジュールが…<br />\n当初の目的のCPU extensionは使えるので、掲載しとく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n当初、64bit版debianをベースに作業しようとしたが、\npybind11のbuildで以下のように怒られる。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Make Error at build/_deps/pybind11-src/tools/FindPythonLibsNew.cmake:127 (message):\n  Python config failure: Python is 64-bit, chosen compiler is 32-bit\nCall Stack (most recent call first):\n  build/_deps/pybind11-src/tools/pybind11Tools.cmake:16 (find_package)\n  build/_deps/pybind11-src/CMakeLists.txt:33 (include)\n</code></pre></div>  </div>\n  <p>以下のような対策が考えられる。</p>\n  <ul>\n    <li>FindPythonLibsNew.cmakeにbit数チェックをしないようにパッチを当てる\n      <ul>\n        <li>やり方がよう分からん…</li>\n      </ul>\n    </li>\n    <li>amd64なdebianに32bitのpythonをインストールする\n      <ul>\n        <li>イマイチうまくインストールできなかった</li>\n      </ul>\n    </li>\n  </ul>\n\n  <p>しかたないので、32bit版debianで作ることにした</p>\n</blockquote>\n\n<h2 id=\"準備-1\">準備</h2>\n\n<h3 id=\"作業用ディレクトリの準備-1\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_buster_32 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_buster_32\n</code></pre></div></div>\n<h3 id=\"openvino-の-gitリポジトリを-clone-1\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> i386/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> armhf <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-armhf <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:armhf <span class=\"se\">\\\n</span>    libgtk-3-dev:armhf <span class=\"se\">\\\n</span>    libavcodec-dev:armhf <span class=\"se\">\\\n</span>    libavformat-dev:armhf <span class=\"se\">\\\n</span>    libswscale-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:armhf <span class=\"se\">\\\n</span>    libpython3-dev:armhf <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python-argparse <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"c\"># aptでインストールするので削除</span>\n<span class=\"c\"># RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.3/cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     tar xzvf cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     (cd cmake-3.21.3 && ./bootstrap --parallel=$(nproc --all) -- -DCMAKE_USE_OPENSSL=OFF && make --jobs=$(nproc --all) && make install) && \\</span>\n<span class=\"c\">#     rm -rf cmake-3.21.3 cmake-3.21.3.tar.gz</span>\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"patchファイルを作成-1\">patchファイルを作成</h3>\n\n<p>以下の2つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch1.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake\nindex 6cb15a0..66a1ef6 100644\n</span><span class=\"gd\">--- a/cmake/dependencies.cmake\n</span><span class=\"gi\">+++ b/cmake/dependencies.cmake\n</span><span class=\"p\">@@ -19,8 +19,9 @@</span> if(CMAKE_CROSSCOMPILING AND CMAKE_HOST_SYSTEM_NAME MATCHES Linux AND CMAKE_HOST_\n     find_program(\n         SYSTEM_PROTOC\n         NAMES protoc\n<span class=\"gd\">-        PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n-        NO_DEFAULT_PATH)\n</span><span class=\"gi\">+        # PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n+        # NO_DEFAULT_PATH)\n+        )\n</span>     if(NOT SYSTEM_PROTOC)\n         message(FATAL_ERROR \"[ONNX IMPORTER] Missing host protoc binary\")\n     endif()\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる-1\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../patch1.patch<span class=\"o\">)</span>\n<span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino apply ../../patch1.patch\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_buster_32 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32_1</code> を使用。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_buster_32_1 ov_pi_buster_32 /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/386) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_buster_32_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_buster_32_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make-1\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n\n<p>コンテナから出て、<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の \n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l</code>/<br />\nへコピーする</p>\n\n<blockquote>\n  <p>[!WARNING]\ncythonの出力がx86のコードを吐くので、pythonモジュールの一部に正常に動作しないものがある。<br />\npythonモジュールを使いたいときはセルフコンパイルするしかないかな?</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerでopenVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerでopenVINO</h1>\n      <p>DockerでopenVINOプログラムの開発</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>DockerコンテナでopenVINOのプログラム開発を行う手順。<br />\n↓ここを参考にUbuntu 20.04/openVINO 2021.3に変更してみる。ついでによく使う機能の準備もやっておく。<br />\n<a href=\"https://kuttsun.blogspot.com/2021/06/openvino-docker.html\">https://kuttsun.blogspot.com/2021/06/openvino-docker.html</a></p>\n\n<h1 id=\"dockerイメージの作成\">Dockerイメージの作成</h1>\n\n<p>上の参照先を参考に公式イメージに必要な処理を加えておく。<br />\nDockerfile は以下。<br />\n参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>ベースをopenVINO/ubuntu20に変更</li>\n  <li>sudoとvimとless入れとく。sudoはパスワードなしで動作するようにしとく。</li>\n  <li>開発マシンなのでbaskhの補完機能を有効にしておく</li>\n  <li>キーバインド変更 ( <code class=\"language-plaintext highlighter-rouge\">^p</code> / <code class=\"language-plaintext highlighter-rouge\">^n</code> )</li>\n  <li>日本語文字化け対策</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code> がキー入力待ちになってbuildエラーになるので<code class=\"language-plaintext highlighter-rouge\">-y</code>オプションを追加</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-docker highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースイメージ</span>\n<span class=\"k\">FROM</span><span class=\"s\"> openvino/ubuntu20_dev:2021.3</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">ENV</span><span class=\"s\"> DEBIAN_FRONTEND=noninteractive</span>\n\n<span class=\"c\"># sudo と vim と less のインストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install sudo </span>vim less <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo </span>openvino <span class=\"nv\">ALL</span><span class=\"o\">=</span><span class=\"se\">\\(</span>root<span class=\"se\">\\)</span> NOPASSWD:ALL <span class=\"o\">></span> /etc/sudoers.d/openvino <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">chmod </span>0440 /etc/sudoers.d/openvino\n\n<span class=\"c\"># bashの補完機能 & キーバインドの設定 & 日本語文字化け対策</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nb\">install </span>bash-completion <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"s2\">\". /usr/share/bash-completion/bash_completion\"</span> <span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-n</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-forward' </span><span class=\"se\">\\n\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-p</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-backward'</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">export LANG=C.UTF-8</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">export LANGUAGE=en_US:</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc\n\n<span class=\"c\"># 依存パッケージのインストール(-yオプションで Yes自動選択)</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies <span class=\"o\">&&</span> ./install_openvino_dependencies.sh <span class=\"nt\">-y</span>\n\n<span class=\"c\"># サンプル、デモアプリのビルド</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/samples/cpp <span class=\"o\">&&</span> ./build_samples.sh\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/demos <span class=\"o\">&&</span> ./build_demos.sh\n<span class=\"c\"># /opt/intel/openvino_2021/deployment_tools/demo にデモアプリがある</span>\n\n<span class=\"c\"># 他に必要なものを適宜インストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>wget git python3-pip\n<span class=\"k\">RUN </span>pip3 <span class=\"nb\">install </span>onnxruntime flask\n\n<span class=\"c\"># aptのクリア</span>\n<span class=\"k\">RUN </span>apt clean <span class=\"o\">&&</span> <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> /var/lib/apt/lists/<span class=\"k\">*</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> openvino</span>\n\n<span class=\"c\"># bash起動</span>\n<span class=\"k\">CMD</span><span class=\"s\"> [ \"/bin/bash\" ]</span>\n</code></pre></div></div>\n\n<h1 id=\"ビルド\">ビルド</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker build <span class=\"nt\">-t</span> myopenvino/ubuntu20_dev:2021.3 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h1 id=\"コンテナの生成\">コンテナの生成</h1>\n<p>参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>カレントディレクトリ下のworkを/workに割り当てるように追加</li>\n  <li>GPU関連の設定を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ./work\ndocker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"se\">\\</span>\n       <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"se\">\\</span>\n       myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nX-Windowの表示先(<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code> 変数) は ここで固定されるので、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を変更したい場合は<br />\nコンテナをスタートした後、コンテナ内で手打ちで設定するか、<br />\n変更後の<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を設定したターミナルから以下を実行。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> openvino_2021.3 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<p>Windows の場合は以下な感じ。<br />\nDISPLAY変数は環境に合わせて変更してちょ。<br />\nNCS周りの設定は削除してある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.204:0.0 <span class=\"nt\">-v</span> %CD%<span class=\"se\">\\w</span>ork:/work myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ndocker をWSL上のコマンドラインから起動しているときは<code class=\"language-plaintext highlighter-rouge\">%CD%</code>でなく<code class=\"language-plaintext highlighter-rouge\">$PWD</code><br />\nPowerShellでコマンドを複数行に分割する場合は、行末記号は<code class=\"language-plaintext highlighter-rouge\">\\</code> ではなく <code class=\"language-plaintext highlighter-rouge\">`</code><br />\nコマンドプロンプトでは<code class=\"language-plaintext highlighter-rouge\">^</code> NYAGOSは分からん😢<br />\nそれぞれ違ってびみょーにストレス…</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> openvino_2021.3\n</code></pre></div></div>\n\n<p>コンテナ内でデモを動かしてみる<br />\n(デモの実行で必要なライブラリ類がインストールされたりするので、実行しましょう)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ~/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/demo1.log\n\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/dem2.log\n</code></pre></div></div>\n\n<p>前に作ったプログラムを試してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\ngit clone https://github.com/ippei8jp/ov_trial.git\n<span class=\"c\"># 入力画像の準備</span>\n<span class=\"nb\">cd </span>ov_trial/images/\nbash download.sh\n<span class=\"c\"># モデルファイルの準備(mobilenet-ssdのダウンロードがエラーになるけど大勢に影響ない) </span>\n<span class=\"nb\">cd</span> ../convert_model_ssd/\nbash convert_model_ssd.sh \n\n<span class=\"c\"># 認識してみる</span>\n<span class=\"nb\">cd</span> ../ssd/\nbash test.sh list\nbash test.sh 6\n</code></pre></div></div>\n\n<h1 id=\"ncs2の使用ubuntuのみ\">NCS2の使用(ubuntuのみ)</h1>\n<p>ubuntuではホストに接続したNCS2を使用することもできる。<br />\nただし、DockerコンテナからNCS2を使用するにはDokerホスト側にドライバをインストールしておく必要がある。<br />\n(udevルールだけ?イマイチ自信ないのでフルパッケージでインストールしておいた)<br />\n以下の部分がNCS2を使用するために必要な設定。(上記コマンド例では設定済み)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PyPiからopenVINOをインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>PyPiからopenVINOをインストール</h1>\n      <p>PyPiで配布されているopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>openVINOを使いたいが、SDKをインストールするのは面倒というズボラさんのためのTips😅<br />\nNCS2を使うためのドライバをインストールするにはSDK必要だが(WSLだとそもそもNCS2は使えないけど)、CPUだけでさくっと使いたいときなんかは有効かな?<br />\nあと、SDKインストール済みだけど、別のバージョン試したいときとか。</p>\n\n<p>対象はWindwos(試してないけど)、Ubuntu(x86_64 の 18.04、20.04)。(macOSも対象らしいけど使ったことないのでよーわからん😅)<br />\nPython は3.6、3.7、3.8<br />\nRasoberryPiは現在のところ対象外。</p>\n\n<h1 id=\"pypiのページ\">PyPiのページ</h1>\n\n<p>PyPiは以下にページがある。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino/\" target=\"_blank\">openvino · PyPI</a></li>\n</ul>\n\n<p>ただし、現状はUbuntuでPython3.8を使用する場合は以下を使用(Ubuntu Python3.7は両方用意されているらしい)。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino-ubuntu20/\" target=\"_blank\">openvino-ubuntu20 · PyPI</a></li>\n</ul>\n\n<h1 id=\"pythonモジュールのインストール\">pythonモジュールのインストール</h1>\n<p>上記ページに記載された通りだが、大抵openCVも必要になるので、インストールしておく。 <br />\n最近はopenCVも<code class=\"language-plaintext highlighter-rouge\">pip</code>コマンドイッパツでインストールできるのでラクチン😊</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOのインストール</span>\npip <span class=\"nb\">install </span>openvino\n<span class=\"c\"># またはこちら</span>\n<span class=\"c\"># pip install openvino-ubuntu20</span>\n\n<span class=\"c\"># openCVのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<p>インストールすると、現状、以下のモジュールがインストールされる(ubuntuでpython3.7/3.8の場合)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>numpy==1.20.1\nopencv-python==4.5.1.48\nopenvino==2021.2\ntbb==2020.3.254\n</code></pre></div></div>\n\n<h1 id=\"実行前の準備\">実行前の準備</h1>\n\n<p>openVINOモジュールは<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>の設定が必要なので、\nシステムのpythonを使用するときは上記ページに記載された通りに<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>を設定する。<br />\nただし、pyenvを使用している場合は、以下のように設定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"k\">}</span>:<span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/versions/<span class=\"sb\">`</span>pyenv version-name<span class=\"sb\">`</span>/lib\n</code></pre></div></div>\n\n<p>pyenvで環境を切り替えることを考えると、<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>で設定するより、スクリプト実行ラッパで設定した方が無難かも。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu20.04 on WSL2 で openVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu20.04 on WSL2 で openVINO</h1>\n      <p>WSL2上のUbuntu20.04でopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"環境構築\">環境構築</h1>\n\n<p>WSL環境ではNCS2は使えないが、CPU演算での実行は可能。<br />\n以下インストール~デモ実行までのメモ。</p>\n\n<p>基本は以下を参考に。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></li>\n  <li><a href=\"/memoBlog/2020/10/18/openVINO_ubuntu_3.html\">openVINO フルパッケージ(2021.1)をインストール(追加)</a></li>\n</ul>\n\n<p>WSLのインストールメモはこちら:<a href=\"/memoBlog/2021/03/03/WSL_memo.html\">WSL2 メモ</a><br />\nUbuntuは20.04。<br />\n今回はopenVINO 2021.2を使用した。</p>\n\n<h2 id=\"pyenvの仮想環境を作成\">pyenvの仮想環境を作成</h2>\n<p>まずは、pythonの環境を準備。<br />\n以下ではpythonは3.7.10を使用。(3.8を使えばTensorflow2を使えるらしい(?))</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.10 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n\n<p>ubuntuのライブラリ類をインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev \n<span class=\"c\"># 他にもあるかもしれんけど、とりあえずこれだけ。</span>\n</code></pre></div></div>\n\n<p>WSLでは以下も必要(グラフィック系処理が入ってないので)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgtk-3-0\n</code></pre></div></div>\n<h2 id=\"ダウンロードしたopenvinoアーカイブの展開とインストール\">ダウンロードしたopenVINOアーカイブの展開とインストール</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/mnt/f/Download/</code>にダウンロードしたファイルがあるとして。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\n<span class=\"nb\">tar </span>xzvf /mnt/f/Download/l_openvino_toolkit_p_2021.2.185.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2021.2.185/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n<span class=\"c\"># なぜかXwindow設定しててもテキストベースになる...</span>\n<span class=\"c\"># てきとーに答えていく。</span>\n</code></pre></div></div>\n\n<p>スクリプト終了したら、以下に従い進めていく。<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html</a></p>\n\n<h2 id=\"後半のコマンド一覧と注意事項\">後半のコマンド一覧と注意事項</h2>\n\n<ul>\n  <li>環境変数の設定とpythonモジュールのインストール</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># このコマンド、~/.bashrcにも書いておくこと</span>\n<span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n\n<span class=\"c\"># このコマンド実行すると、pyenvでなくsystemのpipでモジュールがインストールされるので実行しない</span>\n<span class=\"c\"># しかも、systemのpip3が壊れる...すごい罠😡</span>\n<span class=\"c\"># cd /opt/intel/openvino_2021/deployment_tools/model_optimizer/install_prerequisites/</span>\n<span class=\"c\"># sudo -E ./install_prerequisites.sh </span>\n\n<span class=\"c\"># 代わりに以下を実行(上記スクリプトは結局これを実行しているだけなので)</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npython 3.7で実行すると、</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version >= \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われるけど、無視して良い。<br />\nこれはPython3.8未満か以上で異なるバージョンのTensorflowがインストールされるように設定されているため。<br />\nちなみに、python 3.8でやると</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version < \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nもし、<code class=\"language-plaintext highlighter-rouge\">install_prerequisites.sh</code>を実行してしまい、pip3が壊れてしまった場合は\n以下で復旧する(一旦アンインストールしてから再インストール)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove python3-pip \n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip \n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"デモ実行\">デモ実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino_2021/deployment_tools/demo\n<span class=\"nb\">sudo cp</span> /work/.python-version <span class=\"nb\">.</span>\n\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/demo1.log\n\n<span class=\"c\"># このデモはグラフィック表示可能環境で実行する必要がある。  </span>\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/dem2.log\n</code></pre></div></div>\n\n<h1 id=\"別の仮想環境を用意する場合\">別の仮想環境を用意する場合</h1>\n\n<p>別の仮想環境を用意するときは以下で新しい仮想環境下にモジュールをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージ(2021.1)をインストール(追加)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージ(2021.1)をインストール(追加)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2021.1対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a>で\nubuntuへopenVINO 2020.3のインストールしたが、今回は 2021.1 を追加インストールしたのでメモ。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>前に登録したときに通知されたURLから「Choose Version」でバージョン選んでダウンロードできる。<br />\n新しく登録しなても大丈夫(登録方法は<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>参照)。</p>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>これは前回と同じ。</p>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫だが、<br />\ncmakeは<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたバージョンだと古くてNGといわれてしまうので、<br />\n別途本家からダウンロードしてインストールする(ubuntu 18.04の場合。20.04だとたぶん<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたので大丈夫)。</p>\n\n<ul>\n  <li>既に<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストール済みの場合は、アンインストールする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt purge <span class=\"nt\">--auto-remove</span> cmake\n</code></pre></div>    </div>\n  </li>\n  <li>本家からダウンロードして展開\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/Kitware/CMake/releases/download/v3.18.4/cmake-3.18.4-Linux-x86_64.tar.gz  \n<span class=\"nb\">tar </span>xzvf cmake-3.18.4-Linux-x86_64.tar.gz \n</code></pre></div>    </div>\n  </li>\n  <li>/opt ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv </span>cmake-3.18.4-Linux-x86_64 /opt/\n</code></pre></div>    </div>\n  </li>\n  <li>/usr/bin ディレクトリにシンボリックリンク作成\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /opt/cmake-3.18.4-Linux-x86_64/bin/<span class=\"k\">*</span> /usr/bin/\n</code></pre></div>    </div>\n  </li>\n  <li>バージョン確認\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">--version</span> \n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>インストール手順も<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>と同じで大丈夫。</p>\n\n<p>完了したらこれが表示されるページのURLは以下に変更されている。<br />\n<a href=\"https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2021.1/openvino_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<p>2020.3インストール済みだと端折っても大丈夫かと思ったけど、微妙にパッケージ増えてたりするので、再度やった方が良い。<br />\n環境変数の設定のために、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に記述する処理は以下に変更(<code class=\"language-plaintext highlighter-rouge\">openvino</code>→<code class=\"language-plaintext highlighter-rouge\">openvino_2021</code>)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!WARNING]\n<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を実行すると、再度<code class=\"language-plaintext highlighter-rouge\">apt</code>で<code class=\"language-plaintext highlighter-rouge\">cmake</code>がインストールされてしまいます。<br />\nopenVINOのインストール完了後であれば<code class=\"language-plaintext highlighter-rouge\">cmake</code>のバージョンが古くても大丈夫ですが、<br />\n気になるなら、再度アンインストールとシンボリックリンクの作成を行います。<br />\n(実行前に<code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code>を編集してcmake消しておいても良いけど)</p>\n</blockquote>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>これは2020.3インストール済みだと端折ってもOK。<br />\n初めてインストールなら<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">前回のメモ</a>を参照。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール(改訂版)</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする(Ver.2020.3対応)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>以前、<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a>で\nubuntuへのインストール手順を書いたが、今読み返すと結構分かりにくかったので改訂版を書いとく。<br />\n今回はNCS2をubuntuで使えるようにしたので、その手順も追加。<br />\nついでに、今日(2020/06/16)現在の最新版Ver.2020.3での手順確認したので、反映しておく。</p>\n\n<p>使用したubuntuのバージョンは18.04。</p>\n\n<p>参考 :<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">AIを始めよう!OpenVINOのインストールからデモの実行まで[R4対応]</a></p>\n\n<h1 id=\"ソフトウェアのダウンロード\">ソフトウェアのダウンロード</h1>\n<h2 id=\"intelへの登録\">Intelへの登録</h2>\n<p>何やら登録しないとダウンロードさせてくれないらしい。</p>\n<ul>\n  <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download.html\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a> <br />\nLinux* (supports Ubuntu, CentOS, and Yocto Project)を選択\n    <ul>\n      <li><a href=\"https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download/linux.html\">Free Download</a>  <br />\n<span style=\"border: 1px solid;\">Register & Download</span>をクリック\n        <ul>\n          <li><a href=\"https://software.seek.intel.com/openvino-toolkit?os=linux\">Choose & Download Intel® Distribution of OpenVINO™ Toolkit</a><br />\n必要事項を記入して<span style=\"border: 1px solid;\">Submit</span>をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"ダウンロード\">ダウンロード</h2>\n<p>登録したメールアドレス宛にメールが届くので、その中の<span style=\"border: 1px solid;\">Download></span>をクリック<br />\n開いたページでダウンロードするバージョンを選択して、<span style=\"border: 1px solid;\">Full Package</span>をクリックしてダウンロードファイルを保存<br />\n※ 登録しないとダウンロードさせてくれないみたいなので、ダウンロードファイルへの直リンクは記載をやめとく。</p>\n\n<h1 id=\"python-環境の準備\">python 環境の準備</h1>\n<p>openVINO用のpython環境を用意しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work1/\npyenv virtualenv 3.7.7 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n<p>あとで「入ってない」って言われるので先にインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev\n</code></pre></div></div>\n\n<h2 id=\"openvinoのインストール\">openVINOのインストール</h2>\n<p>ダウンロードしたファイルを展開してインストールスクリプトを実行する。<br />\n今回はバージョン 2020.3 で確認した。<br />\n最新版は <a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html</a> を参照。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf l_openvino_toolkit_p_<version>.tgz\n<span class=\"nb\">cd </span>l_openvino_toolkit_p_<version>/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n<p>GUIで次へを押していく。</p>\n\n<p>完了したらこれが表示されるので、したがって進める。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h2 id=\"インストールスクリプト実行後の設定\">インストールスクリプト実行後の設定</h2>\n\n<h3 id=\"install-external-software-dependencies\">Install External Software Dependencies</h3>\n<p>依存パッケージのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh \n</code></pre></div></div>\n\n<h3 id=\"set-the-environment-variables\">Set the Environment Variables</h3>\n<p>環境変数の設定<br />\n~/.bashrc に以下の一文を追加。これでこの後開くコンソールでは環境変数が設定される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>source /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<p>現在のターミナルでも使えるように以下のコマンドを実行しておく。コンソール開きなおしてもOK。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<h3 id=\"configure-the-model-optimizer\">Configure the Model Optimizer</h3>\n<p>モデルオプティマイザのインストール</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh \n</code></pre></div></div>\n\n<p>上記スクリプトではsystemのpython3にpipモジュールがインストールされてしまうので、<br />\npyenv環境にも必要なpipモジュールをインストールしておく</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv shell openVINO                       <span class=\"c\"># python環境を固定したいので</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\npyenv shell <span class=\"nt\">--unset</span>                        <span class=\"c\"># python環境を戻しておく</span>\n</code></pre></div></div>\n\n<h3 id=\"run-the-verification-scripts-to-verify-installation\">Run the Verification Scripts to Verify Installation</h3>\n<p>デモ実行<br />\n「Verify Installation」って書いてあるけど、実行必須。</p>\n\n<ul>\n  <li>デモ用ディレクトリに移動\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo/\n</code></pre></div>    </div>\n  </li>\n  <li>sudoでpyenvが使えないので、代わりに <code class=\"language-plaintext highlighter-rouge\">/work1</code>  で作成した <code class=\"language-plaintext highlighter-rouge\">.python-version</code>をコピーしておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp</span> /work1/.python-version <span class=\"nb\">.</span>\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境にデモ環境で必要なpipモジュールをインストールしておく 。Systemのpython使うときは↓のスクリプト実行時にインストールされる。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その1\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/demo1.log\n</code></pre></div>    </div>\n  </li>\n  <li>デモ build & RUN  その2\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work1/tmp/dem2.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h3 id=\"steps-for-intel-processor-graphics-gpu\">Steps for Intel® Processor Graphics (GPU)</h3>\n<p>今回はGPUを使わないのでスキップ</p>\n\n<h3 id=\"steps-for-intel-movidius-neural-compute-stick-and-intel-neural-compute-stick-2\">Steps for Intel® Movidius™ Neural Compute Stick and Intel® Neural Compute Stick 2</h3>\n\n<p>NCS2の準備<br />\n色々書いてあるけど、これ一発でOK。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n中ではこんなことをやってます。<br />\nグループusersに自分を追加<br />\n(ログアウト & 再ログインするまで追加は反映されません)<br />\nudevルールの作成と再ロード</p>\n</blockquote>\n\n<p>NCS2をUSBポートにブッ挿すして認識したか確認</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下があったら認識できてる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ID 03e7:2485\n</code></pre></div></div>\n\n<h3 id=\"steps-for-intel-vision-accelerator-design-with-intel-movidius-vpus\">Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPUs</h3>\n<p>今回はVPUを使わないのでスキップ</p>\n\n<p>デモプログラムの実行で動作確認</p>\n\n<p>で、Run a Sample Application に行く前に、ログアウト&再ログインでいいはずだけど、念のためリブート。</p>\n\n<h3 id=\"run-a-sample-application\">Run a Sample Application</h3>\n<p>リブートして開いてたページが分からなくなるといけないので、念のためURL貼っとく。<br />\n<a href=\"https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample\">https://docs.openvinotoolkit.org/2020.2/_docs_install_guides_installing_openvino_linux.html#run-a-sample</a></p>\n\n<ul>\n  <li>デモ実行ディレクトリに移動。\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ~/inference_engine_samples_build/intel64/Release\n</code></pre></div>    </div>\n  </li>\n  <li>CPUでデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> CPU\n</code></pre></div>    </div>\n  </li>\n  <li>NCS2でデモ実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./classification_sample_async <span class=\"nt\">-i</span> /opt/intel/openvino/deployment_tools/demo/car.png <span class=\"nt\">-m</span> ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml <span class=\"nt\">-d</span> MYRIAD\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<p>このページの手順はここでおしまい。</p>\n\n<h1 id=\"他のサンプルも試してみよう\">他のサンプルも試してみよう。</h1>\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n<h3 id=\"前準備\">前準備</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work1/NCS/sample <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work1/NCS/sample/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release /opt/intel/openvino_2020.3.194/deployment_tools/inference_engine/samples/cpp/\n</code></pre></div></div>\n\n<h3 id=\"ssdを試してみよう\">SSDを試してみよう</h3>\n<h4 id=\"build\">build</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">-j2</span> object_detection_sample_ssd\n</code></pre></div></div>\n<h4 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R4/20200117_150000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n</code></pre></div></div>\n\n<h4 id=\"実行\">実行</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./intel64/Release/object_detection_sample_ssd <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> /work/data/data2/z_20141013051441.jpg \n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nコマンド実行時の<code class=\"language-plaintext highlighter-rouge\">-i</code>オプションは入力画像ファイル。<br />\n人の顔が写っているjpegファイルを指定しましょう。 \n顔が写ってなければ顔検出できません(^^ゞ</p>\n</blockquote>\n\n<p><code class=\"language-plaintext highlighter-rouge\">[ INFO ] Execution successful</code>と表示されたら実行成功だと思う。</p>\n\n<h4 id=\"結果画像を表示してみる\">結果画像を表示してみる。</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>eog out_0.bmp \n</code></pre></div></div>\n\n<h4 id=\"おーーーー\"><strong><em>おーーーー</em></strong></h4>\n\n<h1 id=\"ここまでの作業でインストールしたpipパッケージ一覧\">ここまでの作業でインストールしたpipパッケージ一覧</h1>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.9.0\nastor==0.8.1\ncertifi==2020.4.5.2\nchardet==3.0.4\ndecorator==4.4.2\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.2.0\ngraphviz==0.8.4\ngrpcio==1.29.0\nh5py==2.10.0\nidna==2.9\nimportlib-metadata==1.6.1\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.2\nMarkdown==3.2.2\nmxnet==1.5.1\nnetworkx==2.4\nnumpy==1.18.5\nonnx==1.7.0\nopt-einsum==3.2.1\nprotobuf==3.6.1\nPyYAML==5.3.1\nrequests==2.23.0\nsix==1.15.0\ntensorboard==1.15.0\ntensorflow==1.15.3\ntensorflow-estimator==1.15.1\ntermcolor==1.1.0\ntyping-extensions==3.7.4.2\nurllib3==1.25.9\nWerkzeug==1.0.1\nwrapt==1.12.1\nzipp==3.1.0\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD(その2)</h1>\n      <p>openVINOのSSDのサンプルプログラムのモデルデータを変更してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> でSSDを動かしてみたが、\n検出できるオブジェクトの種類が少なくてちょっと寂しかったので、別のモデルがないか探してみた。</p>\n\n<p>で、調べてみると、openCVのopen_model_zoo以外にもTensorFlowの公式モデルなどをダウンロードして変換するスクリプトが用意されていた。<br />\nで、以下手順。</p>\n\n<h1 id=\"モデルのダウンロードモデルのirへの変換\">モデルのダウンロード&モデルのIRへの変換</h1>\n\n<h4 id=\"テンポラリディレクトリの作成移動\">テンポラリディレクトリの作成&移動</h4>\n\n<p>とりあえず作業用のディレクトリを作成しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/temp\n<span class=\"nb\">cd</span> /work/temp\n</code></pre></div></div>\n\n<h3 id=\"使用できるモデルの一覧を表示\">使用できるモデルの一覧を表示</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py  <span class=\"nt\">--print_all</span>\n</code></pre></div></div>\n\n<p>ちなみに、モデル毎の設定は以下にあるので、雰囲気で解読してちょ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>${INTEL_OPENVINO_DIR}/deployment_tools/open_model_zoo/models/public/${modelname}/model.yml\n</code></pre></div></div>\n\n<h3 id=\"このへんのモデルを使ってみる\">このへんのモデルを使ってみる</h3>\n\n<p>なんとなく、mobilenetが小さそうなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssd_mobilenet_v2_coco\n</code></pre></div></div>\n\n<p>または</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">modelname</span><span class=\"o\">=</span>ssdlite_mobilenet_v2\n</code></pre></div></div>\n\n<p>ssdlightの方がモデルデータが小さい。その分精度は落ちるらしい。<br />\n検出できるオブジェクトの種類は同じ。<br />\n出力は90種類だが、途中欠番があるみたいなので実質80種類くらい。<br />\n変わったところでは「テディベア」なんてのもある。試してみたらちゃんと認識した(あたりまえか…)。<br />\ncocoデータセット<a href=\"http://cocodataset.org/#home\">http://cocodataset.org/#home</a>なので、有名どころですね。<br />\nあ、「80 object categories 91 stuff categories」ってちゃんと書いてある…</p>\n\n<h3 id=\"ダウンロード\">ダウンロード</h3>\n\n<p>まずはダウンロード。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/downloader.py <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/</code>にモデルがダウンロードされる。</p>\n\n<h3 id=\"モデルデータをirファイルへ変換\">モデルデータをIRファイルへ変換</h3>\n\n<p>もとのモデルデータはTensorFlowで使用するProtocolBuffer形式なので、openVINOで使用できるIR形式に変換する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">${</span><span class=\"nv\">INTEL_OPENVINO_DIR</span><span class=\"k\">}</span>/deployment_tools/tools/model_downloader/converter.py <span class=\"nt\">--precisions</span> FP16 <span class=\"nt\">--name</span> <span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">public/${modelname}/FP16/</code>にIRモデルが出来る。</p>\n\n<h3 id=\"そのままの場所で使用しても良いが他のモデルとまとめておく\">そのままの場所で使用しても良いが、他のモデルとまとめておく</h3>\n\n<p>モデルがあちこちにあると管理しずらくなるので、他のモデルと同じところに置いておく。<br />\n必要なのはxmlとbin。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>public/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>/FP16/<span class=\"k\">${</span><span class=\"nv\">modelname</span><span class=\"k\">}</span>.<span class=\"o\">{</span>xml,bin<span class=\"o\">}</span> /work/NCS2/openvino_models/FP16/\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">.{xml,bin}</code>のところにスペースなどを入れてしまうとうまく動かないので注意。<br />\n結構「あとで読みやすいように」と入れてしまいがち(特にスクリプト書くとき)なので注意。</p>\n\n<h3 id=\"ラベルファイルの作成\">ラベルファイルの作成</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/work/NCS2/openvino_models/FP16/${modelname}.labels</code>にラベルデータを作成しておく。<br />\nなくても可。<br />\n作り方は後述。</p>\n\n<h3 id=\"実行\">実行</h3>\n\n<p><a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> の「デモ実行」と同じ手順で\nモデルファイルを差し替えて(<code class=\"language-plaintext highlighter-rouge\">--model</code>オプション)実行すれば良い。</p>\n\n<h1 id=\"ラベルファイルの作成方法\">ラベルファイルの作成方法</h1>\n\n<p>ラベルデータはモデルデータには含まれていないようなので、作成する方法を検討してみた。</p>\n\n<h3 id=\"tensorflowのmodelsモジュールをダウンロード\">tensorflowのmodelsモジュールをダウンロード</h3>\n\n<p>まず、モデルデータの作成情報のあるモジュールをダウンロードしておく。<br />\ngitでなくてもzipをダウンロードして展開しておいても可(ちょっとデカいので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git models_tf\n</code></pre></div></div>\n\n<h3 id=\"作業ディレクトリに移動\">作業ディレクトリに移動</h3>\n\n<p>あとでpythonプログラムを作成するときに色々面倒がないので、作業ディレクトリはココで。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models_tf/research\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">object_detection/samples/configs</code>から対応するconfigファイルを探して(なんとなく雰囲気で探せ!)表示<br />\n<code class=\"language-plaintext highlighter-rouge\">label_map_path</code>に記載されたファイルがlabel_mapファイル<br />\nこのとき、PATH_TO_BE_CONFIGURED は <code class=\"language-plaintext highlighter-rouge\">object_detection/data</code> に読み替えること</p>\n\n<p>ssd_mobilenet_v2_cocoの場合は以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/samples/configs/ssd_mobilenet_v2_coco.config\n</code></pre></div></div>\n\n<p>上記ファイルの場合、label_mapは以下のファイル。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>object_detection/data/mscoco_label_map.pbtxt\"\n</code></pre></div></div>\n\n<p>こにファイルにIDとラベルが定義されているが、そのままラベルファイルとしては認識できない。<br />\nIDには途中抜けがあるので注意(そのままgrepで抜き出してはダメ)</p>\n\n<h2 id=\"ラベルデータ変換プログラムを作成する\">ラベルデータ変換プログラムを作成する</h2>\n\n<p>label_map.pbtxtからラベル一覧を取得するのを手作業で行うのは大変なので、プログラムを作成する。</p>\n\n<h3 id=\"protocのインストール\">protocのインストール</h3>\n\n<p>まずは必要なモジュールのインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n</code></pre></div></div>\n\n<h3 id=\"protoファイルからpythonモジュールを作成する\">protoファイルからpythonモジュールを作成する</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>protoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"変換プログラムのソース\">変換プログラムのソース</h3>\n\n<p>label_mapからテーブルを作成するスクリプト(labelmap2labels.py)をカレントディレクトリに作成する。<br />\nやっつけ仕事なので、かなりテキトー(笑)、、、</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">object_detection.utils</span> <span class=\"kn\">import</span> <span class=\"n\">label_map_util</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"==== USAGE ====\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"    python </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> label_map_file\"</span><span class=\"p\">)</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">2</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># パラメータが1個でない\n</span>    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_map_file = \"object_detection/data/mscoco_complete_label_map.pbtxt\"\n</span><span class=\"n\">label_map_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># 第一パラメータのファイルが存在しない\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"error: '</span><span class=\"si\">{</span><span class=\"n\">label_map_file</span><span class=\"si\">}</span><span class=\"s\">' not exist</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># label_mapからカテゴリインデックスを作成\n</span><span class=\"n\">category_index</span> <span class=\"o\">=</span> <span class=\"n\">label_map_util</span><span class=\"p\">.</span><span class=\"n\">create_category_index_from_labelmap</span><span class=\"p\">(</span><span class=\"n\">label_map_file</span><span class=\"p\">)</span>\n\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># print(i)\n</span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">category_index</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">\"name\"</span><span class=\"p\">]</span>\n    <span class=\"k\">except</span><span class=\"p\">:</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'{name}\\t# {i}')\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n    \n<span class=\"c1\"># 個数確認のためにダミーを出力\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">category_index</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スクリプトの実行\">スクリプトの実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.py label_map_file\n</code></pre></div></div>\n\n<p>結果は標準出力へ出力されるので、ファイルにcastして使用する</p>\n\n<p>例:</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python labelmap2labels.pyobject_detection/data/mscoco_complete_label_map.pbtxt <span class=\"o\">></span> mscoco_complete.labels\n</code></pre></div></div>\n\n<p>出来上がったlabelsファイルを必要なところへコピーして使ってちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO で顔検出(特定人物識別)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO で顔検出(特定人物識別)</h1>\n      <p>openVINOの顔検出(特定人物識別)のサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOで顔検出(特定人物識別)するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"ソースをワークディレクトリにコピー\">ソースをワークディレクトリにコピー</h1>\n\n<p>ファイルのオーナがrootなので、編集しやすいようにワークディレクトリにソースをコピーし、そこで作業する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/face_recognition_demo <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>face_recognition_demo/\n</code></pre></div></div>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p>いくつかのモデルデータが必要になるので、ダウンロードする。<br />\nワイルドカードでファイル指定したかったので、wgetでなくcurlを使う。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/landmarks-regression-retail-0009/FP16/landmarks-regression-retail-0009.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\ncurl https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/face-reidentification-retail-0095/FP16/face-reidentification-retail-0095.<span class=\"se\">\\{</span>xml,bin<span class=\"se\">\\}</span> <span class=\"nt\">-O</span>\n<span class=\"nb\">cd</span> ..\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ncurlは「カレントディレクトリにターゲットと同じファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-O</code> と 「任意のファイル名で保存」の<code class=\"language-plaintext highlighter-rouge\">-o</code>オプションしかなく、\nwgetの「ターゲットと同じファイル名で保存先ディレクトリを指定して保存」の<code class=\"language-plaintext highlighter-rouge\">-P</code>に相当するオプションがないので、\nカレントディレクトリを保存先に移動してから<code class=\"language-plaintext highlighter-rouge\">-O</code> オプションでコマンドを実行する。</p>\n</blockquote>\n\n<h1 id=\"足りないモジュールのインストール\">足りないモジュールのインストール</h1>\n\n<p>使用するモジュールでこれまでのお試しで未インストールのモジュールがあるのでインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>scipy\n</code></pre></div></div>\n\n<h1 id=\"ソースの修正\">ソースの修正</h1>\n\n<p>ソースはそのままで問題ないが、ちょっと修正しておく。</p>\n\n<p>主な変更内容は以下の通り。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code> オプションの追加と関連処理</li>\n  <li>Unknownと識別できた場合で検出枠の色を変える</li>\n  <li>入力ファイルを絶対パスに変換(不具合対策)</li>\n  <li>出力ファイルのフォーマットのmp4対応を追加(オリジナルはaviのみ対応)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur face_recognition_demo.org/face_recognition_demo.py face_recognition_demo/face_recognition_demo.py\n</span><span class=\"gd\">--- face_recognition_demo.org/face_recognition_demo.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/face_recognition_demo.py\t2019-11-27 06:29:07.507574900 +0900\n</span><span class=\"p\">@@ -62,6 +62,10 @@</span>\n     gallery.add_argument('--run_detector', action='store_true',\n                          help=\"(optional) Use Face Detection model to find faces\" \\\n                          \" on the face images, otherwise use full images.\")\n<span class=\"gi\">+    gallery.add_argument('--run_detector_no_save', action='store_true',\n+                         help=\"(optional) Use Face Detection model to find faces\" \\\n+                         \" on the face images, otherwise use full images.\" \\\n+                         \" not save detected face image.\")\n</span> \n     models = parser.add_argument_group('Models')\n     models.add_argument('-m_fd', metavar=\"PATH\", default=\"\", required=True,\n<span class=\"p\">@@ -142,7 +146,7 @@</span>\n         log.info(\"Building faces database using images from '%s'\" % (args.fg))\n         self.faces_database = FacesDatabase(args.fg, self.face_identifier,\n                                             self.landmarks_detector,\n<span class=\"gd\">-                                            self.face_detector if args.run_detector else None, args.no_show)\n</span><span class=\"gi\">+                                            self.face_detector if args.run_detector or args.run_detector_no_save else None, args.no_show, args.run_detector_no_save)\n</span>         self.face_identifier.set_faces_database(self.faces_database)\n         log.info(\"Database is built, registered %s identities\" % \\\n             (len(self.faces_database)))\n<span class=\"p\">@@ -261,9 +265,8 @@</span>\n             .face_identifier.get_identity_label(identity.id)\n \n         # Draw face ROI border\n<span class=\"gd\">-        cv2.rectangle(frame,\n-                      tuple(roi.position), tuple(roi.position + roi.size),\n-                      (0, 220, 0), 2)\n</span><span class=\"gi\">+        color1 = (0, 220, 0) if identity.id == FaceIdentifier.UNKNOWN_ID else (0, 0, 220)\n+        cv2.rectangle(frame, tuple(roi.position), tuple(roi.position + roi.size), color1, 2)\n</span> \n         # Draw identity label\n         text_scale = 0.5\n<span class=\"p\">@@ -398,19 +401,17 @@</span>\n         try:\n             stream = int(path)\n         except ValueError:\n<span class=\"gd\">-            pass\n</span><span class=\"gi\">+            # 数字でなければ絶対パスに変換\n+            stream = osp.abspath(path)\n</span>         return cv2.VideoCapture(stream)\n \n     @staticmethod\n     def open_output_stream(path, fps, frame_size):\n         output_stream = None\n         if path != \"\":\n<span class=\"gd\">-            if not path.endswith('.avi'):\n-                log.warning(\"Output file extension is not 'avi'. \" \\\n-                        \"Some issues with output can occur, check logs.\")\n</span><span class=\"gi\">+            forcc = cv2.VideoWriter.fourcc(*'mp4v') if path.endswith('.mp4') else cv2.VideoWriter.fourcc(*'MJPG')\n</span>             log.info(\"Writing output to '%s'\" % (path))\n<span class=\"gd\">-            output_stream = cv2.VideoWriter(path,\n-                                            cv2.VideoWriter.fourcc(*'MJPG'), fps, frame_size)\n</span><span class=\"gi\">+            output_stream = cv2.VideoWriter(path, forcc, fps, frame_size)\n</span>         return output_stream\n \n \n<span class=\"gh\">diff -ur face_recognition_demo.org/faces_database.py face_recognition_demo/faces_database.py\n</span><span class=\"gd\">--- face_recognition_demo.org/faces_database.py\t2019-11-20 05:58:14.497000000 +0900\n</span><span class=\"gi\">+++ face_recognition_demo/faces_database.py\t2019-11-20 06:31:13.481819754 +0900\n</span><span class=\"p\">@@ -36,10 +36,11 @@</span>\n         def cosine_dist(x, y):\n             return cosine(x, y) * 0.5\n \n<span class=\"gd\">-    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False):\n</span><span class=\"gi\">+    def __init__(self, path, face_identifier, landmarks_detector, face_detector=None, no_show=False, no_db_save=False):\n</span>         path = osp.abspath(path)\n         self.fg_path = path\n         self.no_show = no_show\n<span class=\"gi\">+        self.no_db_save = no_db_save\n</span>         paths = []\n         if osp.isdir(path):\n             paths = [osp.join(path, f) for f in os.listdir(path) \\\n<span class=\"p\">@@ -96,7 +97,7 @@</span>\n                     self.add_item(descriptor, label)\n \n     def ask_to_save(self, image):\n<span class=\"gd\">-        if self.no_show:\n</span><span class=\"gi\">+        if self.no_show or self.no_db_save:\n</span>             return None\n         save = False\n         label = None\n<span class=\"p\">@@ -209,12 +210,14 @@</span>\n             match = len(self.database)-1\n         else:\n             filename = \"{}-{}.jpg\".format(label, len(self.database[match].descriptors)-1)\n<span class=\"gd\">-        filename = osp.join(self.fg_path, filename)\n-\n-        log.debug(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n-        if osp.exists(filename):\n-            log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n-        cv2.imwrite(filename, image)\n</span><span class=\"gi\">+        \n+        if name :\n+            filename = osp.join(self.fg_path, filename)\n+            log.info(\"Dumping image with label {} and path {} on disk.\".format(label, filename))\n+            if osp.exists(filename):\n+                log.warning(\"File with the same name already exists at {}. So it won't be stored.\".format(self.fg_path))\n+            else :\n+                cv2.imwrite(filename, image)\n</span>         return match\n \n     def add_item(self, desc, label):\n</code></pre></div></div>\n\n<h1 id=\"前準備\">前準備</h1>\n\n<p>識別したい顔の画像を適当なディレクトリに保存しておく。ファイル形式はjpgまたはpng。<br />\n一人ずつ1画像で顔部分のみ切り出しておく。<br />\n複数の人の顔を識別したい場合はそれぞれ別々に保存しておく。</p>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"実行用スクリプトの作成\">実行用スクリプトの作成</h2>\n\n<p>実行コマンドが長ったらしくて入力が面倒なので、以下のスクリプト(demo.sh)を作成しておく。<br />\nUbuntuとRaspberrypiを識別して自動でコマンドオプションを変更するようにしてある。 \n作成したら実行属性を付与しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/bin/bash</span>\n\n<span class=\"nv\">cmd</span><span class=\"o\">=</span><span class=\"s2\">\"face_recognition_demo.py\"</span>\n\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"       -m_fd models/face-detection-retail-0004.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_lm models/landmarks-regression-retail-0009.xml\"</span>\n<span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -m_reid models/face-reidentification-retail-0095.xml\"</span>\n\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"sb\">`</span><span class=\"nb\">uname</span> <span class=\"nt\">-m</span><span class=\"sb\">`</span> <span class=\"o\">==</span> <span class=\"s2\">\"armv7l\"</span> <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Raspberry Pi\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_fd MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_lm MYRIAD\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -d_reid MYRIAD\"</span>\n<span class=\"k\">else\n    </span><span class=\"nb\">echo</span> <span class=\"s2\">\"Ubuntu\"</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> --cpu_lib /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so\"</span>\n<span class=\"k\">fi\n\n\nif</span> <span class=\"o\">[</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 0 <span class=\"nt\">-o</span> <span class=\"nv\">$# </span><span class=\"nt\">-eq</span> 1 <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n\t<span class=\"c\"># パラメータなし/1個はエラー</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\n</span><span class=\"s2\">==== usage ====\"</span>\n    <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"nv\">$0</span><span class=\"s2\"> database_dir input_file [other option(s)]</span><span class=\"se\">\\n\\n\\n</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">exit </span>1\n<span class=\"k\">else\n    </span><span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> -fg </span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\"> --input </span><span class=\"k\">${</span><span class=\"nv\">2</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n    <span class=\"c\"># 3番目以降すべてのパラメータを追加</span>\n    <span class=\"nv\">opt</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"p\">@</span>:3:<span class=\"p\">(</span><span class=\"nv\">$#-2</span><span class=\"p\">)</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi\n</span><span class=\"nb\">echo</span> <span class=\"s2\">\"python </span><span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span><span class=\"s2\"> </span><span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\npython <span class=\"k\">${</span><span class=\"nv\">cmd</span><span class=\"k\">}</span> <span class=\"k\">${</span><span class=\"nv\">opt</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n\n<p>第1パラメータに識別子する顔画像を保存したディレクトリ、第2パラメータに入力ビデオファイル名を指定する。<br />\nこれらのパラメータは省略不可。<br />\n追加でオプションを指定したい場合は第3パラメータ以降に指定する。<br />\nたとえば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo.sh data data/video.mp4  <span class=\"nt\">--output</span> result.mp4\n</code></pre></div></div>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python face_recognition_demo.py <span class=\"nt\">-h</span>\nusage: face_recognition_demo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-i</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-o</span> PATH] <span class=\"o\">[</span><span class=\"nt\">--no_show</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-tl</span><span class=\"o\">]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-cw</span> CROP_WIDTH] <span class=\"o\">[</span><span class=\"nt\">-ch</span> CROP_HEIGHT] <span class=\"nt\">-fg</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">--run_detector</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--run_detector_no_save</span><span class=\"o\">]</span>\n                                <span class=\"nt\">-m_fd</span> PATH <span class=\"nt\">-m_lm</span> PATH <span class=\"nt\">-m_reid</span> PATH\n                                <span class=\"o\">[</span><span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}]</span>\n                                <span class=\"o\">[</span><span class=\"nt\">-l</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-c</span> PATH] <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]]\n                                <span class=\"o\">[</span><span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]] <span class=\"o\">[</span><span class=\"nt\">-exp_r_fd</span> NUMBER]\n                                <span class=\"o\">[</span><span class=\"nt\">--allow_grow</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit\n\n</span>General:\n  <span class=\"nt\">-i</span> PATH, <span class=\"nt\">--input</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to the input video <span class=\"o\">(</span><span class=\"s1\">'0'</span> <span class=\"k\">for </span>the\n                        camera, default<span class=\"o\">)</span>\n  <span class=\"nt\">-o</span> PATH, <span class=\"nt\">--output</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Path to save the output video to\n  <span class=\"nt\">--no_show</span>             <span class=\"o\">(</span>optional<span class=\"o\">)</span> Do not display output\n  <span class=\"nt\">-tl</span>, <span class=\"nt\">--timelapse</span>      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Auto-pause after each frame\n  <span class=\"nt\">-cw</span> CROP_WIDTH, <span class=\"nt\">--crop_width</span> CROP_WIDTH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this width\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n  <span class=\"nt\">-ch</span> CROP_HEIGHT, <span class=\"nt\">--crop_height</span> CROP_HEIGHT\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Crop the input stream to this height\n                        <span class=\"o\">(</span>default: no crop<span class=\"o\">)</span><span class=\"nb\">.</span> Both <span class=\"nt\">-cw</span> and <span class=\"nt\">-ch</span> parameters should\n                        be specified to use crop.\n\nFaces database:\n  <span class=\"nt\">-fg</span> PATH              Path to the face images directory\n  <span class=\"nt\">--run_detector</span>        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images.\n  <span class=\"nt\">--run_detector_no_save</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Use Face Detection model to find faces on\n                        the face images, otherwise use full images. not save\n                        detected face image.\n\nModels:\n  <span class=\"nt\">-m_fd</span> PATH            Path to the Face Detection model XML file\n  <span class=\"nt\">-m_lm</span> PATH            Path to the Facial Landmarks Regression model XML file\n  <span class=\"nt\">-m_reid</span> PATH          Path to the Face Reidentification model XML file\n\nInference options:\n  <span class=\"nt\">-d_fd</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Detection model\n                        <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_lm</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Facial Landmarks\n                        Regression model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-d_reid</span> <span class=\"o\">{</span>CPU,GPU,FPGA,MYRIAD,HETERO,HDDL<span class=\"o\">}</span>\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Target device <span class=\"k\">for </span>the Face Reidentification\n                        model <span class=\"o\">(</span>default: CPU<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> PATH, <span class=\"nt\">--cpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For MKLDNN <span class=\"o\">(</span>CPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to a shared library with custom layers\n                        implementations\n  <span class=\"nt\">-c</span> PATH, <span class=\"nt\">--gpu_lib</span> PATH\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> For clDNN <span class=\"o\">(</span>GPU<span class=\"o\">)</span><span class=\"nt\">-targeted</span> custom layers, <span class=\"k\">if\n                        </span>any. Path to the XML file with descriptions of the\n                        kernels\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> Be more verbose\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_stats</span>     <span class=\"o\">(</span>optional<span class=\"o\">)</span> Output detailed per-layer performance stats\n  <span class=\"nt\">-t_fd</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Probability threshold <span class=\"k\">for </span>face\n                        detections<span class=\"o\">(</span>default: 0.6<span class=\"o\">)</span>\n  <span class=\"nt\">-t_id</span> <span class=\"o\">[</span>0..1]          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Cosine distance threshold between two\n                        vectors <span class=\"k\">for </span>face identification <span class=\"o\">(</span>default: 0.3<span class=\"o\">)</span>\n  <span class=\"nt\">-exp_r_fd</span> NUMBER      <span class=\"o\">(</span>optional<span class=\"o\">)</span> Scaling ratio <span class=\"k\">for </span>bboxes passed to face\n                        recognition <span class=\"o\">(</span>default: 1.15<span class=\"o\">)</span>\n  <span class=\"nt\">--allow_grow</span>          <span class=\"o\">(</span>optional<span class=\"o\">)</span> Allow to grow faces gallery and to dump on\n                        disk. Available only <span class=\"k\">if</span> <span class=\"nt\">--no_show</span> option is off.\n</code></pre></div></div>\n\n<p>主なオプションの意味は以下の通り。</p>\n\n<h3 id=\"-m_fd\"><code class=\"language-plaintext highlighter-rouge\">-m_fd</code></h3>\n\n<p>必須。<br />\n顔位置検出モデルファイル</p>\n\n<h3 id=\"ーm_lm\"><code class=\"language-plaintext highlighter-rouge\">ーm_lm</code></h3>\n\n<p>必須。<br />\n顔特徴点検出モデルファイル</p>\n\n<h3 id=\"-m_reid\"><code class=\"language-plaintext highlighter-rouge\">-m_reid</code></h3>\n\n<p>必須。<br />\n顔識別モデルファイル</p>\n\n<h3 id=\"-d_fd\"><code class=\"language-plaintext highlighter-rouge\">-d_fd</code></h3>\n\n<p>顔位置検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_lm\"><code class=\"language-plaintext highlighter-rouge\">-d_lm</code></h3>\n\n<p>顔特徴点検出に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"-d_reid\"><code class=\"language-plaintext highlighter-rouge\">-d_reid</code></h3>\n\n<p>顔識別に使用するデバイス。省略時はCPU。</p>\n\n<h3 id=\"--cpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--cpu_lib</code></h3>\n\n<p>CPU用カスタムレイヤライブラリ(?)ファイル</p>\n\n<h3 id=\"--gpu_lib\"><code class=\"language-plaintext highlighter-rouge\">--gpu_lib</code></h3>\n\n<p>GPU用カスタムレイヤライブラリ(?)ファイル(使ったことないからワカラン)</p>\n\n<h3 id=\"-fg\"><code class=\"language-plaintext highlighter-rouge\">-fg</code></h3>\n\n<p>必須。<br />\n識別する顔画像を格納したディレクトリ<br />\nこのディレクトリ内のjpg、pngファイルのみ抽出してくれるので、他のファイルが混在しても大丈夫。</p>\n\n<h3 id=\"--input\"><code class=\"language-plaintext highlighter-rouge\">--input</code></h3>\n\n<p>必須。<br />\n入力ファイル(動画ファイル)を指定する。 <br />\n静止画でもエラーにならないが、一瞬で消えるので、オプション –timelapse でキー入力待ちにするか、\nオプション –outputでファイル出力すると確認できる。<br />\n省略時はカメラが指定される。</p>\n\n<h3 id=\"--output\"><code class=\"language-plaintext highlighter-rouge\">--output</code></h3>\n\n<p>認識結果をファイルに出力する。<br />\n指定しなければファイルは作成されない(表示のみ)。 \n拡張子がmp4のときはMP4(追加した処理)。<br />\nそれ以外はMJPEGで保存(aviにするのが望ましい。それ以外だとffmpegがなんか言うがファイルはできてるっぽい)。</p>\n\n<h3 id=\"--no_show\"><code class=\"language-plaintext highlighter-rouge\">--no_show</code></h3>\n\n<p>画像表示しない。<br />\n通常は–outputと組み合わせて使う。</p>\n\n<h3 id=\"--timelapse\"><code class=\"language-plaintext highlighter-rouge\">--timelapse</code></h3>\n\n<p>1フレーム表示するごとにキー入力待ちになる。</p>\n\n<h3 id=\"--crop_width--crop_height\"><code class=\"language-plaintext highlighter-rouge\">--crop_width</code>、<code class=\"language-plaintext highlighter-rouge\">--crop_height</code></h3>\n\n<p>入力画像を指定したサイズに切り取る。切り取る場所は元画像の中心。<br />\n両方指定しないと無効。</p>\n\n<h3 id=\"--run_detector\"><code class=\"language-plaintext highlighter-rouge\">--run_detector</code></h3>\n\n<p>オプションを指定するとデータベース作成時に顔検出して新たに顔画像を作成してくれる。<br />\nデータベースファイルが全身画像だったり、複数人数が一緒に写っていてもOK。<br />\n1回指定すれば画像が残っているので以降は指定しなくても良い。</p>\n\n<h3 id=\"--run_detector_no_save\"><code class=\"language-plaintext highlighter-rouge\">--run_detector_no_save</code></h3>\n\n<p>追加したオプション<br />\n指定するとデータベース作成時に顔検出するが、顔画像の保存はしない。</p>\n\n<h3 id=\"--verbose\"><code class=\"language-plaintext highlighter-rouge\">--verbose</code></h3>\n\n<p>指定するとloglevelがDEBUGになる</p>\n\n<h3 id=\"--perf_stats\"><code class=\"language-plaintext highlighter-rouge\">--perf_stats</code></h3>\n\n<p>指定するとフレーム毎にパフォーマンスステータスを表示する</p>\n\n<h3 id=\"-t_fd\"><code class=\"language-plaintext highlighter-rouge\">-t_fd</code></h3>\n\n<p>顔位置検出に使用する閾値。省略時は0.6。</p>\n\n<h3 id=\"-t_reid\"><code class=\"language-plaintext highlighter-rouge\">-t_reid</code></h3>\n\n<p>顔識別に使用する閾値。省略時は0.3。</p>\n\n<h3 id=\"-exp_r_fd\"><code class=\"language-plaintext highlighter-rouge\">-exp_r_fd</code></h3>\n\n<p>顔位置検出した枠のサイズを何倍にするか。ギリギリだとうまく行かないから?省略時は1.15</p>\n\n<h3 id=\"--allow_grow\"><code class=\"language-plaintext highlighter-rouge\">--allow_grow</code></h3>\n\n<p>認識画像で知らない顔が出てきたらその都度登録するか確認する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でYOLO(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でYOLO(その2)</h1>\n      <p>openVINOのYOLOのプログラムをちょこっと改変</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> のソースを\n<a href=\"/memoBlog/2019/11/10/openVINO_SSD.html\">openVINO でSSD</a> のソースと形状を合わせたもの。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">math</span> <span class=\"kn\">import</span> <span class=\"n\">exp</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-iout\"</span><span class=\"p\">,</span> <span class=\"s\">\"--iou_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Intersection over union threshold for overlapping \"</span>\n                                                       <span class=\"s\">\"detections filtering\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-ni\"</span><span class=\"p\">,</span> <span class=\"s\">\"--number_iter\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Number of inference iterations\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pc\"</span><span class=\"p\">,</span> <span class=\"s\">\"--perf_counts\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Report performance counters\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span>\n                      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-r\"</span><span class=\"p\">,</span> <span class=\"s\">\"--raw_output_message\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Output inference results raw values showing\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">YoloParams</span><span class=\"p\">:</span>\n    <span class=\"c1\"># ------------------------------------------- Extracting layer parameters ------------------------------------------\n</span>    <span class=\"c1\"># Magic numbers are copied from yolo samples\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">param</span><span class=\"p\">,</span> <span class=\"n\">side</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"mi\">3</span> <span class=\"k\">if</span> <span class=\"s\">'num'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'num'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">=</span> <span class=\"mi\">4</span> <span class=\"k\">if</span> <span class=\"s\">'coords'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'coords'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">classes</span> <span class=\"o\">=</span> <span class=\"mi\">80</span> <span class=\"k\">if</span> <span class=\"s\">'classes'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'classes'</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">10.0</span><span class=\"p\">,</span> <span class=\"mf\">13.0</span><span class=\"p\">,</span> <span class=\"mf\">16.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">33.0</span><span class=\"p\">,</span> <span class=\"mf\">23.0</span><span class=\"p\">,</span> <span class=\"mf\">30.0</span><span class=\"p\">,</span> <span class=\"mf\">61.0</span><span class=\"p\">,</span> <span class=\"mf\">62.0</span><span class=\"p\">,</span> <span class=\"mf\">45.0</span><span class=\"p\">,</span> <span class=\"mf\">59.0</span><span class=\"p\">,</span> <span class=\"mf\">119.0</span><span class=\"p\">,</span> <span class=\"mf\">116.0</span><span class=\"p\">,</span> <span class=\"mf\">90.0</span><span class=\"p\">,</span> <span class=\"mf\">156.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">198.0</span><span class=\"p\">,</span>\n                        <span class=\"mf\">373.0</span><span class=\"p\">,</span> <span class=\"mf\">326.0</span><span class=\"p\">]</span> <span class=\"k\">if</span> <span class=\"s\">'anchors'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">param</span> <span class=\"k\">else</span> <span class=\"p\">[</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">a</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'anchors'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n\n        <span class=\"k\">if</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">:</span>\n            <span class=\"n\">mask</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">idx</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">[</span><span class=\"s\">'mask'</span><span class=\"p\">].</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">','</span><span class=\"p\">)]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">num</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">mask</span><span class=\"p\">)</span>\n\n            <span class=\"n\">maskedAnchors</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n            <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"n\">mask</span><span class=\"p\">:</span>\n                <span class=\"n\">maskedAnchors</span> <span class=\"o\">+=</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"n\">idx</span> <span class=\"o\">*</span> <span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]]</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">anchors</span> <span class=\"o\">=</span> <span class=\"n\">maskedAnchors</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">=</span> <span class=\"n\">side</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"o\">=</span> <span class=\"s\">'mask'</span> <span class=\"ow\">in</span> <span class=\"n\">param</span>  <span class=\"c1\"># Weak way to determine but the only one.\n</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">log_params</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># params_to_print = {'classes': self.classes, 'num': self.num, 'coords': self.coords, 'anchors': self.anchors}\n</span>        <span class=\"c1\"># [log.info(\"         {:8}: {}\".format(param_name, param)) for param_name, param in params_to_print.items()]\n</span>        <span class=\"k\">pass</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">entry_index</span><span class=\"p\">(</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">coord</span><span class=\"p\">,</span> <span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">location</span><span class=\"p\">,</span> <span class=\"n\">entry</span><span class=\"p\">):</span>\n    <span class=\"n\">side_power_2</span> <span class=\"o\">=</span> <span class=\"n\">side</span> <span class=\"o\">**</span> <span class=\"mi\">2</span>\n    <span class=\"n\">n</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">//</span> <span class=\"n\">side_power_2</span>\n    <span class=\"n\">loc</span> <span class=\"o\">=</span> <span class=\"n\">location</span> <span class=\"o\">%</span> <span class=\"n\">side_power_2</span>\n    <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">side_power_2</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">coord</span> <span class=\"o\">+</span> <span class=\"n\">classes</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">entry</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">loc</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"p\">,</span> <span class=\"n\">h_scale</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"p\">):</span>\n    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">w</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">y</span> <span class=\"o\">-</span> <span class=\"n\">h</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">w</span> <span class=\"o\">*</span> <span class=\"n\">w_scale</span><span class=\"p\">)</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">+</span> <span class=\"n\">h</span> <span class=\"o\">*</span> <span class=\"n\">h_scale</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"nb\">dict</span><span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"o\">=</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"o\">=</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"o\">=</span><span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"o\">=</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">class_id</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">blob</span><span class=\"p\">,</span> <span class=\"n\">resized_image_shape</span><span class=\"p\">,</span> <span class=\"n\">original_im_shape</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">threshold</span><span class=\"p\">):</span>\n    <span class=\"c1\"># ------------------------------------------ Validating output parameters ------------------------------------------\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    <span class=\"k\">assert</span> <span class=\"n\">out_blob_w</span> <span class=\"o\">==</span> <span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"s\">\"Invalid size of output blob. It sould be in NCHW layout and height should \"</span> \\\n                                     <span class=\"s\">\"be equal to width. Current height = {}, current width = {}\"</span> \\\n                                     <span class=\"s\">\"\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">out_blob_h</span><span class=\"p\">,</span> <span class=\"n\">out_blob_w</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ------------------------------------------ Extracting layer parameters -------------------------------------------\n</span>    <span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">orig_im_w</span> <span class=\"o\">=</span> <span class=\"n\">original_im_shape</span>\n    <span class=\"n\">resized_image_h</span><span class=\"p\">,</span> <span class=\"n\">resized_image_w</span> <span class=\"o\">=</span> <span class=\"n\">resized_image_shape</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">predictions</span> <span class=\"o\">=</span> <span class=\"n\">blob</span><span class=\"p\">.</span><span class=\"n\">flatten</span><span class=\"p\">()</span>\n    <span class=\"n\">side_square</span> <span class=\"o\">=</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n\n    <span class=\"c1\"># ------------------------------------------- Parsing YOLO Region output -------------------------------------------\n</span>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">side_square</span><span class=\"p\">):</span>\n        <span class=\"n\">row</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">//</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"n\">col</span> <span class=\"o\">=</span> <span class=\"n\">i</span> <span class=\"o\">%</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n        <span class=\"k\">for</span> <span class=\"n\">n</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">num</span><span class=\"p\">):</span>\n            <span class=\"n\">obj_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">)</span>\n            <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">obj_index</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">scale</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"n\">box_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n            <span class=\"c1\"># Network produces location predictions in absolute coordinates of feature maps.\n</span>            <span class=\"c1\"># Scale it to relative coordinates.\n</span>            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">col</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">0</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">row</span> <span class=\"o\">+</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span> <span class=\"o\">/</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span>\n            <span class=\"c1\"># Value for exp is very big number in some cases so following construction is using here\n</span>            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">w_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n                <span class=\"n\">h_exp</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">box_index</span> <span class=\"o\">+</span> <span class=\"mi\">3</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span><span class=\"p\">])</span>\n            <span class=\"k\">except</span> <span class=\"nb\">OverflowError</span><span class=\"p\">:</span>\n                <span class=\"k\">continue</span>\n            <span class=\"c1\"># Depends on topology we need to normalize sizes by feature maps (up to YOLOv3) or by input shape (YOLOv3)\n</span>            <span class=\"n\">w</span> <span class=\"o\">=</span> <span class=\"n\">w_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_w</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"n\">h</span> <span class=\"o\">=</span> <span class=\"n\">h_exp</span> <span class=\"o\">*</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">anchors</span><span class=\"p\">[</span><span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">n</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">resized_image_h</span> <span class=\"k\">if</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">isYoloV3</span> <span class=\"k\">else</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">):</span>\n                <span class=\"n\">class_index</span> <span class=\"o\">=</span> <span class=\"n\">entry_index</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">side</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">classes</span><span class=\"p\">,</span> <span class=\"n\">n</span> <span class=\"o\">*</span> <span class=\"n\">side_square</span> <span class=\"o\">+</span> <span class=\"n\">i</span><span class=\"p\">,</span>\n                                          <span class=\"n\">params</span><span class=\"p\">.</span><span class=\"n\">coords</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\">+</span> <span class=\"n\">j</span><span class=\"p\">)</span>\n                <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"n\">scale</span> <span class=\"o\">*</span> <span class=\"n\">predictions</span><span class=\"p\">[</span><span class=\"n\">class_index</span><span class=\"p\">]</span>\n                <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"n\">threshold</span><span class=\"p\">:</span>\n                    <span class=\"k\">continue</span>\n                <span class=\"n\">objects</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">scale_bbox</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">=</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">=</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">h</span><span class=\"o\">=</span><span class=\"n\">h</span><span class=\"p\">,</span> <span class=\"n\">w</span><span class=\"o\">=</span><span class=\"n\">w</span><span class=\"p\">,</span> <span class=\"n\">class_id</span><span class=\"o\">=</span><span class=\"n\">j</span><span class=\"p\">,</span> <span class=\"n\">confidence</span><span class=\"o\">=</span><span class=\"n\">confidence</span><span class=\"p\">,</span>\n                                          <span class=\"n\">h_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_h</span><span class=\"p\">,</span> <span class=\"n\">w_scale</span><span class=\"o\">=</span><span class=\"n\">orig_im_w</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"n\">objects</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">,</span> <span class=\"n\">box_2</span><span class=\"p\">):</span>\n    <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">height_of_overlap_area</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">])</span> <span class=\"o\">-</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span>\n    <span class=\"k\">if</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">height_of_overlap_area</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">area_of_overlap</span> <span class=\"o\">=</span> <span class=\"n\">width_of_overlap_area</span> <span class=\"o\">*</span> <span class=\"n\">height_of_overlap_area</span>\n    <span class=\"n\">box_1_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_1</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">box_2_area</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">])</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">box_2</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">])</span>\n    <span class=\"n\">area_of_union</span> <span class=\"o\">=</span> <span class=\"n\">box_1_area</span> <span class=\"o\">+</span> <span class=\"n\">box_2_area</span> <span class=\"o\">-</span> <span class=\"n\">area_of_overlap</span>\n    <span class=\"k\">if</span> <span class=\"n\">area_of_union</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"mi\">0</span>\n    <span class=\"k\">return</span> <span class=\"n\">area_of_overlap</span> <span class=\"o\">/</span> <span class=\"n\">area_of_union</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">()</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>                 <span class=\"c1\"># 冒頭でinputは一つでなければエラーになってるので決め打ちで[0]\n</span>    <span class=\"n\">in_frame_shape</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">:]</span>       <span class=\"c1\"># HWC→BCHWに変更してあるので、height/widthはshape[2:]で取得\n</span>    <span class=\"k\">for</span> <span class=\"n\">layer_name</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">.</span><span class=\"n\">items</span><span class=\"p\">():</span>\n        <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">parents</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]].</span><span class=\"n\">shape</span><span class=\"p\">)</span>\n        <span class=\"n\">layer_params</span> <span class=\"o\">=</span> <span class=\"n\">YoloParams</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">[</span><span class=\"n\">layer_name</span><span class=\"p\">].</span><span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">out_blob</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n        <span class=\"c1\"># log.info(\"Layer {} parameters: \".format(layer_name))\n</span>        <span class=\"n\">layer_params</span><span class=\"p\">.</span><span class=\"n\">log_params</span><span class=\"p\">()</span>\n        <span class=\"n\">objects</span> <span class=\"o\">+=</span> <span class=\"n\">parse_yolo_region</span><span class=\"p\">(</span><span class=\"n\">out_blob</span><span class=\"p\">,</span> \n                                        <span class=\"n\">in_frame_shape</span><span class=\"p\">,</span>\n                                        <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">],</span> \n                                        <span class=\"n\">layer_params</span><span class=\"p\">,</span>\n                                        <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Filtering overlapping boxes with respect to the --iou_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"nb\">sorted</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">,</span> <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"k\">lambda</span> <span class=\"n\">obj</span> <span class=\"p\">:</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">reverse</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n        <span class=\"k\">if</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)):</span>\n            <span class=\"k\">if</span> <span class=\"n\">intersection_over_union</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">],</span> <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">])</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">iou_threshold</span><span class=\"p\">:</span>\n                <span class=\"n\">objects</span><span class=\"p\">[</span><span class=\"n\">j</span><span class=\"p\">][</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># Drawing objects with respect to the --prob_threshold CLI parameter\n</span>    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">obj</span> <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span> <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">objects</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">Detected boxes for batch {}:\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">))</span>\n        <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\" Class ID | Confidence | XMIN | YMIN | XMAX | YMAX | COLOR \"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">origin_im_size</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objects</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Validation bbox of detected object\n</span>        <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">origin_im_size</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"c1\"># color = (int(min(obj['class_id'] * 12.5, 255)),\n</span>        <span class=\"c1\">#          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span>        <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n        <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]]</span> <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"ow\">and</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">>=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">]</span> <span class=\"k\">else</span> \\\n            <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'class_id'</span><span class=\"p\">])</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">raw_output_message</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span>\n                <span class=\"s\">\"{:^9} | {:10f} | {:4} | {:4} | {:4} | {:4} | {} \"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">det_label</span><span class=\"p\">,</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">],</span>\n                                                                          <span class=\"n\">color</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]),</span> <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmax'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymax'</span><span class=\"p\">]),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span>\n                    <span class=\"s\">\"#\"</span> <span class=\"o\">+</span> <span class=\"n\">det_label</span> <span class=\"o\">+</span> <span class=\"s\">' '</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'confidence'</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"s\">' %'</span><span class=\"p\">,</span>\n                    <span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'xmin'</span><span class=\"p\">],</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"s\">'ymin'</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.6</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"c1\"># YOLOのoutputsは1ではない\n</span>    \n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Sample supports only YOLO V3 based single input topologies\"</span>\n    <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>     <span class=\"c1\"># inputは一つだけなので決め打ちで[0]\n</span>    \n    <span class=\"c1\">#  Defaulf batch_size is 1\n</span>    <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n    \n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n        \n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span> <span class=\"o\">=</span>      <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span> <span class=\"o\">=</span>   <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span> <span class=\"o\">=</span>    <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                    <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span>  <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_yolov3_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                             <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                             <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                             <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-iout</span> IOU_THRESHOLD]\n                                             <span class=\"o\">[</span><span class=\"nt\">-ni</span> NUMBER_ITER] <span class=\"o\">[</span><span class=\"nt\">-pc</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-r</span><span class=\"o\">]</span>\n                                             <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG]\n                                             <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n  <span class=\"nt\">-iout</span> IOU_THRESHOLD, <span class=\"nt\">--iou_threshold</span> IOU_THRESHOLD\n                        Optional. Intersection over union threshold <span class=\"k\">for\n                        </span>overlapping detections filtering\n  <span class=\"nt\">-ni</span> NUMBER_ITER, <span class=\"nt\">--number_iter</span> NUMBER_ITER\n                        Optional. Number of inference iterations\n  <span class=\"nt\">-pc</span>, <span class=\"nt\">--perf_counts</span>    Optional. Report performance counters\n  <span class=\"nt\">-r</span>, <span class=\"nt\">--raw_output_message</span>\n                        Optional. Output inference results raw values showing\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でSSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でSSD</h1>\n      <p>openVINOのSSDのサンプルプログラムを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>YOLOとは別のアルゴリズムSSDで物体認識するサンプルプログラムがあったので動かしてみた。<br />\nサンプルプログラムはフルパッケージにしか入ってないので、元のプログラムはフルパッケージをインストールして確認してちょ。\n/opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_ssd_async</p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"モデルデータのダウンロード\">モデルデータのダウンロード</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">models.list</code>によると、以下のモデルデータが使用できるらしい。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>face-detection-adas-????\nface-detection-adas-binary-????\nface-detection-retail-????\npedestrian-and-vehicle-detector-adas-????\npedestrian-detection-adas-????\npedestrian-detection-adas-binary-????\nperson-detection-retail-????\nvehicle-detection-adas-????\nvehicle-detection-adas-binary-????\nvehicle-license-plate-detection-barrier-????\n</code></pre></div></div>\n\n<p>ここでは、vehicle-detection-adas-binary-????を使ってみることにする。</p>\n\n<p>以下の手順でモデルデータをダウンロードする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R3/20190905_163000_models_bin/pedestrian-and-vehicle-detector-adas-0001/FP16/pedestrian-and-vehicle-detector-adas-0001\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>ラベルデータは用意されていないので、ラベルデータを以下の内容で、<code class=\"language-plaintext highlighter-rouge\">${models_diir}/pedestrian-and-vehicle-detector-adas-0001.labels</code>のファイル名で作成する。<br />\nオリジナルでは<code class=\"language-plaintext highlighter-rouge\">--label</code>オプションでラベルデータファイルを指定するようになっているが、\nモデルデータファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものをデフォルトのラベルデータファイルとして認識するように変更しておいた。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>UNKNOWN\nvehicles\npedestrians\nUNKNOWN\n</code></pre></div></div>\n\n<p>どのIDが何を示すか書いてる場所を見つけられなかったんだよなぁ~。<br />\nとりあえず、結果表示から推測するしかないか。</p>\n\n<h2 id=\"デモプログラムのソース\">デモプログラムのソース</h2>\n\n<p>ちょっとのつもりで改造してたら、結構たくさんの変更になったので、ソース全体を掲載しておく。<br />\n(RaspberryPiにはソース入ってないし)<br />\nおもな変更点は以下</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--save</code> <code class=\"language-plaintext highlighter-rouge\">--log</code> <code class=\"language-plaintext highlighter-rouge\">--sync</code> <code class=\"language-plaintext highlighter-rouge\">--no_disp</code> オプションの追加</li>\n  <li>結果解析部分の関数化(後でYOLOと比較しやすいように)</li>\n</ul>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"s\">\"\"\"\n Copyright (C) 2018-2019 Intel Corporation\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\"\"\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IECore</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> \n                      <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--cpu_extension\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Required for CPU custom layers. Absolute path to a shared library with \"</span>\n                           <span class=\"s\">\"the kernels implementations.\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is \"</span>\n                           <span class=\"s\">\"acceptable. The demo will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-pt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--prob_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Probability threshold for detections filtering\"</span><span class=\"p\">,</span>\n                      <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--sync\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Sync mode\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">out_blob</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">())[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># print(res[out_blob].shape)\n</span>    <span class=\"c1\">#  -> (1, 1, 200, 7)        200:バウンディングボックスの数\n</span>    <span class=\"c1\"># データ構成は\n</span>    <span class=\"c1\"># https://docs.openvinotoolkit.org/2019_R1/_pedestrian_and_vehicle_detector_adas_0001_description_pedestrian_and_vehicle_detector_adas_0001.html\n</span>    <span class=\"c1\"># の「outputs」を参照\n</span>    <span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"n\">out_blob</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]:</span>     <span class=\"c1\"># このループは200回まわる\n</span>        <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>                       <span class=\"c1\"># confidence for the predicted class(スコア)\n</span>        <span class=\"k\">if</span> <span class=\"n\">conf</span> <span class=\"o\">></span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">prob_threshold</span><span class=\"p\">:</span>      <span class=\"c1\"># 閾値より大きいものだけ処理\n</span>            <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n            <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_width</span><span class=\"p\">)</span>\n            <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 表示色\n</span>            <span class=\"c1\"># color = (min(class_id * 12.5, 255), min(class_id * 7, 255), min(class_id * 5, 255))\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>            <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">det_label</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># バウンディングボックスとラベル、スコアを表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">det_label</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">conf</span> <span class=\"o\">*</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">%\"</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"mi\">7</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.4</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model_xml</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">model_bin</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".bin\"</span>\n    \n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model_xml</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">ie</span> <span class=\"o\">=</span> <span class=\"n\">IECore</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span> <span class=\"ow\">and</span> <span class=\"s\">'CPU'</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">add_extension</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">cpu_extension</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) --------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Loading network files:</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_xml</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_bin</span><span class=\"si\">}</span><span class=\"se\">\\n\\t</span><span class=\"si\">{</span><span class=\"n\">model_label</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n    <span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">model_xml</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">model_bin</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------\n</span>    <span class=\"k\">if</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">:</span>\n        <span class=\"n\">supported_layers</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">query_network</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"s\">\"CPU\"</span><span class=\"p\">)</span>\n        <span class=\"n\">not_supported_layers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">l</span> <span class=\"k\">for</span> <span class=\"n\">l</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">layers</span><span class=\"p\">.</span><span class=\"n\">keys</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">l</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">supported_layers</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Following layers are not supported by the plugin for specified device {}:</span><span class=\"se\">\\n</span><span class=\"s\"> {}\"</span><span class=\"p\">.</span>\n                      <span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">,</span> <span class=\"s\">', '</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">not_supported_layers</span><span class=\"p\">)))</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s\">\"Please try to specify cpu extensions library path in sample's command line parameters using -l \"</span>\n                      <span class=\"s\">\"or --cpu_extension command line argument\"</span><span class=\"p\">)</span>\n            <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ---------------------------------------------- \n</span>    <span class=\"c1\"># print(net.outputs)\n</span>    <span class=\"k\">assert</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">outputs</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"Demo supports only single output topologies\"</span>\n\n    <span class=\"c1\"># ---------------------------------------------- 4. Preparing inputs -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Preparing inputs\"</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(net.inputs)\n</span>    <span class=\"c1\"># SSDのinputsは1とは限らないのでスキャンする\n</span>    <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">for</span> <span class=\"n\">blob_name</span> <span class=\"ow\">in</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">:</span>\n        <span class=\"c1\"># print(f'{blob_name}   {net.inputs[blob_name].shape}')\n</span>        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">4</span><span class=\"p\">:</span>\n            <span class=\"n\">input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">2</span><span class=\"p\">:</span>\n            <span class=\"n\">img_info_input_blob</span> <span class=\"o\">=</span> <span class=\"n\">blob_name</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"nb\">RuntimeError</span><span class=\"p\">(</span><span class=\"s\">\"Unsupported {}D input layer '{}'. Only 2D and 4D input layers are supported\"</span>\n                               <span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">blob_name</span><span class=\"p\">].</span><span class=\"n\">shape</span><span class=\"p\">),</span> <span class=\"n\">blob_name</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># Read and pre-process input image\n</span>    <span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span> <span class=\"o\">=</span> <span class=\"n\">net</span><span class=\"p\">.</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">].</span><span class=\"n\">shape</span>\n    \n    <span class=\"n\">feed_dict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    <span class=\"k\">if</span> <span class=\"n\">img_info_input_blob</span><span class=\"p\">:</span>\n        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">img_info_input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># print(f'save flag : {args.save}')\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"n\">cur_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference in async mode...\"</span><span class=\"p\">)</span>\n    <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sync</span>\n\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n</span>    <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># ----------------------------------------- 5. Loading model to the plugin -----------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Loading model to the plugin\"</span><span class=\"p\">)</span>\n    <span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">ie</span><span class=\"p\">.</span><span class=\"n\">load_network</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">num_requests</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">device_name</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To switch between sync/async modes, press TAB key in the output window\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">next_frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレーム\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n\n        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">next_frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">request_id</span> <span class=\"o\">=</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># resize input_frame to network size\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>  <span class=\"c1\"># Change data layout from HWC to CHW\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"n\">input_n</span><span class=\"p\">,</span> <span class=\"n\">input_colors</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">))</span>     <span class=\"c1\"># CHW→BCHW\n</span>        <span class=\"n\">feed_dict</span><span class=\"p\">[</span><span class=\"n\">input_blob</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span>\n        \n        <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">start_async</span><span class=\"p\">(</span><span class=\"n\">request_id</span><span class=\"o\">=</span><span class=\"n\">request_id</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"n\">feed_dict</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>\n            \n            <span class=\"c1\"># Parse detection results of the current request\n</span>            <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">outputs</span>\n            <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">net</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n            <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n            <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>\n            \n            <span class=\"c1\"># Draw performance stats\n</span>            <span class=\"n\">inf_time_message</span>     <span class=\"o\">=</span> <span class=\"s\">\"Inference time: N\\A for async mode\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Inference time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">frame_time_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Frame time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">render_time_message</span>  <span class=\"o\">=</span> <span class=\"s\">\"OpenCV rendering time: {:.3f} ms\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            <span class=\"n\">async_mode_message</span>   <span class=\"o\">=</span> <span class=\"s\">\"Async mode is on. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> \\\n                                   <span class=\"s\">\"Async mode is off. Processing request {}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">cur_request_id</span><span class=\"p\">)</span>\n            <span class=\"n\">parsing_time_message</span> <span class=\"o\">=</span> <span class=\"s\">\"parse time is {:.3f}\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n            \n            <span class=\"s\">\"\"\"\n            cv2.putText(frame, inf_time_message,    (15, 15),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, parsing_time_message,(15, 30),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, render_time_message, (15, 45),                   cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            cv2.putText(frame, frame_time_message,  (10, int(img_height - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n            cv2.putText(frame, async_mode_message,  (10, int(img_height - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n            \"\"\"</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>    <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">async_mode_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>\n        \n        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 非同期モードではフレームバッファ入れ替え\n</span>            <span class=\"n\">cur_request_id</span><span class=\"p\">,</span> <span class=\"n\">next_request_id</span> <span class=\"o\">=</span> <span class=\"n\">next_request_id</span><span class=\"p\">,</span> <span class=\"n\">cur_request_id</span>\n            <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">next_frame</span>\n        \n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n            <span class=\"c1\"># TABキー\n</span>            <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">requests</span><span class=\"p\">[</span><span class=\"n\">cur_request_id</span><span class=\"p\">].</span><span class=\"n\">wait</span><span class=\"p\">()</span>    <span class=\"c1\"># ASYNC→SYNC切り替え時にREQUEST_BUSYでアボートする不具合の対策\n</span>            <span class=\"n\">is_async_mode</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">is_async_mode</span>\n            <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Switched to {} mode\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"s\">\"async\"</span> <span class=\"k\">if</span> <span class=\"n\">is_async_mode</span> <span class=\"k\">else</span> <span class=\"s\">\"sync\"</span><span class=\"p\">))</span>\n        \n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd_async.py  <span class=\"nt\">-h</span>\n\nusage: object_detection_demo_ssd_async.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT\n                                          <span class=\"o\">[</span><span class=\"nt\">-l</span> CPU_EXTENSION] <span class=\"o\">[</span><span class=\"nt\">-d</span> DEVICE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--labels</span> LABELS]\n                                          <span class=\"o\">[</span><span class=\"nt\">-pt</span> PROB_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE]\n                                          <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--sync</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--sync</span>                Optional. Sync mode\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> CPU_EXTENSION, <span class=\"nt\">--cpu_extension</span> CPU_EXTENSION\n                        Optional. Required <span class=\"k\">for </span>CPU custom layers. Absolute\n                        path to a shared library with the kernels\n                        implementations.\n  <span class=\"nt\">-d</span> DEVICE, <span class=\"nt\">--device</span> DEVICE\n                        Optional. Specify the target device to infer on<span class=\"p\">;</span> CPU,\n                        GPU, FPGA, HDDL or MYRIAD is acceptable. The demo will\n                        look <span class=\"k\">for </span>a suitable plugin <span class=\"k\">for </span>device specified.\n                        Default value is CPU\n  <span class=\"nt\">--labels</span> LABELS       Optional. Labels mapping file\n  <span class=\"nt\">-pt</span> PROB_THRESHOLD, <span class=\"nt\">--prob_threshold</span> PROB_THRESHOLD\n                        Optional. Probability threshold <span class=\"k\">for </span>detections\n                        filtering\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>buntuでの実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>ubuntuでの実行コマンドは以下。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>RaspberryPiでの実行コマンドは以下。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_ssd_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/pedestrian-and-vehicle-detector-adas-0001.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--save</code>オプションでファイル名を指定すると認識結果をファイルに保存する。<br />\n上書き確認などは行わないので、ファイル名指定は注意すること。</p>\n\n<h2 id=\"各処理の実行時間をファイルに記録する\">各処理の実行時間をファイルに記録する</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--log</code>オプションでファイル名を指定する。<br />\nどこの実行時間かはソース参照してちょ。</p>\n\n<p>ファイルの内容はこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time\n    0, 178.326, 1.303, 0.000, 0.000, 153.768, 9.029\n    1, 39.792, 1.131, 20.440, 1.309, 0.123, 16.418\n    2, 132.989, 1.615, 125.333, 1.368, 0.125, 4.147\n    3, 99.224, 1.106, 84.768, 1.487, 0.136, 11.368\n    4, 78.163, 1.054, 73.622, 1.362, 0.156, 1.577\n</code></pre></div></div>\n\n<h2 id=\"認識結果の画像を表示しない\">認識結果の画像を表示しない</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--no_disp</code>オプションを指定すると、認識結果の画像を表示しない。<br />\nあまり使い道はないが、GUI環境がない場合に<code class=\"language-plaintext highlighter-rouge\">--save</code>オプションとともに指定すると、GUIがない場合でも実行できる。<br />\n(実際は、VS codeのリモート開発でデバッグ時に画像表示部分がエラーになってデバッグできなかったので、入れただけなんだけどね)</p>\n\n<h2 id=\"同期モードで実行する\">同期モードで実行する</h2>\n\n<p>TABキーを入力することで、非同期モード⇔同期モードを切り替えられるが、\n実行開始時から同期モードで動作させたいときに<code class=\"language-plaintext highlighter-rouge\">--sync</code>オプションを指定する。<br />\nデフォルトでは非同期モードで実行。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO(C++版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO(C++版)</h1>\n      <p>tinyYOLOのC++版デモプログラムのbuildと実行</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nのpythonで実行したデモプログラムのC++版をbuild&実行してみる。</p>\n\n<h1 id=\"ubuntu環境での実行\">ubuntu環境での実行</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h2 id=\"デモのソースプログラム\">デモのソースプログラム</h2>\n\n<p>ドライバのインストール先 <code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/deployment_tools/open_model_zoo/demos</code> にあるので、そのまま参照しても良いが、\nソース修正に備えて、ソースをコピっておく(オーナーも変更)と何かと便利。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++/openvino_demo <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos <span class=\"nb\">.</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> demos/\n</code></pre></div></div>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>出力文字列のサイズと位置を調整</li>\n  <li>-saveオプションの追加と認識結果画像ファイルの保存処理の追加</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.hpp.org\t2019-10-31 14:39:14.757039048 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.hpp\t2019-10-31 06:16:49.178945707 +0900\n</span><span class=\"p\">@@ -93,6 +93,7 @@</span>\n /// \\brief Define a flag to disable showing processed video<br>\n /// It is an optional parameter\n DEFINE_bool(no_show, false, no_show_processed_video);\n<span class=\"gi\">+DEFINE_bool(save, false, \"Optional. save image file.\");\n</span> \n /**\n * \\brief This function shows a help message\n<span class=\"p\">@@ -115,4 +116,5 @@</span>\n     std::cout << \"    -iou_t                    \" << iou_thresh_output_message << std::endl;\n     std::cout << \"    -auto_resize              \" << input_resizable_message << std::endl;\n     std::cout << \"    -no_show                  \" << no_show_processed_video << std::endl;\n<span class=\"gi\">+    std::cout << \"    -save                     \" << \"Optional. save image file.\" << std::endl;\n</span> }\n</code></pre></div></div>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.org\t2019-10-31 05:46:38.515000000 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"p\">@@ -197,6 +197,21 @@</span>\n         }\n         // -----------------------------------------------------------------------------------------------------\n \n<span class=\"gi\">+        // =====================================================================================\n+        // 動画ファイルを書き出すためのオブジェクトを宣言する\n+        cv::VideoWriter writer;\n+        // =====================================================================================\n+        // =====================================================================================\n+        if (FLAGS_save) {\n+            double fps    = cap.get(cv::CAP_PROP_FPS);\t\t\t\t// フレームレートを取得\n+            int fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v');\t\t// MP4形式を指定\n+            // * エンコード形式 \"XVID\" = AVI, \"MP4V\" = MPEG4, \"WMV1\" = WMV\n+\n+            // 動画ファイルを書き出すためのファイルをオープンする\n+            writer.open(\"result.mp4\", fourcc, fps, cv::Size(width, height));\n+        }\n+        // =====================================================================================\n+\n</span>         // --------------------------- 1. Load inference engine -------------------------------------\n         slog::info << \"Loading Inference Engine\" << slog::endl;\n         Core ie;\n<span class=\"p\">@@ -356,17 +371,17 @@</span>\n                 std::ostringstream out;\n                 out << \"OpenCV cap/render time: \" << std::fixed << std::setprecision(2)\n                     << (ocv_decode_time + ocv_render_time) << \" ms\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 25), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 255, 0));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 15), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 255, 0));\n</span>                 out.str(\"\");\n                 out << \"Wallclock time \" << (isAsyncMode ? \"(TRUE ASYNC):      \" : \"(SYNC, press Tab): \");\n                 out << std::fixed << std::setprecision(2) << wall.count() << \" ms (\" << 1000.f / wall.count() << \" fps)\";\n<span class=\"gd\">-                cv::putText(frame, out.str(), cv::Point2f(0, 50), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 0, 255));\n</span><span class=\"gi\">+                cv::putText(frame, out.str(), cv::Point2f(0, 30), cv::FONT_HERSHEY_TRIPLEX, 0.4, cv::Scalar(0, 0, 255));\n</span>                 if (!isAsyncMode) {  // In the true async mode, there is no way to measure detection time directly\n                     out.str(\"\");\n                     out << \"Detection time  : \" << std::fixed << std::setprecision(2) << detection.count()\n                         << \" ms (\"\n                         << 1000.f / detection.count() << \" fps)\";\n<span class=\"gd\">-                    cv::putText(frame, out.str(), cv::Point2f(0, 75), cv::FONT_HERSHEY_TRIPLEX, 0.6,\n</span><span class=\"gi\">+                    cv::putText(frame, out.str(), cv::Point2f(0, 45), cv::FONT_HERSHEY_TRIPLEX, 0.4,\n</span>                                 cv::Scalar(255, 0, 0));\n                 }\n \n<span class=\"p\">@@ -410,7 +425,7 @@</span>\n                         cv::putText(frame,\n                                 (label < static_cast<int>(labels.size()) ?\n                                         labels[label] : std::string(\"label #\") + std::to_string(label)) + conf.str(),\n<span class=\"gd\">-                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 1,\n</span><span class=\"gi\">+                                    cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin - 5)), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.4,\n</span>                                     cv::Scalar(0, 0, 255));\n                         cv::rectangle(frame, cv::Point2f(static_cast<float>(object.xmin), static_cast<float>(object.ymin)),\n                                       cv::Point2f(static_cast<float>(object.xmax), static_cast<float>(object.ymax)), cv::Scalar(0, 0, 255));\n<span class=\"p\">@@ -420,6 +435,11 @@</span>\n             if (!FLAGS_no_show) {\n                 cv::imshow(\"Detection results\", frame);\n             }\n<span class=\"gi\">+            // =====================================================================================\n+            if (FLAGS_save) {\n+                writer << frame;\n+            }\n+            // =====================================================================================\n</span> \n             t1 = std::chrono::high_resolution_clock::now();\n             ocv_render_time = std::chrono::duration_cast<ms>(t1 - t0).count();\n<span class=\"p\">@@ -457,6 +477,11 @@</span>\n         if (FLAGS_pc) {\n             printPerformanceCounts(*async_infer_request_curr, std::cout, getFullDeviceName(ie, FLAGS_d));\n         }\n<span class=\"gi\">+        // =====================================================================================\n+        if (FLAGS_save) {\n+            writer.release();\n+        }\n+        // =====================================================================================\n</span>     }\n     catch (const std::exception& error) {\n         std::cerr << \"[ ERROR ] \" << error.what() << std::endl;\n\n</code></pre></div></div>\n\n<h2 id=\"buildディレクトリの作成とbuild\">buildディレクトリの作成とbuild</h2>\n\n<p>cmakeの実行とbuild</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<p>ちょっと時間がかかる。</p>\n\n<h2 id=\"モデルデータ\">モデルデータ</h2>\n\n<p><a href=\"/memoBlog/2019/10/30/openVINO_YOLO.html\">openVINO でtinyYOLO</a> \nで作成したモデルデータをそのまま使用する。<br />\nラベルデータファイルのファイル名はモデルデータのxmlファイルの拡張子を<code class=\"language-plaintext highlighter-rouge\">.labels</code>に変更したものに固定だが、モデルデータ作成時にコピー済み。</p>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./intel64/Release/</code>に作成される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./intel64/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-l</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> ../../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<p>-save オプションを指定すると、認識結果の動画をresult.mp4(ファイル名は固定)に保存する。</p>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>デモプログラムはRasspberryPiでも動作させることができる。<br />\nソースはRaspberryPi側にはないので、ubuntuからコピーする。</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>ubuntuで作成した /work/NCS2/c++/openvino_demo/demos ディレクトリと/work/NCS2/openvino_models ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"buildディレクトリの作成とbuild-1\">buildディレクトリの作成とbuild</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2/c++/openvino_demo\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build/\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a -Wno-psabi\"</span> ../demos/\nmake object_detection_demo_yolov3_async\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>実行ファイルは<code class=\"language-plaintext highlighter-rouge\">./armv7l/Release/</code>に作成される。<br />\n入力ファイル(-i オプション)はフルパスで指定すること。相対パスだとファイルが見つからないと怒られる。<br />\n※ 下のパッチを当てると相対パスでも大丈夫になる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n./armv7l/Release/object_detection_demo_yolov3_async <span class=\"se\">\\</span>\n<span class=\"nt\">-m</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">-d</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">-i</span> /work/NCS2/data/testvideo3.mp4 \n</code></pre></div></div>\n\n<p>なぜか-saveオプションが効かない。。。</p>\n\n<h2 id=\"入力ファイル名に相対パスを使用できるようにするためのパッチ\">入力ファイル名に相対パスを使用できるようにするためのパッチ</h2>\n\n<p>入力ファイル名をrealpath()で絶対パスに変換して使用することで対応。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.cpp.1\t2019-10-31 14:23:11.411692408 +0900\n</span><span class=\"gi\">+++ main.cpp\t2019-11-01 11:25:29.720856218 +0900\n</span><span class=\"p\">@@ -30,6 +30,9 @@</span>\n #include <ext_list.hpp>\n #endif\n \n<span class=\"gi\">+#include <limits.h>\n+#include <unistd.h>\n+\n</span> using namespace InferenceEngine;\n \n bool ParseAndCheckCommandLine(int argc, char *argv[]) {\n<span class=\"p\">@@ -180,7 +183,23 @@</span>\n \n         slog::info << \"Reading input\" << slog::endl;\n         cv::VideoCapture cap;\n<span class=\"gd\">-        if (!((FLAGS_i == \"cam\") ? cap.open(0) : cap.open(FLAGS_i.c_str()))) {\n</span><span class=\"gi\">+\n+        bool open_status;\n+        if (FLAGS_i == \"cam\") {\n+            open_status = cap.open(0);\n+        }\n+        else {\n+            std::string input_filename;\n+            char input_filename_char[PATH_MAX+1];\n+            if (!realpath(FLAGS_i.c_str(), input_filename_char)) {\n+                throw std::logic_error(\"Cannot get realpath\");\n+            }\n+            input_filename = input_filename_char;\n+            slog::info << \"input filename :\" + input_filename << slog::endl;\n+            open_status = cap.open(input_filename.c_str());\n+\n+        }\n+        if (!open_status) {\n</span>             throw std::logic_error(\"Cannot open input file or camera: \" + FLAGS_i);\n         }\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO でtinyYOLO</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO でtinyYOLO</h1>\n      <p>darknetのモデルデータをopenVINOのモデルデータに変換し、tinyYOLOで画像認識を行う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>openVINOの2019 R3.1 がリリー(2019.10.29現在、ubuntu用のみ)スされ、YOLOのサンプルプログラムが用意されていたので、tinyYOLOを実行してみた。</p>\n\n<p>参考:<a href=\"https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html\">https://docs.openvinotoolkit.org/latest/_docs_MO_DG_prepare_model_convert_model_tf_specific_Convert_YOLO_From_Tensorflow.html</a></p>\n\n<p>pythonはpyenv環境で3.7.4を使用</p>\n\n<p>以下は \n<a href=\"/memoBlog/2019/10/17/openVINO_ubuntu.html\">openVINO フルパッケージをubuntuにインストール</a> \nにしたがって、openVINO フルパッケージ(2019 R3.1) をインストールしたubuntuでの作業。</p>\n\n<h1 id=\"darknetのモデルデータをopenvinoのモデルデータに変換\">darknetのモデルデータをopenVINOのモデルデータに変換</h1>\n\n<p>上記参考サイトの手順に従って、darknetのtinyYOLOモデルデータをopenVINOのモデルデータに変換する。</p>\n\n<h2 id=\"darknet--tensorflow-変換のためのプログラム取得\">darknet → tensorflow 変換のためのプログラム取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/NCS2\ngit clone https://github.com/mystic123/tensorflow-yolo-v3.git\n<span class=\"nb\">cd </span>tensorflow-yolo-v3/\ngit checkout ed60b90\n</code></pre></div></div>\n\n<h2 id=\"darknet-tinyyoloモデルデータ取得\">darknet tinyYOLOモデルデータ取得</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://raw.githubusercontent.com/pjreddie/darknet/master/data/coco.names\nwget https://pjreddie.com/media/files/yolov3-tiny.weights\n</code></pre></div></div>\n\n<h1 id=\"darknet--tensorflow-モデルデータ変換\">darknet → tensorflow モデルデータ変換</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python convert_weights_pb.py <span class=\"nt\">--class_names</span> coco.names <span class=\"nt\">--data_format</span> NHWC <span class=\"nt\">--weights_file</span> yolov3-tiny.weights <span class=\"nt\">--tiny</span>\n<span class=\"nb\">mv </span>frozen_darknet_yolov3_model.pb yolo_v3_tiny.pb\n</code></pre></div></div>\n\n<h2 id=\"モデルデータを変換\">モデルデータを変換</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP16 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div></div>\n\n<p>/work/NCS2/openvino_models/FP16ディレクトリに yolo_v3_tiny.bin yolo_v3_tiny.mapping yolo_v3_tiny.xml の3つが出来る</p>\n\n<blockquote>\n  <p>[!NOTE]\nFP32で計算する場合はこちら<br />\nNCStick使用時はFP16のみサポートなので、FP16で作っておくと使い回しできて楽。<br />\nそんなに認識精度が変わるわけでもなさそうだし。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP32\npython /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py <span class=\"se\">\\</span>\n<span class=\"nt\">--input_model</span> yolo_v3_tiny.pb <span class=\"se\">\\</span>\n<span class=\"nt\">--tensorflow_use_custom_operations_config</span> /opt/intel/openvino/deployment_tools/model_optimizer/extensions/front/tf/yolo_v3_tiny.json <span class=\"se\">\\</span>\n<span class=\"nt\">--output_dir</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n<span class=\"nt\">--data_type</span> FP32 <span class=\"se\">\\</span>\n<span class=\"nt\">--batch</span> 1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"ラベルデータもコピー\">ラベルデータもコピー</h2>\n\n<p>pbファイルにはラベルデータが入っているはずだが、この後の変換でラベルデータは欠落するらしい。<br />\n後のプログラムのためにファイル名変更しておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp </span>coco.names <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels\n</code></pre></div></div>\n\n<h2 id=\"デモプログラムをコピー\">デモプログラムをコピー</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ..\n<span class=\"nb\">cp</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/demos/python_demos/object_detection_demo_yolov3_async <span class=\"nb\">.</span>\n<span class=\"nb\">cd </span>object_detection_demo_yolov3_async/\n</code></pre></div></div>\n\n<h1 id=\"デモ実行\">デモ実行</h1>\n\n<h2 id=\"ソース修正\">ソース修正</h2>\n\n<p>コピったソースそのままでも大丈夫だが、ちょっと修正しておく。</p>\n\n<ul>\n  <li>MP4ファイルのパスが絶対パスでないと正常にオープンできない対策(ubuntuではやらなくても大丈夫)</li>\n  <li>1フレームあたりの処理時間の計測と表示処理を追加</li>\n  <li>認識枠の表示色変更(ちょっと見難かったので)</li>\n  <li>計測データ表示処理の並べ替え(ソースが見難かったので。フレーム時間の追加以外の動作は変更なし)</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py.org\t2019-10-29 05:08:34.982999999 +0900\n</span><span class=\"gi\">+++ object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"p\">@@ -210,7 +210,8 @@</span>\n     else:\n         labels_map = None\n \n<span class=\"gd\">-    input_stream = 0 if args.input == \"cam\" else args.input\n</span><span class=\"gi\">+    # input_stream = 0 if args.input == \"cam\" else args.input\n+    input_stream = 0 if args.input == \"cam\" else os.path.abspath(args.input)\n</span> \n     is_async_mode = True\n     cap = cv2.VideoCapture(input_stream)\n<span class=\"p\">@@ -234,6 +235,8 @@</span>\n     next_request_id = 1\n     render_time = 0\n     parsing_time = 0\n<span class=\"gi\">+    frame_time = 0\n+    prev_time = time()\n</span> \n     # ----------------------------------------------- 6. Doing inference -----------------------------------------------\n     log.info(\"Starting inference...\")\n<span class=\"p\">@@ -263,6 +266,8 @@</span>\n \n         # Start inference\n         start_time = time()\n<span class=\"gi\">+        frame_time = start_time - prev_time         # 1フレームの処理時間\n+        prev_time = start_time\n</span>         exec_net.start_async(request_id=request_id, inputs={input_blob: in_frame})\n         det_time = time() - start_time\n \n<span class=\"p\">@@ -303,8 +308,9 @@</span>\n             # Validation bbox of detected object\n             if obj['xmax'] > origin_im_size[1] or obj['ymax'] > origin_im_size[0] or obj['xmin'] < 0 or obj['ymin'] < 0:\n                 continue\n<span class=\"gd\">-            color = (int(min(obj['class_id'] * 12.5, 255)),\n-                     min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n</span><span class=\"gi\">+            # color = (int(min(obj['class_id'] * 12.5, 255)),\n+            #          min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255))\n+            color = (255, 128, 128)\n</span>             det_label = labels_map[obj['class_id']] if labels_map and len(labels_map) >= obj['class_id'] else \\\n                 str(obj['class_id'])\n \n<span class=\"p\">@@ -322,16 +328,17 @@</span>\n         # Draw performance stats over frame\n         inf_time_message = \"Inference time: N\\A for async mode\" if is_async_mode else \\\n             \"Inference time: {:.3f} ms\".format(det_time * 1e3)\n<span class=\"gi\">+        frame_time_message = \"Frame time: {:.3f} ms\".format(frame_time * 1e3)\n</span>         render_time_message = \"OpenCV rendering time: {:.3f} ms\".format(render_time * 1e3)\n         async_mode_message = \"Async mode is on. Processing request {}\".format(cur_request_id) if is_async_mode else \\\n             \"Async mode is off. Processing request {}\".format(cur_request_id)\n         parsing_message = \"YOLO parsing time is {:.3f}\".format(parsing_time * 1e3)\n \n<span class=\"gd\">-        cv2.putText(frame, inf_time_message, (15, 15), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200, 10, 10), 1)\n-        cv2.putText(frame, render_time_message, (15, 45), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n-        cv2.putText(frame, async_mode_message, (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5,\n-                    (10, 10, 200), 1)\n-        cv2.putText(frame, parsing_message, (15, 30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1)\n</span><span class=\"gi\">+        cv2.putText(frame, inf_time_message,    (15, 15),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, parsing_message,     (15, 30),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, render_time_message, (15, 45),                          cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n+        cv2.putText(frame, frame_time_message,  (10, int(origin_im_size[0] - 35)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200,  10,  10), 1)\n+        cv2.putText(frame, async_mode_message,  (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, ( 10,  10, 200), 1)\n</span> \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n</code></pre></div></div>\n\n<p>上のパッチ内容をa.patchとして保存したとして、以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch object_detection_demo_yolov3_async.py a.patch \n\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合\">静止画の場合</h2>\n\n<p>実行コマンドは以下。<br />\ndataディレクトリに認識用の画像データを用意してある(以下同じ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\n入力ファイルをmp4に変えるだけ。<br />\nカメラからの入力を使用する場合は<code class=\"language-plaintext highlighter-rouge\">--input cam</code>とするらしいが、カメラないので未確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\npython object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--cpu_extension</span> /opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_avx2.so <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"raspberrypi3b---ncstickでデモを動かす\">RaspberryPi3B+  + NCStickでデモを動かす</h1>\n\n<p>以下は \n<a href=\"/memoBlog/2019/09/01/NCS_1.html\">Intel NCStick2用動作環境の構築</a> \nにしたがって環境構築したRaspberryPiを使用。</p>\n\n<p>RaspberryPi用はopenVINO 2019R3のまま(2019.10.29現在、R3.1はリリースされていない)だけど、問題なし。</p>\n\n<p>ubuntuで作成した object_detection_demo_yolov3_async ディレクトリをまるごとRaspberryPiにコピーする。</p>\n\n<h2 id=\"静止画の場合-1\">静止画の場合</h2>\n\n<p>実行コマンドは以下。  ubuntuの実行コマンドと比べて、以下の変更がある。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">--device MYRIAD</code>を追加</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">--cpu_extension</code>を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/000004.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合-1\">動画の場合</h2>\n\n<p>実行コマンドは以下。<br />\nこちらも入力ファイルをmp4に変えるだけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_yolov3_async.py <span class=\"se\">\\</span>\n<span class=\"nt\">--device</span> MYRIAD <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.xml <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>/yolo_v3_tiny.labels <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> ../../data/testvideo3.mp4\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n\n<h2 id=\"認識結果をmp4ファイルに保存する\">認識結果をMP4ファイルに保存する</h2>\n\n<p>openCVではMP4ファイルを保存することができる。<br />\nobject_detection_demo_yolov3_async.py に以下の変更を加えることで、認識結果をMP4ファイルに保存することができる。</p>\n\n<p>以下の修正ファイルは簡易的に保存する処理を追加したため、保存ファイル名は決め打ち。 <br />\n汎用的にするなら、オプションで指定できるようにしてもいいかもね。</p>\n\n<p>ただし、実際に保存するタイミングとMP4ファイルのタイムインデックスが一致するわけではないので、\n処理時の見た目と保存ファイルを再生したときの見た目は異なるので注意が必要。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- object_detection_demo_yolov3_async.py\t2019-10-29 11:20:46.112091500 +0900\n</span><span class=\"gi\">+++ record.py\t2019-10-29 11:35:37.296005608 +0900\n</span><span class=\"p\">@@ -218,6 +218,18 @@</span>\n     number_input_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n     number_input_frames = 1 if number_input_frames != -1 and number_input_frames < 0 else number_input_frames\n \n<span class=\"gi\">+    # =====================================================================================\n+    # 幅と高さを取得\n+    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n+    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n+    size = (width, height)\n+    # フレームレート(1フレームの時間単位はミリ秒)の取得\n+    frame_rate = int(cap.get(cv2.CAP_PROP_FPS))\n+    # フォーマット\n+    fmt = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')\n+    writer = cv2.VideoWriter('./outtest.mp4', fmt, frame_rate, size)\n+    # =====================================================================================\n+\n</span>     wait_key_code = 1\n \n     # Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case\n<span class=\"p\">@@ -342,6 +354,9 @@</span>\n \n         start_time = time()\n         cv2.imshow(\"DetectionResults\", frame)\n<span class=\"gi\">+        # =====================================================================================\n+        writer.write(frame)\n+        # =====================================================================================\n</span>         render_time = time() - start_time\n \n         if is_async_mode:\n<span class=\"p\">@@ -359,6 +374,10 @@</span>\n             is_async_mode = not is_async_mode\n             log.info(\"Switched to {} mode\".format(\"async\" if is_async_mode else \"sync\"))\n \n<span class=\"gi\">+    # =====================================================================================\n+    writer.release()\n+    # =====================================================================================\n+\n</span>     cv2.destroyAllWindows()\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO フルパッケージをubuntuにインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO フルパッケージをubuntuにインストール</h1>\n      <p>openVINO フルパッケージをubuntuにインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>改訂版はこちら→<a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></p>\n\n<p>caffeモデルなどをopenVINOへ変換するには、フルパッケージが必要らしい。<br />\nでもって、フルパッケージはRaspberryPiでは使用できなくて、WindowsやLinux、macOSが必要。<br />\nということで、openVINO フルパッケージをubuntu 18.04にインストールする。 <br />\n(16.04でも大丈夫かもしれないけど、今回は18.04を使う。LTSじゃないのはやめといた方が良さそう)</p>\n\n<h1 id=\"ダウンロード--インストール前半\">ダウンロード & インストール前半</h1>\n\n<p>ダウンロードはこの辺を参考に。。。<br />\n<a href=\"https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758\">https://qiita.com/ammo0613/items/a9bb3b7f20dc02a8d758</a><br />\nなにやら登録しないといけないらしい。</p>\n\n<p>ダウンロードしたら、てきとーなところに展開して、インストーラを実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\n2910.10 「2019 R3.1」がリリースされた。ファイル名は「l_openvino_toolkit_p_2019.3.376.tgz」</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tar </span>xzvf /Share/l_openvino_toolkit_p_2019.3.334.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2019.3.334\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n</code></pre></div></div>\n\n<p>nextをクリックしていけば大丈夫(Agreeするとこはあるけど)。<br />\nあとで色々インストールしろと言われるけど、あとでやるので無視して大丈夫<br />\n・・・・しばらく待つ・・・・<br />\nいったんFinishするとブラウザが表示される<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies\">https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html#install-external-dependencies</a></p>\n\n<h1 id=\"インストール後半--動作確認\">インストール後半 & 動作確認</h1>\n\n<h2 id=\"install-external-software-dependenciesとな\">「Install External Software Dependencies」とな?</h2>\n\n<p>なんか実行してインストールしろってことらしい。<br />\nroot権限で実行しないとエラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_openvino_dependencies.sh\n</code></pre></div></div>\n\n<p>なんか色々インストールされるっぽい。<br />\n中身はOSのディストリビューションとバージョンでインストールパッケージを切り替えてインストールしてるらしい。</p>\n\n<h2 id=\"set-the-environment-variablesとな\">「Set the Environment Variables」とな?</h2>\n\n<p>環境変数の設定らしい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n\n<p>~/.bashrcに追加しておくと良いとのことなので、そうする。</p>\n\n<h2 id=\"configure-the-model-optimizerとな\">「Configure the Model Optimizer」とな?</h2>\n\n<p>モデルオプティマイザの設定。<br />\nこれが欲しかったのよ。</p>\n\n<p>必要なpipモジュールをインストールするらしい。<br />\n必要なものだけインストールすることもできるけど、一括でインストールしといた方が手間がかからないでしょう。</p>\n\n<p>pyenvを使ってると、<code class=\"language-plaintext highlighter-rouge\">sudo pip3</code>されると、systemのpip3が動いてしまい、pyenv環境にモジュールがインストールされない。<br />\nスクリプトの中で必要なコマンドだけ実行する(随分スッキリしちゃったなぁ)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/model_optimizer/requirements.txt\n</code></pre></div></div>\n\n<p>バージョン不一致とか言われたら、適宜バージョン合わせてアップグレードorダウングレードしてちょ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nsetuptoolsは<code class=\"language-plaintext highlighter-rouge\">pip install -U setuptools</code>でOKなはず。<br />\nnumpyは<code class=\"language-plaintext highlighter-rouge\">mxnet 1.3.1 has requirement numpy<1.15.0,>=1.8.2, but you'll have numpy 1.17.3 which is incompatible.</code>と言われるのだけど、tensorflow 1.15.0だとnumpy 1.16.0以上を要求する。<br />\nとりあえず、tenssorflowを1.13.1にしてnumpyを1.14.6にしてみて様子見。<br />\n現状のバージョン一覧は以下。これを<code class=\"language-plaintext highlighter-rouge\">requirements.txt</code>として保存し、<code class=\"language-plaintext highlighter-rouge\">pip install -r requirements.txt</code>するとこのバージョンでそろえてくれるはず。</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.8.1\nastor==0.8.0\ncertifi==2019.9.11\nchardet==3.0.4\ndecorator==4.4.0\ndefusedxml==0.6.0\ngast==0.2.2\ngoogle-pasta==0.1.7\ngraphviz==0.8.4\ngrpcio==1.24.3\nh5py==2.10.0\nidna==2.8\nKeras-Applications==1.0.8\nKeras-Preprocessing==1.1.0\nMarkdown==3.1.1\nmock==3.0.5\nmxnet==1.3.1\nnetworkx==2.3\nnumpy==1.14.6\nonnx==1.6.0\nopt-einsum==3.1.0\npipdeptree==0.13.2\nprotobuf==3.6.1\nrequests==2.22.0\nsix==1.12.0\ntensorboard==1.13.1\ntensorflow==1.13.1\ntensorflow-estimator==1.13.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4\nurllib3==1.25.6\nWerkzeug==0.16.0\nwrapt==1.11.2\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nオリジナルの方法はこちら</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_prerequisites.sh\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"run-the-verification-scripts-to-verify-installationとな\">「Run the Verification Scripts to Verify Installation」とな?</h2>\n\n<p>なになに、実行必須?たしかにapt installが実行される。<br />\nなら、タイトルに “to Verify Installation” とか書くなよ!</p>\n\n<p>build前に<code class=\"language-plaintext highlighter-rouge\">apt install</code> と <code class=\"language-plaintext highlighter-rouge\">pip install</code>が走る。</p>\n\n<p>こっちもpyenv使ってるとpipで悲しいことになるので、先にpipだけ実行しておく。<br />\nスクリプト側でもpipが走ってsystemのモジュールが追加されるが、悪影響はないと思うので、そのままにしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/requirements.in \n</code></pre></div></div>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n./demo_squeezenet_download_convert_run.sh\n</code></pre></div></div>\n\n<p>・・・・こんなことをやってるらしい・・・・</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">target_precision</code> は FP16 になっている</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">apt install</code> で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">pip install</code>で必要なモジュールをインストール</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/open_model_zoo/tools/downloaderdownloader.py</code>でモデルのダウンロードを行う\n    <ul>\n      <li>ダウンロード済みならスキップ»</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">deployment_tools/model_optimizer/mo.py</code>でモデル変換を行う\n    <ul>\n      <li>変換済みならスキップ»</li>\n    </ul>\n  </li>\n  <li>サンプルプログラムのbuild</li>\n  <li>サンプルプログラム(classification_sample_async)の実行<br />\n  実行結果はこんな感じ</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./classification_sample_async -d CPU -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/openvino_models/ir/FP16//public/squeezenet1.1/squeezenet1.1.xml \n\n[ INFO ] InferenceEngine: \n\tAPI version ............ 2.1\n\tBuild .................. custom_releases/2019/R3_cb6cad9663aea3d282e0e8b3e0bf359df665d5d0\n\tDescription ....... API\n[ INFO ] Parsing input parameters\n[ INFO ] Parsing input parameters\n[ INFO ] Files were added: 1\n[ INFO ]     /opt/intel/openvino/deployment_tools/demo/car.png\n[ INFO ] Creating Inference Engine\n\tCPU\n\tMKLDNNPlugin version ......... 2.1\n\tBuild ........... 30677\n\n[ INFO ] Loading network files\n[ INFO ] Preparing input blobs\n[ WARNING ] Image is resized from (787, 259) to (227, 227)\n[ INFO ] Batch size is 1\n[ INFO ] Loading model to the device\n[ INFO ] Create infer request\n[ INFO ] Start inference (10 asynchronous executions)\n[ INFO ] Completed 1 async request execution\n[ INFO ] Completed 2 async request execution\n[ INFO ] Completed 3 async request execution\n[ INFO ] Completed 4 async request execution\n[ INFO ] Completed 5 async request execution\n[ INFO ] Completed 6 async request execution\n[ INFO ] Completed 7 async request execution\n[ INFO ] Completed 8 async request execution\n[ INFO ] Completed 9 async request execution\n[ INFO ] Completed 10 async request execution\n[ INFO ] Processing output blobs\n\nTop 10 results:\n\nImage /opt/intel/openvino/deployment_tools/demo/car.png\n\nclassid probability label\n------- ----------- -----\n817     0.8364176   sports car, sport car\n511     0.0945683   convertible\n479     0.0419195   car wheel\n751     0.0091233   racer, race car, racing car\n436     0.0068038   beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon\n656     0.0037315   minivan\n586     0.0025940   half track\n717     0.0016044   pickup, pickup truck\n864     0.0012045   tow truck, tow car, wrecker\n581     0.0005833   grille, radiator grille\n\n[ INFO ] Execution successful\n\n[ INFO ] This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool\n</code></pre></div></div>\n\n<ul>\n  <li>終了</li>\n</ul>\n\n<p>もういっちょでも実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./demo_security_barrier_camera.sh\n</code></pre></div></div>\n\n<p>やってることは前のと同じ。<br />\nこっちはopenVINOのモデルをダウンロードするので、モデル変換はない。<br />\n最終的に実行しているデモプログラムはこんな感じ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Run ./security_barrier_camera_demo -d CPU -d_va CPU -d_lpr CPU -i /opt/intel/openvino/deployment_tools/demo/car_1.bmp -m ~/openvino_models/ir/FP16/intel/vehicle-license-plate-detection-barrier-0106/FP16/vehicle-license-plate-detection-barrier-0106.xml -m_lpr ~/openvino_models/ir/FP16/intel/license-plate-recognition-barrier-0001/FP16/license-plate-recognition-barrier-0001.xml -m_va ~/openvino_models/ir/FP16/intel/vehicle-attributes-recognition-barrier-0039/FP16/vehicle-attributes-recognition-barrier-0039.xml \n</code></pre></div></div>\n\n<h2 id=\"gpuやncstick使わないから以下スキップ\">GPUやNCStick使わないから以下スキップ</h2>\n\n<!--\n## 「Run a Sample Application」\n\nNCStickなどVPUベースの環境で実行するにはFP16モデルが必要\nデフォルトはFP32\n\nFP16: 16bit浮動小数点\nFP32: 32bit浮動小数点\n====\nmkdir ~/squeezenet1.1_FP16\ncd ~/squeezenet1.1_FP16\npython3 /opt/intel/openvino/deployment_tools/model_optimizer/mo.py --input_model ~/openvino_models/models/FP32/classification/squeezenet/1.1/caffe/squeezenet1.1.caffemodel --data_type FP16 --output_dir .\n\n====\n\n\n\n\n./classification_sample_async -i /opt/intel/openvino/deployment_tools/demo/car.png -m ~/squeezenet1.1_FP16/squeezenet1.1.xml -d CPU\n-->\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PythonでIntel NCStick2</title>\n  </head>\n  <body>\n    <header>\n      <h1>PythonでIntel NCStick2</h1>\n      <p>PythonでIntel NCStick2を操作する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"事前準備\">事前準備</h1>\n<p>何はなくともPythonが必要。<br />\n実際には3.7.4を使用して動作確認。</p>\n\n<p>Pythonはpyenvでインストールしておくのが便利。インストール方法は \n<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a> を参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\npyenvとの相性が悪いらしく、pyenvで3.7.xがインストールされていると\n(python3.7コマンド自体は存在するので;実行自体はエラーで返ってくるが)、\nsetupvars.shでPYTHONPATHにpython3.7用pathが設定されてしまう。\nプログラム中で<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>でpathを追加しても、sys.pathの末尾に追加されてしまい、\n先に設定された3.7用モジュールがインポートされてしまう。\nもし、他のバージョンのpythonで実行する場合は<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">sys.path.insert</code>で\npathの先頭に追加するようにしないといけないようだ(試してないけど)。</p>\n\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n    <span class=\"err\">↓</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"err\">《</span><span class=\"n\">path</span><span class=\"err\">》</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>ということで、下のプログラムソースの<code class=\"language-plaintext highlighter-rouge\">sys.path.append</code>の行は不要。</p>\n</blockquote>\n\n<h2 id=\"モジュールのインストール\">モジュールのインストール</h2>\n\n<p>必要なモジュール類をインストールする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgfortran-6-dev\npip <span class=\"nb\">install </span>numpy\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h2 id=\"ワークディレクトリ\">ワークディレクトリ</h2>\n\n<p>色々共通で使いたいサイズのでっかいファイルがあるので、ワークディレクトリを以下の構成で作成しておく。<br />\n以降のopenVINO関連の投稿もこのディレクトリ構成を使うようにする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># C++プログラム湯尾</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/c++\n<span class=\"c\"># pythonプログラム用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/python\n<span class=\"c\"># モデルデータ用</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP16\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/openvino_models/FP32\n</code></pre></div></div>\n\n<h1 id=\"参考\">参考</h1>\n\n<p><del>パクった</del> 参考にしたのは以下のあたり<br />\n解説や実行方法などはこっちを参照してちょ(相変わらずの他力本願ぶり…))</p>\n\n<ul>\n  <li><a href=\"http://jellyware.jp/openvino/\">JELLYWARE ゼロから学ぶディープラーニング推論</a>\n    <ul>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c07_ie_emotion.html\">Inference Engineを学んで感情分類</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c08_face_detection.html\">リアルタイム顔検出</a></li>\n      <li><a href=\"http://jellyware.jp/kurage/openvino/c09_emotion_app.html\">リアルタイム感情分析アプリ</a></li>\n    </ul>\n  </li>\n</ul>\n\n<p>顔検出+感情分類の参照元はカメラキャプチャした画像を処理しているけど、手元に適当なカメラがなかったので、JPEGファイルで実行するようにしてある(こっちの方が余計な処理なくて分かりやすいかな、と思ったのもある)。</p>\n\n<h1 id=\"感情分類\">感情分類</h1>\n\n<p>感情分類のプログラムを試す。</p>\n\n<h3 id=\"準備\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/emotions-recognition-retail-0003/FP16/emotions-recognition-retail-0003\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する顔画像(顔部分のみ切り出し)をPHOTO/face.jpgとして保存しておく。</p>\n\n<h3 id=\"プログラム\">プログラム</h3>\n\n<p>試したソースはこちら。<br />\nPCのubuntuで実行するための処理も追加済み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/face.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 結果取り出し\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>\n<span class=\"c1\"># 結果の最大値を持つインデックスを取得\n</span><span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 結果表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">結果'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">index_max</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"c1\"># 結果の詳細表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">---------------------</span><span class=\"se\">\\n</span><span class=\"s\">詳細'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'スコア:</span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">list_emotion_jp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">): </span><span class=\"si\">{</span><span class=\"n\">out</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出\">顔検出</h1>\n\n<p>顔検出のプログラムを試す。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-1\">準備</h3>\n\n<p>モデルデータをダウンロードしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">models_dir</span><span class=\"o\">=</span>/work/NCS2/openvino_models/FP16\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R1/models_bin/face-detection-retail-0004/FP16/face-detection-retail-0004\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.bin <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\nwget <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>.xml <span class=\"nt\">-P</span> <span class=\"k\">${</span><span class=\"nv\">models_dir</span><span class=\"k\">}</span>\n</code></pre></div></div>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-1\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n\n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n\n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-1\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_detect.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_detect.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_detect.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<!-- -------------------------------------------------------------------------------------------------------------------------------  -->\n<h1 id=\"顔検出感情分類\">顔検出+感情分類</h1>\n\n<p>上の2つを合体させ、顔検出した結果に感情分類を実行する。<br />\n結果画像を表示するので、X環境での実行必須。</p>\n\n<h3 id=\"準備-2\">準備</h3>\n\n<p>モデルデータは上の2つをそのまま使用。</p>\n\n<p>使用する画像をPHOTO/photo.jpgとして保存しておく。<br />\nまたは実行時にコマンドラインパラメータとしてファイル名を指定。</p>\n\n<h3 id=\"プログラム-2\">プログラム</h3>\n\n<p>試したソースはこちら。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 顔検出 + 感情分析\n</span>\n<span class=\"c1\"># モジュール読み込み \n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"c1\"># sys.path.append('/opt/intel/openvino/python/python3.7')\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># =======================================================\n# 使用する画像ファイル名\n</span><span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"s\">'PHOTO/photo.jpg'</span>\n\n<span class=\"c1\"># 使用するモデルファイルのディレクトリ\n</span><span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"s\">'/work/NCS2/openvino_models/FP16/'</span>\n\n<span class=\"c1\"># 各感情の文字列をリスト化 \n# 日本語表示にはPillow使うとかしないといけないので、英語で。\n</span><span class=\"n\">list_emotion</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'neutral'</span><span class=\"p\">,</span> <span class=\"s\">'happy'</span><span class=\"p\">,</span> <span class=\"s\">'sad'</span><span class=\"p\">,</span>    <span class=\"s\">'surprise'</span><span class=\"p\">,</span> <span class=\"s\">'anger'</span><span class=\"p\">]</span>\n<span class=\"n\">list_emotion_jp</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'無表情'</span><span class=\"p\">,</span>  <span class=\"s\">'幸福'</span><span class=\"p\">,</span>  <span class=\"s\">'悲しみ'</span><span class=\"p\">,</span> <span class=\"s\">'驚き'</span><span class=\"p\">,</span>     <span class=\"s\">'怒り'</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># =======================================================\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to a image/video file. default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">image_filename</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model_dir\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"sa\">f</span><span class=\"s\">\"Optional. Path to an .xml file with a trained model.default is </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-d\"</span><span class=\"p\">,</span> <span class=\"s\">\"--device\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is\"</span>\n                           <span class=\"s\">\" acceptable. The sample will look for a suitable plugin for device specified. \"</span>\n                           <span class=\"s\">\"Default value is CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"CPU\"</span><span class=\"p\">,</span> \n                        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># =======================================================\n# アスペクト比固定でリサイズする関数\n</span><span class=\"k\">def</span> <span class=\"nf\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"p\">):</span>\n    <span class=\"n\">scale</span> <span class=\"o\">=</span> <span class=\"n\">width</span> <span class=\"o\">/</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">dsize</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"n\">fx</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">,</span> <span class=\"n\">fy</span><span class=\"o\">=</span><span class=\"n\">scale</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# バウンティングボックスとラベルを表示する関数\n</span><span class=\"k\">def</span> <span class=\"nf\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ラベル領域サイズ\n</span>    <span class=\"n\">LABEL_W</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">12</span>    <span class=\"c1\"># 等幅フォントじゃないので正確ではないけど、大体こんな感じ\n</span>    <span class=\"n\">LABEL_H</span> <span class=\"o\">=</span> <span class=\"mi\">14</span>                <span class=\"c1\"># こっちもトライアンドエラーで微調整\n</span>    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">IMAGE_W</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">IMAGE_H</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># バウンディングボックス表示 \n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># ラベル表示位置(X)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">xmin</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">IMAGE_W</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">IMAGE_W</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_W</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_x</span> <span class=\"o\">=</span> <span class=\"n\">xmin</span>\n    \n    <span class=\"c1\"># ラベル表示位置(Y)\n</span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 画面からはみ出さないように\n</span>        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">label_y</span> <span class=\"o\">=</span> <span class=\"n\">ymin</span> <span class=\"o\">-</span> <span class=\"n\">LABEL_H</span>\n    \n    <span class=\"c1\"># 文字列背景描画(塗りつぶし)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">label_x</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_W</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 文字列描画(座標は文字の左下)\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">label_x</span><span class=\"p\">,</span> <span class=\"n\">label_y</span> <span class=\"o\">+</span> <span class=\"n\">LABEL_H</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX_SMALL</span><span class=\"p\">,</span> <span class=\"mf\">0.8</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># =======================================================\n# オプション指定値取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"n\">image_filename</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n<span class=\"n\">models_dir</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model_dir</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">' image_filename = </span><span class=\"si\">{</span><span class=\"n\">image_filename</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\"> models_dir=</span><span class=\"si\">{</span><span class=\"n\">models_dir</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ターゲットデバイスの指定 \n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span><span class=\"p\">)</span>\n<span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">device</span> <span class=\"o\">==</span> <span class=\"s\">\"CPU\"</span> <span class=\"ow\">and</span>  <span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">processor</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s\">'x86_64'</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># avx2対応extensionの追加\n</span>    <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">add_cpu_extension</span><span class=\"p\">(</span><span class=\"s\">\"libcpu_extension_avx2.so\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(顔検出) \n</span><span class=\"n\">net_detect</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'face-detection-retail-0004.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_detect</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_detect</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み(感情分類) \n</span><span class=\"n\">net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.xml'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">models_dir</span><span class=\"o\">+</span><span class=\"s\">'emotions-recognition-retail-0003.bin'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net_emotion</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net_emotion</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力画像読み込み \n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"n\">image_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 入力データフォーマットへ変換 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">300</span><span class=\"p\">,</span> <span class=\"mi\">300</span><span class=\"p\">))</span> <span class=\"c1\"># サイズ変更 \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">img</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>      <span class=\"c1\"># HWC > CHW \n</span><span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>   <span class=\"c1\"># 次元合せ \n</span>\n<span class=\"c1\"># 推論実行 \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_detect</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'detection_out'</span><span class=\"p\">]</span>\n<span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#サイズ1の次元を全て削除 \n</span>\n<span class=\"c1\"># アスペクト比固定で表示用画像をリサイズ\n</span><span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">scale_to_width</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"mi\">640</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 検出されたすべての顔領域に対して1つずつ処理 \n</span><span class=\"k\">for</span> <span class=\"n\">detection</span> <span class=\"ow\">in</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"c1\"># conf値の取得 \n</span>    <span class=\"n\">confidence</span> <span class=\"o\">=</span> <span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># conf値が0.5より小さい場合はスキップ\n</span>    <span class=\"k\">if</span> <span class=\"n\">confidence</span> <span class=\"o\"><</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n        <span class=\"k\">continue</span>\n    \n    <span class=\"c1\"># バウンディングボックス座標を入力画像のスケールに変換 \n</span>    <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">5</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">detection</span><span class=\"p\">[</span><span class=\"mi\">6</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># 顔検出領域はカメラ範囲内に補正する。特にminは補正しないとエラーになる\n</span>    <span class=\"k\">if</span> <span class=\"n\">xmin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">xmin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymin</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">ymin</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">xmax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">xmax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"k\">if</span> <span class=\"n\">ymax</span> <span class=\"o\">></span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]:</span>\n        <span class=\"n\">ymax</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 顔領域のみ切り出し \n</span>    <span class=\"n\">frame_face</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">[</span> <span class=\"n\">ymin</span><span class=\"p\">:</span><span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">:</span><span class=\"n\">xmax</span> <span class=\"p\">]</span>\n    \n    <span class=\"c1\"># 入力データフォーマットへ変換 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame_face</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"mi\">64</span><span class=\"p\">))</span>   <span class=\"c1\"># サイズ変更 \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">img_face</span><span class=\"p\">.</span><span class=\"n\">transpose</span><span class=\"p\">((</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">))</span>    <span class=\"c1\"># HWC > CHW \n</span>    <span class=\"n\">img_face</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">img_face</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"c1\"># 次元合せ \n</span>    \n    <span class=\"c1\"># 推論実行 \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net_emotion</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img_face</span><span class=\"p\">})</span>\n    \n    <span class=\"c1\"># 出力から必要なデータのみ取り出し \n</span>    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">out</span><span class=\"p\">[</span><span class=\"s\">'prob_emotion'</span><span class=\"p\">]</span>\n    <span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">squeeze</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span> <span class=\"c1\">#不要な次元の削減 \n</span>    \n    <span class=\"c1\"># 出力値が最大のインデックスを得る \n</span>    <span class=\"n\">index_max</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">out</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 結果表示\n</span>    <span class=\"c1\"># print(list_emotion[index_max])\n</span>    <span class=\"n\">disp_Bounting_box</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">xmin</span><span class=\"p\">,</span> <span class=\"n\">ymin</span><span class=\"p\">,</span> <span class=\"n\">xmax</span><span class=\"p\">,</span> <span class=\"n\">ymax</span><span class=\"p\">,</span> <span class=\"n\">list_emotion</span><span class=\"p\">[</span><span class=\"n\">index_max</span><span class=\"p\">],</span> <span class=\"p\">(</span><span class=\"mi\">120</span><span class=\"p\">,</span> <span class=\"mi\">90</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 画像表示 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'frame'</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 何らかのキーが押されたら終了 \n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"プログラムの実行-2\">プログラムの実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ヘルプの表示</span>\npython face_emotion.py <span class=\"nt\">-h</span>\n\n<span class=\"c\"># PCのCPUを使用した場合(RasPiのCPU使用だとエラーになる)</span>\npython face_emotion.py <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n\n<span class=\"c\"># NCS2を使用した場合</span>\npython face_emotion.py <span class=\"nt\">-d</span> MYRIAD <span class=\"o\">[</span><span class=\"nt\">-i</span> jpegファイル]\n</code></pre></div></div>\n\n<h1 id=\"考察\">考察</h1>\n\n<p>基本パターンはこんな感じ。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># モジュールのロード\n</span><span class=\"kn\">from</span> <span class=\"nn\">openvino.inference_engine</span> <span class=\"kn\">import</span> <span class=\"n\">IENetwork</span><span class=\"p\">,</span> <span class=\"n\">IEPlugin</span>\n\n<span class=\"c1\"># 初期化\n</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">IEPlugin</span><span class=\"p\">(</span><span class=\"n\">device</span><span class=\"o\">=</span><span class=\"s\">\"MYRIAD\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># モデルの読み込み\n</span><span class=\"n\">net</span> <span class=\"o\">=</span> <span class=\"n\">IENetwork</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"o\">=</span><span class=\"s\">'xmlファイル'</span><span class=\"p\">,</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"s\">'binファイル'</span><span class=\"p\">)</span>\n<span class=\"n\">exec_net</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"o\">=</span><span class=\"n\">net</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 推論実行 \n# imgは入力データ、Numpy配列 ndarray型\n</span><span class=\"n\">out</span> <span class=\"o\">=</span> <span class=\"n\">exec_net</span><span class=\"p\">.</span><span class=\"n\">infer</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s\">'data'</span><span class=\"p\">:</span> <span class=\"n\">img</span><span class=\"p\">})</span>\n\n<span class=\"c1\"># outが出力データ、Numpy配列 ndarray型\n</span>\n</code></pre></div></div>\n\n<p>入出力データの並びは読み込んだモデルに依存する。<br />\n入力データのサイズやRGB並び順などを合わせる。<br />\n(モデルに入力する際にリサイズすれば、元の画像ファイルのサイズは任意で良い。)<br />\n出力データはそのままでは「何のこっちゃ?」なので、きちんと整形してやる必要がある。</p>\n\n<p>ここに学習済みデータが色々登録されているらしい。<br />\n<a href=\"https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html\">https://docs.openvinotoolkit.org/2019_R1/_docs_Pre_Trained_Models.html</a></p>\n\n<p>TensorflowやCaffeで作成した学習済みデータを変換することもできるらしいが、やり方はこれから調査。</p>\n\n<h1 id=\"参考情報\">参考情報</h1>\n<p><a href=\"https://software.intel.com/en-us/articles/OpenVINO-RelNotes\">openVINO toolkit リリースノート</a><br />\n<a href=\"https://git.uni-paderborn.de/rnagle/dldt/tree/noctua_plugin_develop\">openVINO toolkit リポジトリ</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Intel NCStick2用動作環境の構築</title>\n  </head>\n  <body>\n    <header>\n      <h1>Intel NCStick2用動作環境の構築</h1>\n      <p>Intel NCStick2用動作環境の構築</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Dセンセの悪魔の囁きに踊らされ、Intel NCStick2をポチってしまった。<br />\nで、動作環境を構築したときのメモを残しておく。</p>\n\n<p>ホストマシンは、RaspberryPi3 model B+ で Raspbian Buster を使用。</p>\n\n<p>Raspbian Busterのインストールは、\n<a href=\"/memoBlog/2019/08/31/raspbian_buster_1.html\">Raspbian Busterのインストール</a>\nの手順で行った。</p>\n\n<p><a href=\"http://jellyware.jp/openvino/\">JellyWare:ゼロから学ぶディープラーニング推論</a> \n → <a href=\"http://jellyware.jp/kurage/openvino/c03_setting.html\">ゼロから始めるインストール</a> をマネしただけだが、\nダウンロード先の<strong>URLが微妙に変更</strong>されてたり、\nこのページの説明が<strong>細かすぎてちょっとイラっとした</strong>ので、\n以下に手順の要約を書いておく。</p>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2\n<span class=\"nb\">cd</span> /work/NCS2/\n</code></pre></div></div>\n\n<h2 id=\"openvino-の取得とインストール\">openVINO の取得とインストール</h2>\n\n<p>アーカイブファイル落としてきて、展開するだけ。<br />\nR3がリリースされているようなので、これを使う。(2019/10/01現在)\nちょくちょくリリースされるみたいなので、<a href=\"https://download.01.org/opencv/2019/openvinotoolkit/\">https://download.01.org/opencv/2019/openvinotoolkit/</a>をチェックしてね。<br />\n2020年になったら、~download.01.org/opencv/2020/~ なのかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R3/l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz\n\n<span class=\"c\"># インストール先ディレクトリの作成 & オーナー変更(あとあとめんどくさいので)</span>\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span>  <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n\n<span class=\"c\"># 展開</span>\n<span class=\"nb\">tar </span>xzvf l_openvino_toolkit_runtime_raspbian_p_2019.3.334.tgz <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span> <span class=\"nt\">--strip-components</span><span class=\"o\">=</span>1\n<span class=\"nb\">sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n以下以前の情報</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://download.01.org/opencv/2019/openvinotoolkit/R2/l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz\n\n<span class=\"nv\">VINO_DIR_TMP</span><span class=\"o\">=</span>/opt/intel/openvino\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo tar</span> <span class=\"nt\">-xf</span> l_openvino_toolkit_runtime_raspbian_p_2019.2.242.tgz <span class=\"nt\">--strip</span> 1 <span class=\"nt\">-C</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>\n<span class=\"nb\">sudo sed</span> <span class=\"nt\">-i</span> <span class=\"s2\">\"s|<INSTALLDIR>|</span><span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span><span class=\"s2\">|\"</span> <span class=\"k\">${</span><span class=\"nv\">VINO_DIR_TMP</span><span class=\"k\">}</span>/bin/setupvars.sh\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h2 id=\"cmakeのインストール\">cmakeのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n</code></pre></div></div>\n\n<p>他にもmakeとかbuild-essentialとか要るけど、<a href=\"/memoBlog/2019/06/27/pyenv.html\">ここ</a>\nでインストールしたやつがあれば大丈夫っぽい。</p>\n\n<h2 id=\"初期化スクリプトの変更\">初期化スクリプトの変更</h2>\n\n<p>~/.bashrc の最後に以下を追加。<br />\nここでは<code class=\"language-plaintext highlighter-rouge\">${VINO_DIR_TMP}</code>使っちゃダメよ~。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOの設定</span>\n<span class=\"nb\">source</span> /opt/intel/openvino/bin/setupvars.sh\n</code></pre></div></div>\n<h2 id=\"初期化スクリプトの変更を反映\">初期化スクリプトの変更を反映</h2>\n\n<p>シリアルコンソールやSSHでlog inしてる場合は、ここで一旦log offして再log in。<br />\nX使ってるならターミナル開きなおす。<br />\nもちろん、<code class=\"language-plaintext highlighter-rouge\">source</code>するだけでも良いけど。<br />\nいちお、.bashrcにちゃんと書けてるか確認の意味で一旦log off or ターミナル開きなおしするのがいいかな。  <br />\n(.bashrcの変更だけなので、再起動までは必要ない) <br />\nlog in時 or 新しいターミナルを開いた時に <code class=\"language-plaintext highlighter-rouge\">[setupvars.sh] OpenVINO environment initialized</code> と表示されることを確認。</p>\n\n<h2 id=\"グループの追加\">グループの追加</h2>\n\n<p>ユーザがグループusersを持っているか確認。(デフォルトなら持ってるハズ) 持ってなかったら追加。<br />\n次のコマンドで追加してくれるっぽいけど。。。</p>\n\n<h2 id=\"udevルールの追加\">udevルールの追加</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sh <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/install_dependencies/install_NCS_udev_rules.sh\n</code></pre></div></div>\n\n<h2 id=\"いよいよncstick2の登場だ\">いよいよNCStick2の登場だ~~~</h2>\n\n<p>NCStick2をUSBポートにぶっ挿す。<br />\nデカくて他のポートに干渉するので、必要なら延長ケーブルを使ってちょ。</p>\n\n<p>で、認識されたか確認。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n<span class=\"c\"># こんな感じで表示されるハズ。XXX部分は ぶっ挿したUSBポートで変わる。</span>\n・・・\nBus XXX Device XXX: ID 03e7:2485 Intel Movidius MyriadX\n・・・\n</code></pre></div></div>\n\n<h2 id=\"サンプルのbuild\">サンプルのbuild</h2>\n\n<p>とりあえず、ワークディレクトリは<code class=\"language-plaintext highlighter-rouge\">/work/NCS2/</code>を使ってる。<br />\nhome に色々ぶち込むの嫌いなので。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">/work</code>は作成済みで<code class=\"language-plaintext highlighter-rouge\">chown</code>済みとする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ワークディレクトリの作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/NCS2/sample\n<span class=\"nb\">cd</span> /work/NCS2/sample\n\n<span class=\"c\"># cmakeの実行</span>\ncmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-march=armv7-a\"</span> <span class=\"k\">${</span><span class=\"nv\">INTEL_CVSDK_DIR</span><span class=\"k\">}</span>/deployment_tools/inference_engine/samples\n\n<span class=\"c\"># makeの実行</span>\nmake <span class=\"nt\">-j2</span> object_detection_sample_ssd\n\n<span class=\"c\"># ネットワークデータの取得</span>\n<span class=\"c\"># shell変数の設定時はスペース入れちゃダメだよ~</span>\n<span class=\"nv\">DL_URL1</span><span class=\"o\">=</span>https://download.01.org/opencv/2019/open_model_zoo/R2/20190716_170000_models_bin/face-detection-adas-0001/FP16\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.bin\nwget <span class=\"nt\">--no-check-certificate</span> <span class=\"k\">${</span><span class=\"nv\">DL_URL1</span><span class=\"k\">}</span>/face-detection-adas-0001.xml\n\n<span class=\"c\"># 入力ファイルをどっかから持ってきて、<<入力ファイル>>.jpgとしてカレントディレクトリに保存しておく</span>\n<span class=\"c\"># 顔検出のデモなので、人物が何人か写ってる画像を用意してね。</span>\n\n<span class=\"c\"># サンプル実行</span>\n./armv7l/Release/object_detection_sample_ssd  <span class=\"nt\">-m</span> face-detection-adas-0001.xml <span class=\"nt\">-d</span> MYRIAD <span class=\"nt\">-i</span> <<入力ファイル>>.jpg\n\n<span class=\"c\"># out_0.bmpができる</span>\n</code></pre></div></div>\n\n<h2 id=\"結果の確認\">結果の確認</h2>\n\n<p>out_0.bmpをテキトーに表示。<br />\n人物の顔が四角で囲まれていることを確認。</p>\n\n<h2 id=\"インストールと動作確認完了\">インストールと動作確認完了</h2>\n\n<p>めでたしめでたし。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "WebIOPi": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WebIOPiをRaspbian Busterで動かす</title>\n  </head>\n  <body>\n    <header>\n      <h1>WebIOPiをRaspbian Busterで動かす</h1>\n      <p>WebIOPiをRaspbian Busterで動かす</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"背景\">背景</h1>\n\n<p>知人がWebIOPiをRaspbian Busterで動かそうとして、Raspbian Stretch では動いたが、Raspbian Busterだと動かないと言っていたので、\n興味本位でデバッグしてみた。</p>\n\n<p>私はこれを使おうと思ってないので、「鳴かぬなら鳴かせてみせようホトトギス」なだけなので、詳しい使い方とかは調べてません。</p>\n\n<h1 id=\"参照\">参照</h1>\n\n<p>そもそものインストール手順は、<br />\n<a href=\"https://www.hiramine.com/physicalcomputing/raspberrypi3/webiopi_install.html\">WebIOPi のインストール</a><br />\n<a href=\"https://www.fabshop.jp/%E9%96%8B%E7%99%BA%E3%81%8C%E7%B5%82%E4%BA%86%E3%81%97%E3%81%9Fwebiopi%E3%82%92%E6%9C%80%E6%96%B0%E3%81%AEraspbian%E3%81%A7%E5%8B%95%E4%BD%9C%E3%81%95%E3%81%9B%E3%82%88%E3%81%86%E3%80%82/?fbclid=IwAR1u1Hq0wSqnDhPnKDeoyf1b2AmrdpO99TLSevUTZ237D5Ny97pliLjlOwU\">開発が終了したWebIOPiを最新のRaspbianで動作させよう。</a><br />\nあたりを参考にしてちょ。</p>\n\n<h1 id=\"いきなり結論\">いきなり結論</h1>\n\n<p>で、まぁ結論から言うと、根本原因は、BusterのPython3がPython3.7にバージョンアップされたこと。<br />\nちなみに、StretchのPython3はPython3.5 。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">python/webiopi/utils/thread.py</code> 内の 関数 <code class=\"language-plaintext highlighter-rouge\">runLoop()</code>の中で<code class=\"language-plaintext highlighter-rouge\">async</code>を変数に使っていたため、SyntaxErrorが発生していた模様。<br />\nPythom3.7では(正確にはPython3.6から)<code class=\"language-plaintext highlighter-rouge\">async</code>は予約語になっているため、エラーとなっていた。</p>\n\n<p>で、変数名を<code class=\"language-plaintext highlighter-rouge\">async</code>からそれ以外(例えば<code class=\"language-plaintext highlighter-rouge\">async_Flag</code>)に変更すれば良い。</p>\n\n<h1 id=\"でpatchファイル\">で、patchファイル</h1>\n\n<p>修正内容のpatchファイルがこちら。<br />\nついでにCプログラムのコンパイルの際に出るワーニングも消すようにちょこっと修正しときました。(こっちの修正は、かなりヤッツケ…)</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/cpuinfo.c WebIOPi-0.7.1/python/native/cpuinfo.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/cpuinfo.c\t2019-09-03 00:04:59.959369913 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/cpuinfo.c\t2019-09-02 23:55:16.207501342 +0900\n</span><span class=\"p\">@@ -35,7 +35,8 @@</span> char *get_cpuinfo_revision(char *revisio\n       return 0;\n \n    while(!feof(fp)) {\n<span class=\"gd\">-      fgets(buffer, sizeof(buffer) , fp);\n</span><span class=\"gi\">+      char* aaa = fgets(buffer, sizeof(buffer) , fp);\n+      aaa = aaa;\n</span>       sscanf(buffer, \"Hardware\t: %s\", hardware);\n       if (strcmp(hardware, \"BCM2708\") == 0)\n          rpi_found = 1;\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/native/gpio.c WebIOPi-0.7.1/python/native/gpio.c\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/native/gpio.c\t2019-09-03 00:04:59.969368480 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/native/gpio.c\t2019-09-02 23:58:58.757767098 +0900\n</span><span class=\"p\">@@ -23,6 +23,7 @@</span> SOFTWARE.\n #include <stdio.h>\n #include <stdint.h>\n #include <stdlib.h>\n<span class=\"gi\">+#include <unistd.h>\n</span> #include <string.h>\n #include <fcntl.h>\n #include <sys/mman.h>\n<span class=\"gh\">diff -upr WebIOPi-0.7.1.old/python/webiopi/utils/thread.py WebIOPi-0.7.1/python/webiopi/utils/thread.py\n</span><span class=\"gd\">--- WebIOPi-0.7.1.old/python/webiopi/utils/thread.py\t2019-09-03 00:04:44.520586361 +0900\n</span><span class=\"gi\">+++ WebIOPi-0.7.1/python/webiopi/utils/thread.py\t2019-09-02 23:54:10.087479478 +0900\n</span><span class=\"p\">@@ -33,14 +33,14 @@</span> def stop(signum=0, frame=None):\n             task.stop()\n                 \n \n<span class=\"gd\">-def runLoop(func=None, async=False):\n</span><span class=\"gi\">+def runLoop(func=None, async_Flag=False):\n</span>     global RUNNING\n     RUNNING = True\n     signal.signal(signal.SIGINT, stop)\n     signal.signal(signal.SIGTERM, stop)\n \n     if func != None:\n<span class=\"gd\">-        if async:\n</span><span class=\"gi\">+        if async_Flag:\n</span>             TASKS.append(Task(func, True))\n         else:\n             while RUNNING:\n</code></pre></div></div>\n\n<p>これを<code class=\"language-plaintext highlighter-rouge\">webiopi-buster.patch</code>として保存し、以下のコマンドを実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch <span class=\"nt\">-p1</span> <span class=\"nt\">-i</span> webiopi-buster.patch\n</code></pre></div></div>\n\n<p>で後は<code class=\"language-plaintext highlighter-rouge\">settup.sh</code>を実行して、その後は参照ページの通り進めれば良い。</p>\n\n<h1 id=\"めでたしめでたし\">めでたしめでたし</h1>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Node-RED": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その9)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その9)</h1>\n      <p>Node-REDのメモ 応用編 Google spreadsheet Read</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGoogle spreadsheet からデータを取得したときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><strong>その8</strong> に従って準備済みであるものとする。</p>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で作成済みの認証情報を選択するか、「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に操作対象のスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:zzz」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n          <li>Rangeのフォーマットはシート名!開始セル:終了セル\n            <ul>\n              <li>開始セルと終了セルを両方省略することは可能(片方のみ省略は不可のよう)。<br />\nこの場合、シート全体が取得される。ただし、↑のように特定のシート名はダメかもしれない。</li>\n              <li>開始セル/終了セルはカラム名と行番号で構成されるが、カラム名か行番号は省略可能。\nたぶん、こんな感じ。\n                <ul>\n                  <li>開始カラム名を省略するとAが指定されたとみなす</li>\n                  <li>開始行番号を省略すると1が指定されたとみなす</li>\n                  <li>終了カラム名を省略すると最終カラム(zzz?)が指定されたとみなす</li>\n                  <li>終了行番号を省略すると最終行が指定されたとみなす</li>\n                </ul>\n              </li>\n              <li>大きな範囲を指定しても、以降空白セルであった場合は無視される(有効なデータがある範囲だけ読み込まれる)</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n          <li>プロパティ名はシート名_開始セル_終了セル</li>\n          <li>globalに記録しておけば、キャッシュとして使用出来て、なんども同じデータを読まなくて済む、という使い方かな?</li>\n        </ul>\n      </li>\n      <li>\n        <p>「Action」に「Get Data」を選択し、その右は「By line」を選択</p>\n      </li>\n      <li>「Labels」の「First line for labels」を選択しすると、outputの型がDictionaryになる。指定したセル範囲の開始カラム(シート全体の開始カラムではない)がキー名となる。<br />\n 選択しなければ、outputの型がArrayになる</li>\n      <li>「Labels」の「First column for labels」を選択しすると、outputの各要素の型がDictionaryになる。指定したセル範囲の開始行(シート全体の開始行ではない)の内容がキー名となる。<br />\n 選択しなければ、outputの各要素の型がArrayになる</li>\n      <li>\n        <p>この2つ、なんか逆な気もするけど…</p>\n      </li>\n      <li>outputにリード結果が入る。とりあえず「msg」を選択し、「_output」にしておく\n内容は「Labels」の設定内容によって変わる</li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>設定内容と取得内容の関係はよくワカランので、色々試してみてください。<br />\n現実的には、細かくデータを取得してどうこうするより、シート全体を取得して処理するような使い方になるのかな??</p>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、スプレッドシートの内容が取得されるハズ。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"5eb2475f.ea747\",\n        \"type\": \"tab\",\n        \"label\": \"spreadsheet_read\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"60d62f37.80a8a\",\n        \"type\": \"inject\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"bba510f2.5bb2d8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e183b4f0.c372f\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"37bd743e.1ca96c\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"bba510f2.5bb2d8\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"spreadsheet read\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:zzz\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"get\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": true,\n        \"fields\": \"all\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"\",\n        \"output\": \"_output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 290,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"e183b4f0.c372f\"\n            ],\n            [\n                \"37bd743e.1ca96c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その8)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その8)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Google spreadsheet</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをGoogle spreadsheet に記録するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"google-spreadsheet用ノードのインストール\">Google spreadsheet用ノードのインストール</h2>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-contrib-viseo-google-」と入力</li>\n  <li>下に検索結果が出るので、「node-red-contrib-viseo-google-authentication」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら続けて「node-red-contrib-viseo-google-spreadsheet」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h2 id=\"googleの準備\">Googleの準備</h2>\n\n<p><a href=\"https://techblog.lclco.com/entry/2018/11/30/120000\">具体的な手順はこちらを参考にしてくだされ。</a> (コードの実装の手前まで)  <br />\nただし、<span style=\"color: red; \">有効にするAPI</span>は「Google Drive API」ではなく、「<span style=\"color: red; \">Google Sheets API</span>」なので、注意!!</p>\n\n<h3 id=\"認証情報の作成\">認証情報の作成</h3>\n\n<ul>\n  <li><a href=\"https://console.developers.google.com/project\">Google Developers Console</a> でプロジェクトを作成</li>\n  <li>Google Sheets APIを有効化</li>\n  <li>認証情報(サービスアカウント キー)を作成</li>\n  <li>保存された認証情報の秘密鍵をダウンロード<br />\n  このファイルはセキュリティ上 <strong>超重要</strong> なので、まちがって公開しないように!!!!<br />\n  ・・・・公開して後悔…なんちゃって(^^ゞ</li>\n</ul>\n\n<h3 id=\"記録用スプレッドシートの作成\">記録用スプレッドシートの作成</h3>\n\n<ul>\n  <li><a href=\"https://drive.google.com/drive/u/0/my-drive\">Google Drive</a>から記録するスプレッドシートを作成する(マイドライブからgoogleスプレッドシートを選択すると新規ファイルが作成される)</li>\n  <li>作成されたスプレッドシートに共有ユーザ(サービスアカウントキーのメールアドレス)を追加。権限を編集者、通知のチェックははずしてOKする</li>\n  <li>必要ならシートの追加や名前の変更を行っておく(以下ではシート名が「BME280」になっているものとして説明)</li>\n  <li>1行目に項目名を入れておく。ここではA列から「epoch」「日付」「温度」「湿度」「気圧」としている</li>\n  <li>B列(「日付」の列)を選択し、メニューから「表示形式」→「数値」→「日時」を選択(これをやらないと時刻が見えない))</li>\n  <li>作成されたスプレッドシートのID(URLの docs.google.com/spreadsheets/d/<span style=\"color: red; \">この部分</span>/edit~)をメモしておく</li>\n</ul>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"bme280ノード\">BME280ノード</h3>\n\n<ul>\n  <li><strong>その2</strong>の<strong>BME280を使用するフローを作成する</strong>と同様の手順でBME280ノードを作成する</li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>出力側にFunctionノードを接続\n  コードは以下。<br />\n  あとで時刻を使用しやすいようにエポック時刻で記録するようにしている。<br />\n  また、エポック時刻のままだとスプレッドシーで見たときに日時が分かり難いので、エポック時刻から日時に変更する計算式を入れておく。(ここで直接文字列にすることもできるが)<br />\n  また、Google Sheetsノードの入力はArrayである必要があるようで、Ayyayでラップしておく。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">var</span> <span class=\"nx\">date</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">epoch</span> <span class=\"o\">=</span> <span class=\"nx\">date</span><span class=\"p\">.</span><span class=\"nx\">getTime</span><span class=\"p\">();</span>\n<span class=\"c1\">// msg.payload.date  = date.toString();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">date</span>  <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">=indirect(\"R[0]C[-1]\", false) / (1000*60*60*24) + (9/24) + DATE(1970, 1, 1)</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">];</span>\n\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に上でメモっておいたスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:z」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>set dataのときは使用されないようだ</li>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n        </ul>\n      </li>\n      <li>「Action」に「Set Data」を選択し、その右は「Append」を選択</li>\n      <li>「input」は「msg」を選択し、「payload」を入力</li>\n      <li>「Fields」で「Select」を選択</li>\n      <li>その下に「key」と入力欄が表示されるので、「epoch」と入力し、「追加」をクリック</li>\n      <li>「date」と入力し、「追加」をクリック</li>\n      <li>「temperature_C」と入力し、「追加」をクリック</li>\n      <li>「humidity」と入力し、「追加」をクリック</li>\n      <li>「pressure_hPa」と入力\n        <ul>\n          <li>このデータの並びが入力のプロパティ名とスプレッドシートのセルの並びに対応する</li>\n        </ul>\n      </li>\n      <li>outputもよー分からんけど、とりあえず「msg」を選択し、「_output」にしておく\n        <ul>\n          <li>set dataのときは処理結果が入るようだ</li>\n          <li>get dataのときはリード結果が入るようだ</li>\n        </ul>\n      </li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>このノードの入力にファンクションノードの出力を接続</li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、温度等を測定、スプレッドシートに送信される。<br />\nスプレッドシートを確認すれば、そのデータが記録されているハズである。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1a4f21c6.53e09e\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+spreadsheet\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"b4e73f33.99aec8\",\n        \"type\": \"Bme280\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 220,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"a54ed898.2a114\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"b74c37d3.63a48\",\n        \"type\": \"inject\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 90,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"b4e73f33.99aec8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a54ed898.2a114\",\n        \"type\": \"function\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"データ整形\",\n        \"func\": \"var date = new Date();\\nmsg.payload.epoch = date.getTime();\\n// msg.payload.date  = date.toString();\\n// msg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\",false)/1000/60/60/24 + 9/24 + DATE(1970,1,1)';\\nmsg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\", false) / (1000*60*60*24) + (9 / 24) + DATE(1970, 1, 1)';\\n\\nmsg.payload = [msg.payload];\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 390,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"6a4f8cc4.882e54\",\n                \"adad9a.88697a68\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6a4f8cc4.882e54\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:z\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"set\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": false,\n        \"fields\": \"select\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"epoch\",\n            \"date\",\n            \"temperature_C\",\n            \"humidity\",\n            \"pressure_hPa\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"payload\",\n        \"output\": \"__output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 620,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"93209cb1.cd86\"\n            ],\n            [\n                \"9a8717a8.88bae8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"93209cb1.cd86\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9a8717a8.88bae8\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 220,\n        \"wires\": []\n    },\n    {\n        \"id\": \"adad9a.88697a68\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 850,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その7)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その7)</h1>\n      <p>Node-REDのメモ 応用編 GPIO+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIOの入出力データをWebsocketで飛ばして、Dashboardから操作/Dashboardで表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"gpio入出力データをwebsocketで送受信raspberrypi\">GPIO入出力データをWebsocketで送受信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>RaspberryPiでGPIO出力</strong>、<strong>RaspberryPiでGPIO入力</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>、<strong>Websocketでデータを受信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、GPIO入力データをそのまま送信すると、受け取り側で「0はON?それともOFF?」となってしまうので、GPIO入力の0/1をON/OFFの文字列に変換するファンクションノードを追加している。\n  また、GPIO出力側も同様に、送信側から送られてきたON/OFFの文字列をGPIO出力データの1/0の数値に変換するファンクションノードを挿入している。<br />\n  ターゲットボードの正論理/負論理が変更になった場合はこれらのファンクションノードで調整すれば良い。</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"6e229d5a.774af4\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"109b9bce.e015e4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 730,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4834db5b.5c24d4\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": true,\n        \"x\": 190,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"3ff59514.52c732\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7d90bda.d7b4b8\",\n        \"type\": \"websocket in\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"47e24d88.c603e4\",\n        \"x\": 280,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"a38bd8a1.0a5bd8\",\n                \"5e99ea44.cfdac4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9bc37a7.e1e9808\",\n        \"type\": \"websocket out\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"c4985621.1edb48\",\n        \"x\": 830,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"a38bd8a1.0a5bd8\",\n        \"type\": \"debug\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 730,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3ff59514.52c732\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"1/0→OFF/ON\",\n        \"func\": \"if (msg.payload) {\\n    msg.payload = 'OFF';\\n}\\nelse {\\n    msg.payload = 'ON';\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"9bc37a7.e1e9808\",\n                \"a38bd8a1.0a5bd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5e99ea44.cfdac4\",\n        \"type\": \"function\",\n        \"z\": \"6e229d5a.774af4\",\n        \"name\": \"OFF/ON→0/1\",\n        \"func\": \"if (msg.payload == 'OFF') {\\n    msg.payload = 0;\\n}\\nelse {\\n    msg.payload = 1;\\n}\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 540,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"109b9bce.e015e4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47e24d88.c603e4\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/led0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"c4985621.1edb48\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/sw0\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからgpio入出力データを送受信サーバ\">WebsocketからGPIO入出力データを送受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータ送信(サーバ)</strong>、<strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノードに<strong>その4</strong> の <strong>Dashboard のUIを作成する(ボタン)</strong>、<strong>Dashboardでテキストを表示する</strong>で作成したノードを接続すれば良い。</li>\n</ul>\n\n<p>この状態でRaspberryPi側でスイッチをON/OFFすると、Dashboardの「SW」の文字列のON/OFFが切り替わる。\nまた、DashboardのLLED_ON/LED_OFFのボタンをクリックすると、LEDが点灯/消灯する</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"ca6a740f.4d43b8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_GPIO\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"ac19aeee.9f8f5\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 260,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"2098e31e.e6832c\",\n        \"type\": \"ui_button\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"LED0_OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 270,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"299e8287.226e6e\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8db70b6.86a1178\",\n        \"type\": \"ui_text\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"group\": \"b7e42e0e.52bdb\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 610,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f45af19.269e\",\n        \"type\": \"websocket in\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"fad64a63.6141a\",\n        \"client\": \"\",\n        \"x\": 270,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"8db70b6.86a1178\",\n                \"95b08556.d2cce\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"299e8287.226e6e\",\n        \"type\": \"websocket out\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"server\": \"d7b33218.4a1f28\",\n        \"client\": \"\",\n        \"x\": 630,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"95b08556.d2cce\",\n        \"type\": \"debug\",\n        \"z\": \"ca6a740f.4d43b8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 610,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"b7e42e0e.52bdb\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"1b4acf7b.a194c9\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"fad64a63.6141a\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/sw0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"d7b33218.4a1f28\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/led0\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"1b4acf7b.a194c9\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ3\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その6)</h1>\n      <p>Node-REDのメモ MQTT編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでMQTT通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"mqttでデータを送受信\">MQTTでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにmosquitto broker および mosquitto client toolsを使うこととします。<br />\nこれらは以下のコマンドでインストールできます。</p>\n\n<p>Ubuntuで動作確認。RaspberryPiでも大丈夫なはず。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mosquitto mosquitto-clients\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータ送信publish\">MQTTでデータ送信(Publish)</h2>\n\n<p>MQTTでデータを送信してみます</p>\n\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要なら「名前」を設定\n            <ul>\n              <li>省略するとサーバアドレスとポート番号が表示される</li>\n            </ul>\n          </li>\n          <li>「サーバ」 でブローカのアドレス(またはホスト名)を設定(例: PiDev25.local)</li>\n          <li>「ポート」 でポート番号を設定(一般的な設定なら1883のままで大丈夫)</li>\n          <li>SSL/TLS接続を使用する場合は「SSL/TLS接続を使用」のチェックを入れる</li>\n          <li>クライアントIDを指定したい場合は「クライアント」に設定。通常は空欄で大丈夫</li>\n          <li>キープアライブ時間を「キープアライブ時間」に設定</li>\n          <li>「セッションの初期化」?とりあえず初期設定のままで</li>\n          <li>「旧MQTT 3.1のサポート」?とりあえず初期設定のままで</li>\n          <li>「セキュリティ」タブ、「メッセージ」タブの内容は必要なら設定する。設定しなくても大丈夫</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に送信するトピックを設定\n        <ul>\n          <li>省略すると、トリガノードの出力に設定されているtopicが使用される</li>\n        </ul>\n      </li>\n      <li>「QoS」を「0」/「1」/「2」から選択</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される\n            <ul>\n              <li>トピックも省略されている場合はmqttと表示される</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のようにsubscriberコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> 《トピック》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカからすべてのトピック(“#”)を取得するよう指定しています。<br />\n-v 指定により、対象メッセージのトピックも表示されます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_sub <span class=\"nt\">-h</span> Pidev25.local <span class=\"nt\">-v</span> <span class=\"nt\">-t</span> <span class=\"s2\">\"#\"</span>\n</code></pre></div></div>\n<p>Node-RED側で mqttの送信をトリガするとmosquitto_subの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>test_data 0\ntest_data 1\ntest_data true\ntest_data false\ntest_data 文字列\ntest_data {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"f580f01a.f771f\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_publish\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"33450bad.82764c\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ea6d9236.74e038\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d7baa4c.08385\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"82148e63.4b97e\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d0b1ac7f.0ac0b\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"topic\": \"test_data\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7e6180b5.f29098\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"test_data\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6f26fe46.a01f58\",\n        \"type\": \"inject\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"バッファ\",\n        \"topic\": \"test_data\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 140,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d5a5b2db.83462\",\n                \"e6218cda.844308\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d5a5b2db.83462\",\n        \"type\": \"debug\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 500,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"e6218cda.844308\",\n        \"type\": \"mqtt out\",\n        \"z\": \"f580f01a.f771f\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"\",\n        \"qos\": \"\",\n        \"retain\": \"\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 570,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"mqttでデータを受信subscribe\">MQTTでデータを受信(subscribe)</h2>\n\n<p>MQTTでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「mqtt」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「mqtt」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「サーバ」 で 「新規に mqtt-broker を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているブローカを選択</li>\n      <li>「サーバ」 に 今設定した mqtt-broker が表示されていることを確認</li>\n      <li>「トピック」に受信するトピックを設定\n        <ul>\n          <li>すべてのトピックを受信するには#を設定</li>\n          <li>省略することはできない</li>\n        </ul>\n      </li>\n      <li>「QoS」を設定</li>\n      <li>「出力」を「自動判別」/「バイナリバッファ」/「文字列」/「JSONオブジェクト」/「Base64文字列」から選択。通常は「自動判別」でOK</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとトピックが表示される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>デプロイ後、ターミナル or コンソールで以下のようにpublisherコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> 《ブローカのアドレス》 <span class=\"nt\">-t</span> 《トピック》 <span class=\"nt\">-m</span> 《メッセージ》\n</code></pre></div></div>\n\n<p>例えば以下。マシン名PiDev25.localのブローカへ、トピック test_data で、メッセージ test を送信しています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mosquitto_pub <span class=\"nt\">-h</span> PiDev25.local <span class=\"nt\">-t</span> <span class=\"s2\">\"test_data\"</span> <span class=\"nt\">-m</span> <span class=\"s2\">\"test\"</span>\n</code></pre></div></div>\n\n<p>コマンドを実行するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"13f22fdd.2e009\",\n        \"type\": \"tab\",\n        \"label\": \"MQTT_subscribe\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1760f49a.fd2d3b\",\n        \"type\": \"debug\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 420,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"30229cea.13aba4\",\n        \"type\": \"mqtt in\",\n        \"z\": \"13f22fdd.2e009\",\n        \"name\": \"mqtt://PiDev25.local:1883\",\n        \"topic\": \"#\",\n        \"qos\": \"2\",\n        \"datatype\": \"auto\",\n        \"broker\": \"6e6a010.01825\",\n        \"x\": 150,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"1760f49a.fd2d3b\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6e6a010.01825\",\n        \"type\": \"mqtt-broker\",\n        \"z\": \"\",\n        \"name\": \"\",\n        \"broker\": \"PiDev25.local \",\n        \"port\": \"1883\",\n        \"clientid\": \"\",\n        \"usetls\": false,\n        \"compatmode\": true,\n        \"keepalive\": \"60\",\n        \"cleansession\": true,\n        \"birthTopic\": \"\",\n        \"birthQos\": \"0\",\n        \"birthPayload\": \"\",\n        \"closeTopic\": \"\",\n        \"closeQos\": \"0\",\n        \"closePayload\": \"\",\n        \"willTopic\": \"\",\n        \"willQos\": \"0\",\n        \"willPayload\": \"\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その5)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その5)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Websocket+Dashboard</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをWebsocketで飛ばして、Dashboardでグラフ表示するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"bme280データをwebsocketで送信raspberrypi\">BME280データをWebsocketで送信(RaspberryPi)</h1>\n\n<ul>\n  <li><strong>その2</strong> の<strong>BME280を使用するフローを作成する</strong>で作成したノードを</li>\n  <li>\n    <p><strong>その3</strong> の <strong>Websocketでデータ送信(クライアント)</strong>の手順で作成したノードに接続<br />\n  このとき、送信されるデータはmsg.payloadなので、文字列ではなく、object。<br />\n  (WebsocketのパケットにはobjectをJSON文字列化したものが入る)</p>\n  </li>\n  <li>BME280のデータを送信するためのトリガとなるノードをBME280ノードの入力に接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"411d9021.cb1948\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+Websocket\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"72021e21.cce078\",\n        \"type\": \"Bme280\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"571951b6.480168\",\n        \"type\": \"websocket out\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"f24a6df3.ed0608\",\n        \"x\": 660,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"4ce01eb0.f1d438\",\n        \"type\": \"debug\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 570,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"480f869f.968e18\",\n        \"type\": \"function\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"DummyData\",\n        \"func\": \"msg.payload = {\\n\\t\\t\\\"temperature_C\\\": Math.floor((Math.random() * (  40 - (-30)) * 100) / 100) + (-30),\\n\\t\\t\\\"humidity\\\":      Math.floor((Math.random() * ( 100 -    0 ) * 100) / 100) +    0,\\n\\t\\t\\\"pressure_hPa\\\":  Math.floor((Math.random() * (1100 -  800 ) * 100) / 100) +  800,\\n\\t\\t\\\"model\\\":\\\"DUMMY\\\"\\n}\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 310,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"571951b6.480168\",\n                \"4ce01eb0.f1d438\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"c6ba67a3.1c69c\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"72021e21.cce078\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ab623444.9c5148\",\n        \"type\": \"inject\",\n        \"z\": \"411d9021.cb1948\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"480f869f.968e18\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f24a6df3.ed0608\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:1880/ws/bme280\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocketからbme280データを受信サーバ\">WebsocketからBME280データを受信(サーバ)</h1>\n\n<ul>\n  <li><strong>その3</strong> の <strong>Websocketでデータを受信(サーバ)</strong>の手順で作成したWebsocketノード</li>\n</ul>\n\n<p>これだけでWebsocketからデータは受信できる。<br />\nこのとき、Websocketの受信ノードのmag.payloadはJSON文字列なので、objectに変換してやらないと後段で使用できない。<br />\nそのため、Websocketのノードの出力をjsonノードで変換してやる必要がある。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「json」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「json」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「動作」で「常にJavascriptオブジェクトに変換」を選択</li>\n      <li>プロパティは「msg.payload」を設定(デフォルトのまま)</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとjsonが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力側にWebsocketのノードを接続</li>\n  <li>\n    <p>出力側に受信データを処理するノードを接続</p>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>この状態でRaspberryPi側でBME280のデータ送信をトリガすれば、受信したデータで処理ノードが実行される</p>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その1サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その1)(サーバ)</h1>\n\n<p>上記、<strong>WebsocketからBME280データを受信(サーバ)</strong>の処理ノードとして</p>\n<ul>\n  <li><strong>その4</strong> の <strong>Dashboardでゲージグラフを表示する</strong>の手順で作成したノードを接続すれば良い。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nこれで理屈的には大丈夫なハズなんだけど、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.pressure_hPa}}</code>を指定すると、値は正常に表示されるけど、グラフが正常に表示されないことがある。。。<br />\nどうやら、この形で指定すると、値が1000を超えるとグラフ表示がおかしくなるようだ。バグか?<br />\n下の(その2)の方法で回避可能。</p>\n</blockquote>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"61238c01.1e1fdc\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"2163c454.8e4654\",\n        \"type\": \"json\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"8a687382.d3a38\",\n                \"54ecaf20.30611\",\n                \"1e9e6439.3de04c\",\n                \"54f5a1ee.e4fb5\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"de53f105.be0bb\",\n        \"type\": \"websocket in\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"2163c454.8e4654\",\n                \"8a687382.d3a38\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8a687382.d3a38\",\n        \"type\": \"debug\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 530,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54ecaf20.30611\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{msg.payload.temperature_C | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 510,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1e9e6439.3de04c\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度\",\n        \"label\": \"%\",\n        \"format\": \"{{msg.payload.humidity| number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 510,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"54f5a1ee.e4fb5\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"61238c01.1e1fdc\",\n        \"name\": \"\",\n        \"group\": \"9912b800.6921d8\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧\",\n        \"label\": \"hPa\",\n        \"format\": \"{{msg.payload.pressure_hPa| number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 510,\n        \"y\": 200,\n        \"wires\": []\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"9912b800.6921d8\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"websocket経由のbme280データをdashboardでグラフ表示その2サーバ\">Websocket経由のBME280データをDashboardでグラフ表示(その2)(サーバ)</h1>\n\n<p><strong>(その1)</strong>での不具合を回避するため、msg.payloadのオブジェクト内のそれぞれの変数をバラすfunctionノードを追加する</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「function」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら名前にノード名を設定</li>\n      <li>コードを設定(下記参照)</li>\n      <li>出力数に「3」を設定</li>\n      <li>右上の「完了」をクリック。</li>\n    </ul>\n  </li>\n  <li>これでfunctionノードの出力端子が3個になり、上から温度、湿度、気圧データが出力される。</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>// make deep copy\nvar msg_temp  <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_hum   <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\nvar msg_press <span class=\"o\">=</span> JSON.parse<span class=\"o\">(</span>JSON.stringify<span class=\"o\">(</span>msg<span class=\"o\">))</span><span class=\"p\">;</span>\n\nmsg_temp.topic    <span class=\"o\">=</span> <span class=\"s2\">\"temperature_C\"</span><span class=\"p\">;</span>\nmsg_temp.payload  <span class=\"o\">=</span> msg.payload.temperature_C<span class=\"p\">;</span>\nmsg_hum.topic     <span class=\"o\">=</span> <span class=\"s2\">\"humidity\"</span><span class=\"p\">;</span>\nmsg_hum.payload   <span class=\"o\">=</span> msg.payload.humidity<span class=\"p\">;</span>\nmsg_press.topic   <span class=\"o\">=</span> <span class=\"s2\">\"pressure_hPa\"</span><span class=\"p\">;</span>\nmsg_press.payload <span class=\"o\">=</span> msg.payload.pressure_hPa<span class=\"p\">;</span>\n\n<span class=\"k\">return</span> <span class=\"o\">[</span>msg_temp, msg_hum, msg_press]<span class=\"p\">;</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">var msg_temp  = msg;</code>などとしてはいけない。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">msg_temp</code>は<code class=\"language-plaintext highlighter-rouge\">msg</code>の浅いコピーとなってしまうため、その下で<code class=\"language-plaintext highlighter-rouge\">msg_temp.payload</code>を変更すると、<code class=\"language-plaintext highlighter-rouge\">msg.payload</code>も変更されてしまうことになる。<br />\nこれを防ぐため、深いコピーを作成している。これには<code class=\"language-plaintext highlighter-rouge\">msg</code>をJSON文字列化して、再度パースすることで対応している。</p>\n</blockquote>\n\n<p>フローエディタ上で、どの端子がどの信号か分からなくなるのを防ぐため、端子に名前を付けることができる。<br />\n(付けなくても動作上は問題ない)</p>\n\n<ul>\n  <li>「function」ノードをダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>右上の「完了」ボタンの下にある「外観」ボタン(ウィンドウ表示のアイコン)をクリック</li>\n      <li>ポートラベルの下の出力の下、1、2、3に対して、それぞれ分かりやすい名前を付ける</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>functionノードの入力にjsonノードの出力を接続</li>\n  <li>functionノードのそれぞれの出力にそれぞれを表示するゲージグラフノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"9c09bf08.8c36a8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_BME280_2\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"1e53a14c.4133a7\",\n        \"type\": \"json\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"property\": \"payload\",\n        \"action\": \"obj\",\n        \"pretty\": false,\n        \"x\": 310,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"855491ee.723a88\",\n                \"3cee4c1c.c6861c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ada05d07.d2d8b\",\n        \"type\": \"websocket in\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"server\": \"107d62cf.5a6d8d\",\n        \"client\": \"\",\n        \"x\": 134,\n        \"y\": 121,\n        \"wires\": [\n            [\n                \"1e53a14c.4133a7\",\n                \"855491ee.723a88\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"855491ee.723a88\",\n        \"type\": \"debug\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 690,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"51b57ef4.80809\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"温度2\",\n        \"label\": \"℃\",\n        \"format\": \"{{value | number:1}}℃\",\n        \"min\": \"-10\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 670,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"be7cac56.7bcc4\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"湿度2\",\n        \"label\": \"%\",\n        \"format\": \"{{value | number:1}}%\",\n        \"min\": \"0\",\n        \"max\": \"100\",\n        \"colors\": [\n            \"#ff8080\",\n            \"#00ff00\",\n            \"#00ffff\"\n        ],\n        \"seg1\": \"50\",\n        \"seg2\": \"60\",\n        \"x\": 670,\n        \"y\": 120,\n        \"wires\": []\n    },\n    {\n        \"id\": \"f36e338d.e77e6\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"\",\n        \"group\": \"34e8ddba.6c67fa\",\n        \"order\": 0,\n        \"width\": 0,\n        \"height\": 0,\n        \"gtype\": \"gage\",\n        \"title\": \"気圧2\",\n        \"label\": \"hPa\",\n        \"format\": \"{{value | number:0}}hPa\",\n        \"min\": \"900\",\n        \"max\": \"1050\",\n        \"colors\": [\n            \"#00ff00\",\n            \"#00ff00\",\n            \"#00ff00\"\n        ],\n        \"seg1\": \"\",\n        \"seg2\": \"\",\n        \"x\": 670,\n        \"y\": 160,\n        \"wires\": []\n    },\n    {\n        \"id\": \"3cee4c1c.c6861c\",\n        \"type\": \"function\",\n        \"z\": \"9c09bf08.8c36a8\",\n        \"name\": \"BME280\",\n        \"func\": \"// make deep copy\\nvar msg_temp  = JSON.parse(JSON.stringify(msg));\\nvar msg_hum   = JSON.parse(JSON.stringify(msg));\\nvar msg_press = JSON.parse(JSON.stringify(msg));\\n\\nmsg_temp.topic    = \\\"temperature_C\\\";\\nmsg_temp.payload  = msg.payload.temperature_C;\\nmsg_hum.topic     = \\\"humidity\\\";\\nmsg_hum.payload   = msg.payload.humidity;\\nmsg_press.topic   = \\\"pressure_hPa\\\";\\nmsg_press.payload = msg.payload.pressure_hPa;\\n\\nreturn [msg_temp, msg_hum, msg_press];\",\n        \"outputs\": 3,\n        \"noerr\": 0,\n        \"x\": 460,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"51b57ef4.80809\"\n            ],\n            [\n                \"be7cac56.7bcc4\"\n            ],\n            [\n                \"f36e338d.e77e6\"\n            ]\n        ],\n        \"inputLabels\": [\n            \"BME280データ\"\n        ],\n        \"outputLabels\": [\n            \"温度\",\n            \"湿度\",\n            \"気圧\"\n        ]\n    },\n    {\n        \"id\": \"107d62cf.5a6d8d\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/bme280\",\n        \"wholemsg\": \"false\"\n    },\n    {\n        \"id\": \"34e8ddba.6c67fa\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ2\",\n        \"tab\": \"9c00695d.f96b1\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"9c00695d.f96b1\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ2\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その4)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その4)</h1>\n      <p>Node-REDのメモ Dashboard編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでDashboardでUIを作成するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"dashboardをインストールする\">Dashboardをインストールする</h1>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-dashboard」と入力</li>\n  <li>下に検索結果が出るので。「node-red-dashboard」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するボタン\">Dashboard のUIを作成する(ボタン)</h1>\n\n<ul>\n  <li>パレット(左側のペイン)の「dashboard」の下の「button」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「button」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「名前」は適当に設定</li>\n          <li>「タブ」 で「新規に ui_tab を追加…」を選択してその右の編集ボタンをクリック\n            <ul>\n              <li>適当に値を設定する</li>\n              <li>右上の「追加」をクリック</li>\n            </ul>\n          </li>\n          <li>または、既存のタブを選択</li>\n          <li>右上の「追加」をクリック</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Icon」「Tooltip」「Colour」「Background」はオプションなので空欄のままで可</li>\n      <li>「Payload」 に クリックされたときに送信するデータを設定</li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"ブラウザでdashboardのuiに接続する\">ブラウザでDashboardのUIに接続する</h1>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/ui に接続\n    <ul>\n      <li>Dashboardが表示されるハズ\n        <ul>\n          <li>複数のタブがある場合、左上の3本線メニュー(≡)から切り替えられる</li>\n        </ul>\n      </li>\n      <li>ボタンをクリックしたらフローが動作する。</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"dashboard-のuiを作成するスライダ\">Dashboard のUIを作成する(スライダ)</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「slider」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「slider」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Tooltip」はオプションなので空欄のままで可</li>\n      <li>「Range」に値の最小値、最大値、刻みを設定</li>\n      <li>「Output」を設定\n        <ul>\n          <li>「continuously while sliding」:操作中、一定時間ごとにメッセージを出力</li>\n          <li>「only on release」:スライダを離したとき(値を確定したとき)にメッセージを出力</li>\n        </ul>\n      </li>\n      <li>「Topic」は必要なら設定。空欄のままでも可。</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>次段以降のノードを追加</li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"dashboardでゲージグラフを表示する\">Dashboardでゲージグラフを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「guage」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「guage」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>デフォルトの<code class=\"language-plaintext highlighter-rouge\">{{value}}</code>では受信したデータのpayload(<code class=\"language-plaintext highlighter-rouge\">msg.payload</code> )が使用される</li>\n          <li>payloadがobjectの場合、<code class=\"language-plaintext highlighter-rouge\">{{msg.payload.XXX}}</code>のように指定すると特定の変数が表示できる</li>\n          <li>このとき、<code class=\"language-plaintext highlighter-rouge\">{{</code> と <code class=\"language-plaintext highlighter-rouge\">}}</code> は波括弧を2つ重ねたもの。波括弧1つだと正常に処理されないので、注意</li>\n          <li>表示する数値の有効桁数を設定したい場合は以下のようにフィルタを設定\n            <ul>\n              <li>小数点以下1桁まで表示:<code class=\"language-plaintext highlighter-rouge\">{{value | number:1 }}</code></li>\n              <li>整数部のみ表示:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:0 }}</code></li>\n              <li>10の位へ丸める:       <code class=\"language-plaintext highlighter-rouge\">{{value | number:-1 }}</code></li>\n            </ul>\n          </li>\n          <li>単位を表示するなど、決まった文字列を追加したい場合は「<code class=\"language-plaintext highlighter-rouge\">{{・・・}}℃</code>」のように波括弧の外側に追加</li>\n        </ul>\n      </li>\n      <li>「units」 で単位を設定する。温度なら「℃」など。これは数値表示には表示されず、グラフ内部の単位情報として表示される</li>\n      <li>「Range」 でグラフの値の範囲を指定する。「-20」~「40」など。\n        <ul>\n          <li>入力値が範囲外になった場合はグラフが上下限に張り付くだけで、エラーなどにはならない。また値そのものは数値表示される</li>\n        </ul>\n      </li>\n      <li>「Colour gradient」 でグラフの色を指定する。3つの色は下で設定するSectors の範囲に対応する</li>\n      <li>「Sectors」 で 上で指定した色を表示する範囲を設定する\n        <ul>\n          <li>これはオプションなので設定しなくても良い。指定しなかった場合は上の「Range」で指定した値の範囲を3等分して使用される</li>\n        </ul>\n      </li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nValue formatのフィルタの詳細は<a href=\"https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters\">https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters</a>を見ろと書かれていましたが、残念ながら私にはよく分かりませんでした…</p>\n</blockquote>\n\n<h1 id=\"dashboardでテキストを表示する\">Dashboardでテキストを表示する</h1>\n\n<ul>\n  <li>パレットの「dashboard」の下の「text」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「text」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「Group」 で「新規に ui_group を追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>設定方法は上記参照</li>\n        </ul>\n      </li>\n      <li>または、既存のグループを選択</li>\n      <li>「Group」 に 今設定したグループとタブが選択されていることを確認</li>\n      <li>「Size」 で表示サイズを選択。後でレイアウト見ながら変更した方がやりやすいと思う</li>\n      <li>「Type」 でグラフの種類を選ぶ。お好みで</li>\n      <li>「label」 でUI画面での表示名を設定</li>\n      <li>「Value format」 でグラフに表示する値を指定する。\n        <ul>\n          <li>上記参照</li>\n        </ul>\n      </li>\n      <li>「Layout」でレイアウトを選択。お好みで</li>\n      <li>必要なら「Name」を設定\n        <ul>\n          <li>省略すると「Label」に設定した値が表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>表示する値を作成するノードを接続する</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a226513f.c36b1\",\n        \"type\": \"tab\",\n        \"label\": \"Dashboard_1\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"160486fa.dc7159\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 1,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"ON\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"ON\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e89b8821.ec65e8\",\n        \"type\": \"debug\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 580,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d4346336.cf1228\",\n        \"type\": \"ui_button\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 2,\n        \"width\": 2,\n        \"height\": 1,\n        \"passthru\": false,\n        \"label\": \"OFF\",\n        \"tooltip\": \"\",\n        \"color\": \"\",\n        \"bgcolor\": \"\",\n        \"icon\": \"\",\n        \"payload\": \"OFF\",\n        \"payloadType\": \"str\",\n        \"topic\": \"\",\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"84bd2adf.3b5df8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e403fdac.aa3748\",\n        \"type\": \"ui_slider\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"label\": \"温度\",\n        \"tooltip\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 4,\n        \"width\": 0,\n        \"height\": 0,\n        \"passthru\": true,\n        \"outs\": \"all\",\n        \"topic\": \"\",\n        \"min\": \"-30\",\n        \"max\": \"50\",\n        \"step\": 1,\n        \"x\": 140,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"e89b8821.ec65e8\",\n                \"78c10ecb.1eb67\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"78c10ecb.1eb67\",\n        \"type\": \"ui_gauge\",\n        \"z\": \"a226513f.c36b1\",\n        \"name\": \"\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 6,\n        \"width\": 4,\n        \"height\": 4,\n        \"gtype\": \"gage\",\n        \"title\": \"温度\",\n        \"label\": \"℃\",\n        \"format\": \"{{value}}℃\",\n        \"min\": \"-20\",\n        \"max\": \"40\",\n        \"colors\": [\n            \"#0000ff\",\n            \"#e6e600\",\n            \"#ca3838\"\n        ],\n        \"seg1\": \"0\",\n        \"seg2\": \"30\",\n        \"x\": 570,\n        \"y\": 240,\n        \"wires\": []\n    },\n    {\n        \"id\": \"84bd2adf.3b5df8\",\n        \"type\": \"ui_text\",\n        \"z\": \"a226513f.c36b1\",\n        \"group\": \"1127e563.00001b\",\n        \"order\": 3,\n        \"width\": 2,\n        \"height\": 1,\n        \"name\": \"\",\n        \"label\": \"SW\",\n        \"format\": \"{{value}}\",\n        \"layout\": \"row-spread\",\n        \"x\": 560,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"1127e563.00001b\",\n        \"type\": \"ui_group\",\n        \"z\": \"\",\n        \"name\": \"グループ1\",\n        \"tab\": \"6547952b.517b34\",\n        \"disp\": true,\n        \"width\": \"6\",\n        \"collapse\": false\n    },\n    {\n        \"id\": \"6547952b.517b34\",\n        \"type\": \"ui_tab\",\n        \"z\": \"\",\n        \"name\": \"タブ1\",\n        \"icon\": \"dashboard\",\n        \"disabled\": false,\n        \"hidden\": false\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"dashboard-のレイアウトを修正する\">Dashboard のレイアウトを修正する</h1>\n\n<p>ボタンのサイズを小さくしたり、複数のボタンを横に並べたい場合はレイアウトの修正を行う。</p>\n\n<ul>\n  <li>サイドバー(右側のペイン)の「dashboard」ボタン(グラフのアイコン)をクリック</li>\n  <li>配置タブをクリック</li>\n  <li>タブの部分(「ホーム」など)をマウスでポイントし、「レイアウト」をクリック\n    <ul>\n      <li>表示領域の幅を変更するには、右上の「幅」の設定値を変更する。(単位はグリッド数)</li>\n      <li>各要素をドラッグすると、表示位置を入れ替えられる。</li>\n      <li>各要素のサイズを変更するには、\n        <ul>\n          <li>右上の鍵アイコンをクリックして閉じた状態にする(鍵が開いた状態では表示領域幅に一致するように自動変更される)</li>\n          <li>右下に矢印アイコンが表示されるので、これをつまんでサイズを変更</li>\n        </ul>\n      </li>\n      <li>各要素を横並びにしたい場合は、各要素をドラッグして移動する(表示幅に収まらない場合は移動できない)</li>\n      <li>各要素のサイズ/位置はグリッド単位でのみ可能</li>\n      <li>右上の完了をクリック\nー デプロイする</li>\n    </ul>\n  </li>\n</ul>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その3)</h1>\n      <p>Node-REDのメモ TCP通信編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでTCP通信操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDは起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"udpで送信\">UDPで送信</h1>\n<ul>\n  <li>パレット(左側のペイン)の「出力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「送信」で出力するメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト)/「ブロードキャストメッセージ」/「マルチキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で送信先ポート番号を設定\n        <ul>\n          <li>受信プログラムが待ち受けしているポート番号を指定</li>\n        </ul>\n      </li>\n      <li>「アドレス」に送信先アドレス(名前 or IPアドレス)を指定</li>\n      <li>さらにその右で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>特定のポートから送信したいときは「ローカルポートを使用」を選択し、その右に送信元ポート番号を指定する\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n          <li>通常は「ローカルポートをランダムに使用」で大丈夫</li>\n        </ul>\n      </li>\n      <li>入力データがBase64エンコードされたBufferオブジェクトの場合は「Base64形式のペイロードを複合」にチェックを入れる\n        <ul>\n          <li>入力データがBase64文字列かをチェックするだけで、ここでデータを変換するわけではない(?)</li>\n          <li>通常はチェックしないでOK</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると送信先アドレスとポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>送信データを作成するノードを接続\n    <ul>\n      <li>UDPノードはmsg.payloadを送信する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"udpで受信\">UDPで受信</h1>\n<ul>\n  <li>パレットの「入力」の下の「UDP」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「UDP」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「待ち受け」で受信待ちするするメッセージ種別を選択\n        <ul>\n          <li>「UDPメッセージ」(ユニキャスト or マルチキャスト)/「ブロードキャストメッセージ」から選択</li>\n        </ul>\n      </li>\n      <li>「ポート」で受信待ちポート番号を設定\n        <ul>\n          <li>ポート番号は0 ~ 65535が指定可能</li>\n          <li>ただし、1023以下のポート番号は特権ポートなので管理者しか使用できない</li>\n          <li>使用済みポート番号は指定できない</li>\n        </ul>\n      </li>\n      <li>「種類」で使用するIPプロトコル(IPv4/IPv6)を選択</li>\n      <li>「出力」で受信したデータをどのような形式で次段のノードに出力するかを選択する\n        <ul>\n          <li>「バイナリバッファ」を選択すると受信したデータをそのままbufferオブジェクトとして出力</li>\n          <li>「文字列」を選択すると受信したデータをStringオブジェクトにデコードする</li>\n          <li>「Base64文字列」を選択すると受信したデータをBase64 Stringオブジェクトにデコードする</li>\n          <li>「Base64文字列」と「文字列」は内部でtoStringのencodingに’base64’を指定するか’utf8’を指定するかの違い(?)</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると受信待ちポートが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>受信データを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"2506be7d.1b5332\",\n        \"type\": \"tab\",\n        \"label\": \"UDP\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"44364ec0.0b59b8\",\n        \"type\": \"udp out\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"addr\": \"localhost\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"outport\": \"\",\n        \"base64\": false,\n        \"multicast\": \"false\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"20cee006.2fee4\",\n        \"type\": \"inject\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"\",\n        \"payloadType\": \"date\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 150,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"44364ec0.0b59b8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"eb875fd8.7aa5f8\",\n        \"type\": \"udp in\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"iface\": \"\",\n        \"port\": \"4000\",\n        \"ipv\": \"udp4\",\n        \"multicast\": \"false\",\n        \"group\": \"\",\n        \"datatype\": \"utf8\",\n        \"x\": 160,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"a6b72636.514e2\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a6b72636.514e2\",\n        \"type\": \"debug\",\n        \"z\": \"2506be7d.1b5332\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 140,\n        \"wires\": []\n    }\n]\n \n</code></pre></div></div>\n\n<h1 id=\"httpでrest-api\">HTTPでREST API</h1>\n\n<h2 id=\"http入力ノードの作成\">HTTP入力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「入力」の下の「http」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「メソッド」でメソッド種別を選択\n        <ul>\n          <li>ここでは「GET」で設定を進める(他のメソッドは他所で調べてね)</li>\n        </ul>\n      </li>\n      <li>「URL」でエンドポイント(要はパス)を設定</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとメソッドとURLが表示される</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>レスポンスを作成するノード(下記)を接続</li>\n</ul>\n\n<h2 id=\"レスポンス生成ノードの作成\">レスポンス生成ノードの作成</h2>\n\n<p>ここでは、簡単にfunctionノードで固定文字列を返すものを作っています。</p>\n\n<ul>\n  <li>パレットの「機能」の下の「function」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると空欄になるので、なるべく識別できる名前を付けましょう</li>\n        </ul>\n      </li>\n      <li>「コード」に処理するプログラムを記述\n        <ul>\n          <li>msg.payloadに表示するページの本文を設定する</li>\n          <li>例えば以下</li>\n        </ul>\n      </li>\n      <li>「名前」の横のアイコンをクリックすると作成したノードの保存/読み込みが出来る\n        <ul>\n          <li>コードは <code class=\"language-plaintext highlighter-rouge\">~/.node-red/lib/functions/</code> に指定したフォルダとファイル名で保存される</li>\n          <li>保存したコードは別のノードで読み込むことができる</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"dl\">\"</span><span class=\"s2\"><h1> ぼ~っと生きてんじゃね~よ! </H1></span><span class=\"dl\">\"</span><span class=\"p\">;</span>\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h2 id=\"http出力ノードの作成\">HTTP出力ノードの作成</h2>\n\n<ul>\n  <li>パレットの「出力」の下の「http response」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「http」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略すると「http」と表示される</li>\n        </ul>\n      </li>\n      <li>必要なら「状態コード」を設定</li>\n      <li>必要なら「ヘッダ」を設定</li>\n      <li>シンプルな処理の場合、何も設定しなくてもOK</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"入力レスポンス生成出力を接続\">入力、レスポンス生成、出力を接続</h2>\n\n<ul>\n  <li>上記で作成したノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"ブラウザでアクセス接続\">ブラウザでアクセス接続</h2>\n\n<ul>\n  <li>ブラウザで、http://対象IPアドレス:1880/《HTTP入力ノードに設定したURL》 に接続\n    <ul>\n      <li>ブラウザにレスポンス生成ノードで作成したメッセージが表示される</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"7508e635.c8bf48\",\n        \"type\": \"tab\",\n        \"label\": \"HTTP_REST\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c7938d8a.3ae9d\",\n        \"type\": \"http in\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"url\": \"/rest_api_1\",\n        \"method\": \"get\",\n        \"upload\": false,\n        \"swaggerDoc\": \"\",\n        \"x\": 160,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"fb01d5fd.b76918\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fb01d5fd.b76918\",\n        \"type\": \"function\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"ぼ~っと生きてんじゃね~よ!\",\n        \"func\": \"msg.payload = \\\"<h1> ぼ~っと生きてんじゃね~よ! </H1>\\\";\\nreturn msg;\\n\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 430,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"8d3518af.f9da7\",\n                \"86c0f820.b0a56\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8d3518af.f9da7\",\n        \"type\": \"http response\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"statusCode\": \"\",\n        \"headers\": {},\n        \"x\": 690,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"86c0f820.b0a56\",\n        \"type\": \"debug\",\n        \"z\": \"7508e635.c8bf48\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 700,\n        \"y\": 120,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"websocketでデータを送受信\">Websocketでデータを送受信</h1>\n\n<h2 id=\"テストツールのインストール\">テストツールのインストール</h2>\n\n<p>ここではテストツールにwscatを使うこととします。<br />\nwscat は 以下のコマンドでインストールできます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> wscat\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信クライアント\">Websocketでデータ送信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「種類」 で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>「URL」 でサーバのURLを設定(例: ws://PiDev25.local:5000/ws/data01)</li>\n          <li>「送信/受信」でペイロードのみ送受信するか、メッセージ全体を送受信するかを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>送信データは文字列の場合、そのまま送信される。</li>\n      <li>数値の場合、文字列に変換して送信される。\n        <ul>\n          <li>受信側では文字列→数値変換を行う必要がある</li>\n        </ul>\n      </li>\n      <li>オブジェクトの場合、JSON文字列に変換して送信される。\n        <ul>\n          <li>受信側ではJSON文字列のデコードを行う必要がある</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト\">テスト</h3>\n\n<p>あらかじめ、ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5000で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5000\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5000 (press CTRL+C to quit)\nclient connected\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"75e44664.73e018\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"49b725b6.0e0934\",\n        \"type\": \"websocket out\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"server\": \"\",\n        \"client\": \"99ad88ce.8bcf7\",\n        \"x\": 600,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"762ccf62.73a48\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"fe2498d8.71c17\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"47ef3c99.d6eefc\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f97b4d60.afc278\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6d15d519.6289ec\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"87c94e6f.db3458\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"175e465.15aaa3a\",\n        \"type\": \"inject\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"49b725b6.0e0934\",\n                \"e7c2219c.07acf8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e7c2219c.07acf8\",\n        \"type\": \"debug\",\n        \"z\": \"75e44664.73e018\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"99ad88ce.8bcf7\",\n        \"type\": \"websocket-client\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5000/ws/data01\",\n        \"tls\": \"\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータ送信サーバ\">Websocketでデータ送信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを送信してみます</p>\n\n<ul>\n  <li>パレットの「出力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata1 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-1\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest1で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wstest1\n</code></pre></div></div>\n\n<p>Node-RED側で Websocketの送信をトリガするとwscatの表示に送信したデータが表示されます。<br />\n以下の表示例でデータが受信できていることが確認できます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n< 0\n< 1\n< true\n< false\n< 文字列\n< {\"data1\":0,\"data2\":1,\"data3\":\"data\"}\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-3\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"22d6d63b.99a952\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_send_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"d64e2a6a.27ead8\",\n        \"type\": \"websocket out\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"server\": \"d7536de3.b48578\",\n        \"client\": \"\",\n        \"x\": 520,\n        \"y\": 40,\n        \"wires\": []\n    },\n    {\n        \"id\": \"79358fcc.5a5a68\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 40,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"cd6acb87.0a77\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7991d417.429124\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"ee88046b.37b298\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"false\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"7eac2c2e.6fa39c\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"文字列\",\n        \"payloadType\": \"str\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 200,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"650517e9.5e34a8\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"オブジェクト\",\n        \"topic\": \"\",\n        \"payload\": \"{\\\"data1\\\":0,\\\"data2\\\":1,\\\"data3\\\":\\\"data\\\"}\",\n        \"payloadType\": \"json\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 240,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d197151e.8b01e\",\n        \"type\": \"inject\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"バッファ\",\n        \"topic\": \"\",\n        \"payload\": \"[0,1,2,3]\",\n        \"payloadType\": \"bin\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 120,\n        \"y\": 280,\n        \"wires\": [\n            [\n                \"d64e2a6a.27ead8\",\n                \"5871022e.6bbb1c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"5871022e.6bbb1c\",\n        \"type\": \"debug\",\n        \"z\": \"22d6d63b.99a952\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 520,\n        \"y\": 280,\n        \"wires\": []\n    },\n    {\n        \"id\": \"d7536de3.b48578\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wstest1\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信クライアント\">Websocketでデータを受信(クライアント)</h2>\n\n<p>クライアントとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「接続」を選択</li>\n      <li>「URL」 で 「新規に websocket-client を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>URL でサーバのURLを設定(例: ws://PiDev25.local:5002/ws/wsdata2)</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または 既に設定されているサーバを選択</li>\n      <li>URL に 今設定したURLが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとURLが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-2\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、上記設定例にあわせてマシン名PiDev25.localのマシンでポート番号5002で待ち受けしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--listen</span> 5002\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>listening on port 5002 (press CTRL+C to quit)\nclient connected\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-4\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"a45bd125.622fb8\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"24a93730.cf2a7\",\n        \"type\": \"websocket in\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"server\": \"45ba6028.84fc88\",\n        \"client\": \"\",\n        \"x\": 220,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"15576052.1536\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"15576052.1536\",\n        \"type\": \"debug\",\n        \"z\": \"a45bd125.622fb8\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"45ba6028.84fc88\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"ws://PiDev25.local:5002/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n<h2 id=\"websocketでデータを受信サーバ\">Websocketでデータを受信(サーバ)</h2>\n\n<p>サーバとしてWebsocketでデータを受信してみます</p>\n\n<ul>\n  <li>パレットの「入力」の下の「websocket」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「websocket」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>種類で「待ち受け」を選択</li>\n      <li>パス で 「新規に websocket-listner を追加」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>パス を適当に設定(/ws/wsdata2 など)\n            <ul>\n              <li>Websocket の Listen port のポート番号は Node-RED のポート番号と同じになるので、Client側で指定するURLはそのポート番号を指定すること</li>\n            </ul>\n          </li>\n          <li>送信/受信で送受信するデータを選択</li>\n          <li>追加をクリック</li>\n        </ul>\n      </li>\n      <li>または既に設定されているパスを選択</li>\n      <li>パス に 今設定したパスが表示されていることを確認</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>省略するとパスが表示される</li>\n        </ul>\n      </li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>受信したメッセージを処理するノードを接続</li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"テスト-3\">テスト</h3>\n\n<p>ターミナル or コンソールで以下のコマンドを実行します。\n以下の場合、サーバのマシン名がPiDev25.local、サーバ側がポート番号1880、パス/ws/wstest2で待ち受けしているものとします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wscat <span class=\"nt\">--connect</span> ws://PiDev25.local:1880/ws/wsdata2\n</code></pre></div></div>\n\n<p>接続されたあと、適当に文字列を入力するとNode-RED側で受信され、メッセージ処理ノードが実行されます。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>connected (press CTRL+C to quit)\n> 適当に文字を入力する     → Node-REDに送信される\n</code></pre></div></div>\n\n<p>wscatを終了するのはCTRL-Cを入力します。</p>\n\n<h3 id=\"フローの例-5\">フローの例</h3>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"15604b9.9721eb4\",\n        \"type\": \"tab\",\n        \"label\": \"Websocket_recv_server\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"80f59585.469758\",\n        \"type\": \"websocket in\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"server\": \"11528a5d.783b0e\",\n        \"client\": \"\",\n        \"x\": 140,\n        \"y\": 60,\n        \"wires\": [\n            [\n                \"f37c8fe9.6307c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"f37c8fe9.6307c\",\n        \"type\": \"debug\",\n        \"z\": \"15604b9.9721eb4\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 630,\n        \"y\": 60,\n        \"wires\": []\n    },\n    {\n        \"id\": \"11528a5d.783b0e\",\n        \"type\": \"websocket-listener\",\n        \"z\": \"\",\n        \"path\": \"/ws/wsdata2\",\n        \"wholemsg\": \"false\"\n    }\n]\n\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その2)</h1>\n      <p>Node-REDのメモ GPIO & I2C編</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGPIO操作をするときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>Node-REDはRaspberryPiで起動済みでブラウザで接続済みであるものとします。</p>\n\n<h1 id=\"raspberrypiでgpio出力\">RaspberryPiでGPIO出力</h1>\n<ul>\n  <li>パレット(左側のペイン)の「Raspberry Pi」の下の「rpi gpio」(出力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で出力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「出力形式」で「デジタル出力」を選択</li>\n      <li>デプロイしたときに端子状態を初期化したい場合は「端子の状態を初期化」をチェック\n        <ul>\n          <li>「端子の初期状態レベル」を選択</li>\n        </ul>\n      </li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「LED_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを接続\n    <ul>\n      <li>トリガノードはGPIOから出力する値(0 または 1)を出力する</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"51e0a206.805964\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_OUT\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"597df548.0311f4\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_0\",\n        \"pin\": \"18\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"89834ee2.89e27\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 80,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b020b32.e26818\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 120,\n        \"wires\": [\n            [\n                \"597df548.0311f4\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"21621e60.e300ba\",\n        \"type\": \"rpi-gpio out\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"LED_1\",\n        \"pin\": \"22\",\n        \"set\": true,\n        \"level\": \"0\",\n        \"freq\": \"\",\n        \"out\": \"out\",\n        \"x\": 550,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"87abb89b.307418\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"0\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a7ae7810.959a88\",\n        \"type\": \"inject\",\n        \"z\": \"51e0a206.805964\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"1\",\n        \"payloadType\": \"num\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 190,\n        \"y\": 220,\n        \"wires\": [\n            [\n                \"21621e60.e300ba\"\n            ]\n        ]\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでgpio入力\">RaspberryPiでGPIO入力</h1>\n\n<ul>\n  <li>パレットの「Raspberry Pi」の下の「rpi gpio」(入力ノードの方) をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「PIN」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>「端子」で入力する端子を選択\n        <ul>\n          <li>別のノードで使用されている端子が「使用中の端子」として表示されているので、重複しないように注意</li>\n        </ul>\n      </li>\n      <li>「抵抗」で端子に接続するプルアップ/ダウン種別を選択\n        <ul>\n          <li>端子の初期化時に内部のプルアップ/ダウン抵抗のどちらを有効にするかを選択</li>\n          <li>ボード上で処理してれば「なし」を選ぶ</li>\n        </ul>\n      </li>\n      <li>デバウンスにチャタリング除去時間を設定</li>\n      <li>デプロイしたときに端子状態を読み込みたい場合は「~初期状態を読み込む」をチェック</li>\n      <li>必要なら「名前」を設定\n        <ul>\n          <li>「SWITCH_1」など、機能を分かりやすくしたい場合などに</li>\n        </ul>\n      </li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>入力信号を処理するノードを接続\n    <ul>\n      <li>処理ノードへはGPIOから入力された値(0 または 1)が入力される</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-1\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1385085c.ab8648\",\n        \"type\": \"tab\",\n        \"label\": \"GPIO_IN\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"e9177a48.70b74\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW0\",\n        \"pin\": \"15\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"932b0e92.05cdd8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"932b0e92.05cdd8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"8f31f20e.4b6d28\",\n        \"type\": \"rpi-gpio in\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"SW1\",\n        \"pin\": \"16\",\n        \"intype\": \"up\",\n        \"debounce\": \"25\",\n        \"read\": false,\n        \"x\": 150,\n        \"y\": 160,\n        \"wires\": [\n            [\n                \"d27c860d.7de3a8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"d27c860d.7de3a8\",\n        \"type\": \"debug\",\n        \"z\": \"1385085c.ab8648\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 470,\n        \"y\": 160,\n        \"wires\": []\n    }\n]\n\n</code></pre></div></div>\n\n<h1 id=\"raspberrypiでi2cを使用する\">RaspberryPiでI2Cを使用する</h1>\n\n<h2 id=\"事前準備\">事前準備</h2>\n\n<p>以下はターミナルやコンソールでの作業</p>\n\n<ul>\n  <li>I2Cを有効化する\n    <ul>\n      <li>リブートは不要らしい</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config\n    5 Interfacing Options\n        P5 I2C\n            Would you like the ARM I2C interface to be enabled?\n            に対して<はい>を選択\n            The ARM I2C interface is enabled\n            と表示されるので<了解>\n    <Finish>\n</code></pre></div></div>\n<ul>\n  <li>I2Cデバイスアクセス用ツールをインストールする</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>i2c-tools\n</code></pre></div></div>\n\n<ul>\n  <li>i2cバスをスキャンしてみる(RasbberryPi2/3のI2Cバスはバス1が出てる。古いのだと0のもあるらしい)</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#   ↓結果(例)</span>\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00:          <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n10: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n20: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n30: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n40: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n50: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n60: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span>\n70: <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> <span class=\"nt\">--</span> 76 <span class=\"nt\">--</span>\n<span class=\"c\"># 76がBME280(Bosch温湿度センサ)</span>\n</code></pre></div></div>\n\n<ul>\n  <li>I2Cデバイスのレジスタをリードしてみる</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cget <span class=\"nt\">-y</span> 1 0x76 0xd0\n</code></pre></div></div>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ↓ 結果</span>\n0x60\n<span class=\"c\"># レジスタ 0xd0(CHIP ID)をリードするとデバイスのID 0x60が読める</span>\n</code></pre></div></div>\n\n<h2 id=\"bme280用ノードをインストールする\">BME280用ノードをインストールする</h2>\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「bme280」と入力</li>\n  <li>下に検索結果が出るので。「node-red-contrib-bme280」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\n2019/09/13現在、何やらインストール時にエラーになるが、<br />\nモジュールのコンパイル時にwarning/noteが出ているだけのようなので、インストール自体はできているようだ。<br />\nとりあえず下記サンプルは動いているので、大丈夫でしょう。</p>\n</blockquote>\n\n<h2 id=\"bme280を使用するフローを作成する\">BME280を使用するフローを作成する</h2>\n<ul>\n  <li>パレットの「入力」の下の「Bme280」 をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Bme280」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略するとBme280が表示される</li>\n        </ul>\n      </li>\n      <li>Bus# にバス番号(1)を設定</li>\n      <li>I2C Address にI2Cアドレス(0x76)を設定</li>\n      <li>Topicが必要なら設定(デフォルトはbme280)</li>\n      <li>右上の「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>信号を処理するノードを出力側に接続\n    <ul>\n      <li>Bme280ノードの出力メッセージの内容は以下の通り</li>\n    </ul>\n  </li>\n</ul>\n\n<table>\n  <thead>\n    <tr>\n      <th>変数名</th>\n      <th>値の例</th>\n      <th>項目</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>msg.topic</td>\n      <td>“bme280”</td>\n      <td>ノードの設定で設定したTopic</td>\n    </tr>\n    <tr>\n      <td>msg.payload.temperature_C</td>\n      <td>34.23</td>\n      <td>温度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.humidity</td>\n      <td>54.402349427117336</td>\n      <td>湿度</td>\n    </tr>\n    <tr>\n      <td>msg.payload.pressure_hPa</td>\n      <td>1013.9016246356634</td>\n      <td>気圧</td>\n    </tr>\n    <tr>\n      <td>msg.payload.model</td>\n      <td>“BME280”</td>\n      <td>センサ名</td>\n    </tr>\n  </tbody>\n</table>\n\n<ul>\n  <li>デプロイする</li>\n</ul>\n\n<h3 id=\"フローの例-2\">フローの例</h3>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[\n    {\n        \"id\": \"e4065603.3c6dc\",\n        \"type\": \"tab\",\n        \"label\": \"BME280\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"c0602bca.110b8\",\n        \"type\": \"Bme280\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 300,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"8b845ce5.ec2fd\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"8b845ce5.ec2fd\",\n        \"type\": \"debug\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 630,\n        \"y\": 100,\n        \"wires\": []\n    },\n    {\n        \"id\": \"cdbf55ce.3aa94\",\n        \"type\": \"inject\",\n        \"z\": \"e4065603.3c6dc\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 130,\n        \"y\": 100,\n        \"wires\": [\n            [\n                \"c0602bca.110b8\"\n            ]\n        ]\n    }\n]\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その1)</h1>\n      <p>Node-REDのインストール他のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDをインストールや、フローを作成する際の手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"ubuntu-に-node-red-をインストールする\">ubuntu に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejsとnpmのインストール\">Node.jsとnpmのインストール</h2>\n\n<p>自動起動とかやらないなら、Node.js は nodenv とか使っても良い気がするが、\n念のためシステムに直接インストールしておく。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">apt install</code> だと古いバージョンになってしまうので、<br />\nnコマンド をインストールし、<br />\nnコマンドで安定版をインストールする。<br />\nその後、<code class=\"language-plaintext highlighter-rouge\">apt</code> でインストールしたNode.jsは削除。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n\n<span class=\"c\"># nコマンドのインストール</span>\n<span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> n\n\n<span class=\"c\"># 安定版のインストール</span>\n<span class=\"nb\">sudo </span>n stable\n\n<span class=\"c\"># aptでインストールしたnode.jsをアンインストール</span>\n<span class=\"nb\">sudo </span>apt purge <span class=\"nt\">-y</span> nodejs-legacy npm\n\n<span class=\"c\"># バージョン確認</span>\nnode <span class=\"nt\">-v</span>\n</code></pre></div></div>\n\n<h2 id=\"node-redのインストール\">Node-REDのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>npm <span class=\"nb\">install</span> <span class=\"nt\">-g</span> <span class=\"nt\">--unsafe-perm</span> node-red node-red-admin\n</code></pre></div></div>\n\n<p>どうも、ノードの追加とかすると、npmのキャッシュをアクセスするときにpermission deniedと言われてしまうみたいなので、\n以下のコマンドで .npm ディレクトリ以下の所有権を自分にしておく。<br />\n(キャッシュだから削除しても良い気がするが)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo chown</span> <span class=\"nt\">-R</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> ~/.npm\n</code></pre></div></div>\n\n<h2 id=\"起動\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"停止\">停止</h2>\n\n<p>CTRL-Cで停止する。</p>\n\n<h2 id=\"参考\">参考</h2>\n\n<p><a href=\"https://qiita.com/seibe/items/36cef7df85fe2cefa3ea\">https://qiita.com/seibe/items/36cef7df85fe2cefa3ea</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"windows10-に-node-red-をインストールする\">Windows10 に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npmの-インストール\">Node.js と npmの インストール</h2>\n\n<ul>\n  <li><a href=\"https://nodejs.org/ja/\">Node.jsのサイト</a>からWindows版をダウンロードします。\n  推奨版(2019/09/16現在、10.16.3 LTS)をダウンロードしてください。<br />\n  (もし、別のプラットフォームのものが必要なら上部のメニューの「ダウンロード」からダウンロードします)</li>\n  <li>ダウンロードしたnode-vXX.XX.XX-YY.msiを実行してインストーラを起動し、インストールします。\n  特に迷うところはないと思います。大体、そのまま「次へ」で大丈夫。</li>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell を起動します。\n  念のため、<code class=\"language-plaintext highlighter-rouge\">node -v</code> を実行して、<code class=\"language-plaintext highlighter-rouge\">v10.16.3</code>と表示されることを確認します。\n  次にnpmのアップデートを行います。以下のコマンドを実行してください。( 2019/09/16現在、6.11.3 でした)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g npm\n</code></pre></div></div>\n<h2 id=\"node-redのインストール-1\">Node-REDのインストール</h2>\n\n<ul>\n  <li>コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してインストールします。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>npm install -g --unsafe-perm node-red\n</code></pre></div></div>\n\n<ul>\n  <li>インストールが終了したら、コマンドプロンプト または Windows PowerShell で以下のコマンドを実行してNode-REDを起動します。<br />\n実行したウィンドウは閉じないでください。閉じるとNode-REDが終了してしまいます。</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red\n</code></pre></div></div>\n\n<p>なお、初めてNode-REDを起動したとき、\n『このアプリの機能のいくつかがWindows Defender ファイアウォールでブロックされています』\nと警告が表示されることがある。</p>\n\n<p>この場合、\n「通信を許可するネットワーク」を選択して「アクセスを許可する」をクリック\nすれば良い。</p>\n\n<h2 id=\"ちょっとヒトコトメモ\">ちょっとヒトコトメモ</h2>\n\n<p>(ぜんぜんヒトコトじゃないけど。。。)</p>\n\n<p>Node-REDを起動したPCからのアクセス(ブラウザ接続など)は成功するのに、\n外部PCやRaspberryPi(もちろん、同一サブネット上の)からのアクセス(ブラウザやWebsocket接続)が失敗する場合がある。</p>\n\n<p>考えられる原因は色々あるが、最も多そうな原因のひとつにファイアウォールでのブロックが考えられる。<br />\n上の警告ダイアログでアクセス許可した際に、プライベートネットワークのみに通信を許可していて、\nかつ、現在接続されているネットワークがパブリックネットワークである場合である。</p>\n\n<p>ファイアウォールでのブロックされているかは<strong>Node-REDを起動した状態</strong>で以下のコマンドで確認できる。</p>\n\n<ul>\n  <li>RaspberryPiの場合</li>\n</ul>\n\n<p>以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 《IPアドレス》 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>nc <span class=\"nt\">-zv</span> 192.168.1.2 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、コマンドが終了しないので、CTRL+Cで終了する。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">Connection to 《IPアドレス》 《ポート番号》port [tcp/*] succeeded!</code>と表示される。</p>\n\n<ul>\n  <li>Windowsの場合</li>\n</ul>\n\n<p>Windows Poewrshellで(コマンドプロンプトでは不可)以下のコマンドを実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 《IPアドレス》  <span class=\"nt\">-port</span> 《ポート番号》\n</code></pre></div></div>\n\n<p>例えば、こんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Test-NetConnection 192.168.1.2 <span class=\"nt\">-port</span> 1880\n</code></pre></div></div>\n\n<p>ブロックされていれば、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : False</code>と表示される。<br />\nブロックされていなければ(正常であれば)、<code class=\"language-plaintext highlighter-rouge\">TcpTestSucceeded : True</code>と表示される。</p>\n\n<p>これを解決するには、Node-REDを実行しているWindows PCで<br />\n「コントロールパネル」→「Windows Defender ファイアウォール」を開き、<br />\n左側のリストから「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック<br />\n「設定の変更」をクリック\n下のリストから「Node.js: Server-side JavaScript」の右側 パブリックのチェックボックスにチェックを入れる<br />\n「OK」をクリック</p>\n\n<p>この状態で再度RaspberryPi または PCからファイアウォールでのブロックの確認を実行し、ブロックされていないことを確認してください。</p>\n\n<h1 id=\"raspbian-に-node-red-をインストールする\">Raspbian に Node-RED をインストールする。</h1>\n\n<h2 id=\"nodejs-と-npm-と-node-red-のインストール\">Node.js と npm と Node-RED のインストール</h2>\n\n<p>インストールスクリプトを実行すればイッパツで解決。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># インストールスクリプトの取得</span>\nwget  https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered\n\n<span class=\"c\"># 必要なら中身確認してね</span>\n\n<span class=\"c\"># インストールスクリプトの実行</span>\nbash update-nodejs-and-nodered \n</code></pre></div></div>\n\n<h2 id=\"起動-1\">起動</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-start \n</code></pre></div></div>\n<p>CTRL-Cでログ表示のみ止まる(Node-RED自体は動作したまま)</p>\n\n<p>ブラウザで http://対象IPアドレス:1880 に接続</p>\n\n<h2 id=\"ログ表示\">ログ表示</h2>\n\n<p>Node-RED で console.log などを実行したときは、ログに表示される。<br />\n<code class=\"language-plaintext highlighter-rouge\">node-red-start</code>したままなら表示されるが、CTRL-Cでログ表示を止めていた場合は\n以下のコマンドでログ表示を再開できる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-log\n</code></pre></div></div>\n\n<h2 id=\"停止-1\">停止</h2>\n\n<p>Node-RED自体を停止する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>node-red-stop\n</code></pre></div></div>\n\n<h2 id=\"参考-1\">参考</h2>\n\n<p><a href=\"https://qiita.com/utaani/items/7155c62d6c5e96822afb\">https://qiita.com/utaani/items/7155c62d6c5e96822afb</a><br />\n<a href=\"https://nodered.jp/docs/getting-started/local\">https://nodered.jp/docs/getting-started/local</a></p>\n\n<h1 id=\"フローの操作\">フローの操作</h1>\n\n<h2 id=\"フローを保存するエクスポート\">フローを保存する(エクスポート)</h2>\n\n<p>作成したフローは保存することができます。<br />\nしばらく使わないフローを削除したり、別の環境にコピーする場合に保存しておくと良いでしょう。</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「書き出し」→「クリップボード」をクリック →書き出しダイアログが表示される\n    <ul>\n      <li>書き出す範囲を「現在のタブ」「すべてのタブ」から選択。(フローの一部を選択していた場合は「選択したフロー」も選択可能)</li>\n      <li>その下にはその時のJSONファイルの内容が表示されていますので、ここから</li>\n      <li>さらにその下で出力形式を「インデントのないJSONフォーマット」「インデント付きのJSONフォーマット」から選択。多少ファイルサイズが増減しますが、どちらを選んでも特に問題になるようなことはないでしょう。「インデント付き」の方が目視で確認しやすいと思います。</li>\n      <li>「ダウンロード」をクリックすると、ブラウザのファイル保存(ダウンロード)ダイアログが開くので、保存処理を行う(このときのファイル名はflows.json固定なので、必要に応じて保存後リネームしてください)</li>\n      <li>または、「書き出し」をクリックすると、クリップボードへコピーされるので、直接 別の環境の読み込みダイアログやエディタへペーストすることも可能</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"フローを読み込むインポート\">フローを読み込む(インポート)</h2>\n\n<p>保存したフローは読み込んで使用することができます(当然か)</p>\n\n<ul>\n  <li>右上の3本線メニュー(≡) から「読み込み」→「クリップボード」をクリック →読み込みダイアログが表示される\n    <ul>\n      <li>「読み込むファイルを選択してください」をクリックして読み込むファイルを選択 → ファイルの内容がその下のエディットボックスに表示される</li>\n      <li>または、その下のエディットボックスにJSONデータをペースト</li>\n      <li>読み込み先を「現在のタブ」「新規のタブ」から選択(「選択したフロー」で保存してないとどっちでも同じ気がする)</li>\n      <li>「読み込み」をクリック</li>\n    </ul>\n  </li>\n  <li>読み込まれるので、内容を確認。必要なら修正。</li>\n  <li>デプロイする</li>\n</ul>\n\n<h2 id=\"フローを削除する\">フローを削除する</h2>\n\n<p>使用しなくなったフローをいつまでも残しておくとトラブルの元ですから、削除しましょう。<br />\n(念のため保存しておくのを忘れずに)</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、削除したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>左上の「削除」をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(次回デプロイするまで処理は残っているので注意)</li>\n</ul>\n\n<h2 id=\"フローを一時的に停止する\">フローを一時的に停止する</h2>\n\n<p>後で使うから削除したくはないけど、今デバッグしてる作業の邪魔になる、というような場合、\n作成したフローを削除せずに一時的に停止することができます。</p>\n\n<ul>\n  <li>フローエディタの上部のタブで、停止したいフローのタブをダブルクリック→ 編集メニューが表示される\n    <ul>\n      <li>状態を「無効」にする</li>\n      <li>完了をクリック</li>\n    </ul>\n  </li>\n  <li>デプロイする(デプロイしないといつまで経っても停止しないので注意)</li>\n</ul>\n\n<p>再開する場合は上記手順と同じで、状態を「有効」にする。</p>\n\n<h2 id=\"フローを全削除する\">フローを全削除する</h2>\n\n<p>色々フローを作成したけど、一回チャラにしてやりなおしたいときは、\n一旦Node-REDを停止(ブラウザ切断だけじゃなく、サーバプログラムを停止)して\n以下の2つのファイルを削除する</p>\n\n<ul>\n  <li>~/.node-red/flows_《ホスト名》.json</li>\n  <li>~/.node-red/.flows_《ホスト名》.json.backup</li>\n</ul>\n\n<p>もちろん、念のためバックアップ取っておくのが好ましい。<br />\nバックアップから復元すれば元通りになるはず。</p>\n\n<p>その後、Node-Redを起動すると、フローが綺麗さっぱり消えているハズ。</p>\n\n<h2 id=\"その2以降のフローの例について\">その2以降の「フローの例」について</h2>\n\n<p>「フローの例」に書かれたJSONコードはテスト用に作成したフローをエクスポート(書き出し)したものです。<br />\nこのコードの表示部分にマウスを乗せると、右上に「Copy」ボタンが表示されますので、このボタンをクリックしてください。JSONコードがクリップボードにコピーされます(マウスをドラッグしての選択は不要)。</p>\n\n<p>この状態で、上記<strong>フローを読み込む(インポート)</strong>に示した方法でフローをインポートするとフローがコピーされます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n複数のフローをインポートした場合、既に存在するノードと同名のノードは別のノードとして生成されます。このとき、名前に「(_1)」などの別ノードを識別できるような記号は付きません。<br />\n特に、WebsocketのノードやDashboardのタブ/グループはシステムの動作や見た目に影響しますので、注意してください。<br />\n自動でよしなにする方法はありませんので、手動でチマチマと修正してください。<br />\nサイドバー(右側のペイン)の「▼」ボタンをクリックし、ノードの設定を表示でノードの設定を表示し、<br />\n各ノードの右側の数字をクリックすると、そのノードを参照しているノードの一覧が表示されます。<br />\nさらにそのノード一覧の各ノードをダブルクリックすると、そのノードが点滅表示されるので、そのノードのプロパティで参照先を変更すれば良いでしょう。</p>\n\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Google": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Apps Script で メール送信</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Apps Script で メール送信</h1>\n      <p>Google Apps Script から メールを送信する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Google Apps Script(GAS)からメールを送信してみます。</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは<a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> で新しいGoogle Apps Scriptのプロジェクトを作成します。</p>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n\n<ul>\n  <li>新しいウィンドウでスクリプトエディタが開きます。</li>\n  <li>コード.gs に以下のコードを入力してください。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * テスト用関数\n */</span>\n <span class=\"kd\">function</span> <span class=\"nx\">myFunction</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">sendGmail</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">XXXX@gmail.com</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">TEST</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">テストだよ~ん</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n\n<span class=\"cm\">/**\n * Gmail送信処理\n *\n * @param {string|string[]} address    - 送信先アドレス\n * @param {string} subject  - サブジェクト(最大250文字)\n * @param {string} message  - 送信するメッセージ\n * \n * @note 送信先アドレスが間違っていてもここではエラーにならず、送信元アドレスにエラーメールが返る\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">sendGmail</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">,</span> <span class=\"nx\">subject</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n\n  <span class=\"c1\">// アドレスが配列だったらカンマ区切りの文字列に変換する</span>\n  <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nb\">Array</span><span class=\"p\">.</span><span class=\"nx\">isArray</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n    <span class=\"nx\">address</span> <span class=\"o\">=</span> <span class=\"nx\">address</span><span class=\"p\">.</span><span class=\"nx\">join</span><span class=\"p\">(</span><span class=\"dl\">'</span><span class=\"s1\">,</span><span class=\"dl\">'</span><span class=\"p\">);</span>\n  <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// そのまま</span>\n  <span class=\"p\">}</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">options</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"na\">name</span><span class=\"p\">:</span> <span class=\"dl\">\"</span><span class=\"s2\">てすと</span><span class=\"dl\">\"</span>        <span class=\"c1\">// 送信者名を指定したい場合は入れる</span>\n    <span class=\"c1\">// , replyTo: \"ZZZZ@gmail.com\"     // Reply-To を指定したい場合は入れる</span>\n  <span class=\"p\">};</span>\n\n  <span class=\"c1\">// メール送信</span>\n  <span class=\"nx\">GmailApp</span><span class=\"p\">.</span><span class=\"nx\">sendEmail</span><span class=\"p\">(</span><span class=\"nx\">address</span><span class=\"p\">,</span> <span class=\"nx\">subject</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">,</span> <span class=\"nx\">options</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n</code></pre></div></div>\n\n<ul>\n  <li>「実行する関数」に<code class=\"language-plaintext highlighter-rouge\">myFunction</code>を選択(エディタの上、「実行ログ」の左の▼をクリックして選ぶ)</li>\n  <li>「実行」をクリック</li>\n  <li>送信先アドレスへメールが送信されます</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n送信元アドレスにはこのスクリプトを実行しているGoogleユーザ(デプロイ設定によってはそのとき実行しているGoogleユーザ)が使用されます。<br />\noptionsで「from」フィールドを指定する事が出来ますが、このアドレスは送信元アドレスのaliasである必要があります。<br />\nそうでない場合は例外 Invalid argument がthrowされます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n送信先アドレスが間違っていてもここではエラーになりません。<br />\n送信元アドレスにエラーメール(subject:「Delivery Status Notification (Failure)」)が送られてきます。</p>\n</blockquote>\n\n<h1 id=\"最後に\">最後に</h1>\n\n<p>関数化する必要もないくらい簡単ですが😅</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Apps Script で LINE Notify</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Apps Script で LINE Notify</h1>\n      <p>Google Apps Script から LINE に通知を送る</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Google Apps Script(GAS)からリアルタイムな通知を送る方法としてLINEにメッセージを送ってみる。</p>\n\n<p>LINE Notify を使うとアクセストークンを取得すれば、REST APIで簡単にメッセージを送れるので、これを使うことにした。</p>\n\n<h1 id=\"前準備\">前準備</h1>\n\n<p><a href=\"https://qiita.com/iitenkida7/items/576a8226ba6584864d95\" target=\"_blank\">[超簡単]LINE notify を使ってみる</a>  を参考に、\nLINEの設定 および LINE Notifyのアクセストークンの取得を行っておいてください。</p>\n<blockquote>\n  <p>[!NOTE]\nトークルームでなく、『1:1でLINE Notifyから通知を受け取る』を選択した場合は、ID検索で「@linenotify」を検索して友だちに追加してください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://notify-bot.line.me/ja/\" target=\"_blank\">LINE Notifyホーム</a> <br />\n<a href=\"https://notify-bot.line.me/doc/ja/\" target=\"_blank\">ドキュメント</a></p>\n</blockquote>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは<a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> で新しいGoogle Apps Scriptのプロジェクトを作成します。</p>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n\n<ul>\n  <li>新しいウィンドウでスクリプトエディタが開きます。</li>\n  <li>コード.gs に以下のコードを入力してください。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">// アクセストークン </span>\n<span class=\"kd\">const</span> <span class=\"nx\">ACCESS_TOKEN</span> <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">«取得したアクセストークン»</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n\n<span class=\"cm\">/**\n * テスト用関数\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">myFunction</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 時刻文字列取得</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">date_str</span> <span class=\"o\">=</span> <span class=\"nx\">Utilities</span><span class=\"p\">.</span><span class=\"nx\">formatDate</span><span class=\"p\">(</span><span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">(),</span><span class=\"dl\">\"</span><span class=\"s2\">JST</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"dl\">\"</span><span class=\"s2\">yyyy/MM/dd hh:mm:ss</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">token</span> <span class=\"o\">=</span> <span class=\"nx\">ACCESS_TOKEN</span><span class=\"p\">;</span>\n  <span class=\"nx\">LINE_notify</span><span class=\"p\">(</span><span class=\"nx\">token</span><span class=\"p\">,</span> <span class=\"nx\">date_str</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">    てすとぉぉぉ</span><span class=\"dl\">\"</span> <span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n<span class=\"cm\">/**\n * メッセージ送信処理\n *\n * @param {string} token    - アクセストークン\n * @param {string} message  - 送信するメッセージ\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">LINE_notify</span><span class=\"p\">(</span><span class=\"nx\">token</span><span class=\"p\">,</span> <span class=\"nx\">message</span><span class=\"p\">){</span>\n    <span class=\"kd\">const</span> <span class=\"nx\">url</span> <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">https://notify-api.line.me/api/notify</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n    <span class=\"kd\">var</span> <span class=\"nx\">headers</span> <span class=\"o\">=</span> <span class=\"p\">{</span> \n      <span class=\"dl\">'</span><span class=\"s1\">Authorization</span><span class=\"dl\">'</span><span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">Bearer </span><span class=\"dl\">'</span> <span class=\"o\">+</span> <span class=\"nx\">token</span> \n    <span class=\"p\">};</span>\n    <span class=\"kd\">var</span> <span class=\"nx\">options</span> <span class=\"o\">=</span> <span class=\"p\">{</span> \n      <span class=\"dl\">'</span><span class=\"s1\">headers</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"nx\">headers</span> <span class=\"p\">,</span>\n      <span class=\"dl\">'</span><span class=\"s1\">method</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">post</span><span class=\"dl\">'</span> <span class=\"p\">,</span>\n      <span class=\"c1\">// encodeURIComponent()はなくても大丈夫っぽい...</span>\n      <span class=\"c1\">// 'payload' : 'message=' + encodeURIComponent(message)</span>\n      <span class=\"dl\">'</span><span class=\"s1\">payload</span><span class=\"dl\">'</span> <span class=\"p\">:</span> <span class=\"dl\">'</span><span class=\"s1\">message=</span><span class=\"dl\">'</span> <span class=\"o\">+</span> <span class=\"nx\">message</span><span class=\"p\">,</span> \n      <span class=\"dl\">'</span><span class=\"s1\">muteHttpExceptions</span><span class=\"dl\">'</span><span class=\"p\">:</span> <span class=\"kc\">true</span>        <span class=\"c1\">// エラーが返ってきても例外発生させない</span>\n     <span class=\"p\">};</span> \n    <span class=\"kd\">var</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n\n    <span class=\"k\">try</span> <span class=\"p\">{</span>\n      <span class=\"c1\">// メッセージを送信 </span>\n      <span class=\"kd\">var</span> <span class=\"nx\">res</span> <span class=\"o\">=</span> <span class=\"nx\">UrlFetchApp</span><span class=\"p\">.</span><span class=\"nx\">fetch</span><span class=\"p\">(</span><span class=\"nx\">url</span> <span class=\"p\">,</span><span class=\"nx\">options</span><span class=\"p\">);</span>\n\n      <span class=\"kd\">var</span> <span class=\"nx\">resCode</span> <span class=\"o\">=</span> <span class=\"nx\">res</span><span class=\"p\">.</span><span class=\"nx\">getResponseCode</span><span class=\"p\">();</span>              <span class=\"c1\">// HTTP レスポンスステータスコード</span>\n      <span class=\"kd\">var</span> <span class=\"nx\">resBody</span> <span class=\"o\">=</span> <span class=\"nx\">JSON</span><span class=\"p\">.</span><span class=\"nx\">parse</span><span class=\"p\">(</span><span class=\"nx\">res</span><span class=\"p\">.</span><span class=\"nx\">getContentText</span><span class=\"p\">());</span>   <span class=\"c1\">// レスポンス本体はJSONなのでパースする</span>\n\n      <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nx\">resCode</span> <span class=\"o\">===</span> <span class=\"mi\">200</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// レスポンスが200 → 正常終了</span>\n        <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">SUCCESS: %s</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"nx\">resBody</span><span class=\"p\">.</span><span class=\"nx\">message</span><span class=\"p\">);</span>\n      <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// それ以外→エラーレスポンス</span>\n        <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"nx\">Utilities</span><span class=\"p\">.</span><span class=\"nx\">formatString</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">ERROR: status:%d  body:%s</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"nx\">resCode</span><span class=\"p\">,</span> <span class=\"nx\">resBody</span><span class=\"p\">.</span><span class=\"nx\">message</span><span class=\"p\">));</span>\n      <span class=\"p\">}</span>\n    <span class=\"p\">}</span> <span class=\"k\">catch</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n      <span class=\"c1\">// その他のエラー(DNSエラー、タイムアウトなど)は例外が発生する</span>\n      <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">ERROR: </span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">e</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<ul>\n  <li>「実行する関数」に<code class=\"language-plaintext highlighter-rouge\">myFunction</code>を選択(エディタの上、「実行ログ」の左の▼をクリックして選ぶ)\nー 「実行」をクリック</li>\n  <li>LINEに通知が届きます</li>\n</ul>\n\n<h1 id=\"最後に\">最後に</h1>\n\n<p>これだけだと大したことできないけど、ライブラリ化して他のサービスと組み合わせて使えばなんかのPUSH通知っぽく使えるかな?</p>\n\n<blockquote>\n  <p>[!NOTE]\nSpreadsheetの時のように、ウェブアプリにしようかと思ったら、もともとREST APIだから全然意味ないので関数作るだけにしておいた。<br />\n(POST使えない場合にGETで受け付けるラッパみたいなのは考えられなくはないけど)</p>\n</blockquote>\n\n<h1 id=\"参考\">参考</h1>\n\n<p>通知回数の上限は1000回/1時間/アクセストークンです。(そんなに送ったら鬱陶しいでしょうから問題ないかな?)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google spreadsheet にREST APIを追加(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google spreadsheet にREST APIを追加(その2)</h1>\n      <p>Google Apps Scriptのライブラリ化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">Google spreadsheet にREST APIを追加 その1</a>   では\nSpreadsheetに埋め込んだスクリプトにすべて記述しましたが、 新しいSpreadsheetを作成する度にコードをコピーするのは大変ですし、\n何らかの不具合が見つかったときに複数のファイルをメンテナンスしなければならないのは現実的ではありません。<br />\nそこで、スプレッドシートにデータを登録する部分をライブラリ化し、Spreadsheetに埋め込んだスクリプトには最低限のコードだけ記載するようにしてみます。</p>\n\n<h1 id=\"手順\">手順</h1>\n<p>まずはスクリプトライブラリを作成します</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a>   を開く</li>\n  <li>左側「新規」→ 「その他」→「Google Apps Script」で新しいスクリプトエディタが開く\n    <ul>\n      <li>「無題のプロジェクト」をクリックして名前を入力</li>\n      <li>コード.gsに以下を入力(<a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">その1</a>  の<code class=\"language-plaintext highlighter-rouge\">AddDataToSeet()</code>と同一)</li>\n    </ul>\n  </li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストで渡されたデータをスプレッドシートの最終行に追加する\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">AddDataToSeet start</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n\n  <span class=\"c1\">// 記録するシート(現在のスプレッドシートのアクティブなシート)</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">sheet</span> <span class=\"o\">=</span> <span class=\"nx\">SpreadsheetApp</span><span class=\"p\">.</span><span class=\"nx\">getActiveSheet</span><span class=\"p\">();</span>\n\n  <span class=\"kd\">var</span> <span class=\"nx\">dt</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>    <span class=\"c1\">// 日付</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>            <span class=\"c1\">// デフォルト値</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv0が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv1が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv2が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n\n  <span class=\"c1\">// スプレッドシートの最終行に追加</span>\n  <span class=\"nx\">sheet</span><span class=\"p\">.</span><span class=\"nx\">appendRow</span><span class=\"p\">([</span><span class=\"nx\">dt</span><span class=\"p\">,</span> <span class=\"nx\">v0</span><span class=\"p\">,</span> <span class=\"nx\">v1</span><span class=\"p\">,</span> <span class=\"nx\">v2</span><span class=\"p\">]);</span>\n\n  <span class=\"c1\">// HTML表示データを生成</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">createTextOutput</span><span class=\"p\">();</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setMimeType</span><span class=\"p\">(</span><span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">MimeType</span><span class=\"p\">.</span><span class=\"nx\">TEXT</span><span class=\"p\">);</span>\n  <span class=\"c1\">// メッセージボディ</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setContent</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">set data:</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">date=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">dt</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v0=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v0</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v1=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v1</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v2=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v2</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<ul>\n  <li>右上の青いボタン「デプロイ」→「新しいデプロイ」をクリック\n    <ul>\n      <li>「デプロイタイプを選択してください」と言われるので、\n        <ul>\n          <li>「種類の選択」横の歯車アイコンをクリック → 「ライブラリ」をクリック</li>\n          <li>「説明」に説明文を入力(省略可)</li>\n          <li>「デプロイ」をクリック</li>\n        </ul>\n      </li>\n      <li>新しいデプロイウィンドウが表示されるので、「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>画面左の歯車アイコン「プロジェクトの設定」をクリック\n    <ul>\n      <li>「プロジェクトの設定」の真ん中あたりの「スクリプトID」をメモしておく</li>\n    </ul>\n  </li>\n</ul>\n\n<p>次に操作されるspreadsheetを作成します。</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a>   を開く</li>\n  <li>左側「新規」→ 「Googleスプレッドシート」で新しいスプレッドシートが開く</li>\n  <li>無題のスプレッドシート」をクリックして名前を入力</li>\n  <li>SpreadsheetにGoogle Apps Script(GAS)を追加します。\n    <ul>\n      <li>メニューの「ツール」→「スクリプトエディタ」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<p>新しいウィンドウでスクリプトエディタが開きます。</p>\n<ul>\n  <li>「ライブラリ」の横の+マーク(ライブラリを追加)をクリック</li>\n  <li>「ライブラリの追加」ウィンドウが開くので、「スクリプトID」の欄に上でメモしたスクリプトIDを入力し、「検索」をクリック</li>\n  <li>バージョンで使用するバージョンを選択(HAEAD(開発モード)を選択すると、デプロイするまえの最新ソースが使用される)</li>\n  <li>ID を設定します。\n    <blockquote>\n      <p>[!NOTE]\nID は node.jsで言うところの、以下の部分の「変数名」に相当する</p>\n      <div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">var</span> <span class=\"nx\">変数名</span> <span class=\"o\">=</span> <span class=\"nx\">require</span><span class=\"p\">(</span><span class=\"dl\">'</span><span class=\"s1\">モジュール名</span><span class=\"dl\">'</span><span class=\"p\">)</span>\n</code></pre></div>      </div>\n    </blockquote>\n  </li>\n  <li>コード.gs に以下のコードを入力</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストの処理\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">doGet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 処理本体</span>\n  <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">MySpreadsheetLib</span><span class=\"p\">.</span><span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>以降、(<a href=\"/memoBlog/2021/02/15/spreadsheet_RESET.html\" target=\"_blank\">その1</a> のデプロイ作業と同一です。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google spreadsheet にREST APIを追加(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google spreadsheet にREST APIを追加(その1)</h1>\n      <p>HTTP GETリクエストでGoogle spreadsheetに追記する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2019/10/01/spreadsheet.html\" target=\"_blank\">Node.jsでGoogle spreadsheet にデータを書き込む</a> で\nGoogle Drive APIでGoogle spreadsheet にデータを書き込む方法を紹介しましたが、\nクライアント側の処理をもっと簡単にするためにREST APIを追加してHTTP GETリクエストでデータを書き込めるようにしてみました。</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p>まずは操作されるspreadsheetを作成します。</p>\n<ul>\n  <li><a href=\"https://drive.google.com/drive/\" target=\"_blank\">Googleドライブ</a> を開く</li>\n  <li>左側「新規」→ 「Googleスプレッドシート」で新しいスプレッドシートが開く</li>\n  <li>無題のスプレッドシート」をクリックして名前を入力</li>\n</ul>\n\n<p>次に、作成したspreadsheetにGoogle Apps Script(GAS)を追加します。</p>\n<ul>\n  <li>メニューの「ツール」→「スクリプトエディタ」をクリック</li>\n</ul>\n\n<p>新しいウィンドウでスクリプトエディタが開きます。</p>\n<ul>\n  <li>コード.gs に以下のコードを入力</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cm\">/**\n * GETリクエストで渡されたデータをスプレッドシートの最終行に追加する\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"nx\">Logger</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">AddDataToSeet start</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n\n  <span class=\"c1\">// 記録するシート(現在のスプレッドシートのアクティブなシート)</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">sheet</span> <span class=\"o\">=</span> <span class=\"nx\">SpreadsheetApp</span><span class=\"p\">.</span><span class=\"nx\">getActiveSheet</span><span class=\"p\">();</span>\n\n  <span class=\"kd\">var</span> <span class=\"nx\">dt</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>    <span class=\"c1\">// 日付</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>            <span class=\"c1\">// デフォルト値</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"dl\">\"\"</span><span class=\"p\">;</span>\n\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v0</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v0</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv0が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v1</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v1</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv1が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n  <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span> <span class=\"o\">!==</span> <span class=\"kc\">undefined</span><span class=\"p\">){</span>\n    <span class=\"nx\">v2</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">parameter</span><span class=\"p\">.</span><span class=\"nx\">v2</span><span class=\"p\">;</span>    <span class=\"c1\">// GETパラメータでv2が設定されていたら変数設定</span>\n  <span class=\"p\">}</span>\n\n  <span class=\"c1\">// スプレッドシートの最終行に追加</span>\n  <span class=\"nx\">sheet</span><span class=\"p\">.</span><span class=\"nx\">appendRow</span><span class=\"p\">([</span><span class=\"nx\">dt</span><span class=\"p\">,</span> <span class=\"nx\">v0</span><span class=\"p\">,</span> <span class=\"nx\">v1</span><span class=\"p\">,</span> <span class=\"nx\">v2</span><span class=\"p\">]);</span>\n\n  <span class=\"c1\">// HTML表示データを生成</span>\n  <span class=\"kd\">var</span> <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">createTextOutput</span><span class=\"p\">();</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setMimeType</span><span class=\"p\">(</span><span class=\"nx\">ContentService</span><span class=\"p\">.</span><span class=\"nx\">MimeType</span><span class=\"p\">.</span><span class=\"nx\">TEXT</span><span class=\"p\">);</span>\n  <span class=\"c1\">// メッセージボディ</span>\n  <span class=\"nx\">output</span><span class=\"p\">.</span><span class=\"nx\">setContent</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">set data:</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">date=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">dt</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v0=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v0</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v1=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v1</span> <span class=\"o\">+</span> <span class=\"dl\">\"</span><span class=\"s2\">,v2=</span><span class=\"dl\">\"</span> <span class=\"o\">+</span> <span class=\"nx\">v2</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"cm\">/**\n * GETリクエストの処理\n *\n * @param {event object} e - 要求パラメータ\n * @return {object} HTML出力\n */</span>\n<span class=\"kd\">function</span> <span class=\"nx\">doGet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// 処理本体</span>\n  <span class=\"nx\">output</span> <span class=\"o\">=</span> <span class=\"nx\">AddDataToSeet</span><span class=\"p\">(</span><span class=\"nx\">e</span><span class=\"p\">);</span>\n  <span class=\"k\">return</span> <span class=\"nx\">output</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ndoGet関数のパラメータ<code class=\"language-plaintext highlighter-rouge\">e</code>については、<a href=\"https://developers.google.com/apps-script/guides/web\" target=\"_blank\">このへん</a>を参照してください。</p>\n</blockquote>\n\n<ul>\n  <li>右上の青いボタン「デプロイ」→「新しいデプロイ」をクリック\n    <ul>\n      <li>「デプロイタイプを選択してください」と言われるので、「種類の選択」横の歯車アイコンをクリック → 「ウェブアプリ」をクリック\n        <ul>\n          <li>「説明」に説明文を入力(省略可)</li>\n          <li>「ウェブアプリ」の「次のユーザとして実行」で「自分」を選択</li>\n          <li>「アクセスできるユーザ」を適切な範囲に設定  (「全員」にすればパスワードなしでアクセスできる)\n            <blockquote>\n              <p>[!NOTE]\ncurlなどでアクセスしたい場合は、「全員」にしておかないと、認証画面に飛んでしまい、アクセスが完了しません。</p>\n            </blockquote>\n          </li>\n          <li>「デプロイ」をクリック</li>\n        </ul>\n      </li>\n      <li>「このウェブ アプリケーションを使用するには、データへのアクセスを許可する必要があります。」と言われるので「アクセスを承認」をクリック</li>\n      <li>「アカウントの選択」が表示されるので、使用するアカウントを選択</li>\n      <li>「このアプリは Google で確認されていません」と言われるので、左下「詳細」をクリック\n        <ul>\n          <li>「無題のプロジェクト(安全ではないページ)に移動」をクリック</li>\n          <li>「無題のプロジェクトがGoogle アカウントへのアクセスをリクエストしています」と言われるので、「許可」をクリック</li>\n          <li>「新しいデプロイ」が表示される</li>\n          <li>一番下の「ウェブアプリ」のUARLをコピーして使用</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<p>例えば以下のコマンドでアクセスする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>curl <span class=\"nt\">-L</span> <span class=\"s2\">\"«上でコピーしたURL»?v0=1&v1=2&v2=3\"</span>\n</code></pre></div></div>\n\n<p>実行すると、対象のスプレッドシートの最終行に以下のデータが追加されます。</p>\n<ul>\n  <li>A列: 日付と時刻</li>\n  <li>B列: v0で指定した値</li>\n  <li>C列: v1で指定した値</li>\n  <li>D列: v2で指定した値</li>\n</ul>\n\n<p>スクリプトを修正した場合、再度「新しいデプロイ」を実行する必要がある。</p>\n\n<p>または、「デプロイ」→「デプロイをテスト」で表示されるURLを使用すると、デプロイせずに現在の最新ソースで実行できる。<br />\nただし、この場合、ユーザ認証が必須になってしまうので、ブラウザ等でアクセスする必要がある。<br />\nどうしてもcurlでアクセスしたい場合は、ヘッダに<code class=\"language-plaintext highlighter-rouge\">Authorization: Bearer «アクセストークン»</code>を追加してやれば良い。(あまりおススメはしないけど)<br />\nやり方は<a href=\"https://www.ka-net.org/blog/?p=12258\" target=\"_blank\">ここらへん</a>を参考にしてください。</p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>時刻の文字列を取得した場合、知らないタイムゾーンになっていて困ったときはタイムゾーンを変更すれば良い。</p>\n\n<p>タイムゾーンを変更するにはこちら。</p>\n<ul>\n  <li>画面左の歯車アイコン「プロジェクトの設定」をクリック\n    <ul>\n      <li>「「appsscript.json」マニフェスト ファイルをエディタで表示する」にチェックを入れる</li>\n    </ul>\n  </li>\n  <li>画面左の<>アイコン「エディタ」をクリックしてエディタに戻る\n    <ul>\n      <li>ファイル一覧に「appsscript.json」が追加されているのでクリック</li>\n      <li>タイムゾーンを指定している部分を   <code class=\"language-plaintext highlighter-rouge\">\"timeZone\": \"Asia/Tokyo\",</code> に変更</li>\n      <li>保存して再度デプロイ</li>\n    </ul>\n  </li>\n</ul>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その9)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その9)</h1>\n      <p>Node-REDのメモ 応用編 Google spreadsheet Read</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでGoogle spreadsheet からデータを取得したときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><strong>その8</strong> に従って準備済みであるものとする。</p>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で作成済みの認証情報を選択するか、「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に操作対象のスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:zzz」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n          <li>Rangeのフォーマットはシート名!開始セル:終了セル\n            <ul>\n              <li>開始セルと終了セルを両方省略することは可能(片方のみ省略は不可のよう)。<br />\nこの場合、シート全体が取得される。ただし、↑のように特定のシート名はダメかもしれない。</li>\n              <li>開始セル/終了セルはカラム名と行番号で構成されるが、カラム名か行番号は省略可能。\nたぶん、こんな感じ。\n                <ul>\n                  <li>開始カラム名を省略するとAが指定されたとみなす</li>\n                  <li>開始行番号を省略すると1が指定されたとみなす</li>\n                  <li>終了カラム名を省略すると最終カラム(zzz?)が指定されたとみなす</li>\n                  <li>終了行番号を省略すると最終行が指定されたとみなす</li>\n                </ul>\n              </li>\n              <li>大きな範囲を指定しても、以降空白セルであった場合は無視される(有効なデータがある範囲だけ読み込まれる)</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n          <li>プロパティ名はシート名_開始セル_終了セル</li>\n          <li>globalに記録しておけば、キャッシュとして使用出来て、なんども同じデータを読まなくて済む、という使い方かな?</li>\n        </ul>\n      </li>\n      <li>\n        <p>「Action」に「Get Data」を選択し、その右は「By line」を選択</p>\n      </li>\n      <li>「Labels」の「First line for labels」を選択しすると、outputの型がDictionaryになる。指定したセル範囲の開始カラム(シート全体の開始カラムではない)がキー名となる。<br />\n 選択しなければ、outputの型がArrayになる</li>\n      <li>「Labels」の「First column for labels」を選択しすると、outputの各要素の型がDictionaryになる。指定したセル範囲の開始行(シート全体の開始行ではない)の内容がキー名となる。<br />\n 選択しなければ、outputの各要素の型がArrayになる</li>\n      <li>\n        <p>この2つ、なんか逆な気もするけど…</p>\n      </li>\n      <li>outputにリード結果が入る。とりあえず「msg」を選択し、「_output」にしておく\n内容は「Labels」の設定内容によって変わる</li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<p>設定内容と取得内容の関係はよくワカランので、色々試してみてください。<br />\n現実的には、細かくデータを取得してどうこうするより、シート全体を取得して処理するような使い方になるのかな??</p>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、スプレッドシートの内容が取得されるハズ。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"5eb2475f.ea747\",\n        \"type\": \"tab\",\n        \"label\": \"spreadsheet_read\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"60d62f37.80a8a\",\n        \"type\": \"inject\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 110,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"bba510f2.5bb2d8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"e183b4f0.c372f\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 140,\n        \"wires\": []\n    },\n    {\n        \"id\": \"37bd743e.1ca96c\",\n        \"type\": \"debug\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 490,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"bba510f2.5bb2d8\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"5eb2475f.ea747\",\n        \"name\": \"spreadsheet read\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:zzz\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"get\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": true,\n        \"fields\": \"all\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"\",\n        \"output\": \"_output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 290,\n        \"y\": 140,\n        \"wires\": [\n            [\n                \"e183b4f0.c372f\"\n            ],\n            [\n                \"37bd743e.1ca96c\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node-REDのHowTo(その8)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node-REDのHowTo(その8)</h1>\n      <p>Node-REDのメモ 応用編 BME280+Google spreadsheet</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Node-REDでBME280で測定したデータをGoogle spreadsheet に記録するときの設定手順のメモ。<br />\n鶏頭で忘れっぽいのでメモ。</p>\n\n<p>それぞれの基本は、Node-REDのHowTo(その1) ~ (その4)参照</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"google-spreadsheet用ノードのインストール\">Google spreadsheet用ノードのインストール</h2>\n\n<ul>\n  <li>ブラウザでNode-REDに接続した状態で、右上の3本線メニュー(≡) から「パレットの管理」をクリック</li>\n  <li>画面上部の「ノードを追加」をクリック</li>\n  <li>ノードを検索の部分に「node-red-contrib-viseo-google-」と入力</li>\n  <li>下に検索結果が出るので、「node-red-contrib-viseo-google-authentication」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら続けて「node-red-contrib-viseo-google-spreadsheet」の「ノードを追加」をクリック</li>\n  <li>何やらダイアログが出るので、「追加」をクリック</li>\n  <li>完了したら「閉じる」をクリック。</li>\n</ul>\n\n<h2 id=\"googleの準備\">Googleの準備</h2>\n\n<p><a href=\"https://techblog.lclco.com/entry/2018/11/30/120000\">具体的な手順はこちらを参考にしてくだされ。</a> (コードの実装の手前まで)  <br />\nただし、<span style=\"color: red; \">有効にするAPI</span>は「Google Drive API」ではなく、「<span style=\"color: red; \">Google Sheets API</span>」なので、注意!!</p>\n\n<h3 id=\"認証情報の作成\">認証情報の作成</h3>\n\n<ul>\n  <li><a href=\"https://console.developers.google.com/project\">Google Developers Console</a> でプロジェクトを作成</li>\n  <li>Google Sheets APIを有効化</li>\n  <li>認証情報(サービスアカウント キー)を作成</li>\n  <li>保存された認証情報の秘密鍵をダウンロード<br />\n  このファイルはセキュリティ上 <strong>超重要</strong> なので、まちがって公開しないように!!!!<br />\n  ・・・・公開して後悔…なんちゃって(^^ゞ</li>\n</ul>\n\n<h3 id=\"記録用スプレッドシートの作成\">記録用スプレッドシートの作成</h3>\n\n<ul>\n  <li><a href=\"https://drive.google.com/drive/u/0/my-drive\">Google Drive</a>から記録するスプレッドシートを作成する(マイドライブからgoogleスプレッドシートを選択すると新規ファイルが作成される)</li>\n  <li>作成されたスプレッドシートに共有ユーザ(サービスアカウントキーのメールアドレス)を追加。権限を編集者、通知のチェックははずしてOKする</li>\n  <li>必要ならシートの追加や名前の変更を行っておく(以下ではシート名が「BME280」になっているものとして説明)</li>\n  <li>1行目に項目名を入れておく。ここではA列から「epoch」「日付」「温度」「湿度」「気圧」としている</li>\n  <li>B列(「日付」の列)を選択し、メニューから「表示形式」→「数値」→「日時」を選択(これをやらないと時刻が見えない))</li>\n  <li>作成されたスプレッドシートのID(URLの docs.google.com/spreadsheets/d/<span style=\"color: red; \">この部分</span>/edit~)をメモしておく</li>\n</ul>\n\n<h2 id=\"フローの作成\">フローの作成</h2>\n\n<h3 id=\"bme280ノード\">BME280ノード</h3>\n\n<ul>\n  <li><strong>その2</strong>の<strong>BME280を使用するフローを作成する</strong>と同様の手順でBME280ノードを作成する</li>\n  <li>トリガとなるノードを入力側に接続\n    <ul>\n      <li>トリガノードはトリガイベントのみが必要で、入力データは何でも良い</li>\n    </ul>\n  </li>\n  <li>出力側にFunctionノードを接続\n  コードは以下。<br />\n  あとで時刻を使用しやすいようにエポック時刻で記録するようにしている。<br />\n  また、エポック時刻のままだとスプレッドシーで見たときに日時が分かり難いので、エポック時刻から日時に変更する計算式を入れておく。(ここで直接文字列にすることもできるが)<br />\n  また、Google Sheetsノードの入力はArrayである必要があるようで、Ayyayでラップしておく。</li>\n</ul>\n\n<div class=\"language-javascript highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">var</span> <span class=\"nx\">date</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nb\">Date</span><span class=\"p\">();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">epoch</span> <span class=\"o\">=</span> <span class=\"nx\">date</span><span class=\"p\">.</span><span class=\"nx\">getTime</span><span class=\"p\">();</span>\n<span class=\"c1\">// msg.payload.date  = date.toString();</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">date</span>  <span class=\"o\">=</span> <span class=\"dl\">'</span><span class=\"s1\">=indirect(\"R[0]C[-1]\", false) / (1000*60*60*24) + (9/24) + DATE(1970, 1, 1)</span><span class=\"dl\">'</span><span class=\"p\">;</span>\n<span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nx\">msg</span><span class=\"p\">.</span><span class=\"nx\">payload</span><span class=\"p\">];</span>\n\n<span class=\"k\">return</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>\n</code></pre></div></div>\n\n<h3 id=\"google-sheetsノード\">Google Sheetsノード</h3>\n\n<ul>\n  <li>パレットの「data」の下の「Sheets」をフローにドラッグ&ドロップ</li>\n  <li>ドロップした「Google Sheets」をダブルクリック → 編集メニューが表示される\n    <ul>\n      <li>必要ならNameにノード名を設定\n        <ul>\n          <li>省略すると「Google Sheets」が表示される</li>\n        </ul>\n      </li>\n      <li>Credentials で「新規にgoogle-service-accountを追加…」を選択してその右の編集ボタンをクリック\n        <ul>\n          <li>必要ならNameにノード名を設定(どれだか分からなくなりそうなので、名前を付けておくのがおススメ)</li>\n          <li>「config」で「Copy/Paste JSON file」を選択</li>\n          <li>その下の「JSON」ができるので、その右の「…」をクリック\n            <ul>\n              <li>JSONエディタが開くので、上でダウンロードした認証情報の秘密鍵の中身をコピペ</li>\n              <li>「完了」をクリック</li>\n            </ul>\n          </li>\n          <li>「Scopes」で「Sheets」をクリック</li>\n          <li>「完了」をクリック</li>\n        </ul>\n      </li>\n      <li>「ID」に上でメモっておいたスプレッドシートのIDを入力</li>\n      <li>「Range」に使用するシート名とセル範囲(ここでは「BME280!a:z」としておく)\n        <ul>\n          <li>シート名だけでも良いはずだが、なぜかBME280というシート名はセル範囲と誤認されるようなので、セル範囲を追加しておく  <br />\n(シート名がセンサデータとかだどOKなのかな??)<br />\nアルファベット3文字以下+数字だとセル名と認識される仕様のような気がする。。。</li>\n        </ul>\n      </li>\n      <li>「Save」はよくわからんけど、とりあえず、msgを選択して「_sheet」にしておく\n        <ul>\n          <li>set dataのときは使用されないようだ</li>\n          <li>get dataのときはリード結果の生データが入るようだ</li>\n        </ul>\n      </li>\n      <li>「Action」に「Set Data」を選択し、その右は「Append」を選択</li>\n      <li>「input」は「msg」を選択し、「payload」を入力</li>\n      <li>「Fields」で「Select」を選択</li>\n      <li>その下に「key」と入力欄が表示されるので、「epoch」と入力し、「追加」をクリック</li>\n      <li>「date」と入力し、「追加」をクリック</li>\n      <li>「temperature_C」と入力し、「追加」をクリック</li>\n      <li>「humidity」と入力し、「追加」をクリック</li>\n      <li>「pressure_hPa」と入力\n        <ul>\n          <li>このデータの並びが入力のプロパティ名とスプレッドシートのセルの並びに対応する</li>\n        </ul>\n      </li>\n      <li>outputもよー分からんけど、とりあえず「msg」を選択し、「_output」にしておく\n        <ul>\n          <li>set dataのときは処理結果が入るようだ</li>\n          <li>get dataのときはリード結果が入るようだ</li>\n        </ul>\n      </li>\n      <li>「完了」をクリック</li>\n    </ul>\n  </li>\n  <li>このノードの入力にファンクションノードの出力を接続</li>\n  <li>このノードの出力は何が出てくるのかよく分からんので、とりあえず2つともdebugノードを接続しておく\n    <ul>\n      <li>このデバッグノードの対象はmsg.payloadではなく、msgオブジェクト全体にしておいた方が色々確認しやすいのでおススメ</li>\n      <li>上の出力に正常時の処理結果が出てくるらしい(エラー時はundefined))</li>\n      <li>下の出力はエラー時の処理結果が出てくるらしい(正常時はundefined)</li>\n      <li>でも、エラー内容はGoogle Sheets ノードからメッセージが出る</li>\n    </ul>\n  </li>\n  <li>デプロイする</li>\n</ul>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>トリガとなるノードからトリガが入力されれば、温度等を測定、スプレッドシートに送信される。<br />\nスプレッドシートを確認すれば、そのデータが記録されているハズである。</p>\n\n<p>このとき、Google Sheetsノードが<code class=\"language-plaintext highlighter-rouge\">\"Missing VISEO Bot Maker key - Read the documentation.\"</code>というメッセージを出力するが、これは単なるワーニングなので、気にしなくて良い(らしい)。</p>\n\n<h1 id=\"フローの例\">フローの例</h1>\n\n<p>秘密鍵の内容は入っていないので、別途入力すること<br />\nスプレッドシートのIDも削除してあるので、作成したスプレッドシートのIDを入力すること</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\n[\n    {\n        \"id\": \"1a4f21c6.53e09e\",\n        \"type\": \"tab\",\n        \"label\": \"BME280+spreadsheet\",\n        \"disabled\": false,\n        \"info\": \"\"\n    },\n    {\n        \"id\": \"b4e73f33.99aec8\",\n        \"type\": \"Bme280\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"bus\": \"1\",\n        \"address\": \"0x76\",\n        \"topic\": \"bme280\",\n        \"extra\": false,\n        \"x\": 220,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"a54ed898.2a114\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"b74c37d3.63a48\",\n        \"type\": \"inject\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"topic\": \"\",\n        \"payload\": \"true\",\n        \"payloadType\": \"bool\",\n        \"repeat\": \"\",\n        \"crontab\": \"\",\n        \"once\": false,\n        \"onceDelay\": 0.1,\n        \"x\": 90,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"b4e73f33.99aec8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"a54ed898.2a114\",\n        \"type\": \"function\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"データ整形\",\n        \"func\": \"var date = new Date();\\nmsg.payload.epoch = date.getTime();\\n// msg.payload.date  = date.toString();\\n// msg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\",false)/1000/60/60/24 + 9/24 + DATE(1970,1,1)';\\nmsg.payload.date  = '=indirect(\\\"R[0]C[-1]\\\", false) / (1000*60*60*24) + (9 / 24) + DATE(1970, 1, 1)';\\n\\nmsg.payload = [msg.payload];\\n\\nreturn msg;\",\n        \"outputs\": 1,\n        \"noerr\": 0,\n        \"x\": 390,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"6a4f8cc4.882e54\",\n                \"adad9a.88697a68\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"6a4f8cc4.882e54\",\n        \"type\": \"google-spreadsheet\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"auth\": \"9550e71e.d49b88\",\n        \"sheet\": \"ナイショ 自分のシートのIDを書いてね\",\n        \"range\": \"BME280!a:z\",\n        \"method\": \"append\",\n        \"direction\": \"line\",\n        \"action\": \"set\",\n        \"clear\": false,\n        \"line\": false,\n        \"column\": false,\n        \"fields\": \"select\",\n        \"save\": \"_sheet\",\n        \"selfields\": [\n            \"epoch\",\n            \"date\",\n            \"temperature_C\",\n            \"humidity\",\n            \"pressure_hPa\"\n        ],\n        \"cell_l\": \"\",\n        \"cell_c\": \"\",\n        \"input\": \"payload\",\n        \"output\": \"__output\",\n        \"saveType\": \"msg\",\n        \"inputType\": \"msg\",\n        \"outputType\": \"msg\",\n        \"sheetType\": \"str\",\n        \"rangeType\": \"str\",\n        \"cell_lType\": \"str\",\n        \"cell_cType\": \"str\",\n        \"x\": 620,\n        \"y\": 180,\n        \"wires\": [\n            [\n                \"93209cb1.cd86\"\n            ],\n            [\n                \"9a8717a8.88bae8\"\n            ]\n        ]\n    },\n    {\n        \"id\": \"93209cb1.cd86\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 180,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9a8717a8.88bae8\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"true\",\n        \"targetType\": \"full\",\n        \"x\": 830,\n        \"y\": 220,\n        \"wires\": []\n    },\n    {\n        \"id\": \"adad9a.88697a68\",\n        \"type\": \"debug\",\n        \"z\": \"1a4f21c6.53e09e\",\n        \"name\": \"\",\n        \"active\": true,\n        \"tosidebar\": true,\n        \"console\": false,\n        \"tostatus\": false,\n        \"complete\": \"false\",\n        \"x\": 850,\n        \"y\": 80,\n        \"wires\": []\n    },\n    {\n        \"id\": \"9550e71e.d49b88\",\n        \"type\": \"google-service-account\",\n        \"z\": \"\",\n        \"name\": \"edior1@myproject3\",\n        \"scope\": [\n            \"https://www.googleapis.com/auth/spreadsheets\"\n        ],\n        \"way\": \"json\",\n        \"check_dialogflow\": \"\",\n        \"check_speech\": \"\"\n    }\n]\n \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Node.jsでGoogle spreadsheet にデータを書き込む</title>\n  </head>\n  <body>\n    <header>\n      <h1>Node.jsでGoogle spreadsheet にデータを書き込む</h1>\n      <p>Node.jsでGoogle spreadsheet にデータを書き込む</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Node.jsでGoogle spreadsheet にデータを書き込む方法。<br />\nサンプルプログラムを<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>に置きました。</p>\n\n<p>Google Drive API を サービスアカウントで操作する方法を取りました。</p>\n\n<p>OAuth認証を使う方法は事前準備がめんどっちいので、パス。<br />\nAPIキー認証はリードはできたけど、ライトが出来んかった。あと、シートを公開しないといけないが、やな感じだった。</p>\n\n<h1 id=\"詳細\">詳細</h1>\n\n<p>詳細は\n<a href=\"https://github.com/ippei8jp/spreadsheet_serviceaccount\">github</a>\nのREADME おひび ソースコードを参照してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "openCV": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openCV で MPEG再生</title>\n  </head>\n  <body>\n    <header>\n      <h1>openCV で MPEG再生</h1>\n      <p>python + openCV でMPEGファイルを再生する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>python + openCV で MPEGファイルを再生するには、以下のようにread→imshowを繰り返せば良い。<br />\nしかし、これではフレームレートを考慮していないため、実際の時間とは異なる速度で再生されてしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n<span class=\"k\">while</span> <span class=\"n\">true</span><span class=\"p\">:</span>\n    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"k\">break</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>そこで、フレーム間に待ち時間を確保し、実際の時間と同じになるように再生する方法を考える。</p>\n\n<h1 id=\"フレーム間の待ち時間を決め打ちで待つパターン一番シンプルなパターン\">フレーム間の待ち時間を決め打ちで待つパターン(一番シンプルなパターン)</h1>\n\n<p>最も簡単な方法は、フレーム間に決め打ちでwait処理を挿入する方法である。<br />\nフレームレートは一定であるため、待ち時間も一定になる。<br />\n再生中にキー入力による中止を検出したいので、<code class=\"language-plaintext highlighter-rouge\">time.sleep()</code>ではなく、<code class=\"language-plaintext highlighter-rouge\">cv2.waitKey(delay)</code>を使用している。<br />\n試した環境では、<code class=\"language-plaintext highlighter-rouge\">cv2.waitKey()</code> は 25くらいを指定すると大体30fpsに合うくらいの間隔になる(ちょっと早いかも)。<br />\n設定値はトライ&エラーで設定値を探るしかない。</p>\n\n<p>しかし、MPEG再生しか行わない場合はこれでも問題ないが、フレーム間に他の処理を行うと待ち時間が変わってきてしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./video.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 現在時刻\n</span>    <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"n\">index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># delay = 1         # 最速再生\n</span>    <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"mi\">25</span>          <span class=\"c1\"># それっぽい再生速度になるように決め打ちで\n</span>    \n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">delay</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"前回の時刻からフレーム間の待ち時間を決めるパターン\">前回の時刻からフレーム間の待ち時間を決めるパターン</h1>\n\n<p>前回の表示時刻を覚えておき、今回の表示時刻との間隔がフレームレートに一致するように待ち時間を調整する。<br />\nこれなら、フレーム間に他の処理を挿入しても(その処理時間が一定でなくても)、その処理時間を除いて待ち時間を設定できる。</p>\n\n<p>しかし、挿入した処理がフレームレートを超えてしまうと、回復する術がなく、どんどん遅れていってしまう。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./video.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n        <span class=\"n\">tmp_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 現在時刻\n</span>    <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"n\">index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># 待ち時間計算用起点からの差分とsec/frameから待ち時間決定\n</span>    <span class=\"n\">delta_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">tmp_time</span>\n    <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">sec_per_frame</span> <span class=\"o\">-</span> <span class=\"n\">delta_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(f'delta =  {int(delta_time*1000)}    {delay}')\n</span>    <span class=\"c1\"># 待ち時間がsec/frameを超えてたら最小値に設定\n</span>    <span class=\"k\">if</span> <span class=\"n\">delay</span> <span class=\"o\"><</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n\n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">delay</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># 待ち時間計算用起点\n</span>    <span class=\"n\">tmp_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"経過時間から表示すべきフレームを求めて移動しながら表示するパターン\">経過時間から表示すべきフレームを求めて移動しながら表示するパターン</h1>\n\n<p>現在時刻と再生開始時刻の差から表示すべきフレーム番号を求め、必要であれば<code class=\"language-plaintext highlighter-rouge\">cap.set(cv2.CAP_PROP_POS_FRAMES, index)</code>で読み込みフレームを移動して現在時刻とフレームの同期をとる。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">cap.set()</code>は処理に時間がかかるので、無条件で実行すると再生フレームレートが遅くなるため、フレーム飛びが発生したときのみ実行するようにする。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"c1\"># ファイル名はFullpathでないとエラーになる\n# filepath = os.path.abspath(\"./video.mp4\") \n</span><span class=\"n\">filepath</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"s\">\"./stopwatch.mp4\"</span><span class=\"p\">)</span> \n\n<span class=\"c1\"># 動画の読み込み\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 読み込み失敗なら終了\n</span><span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># フレームレート\n</span><span class=\"n\">fps</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>\n<span class=\"n\">sec_per_frame</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">fps</span>\n\n<span class=\"c1\"># 全フレーム数\n</span><span class=\"n\">frame_count</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># 確認\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'FPS = </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">    sec_per_frame = </span><span class=\"si\">{</span><span class=\"n\">sec_per_frame</span><span class=\"si\">}</span><span class=\"s\">    frame_count = </span><span class=\"si\">{</span><span class=\"n\">frame_count</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># フレーム番号の初期化\n</span><span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 再生位置を先頭に設定\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前回時刻を0クリア\n# ここで前回時刻を取得すると、readやimshowの時間が含まれてしまうので具合が悪い\n</span><span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># 動画終了まで繰り返し\n</span><span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># フレームを取得\n</span>    <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最終フレームなどfalseが返ってきたら終了\n</span>        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># フレームを表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Frame\"</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">prev_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 最初のフレームの時のみここで前回時刻を取得\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">start_time</span> <span class=\"o\">=</span> <span class=\"n\">prev_time</span>\n    \n    <span class=\"c1\"># 前回表示フレーム番号の更新\n</span>    <span class=\"n\">prev_index</span> <span class=\"o\">=</span> <span class=\"n\">index</span>\n    \n    <span class=\"k\">while</span> <span class=\"bp\">True</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 現在時刻\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        \n        <span class=\"c1\"># 表示するフレーム位置の取得\n</span>        <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">sec_per_frame</span><span class=\"p\">)</span>\n        <span class=\"c1\"># print(f\"{prev_time}    {cur_time}    {prev_index}    {index}\")\n</span>        <span class=\"k\">if</span> <span class=\"n\">prev_index</span> <span class=\"o\">==</span> <span class=\"n\">index</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 前回と同じフレーム番号ならちょっと待つ\n</span>            <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.001</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"k\">break</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"n\">frame_count</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 終了位置を超えたら終了\n</span>        <span class=\"k\">break</span>\n\n    <span class=\"c1\"># 再生位置と時刻を確認\n</span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index = </span><span class=\"si\">{</span><span class=\"n\">index</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">    time = </span><span class=\"si\">{</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">start_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    </span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">((</span><span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n    \n    <span class=\"c1\"># 表示するフレーム位置が連続するフレームでなければ移動\n</span>    <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">!=</span> <span class=\"n\">prev_index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n        <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_POS_FRAMES</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># qキーが押されたら途中終了\n</span>    <span class=\"k\">if</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">&</span> <span class=\"mh\">0xFF</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">):</span>\n        <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># 動作確認0.5秒待ってみる\n</span>    <span class=\"c1\"># time.sleep(0.5)\n</span>\n<span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n<span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "YOLOv3": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>YOLOv3を試す</title>\n  </head>\n  <body>\n    <header>\n      <h1>YOLOv3を試す</h1>\n      <p>Native & python でYOLOv3を実行してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"yolov3を試す\">YOLOv3を試す</h1>\n\n<p>YOLOv3をubuntu上で実行してみた。<br />\nopneVINOやNCStickは使用していない。<br />\n単にYOLOv3の動作確認したかった&python実装を探してたら見つかったサイトをトレースしてみただけの話。<br />\npyhton のバージョンは3.7.4</p>\n\n<p>元ネタはこちら→ <a href=\"https://qiita.com/massie_g/items/a2bcfac4fed66b1b0717#yolo-v3-tiny-%E3%83%A2%E3%83%87%E3%83%AB\">https://qiita.com/massie_g/items/a2bcfac4fed66b1b0717#yolo-v3-tiny-%E3%83%A2%E3%83%87%E3%83%AB</a></p>\n\n<p>とりあえず動かしてみた後にpythonのソース読んでみた。<br />\nイメージの読み込みも、結果の描画も、保存もNativeなライブラリをコールしてるだけだ… <br />\n完全なwrapperだ。。。<br />\nやりたかったこととちょっと違う。。。orz….</p>\n\n<p>darknetは色々な処理(jpegファイルの操作とか)を自前で実装しているので、\n色々ライブラリをインストールしなくて良いのは助かるんだけど、\n他の処理系に移植するのはめんどくさそうなんだな。。。</p>\n\n<p>ということで、さくっと試した手順だけ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">WORKDIR</span><span class=\"o\">=</span>/work1/YOLO\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>\ngit clone https://github.com/pjreddie/darknet.git\n<span class=\"nb\">cd </span>darknet\nwget https://pjreddie.com/media/files/yolov3.weights\nwget https://pjreddie.com/media/files/yolov3-tiny.weights\n<span class=\"nb\">cd</span> ..\ngit clone https://github.com/mganeko/python3_yolov3.git\n<span class=\"nb\">cp</span> ./python3_yolov3/darknet-tiny-label.py ./darknet/python/\n<span class=\"nb\">cd </span>darknet\nmake\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> <span class=\"k\">${</span><span class=\"nv\">WORKDIR</span><span class=\"k\">}</span>/darknet/libdarknet.so /usr/lib/libdarknet.so\n\n<span class=\"c\"># YOLOv3 native版の実行</span>\n./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg\n<span class=\"c\"># predictions.jpg が認識結果</span>\n<span class=\"nb\">mv </span>predictions.jpg predictions_yolo.jpg \n\n<span class=\"c\"># tinyYOLOv3 native版の実行</span>\n./darknet detect cfg/yolov3-tiny.cfg yolov3-tiny.weights data/dog.jpg\n<span class=\"c\"># predictions.jpg が認識結果</span>\n<span class=\"nb\">mv </span>predictions.jpg predictions_tiny.jpg\n\n<span class=\"c\"># tinyYOLOv3 python版の実行</span>\npython python/darknet-tiny-label.py \n<span class=\"c\"># detect_result.jpg が認識結果</span>\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "VcXsrv": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2でX-serverへの表示</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2でX-serverへの表示</h1>\n      <p>WindowsTerminal上のWSL2コンソールからGUIプログラムを起動する場合の設定メモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>MobaXtermを使えば何もしなくてもGUIプログラムを表示できるけど、\nWindowsTerminalなどから表示したい場合に対応してみた。</p>\n\n<h1 id=\"windows側の設定\">Windows側の設定</h1>\n<p>VcXsrvをインストールして起動しておく。<br />\n参考:<a href=\"/memoBlog/2019/11/26/VcXsrv.html\" target=\"_blank\">WindowsでX-serve</a></p>\n\n<h1 id=\"linux側の設定\">Linux側の設定</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">.bashrc</code>に以下を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># HOSTのIPアドレス取得</span>\n<span class=\"c\"># export HOST_IP_ADDR=$(host `hostname`.mshome.net | sed -r 's/.*address (.*)$/\\1/')</span>\n<span class=\"c\"># HOSTのIPアドレス取得(アドレスが2つ以上返ってきたときは1個目だけ取り出す)</span>\n<span class=\"nb\">export </span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"o\">=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-n</span> 1p<span class=\"si\">)</span>\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"k\">}</span>:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n他の用途でホストのIPアドレス(名前でなく)を使いたいときのために別に変数作っておいた。<br />\n以下のように名前で書いて指定しても良い。<br />\nマシン名は<code class=\"language-plaintext highlighter-rouge\">hostname</code>コマンドで得られるので、別のマシンに移動しても変更の必要はない。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net:0.0\n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">.mshome.net</code>ドメインを指定するとホスト側のIPアドレスが得られるらしい。<br />\nドメインなしだと<code class=\"language-plaintext highlighter-rouge\">localhost</code>になっちゃうから注意。<br />\nぐぐると<code class=\"language-plaintext highlighter-rouge\">/etc/resolv.conf</code>を<code class=\"language-plaintext highlighter-rouge\">awk</code>でごちょごちょやるのが流行っているが<br />\n本来の設定値ではない(結果的に同じだけど)のでちゃんと設定しておくことにする。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nドメイン<code class=\"language-plaintext highlighter-rouge\">mshome.net</code>はHyper-Vのネットワークのドメインらしい。<br />\n要はWSL-Windows間の仮想ネットワークのドメイン名みたい。<br />\nちなみに、WSL2上から<code class=\"language-plaintext highlighter-rouge\">nslookup <<ホストのIPアドレス>></code>とやったら出てきた。</p>\n</blockquote>\n\n<h1 id=\"x-windowを使用するプログラムを起動\">X-Windowを使用するプログラムを起動</h1>\n<p>なんか起動してちょ。\nとりあえず<code class=\"language-plaintext highlighter-rouge\">xeyes</code>とか。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">xeyes</code> は <code class=\"language-plaintext highlighter-rouge\">sudo apt install x11-apps</code>でインストールできる。</p>\n\n<h1 id=\"wslからのgui表示が行えない場合の対処\">WSLからのGUI表示が行えない場合の対処</h1>\n\n<h2 id=\"原因\">原因</h2>\n<p>WSLのネットワークがパブリックネットワークになっており、<br />\nWSLネットワークからの接続要求がファイアウォールで はじかれている。</p>\n\n<h2 id=\"ファイアウォールの設定変更による回避\">ファイアウォールの設定変更による回避</h2>\n\n<p>VcXsrvをパブリックネットワークからの接続も受け付けるようにする \n以下手順。</p>\n\n<ul>\n  <li>コントロール パネル  →  Windows Defender ファイアウォール</li>\n  <li>左側上から2番目「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック</li>\n  <li>名前の欄から「VcXsrv windows xserver」を探す</li>\n  <li>その横のチェックボックスの「パブリック」側(右側)にもチェックを入れる(プライベート側は既にチェックが入っているはず。そっちはそのまま)。</li>\n  <li>OKボタンをクリックして終了</li>\n  <li>コントロールパネルは閉じてOK</li>\n</ul>\n\n<h2 id=\"ちなみに\">ちなみに</h2>\n\n<p>以下のような回避方法もある。</p>\n\n<h3 id=\"display変数を変更して回避\">DISPLAY変数を変更して回避</h3>\n<p>一旦WSLネットワークから外に出て接続すれば接続できる。<br />\n具体的には、DISPLAY変数をWSL側のIPアドレス(172.xxx.xxx.xxx)ではなく、<br />\nWi-Fiやイーサネットに割り当てられたアドレス(一般に 192.168.xxx.xxx)を指定する。<br />\n → WSL側から自動的にアドレスを取得できないのであまりおススメできない。<br />\n    VcXsrvがちゃんと動いているかを確認するには有効な手段かも。</p>\n\n<h3 id=\"根本的回避\">根本的回避</h3>\n<p><a href=\"https://daizo3.tumblr.com/post/150523393217/%E5%82%99%E5%BF%98%E9%8C%B2-%E5%85%88%E6%97%A5%E3%81%AE%E7%B6%9A%E3%81%8D-%E8%AD%98%E5%88%A5%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF-%E3%82%92%E3%83%97%E3%83%A9%E3%82%A4%E3%83%99%E3%83%BC%E3%83%88%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AB%E3%81%99%E3%82%8B\">備忘録 - (先日の続き) 識別されていないネットワーク をプライベートネットワークにする</a><br />\nによると、<br />\n<a href=\"https://www.atmarkit.co.jp/ait/articles/1012/24/news127.html\">Windowsで、「識別されていないネットワーク」の種類を「パブリック ネットワーク」から「プライベート ネットワーク」に変更する</a><br />\nの「レジストリによる設定」に記載された方法でも出来るらしいけど(こっちの方が根本的解決な気がする)、<br />\nレジストリ弄るのは気が引けるので、小手先対処にて。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WindowsでX-serve</title>\n  </head>\n  <body>\n    <header>\n      <h1>WindowsでX-serve</h1>\n      <p>WindowsでX-serveを使用するためにVcXsrvを使う</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>SSH ログインしたLinuxマシンからX-Windowプログラムを実行したときに、ウィンドウをWindoesマシンに表示する方法。<br />\nUbuntu、RaspberryPiともにOK。</p>\n\n<h1 id=\"vcxsrvのインストール\">VcXsrvのインストール</h1>\n\n<p>このあたりを参考に(といっても、ダウンロードしてインストーラ実行するだけだけど)。<br />\n<a href=\"https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html\">https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html</a></p>\n\n<h1 id=\"設定のメモ\">設定のメモ</h1>\n\n<h2 id=\"リモートマシンからの要求を受け付ける\">リモートマシンからの要求を受け付ける</h2>\n\n<p>リモートマシンからの要求を受け付けるには、起動時に3ページ目で”Disable access control” にチェックを入れる。</p>\n\n<blockquote>\n  <p>[!NOTE]\nC:\\Program Files\\VcXsrv\\X0.hosts にクライアント(Linuxマシン)のIPアドレスを書いておくと、”Disable access control”にチェックを入れなくても良いらしい。<br />\nしかし、サブネット全体を指定するために「192.168.1.」とやってもうまく動かない。。。<br />\n個別に「192.168.1.5」と書いておくとOK</p>\n</blockquote>\n\n<h2 id=\"逐一設定するのがめんどい\">逐一設定するのがめんどい</h2>\n\n<p>4ページ目で”Save configuration”\tをクリックして保存した設定ファイル(拡張子は”.xlaunch”)を実行すれば設定済みの状態で起動できる。</p>\n\n<h2 id=\"linux側の設定\">Linux側の設定</h2>\n\n<p>Linux側では~/.bashrcに以下を追加しておくと、SSHでlog inしたときに自動でDISPLAY変数を設定してくれる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n\t</span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XXX.XXX:0.0\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h2 id=\"その他注意事項\">その他注意事項</h2>\n\n<p>VcXsrvを起動するとキーボードが勝手に変わることがあるらしい。<br />\n日本語入力できなくなったらWindows+SPACEで確認すること。</p>\n\n<h2 id=\"愚痴\">愚痴</h2>\n\n<p>コマンドラインオプションで設定できないか調べてみたが、見つからない。<br />\n「Addituinal parameters」という設定項目があるので、何かしら設定できるはずなんだけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Google Coral USB Accelerator": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その1</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その1</h1>\n      <p>Google Coral USB Acceleratorのインストールメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<p>参考サイト:\n<a href=\"https://qiita.com/rhene/items/7b34f60b73645d430789\">RaspberryPi 4でCoral USB TPU Accelerator(EdgeTPU)をとりあえず使う</a></p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<h2 id=\"edgetpu用ライブラリのインストール\">EdgeTPU用ライブラリのインストール</h2>\n\n<p>下記コマンドを実行して、EdgeTPU用ライブラリ(ドライバ類)をインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/coral-edgetpu.list\ncurl https://packages.cloud.google.com/apt/doc/apt-key.gpg | <span class=\"nb\">sudo </span>apt-key add -\n\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># 通常版をインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libedgetpu1-std\n<span class=\"c\"># または、最大クロック版</span>\n<span class=\"c\"># sudo apt install libedgetpu1-max</span>\n</code></pre></div></div>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 coral\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral\n<span class=\"nb\">cd</span> /work/coral\npyenv <span class=\"nb\">local </span>coral \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<p>numpyのinstallで失敗するので、以下を実行しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n</code></pre></div></div>\n\n<h2 id=\"tfliteモジュールのインストール\">TFLiteモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install  </span>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nどれをインストールするかは<a href=\"https://www.tensorflow.org/lite/guide/python\">Python quickstart</a>で確認<br />\n========= 例えば、ubuntu/raspbianのときはpythonのバージョンに応じて以下のどれかを指定 ==============</p>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (x86-64)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl</td>\n      </tr>\n    </tbody>\n  </table>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (ARM 32)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl</td>\n      </tr>\n    </tbody>\n  </table>\n</blockquote>\n\n<h2 id=\"coral-usb-acceleratorの接続と確認\">Coral USB Acceleratorの接続と確認</h2>\n\n<p>USBポートに Coral USB Accelerator を接続する</p>\n\n<p>認識されたことを確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下の表示があったら正常に認識されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>«省略»\nBus XXX Device YYY: ID 1a6e:089a Global Unichip Corp. \n«省略»\n</code></pre></div></div>\n\n<h1 id=\"動作確認サンプルプログラム\">動作確認(サンプルプログラム)</h1>\n\n<h2 id=\"サンプルソースのインストール\">サンプルソースのインストール</h2>\n\n<p>Githubからソースをダウンロードする</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/\ngit<span class=\"k\">**</span> clone https://github.com/google-coral/tflite.git\n</code></pre></div></div>\n\n<h2 id=\"サンプルプログラムの実行その1-classification\">サンプルプログラムの実行(その1) classification</h2>\n\n<h3 id=\"プログラムディレクトリへの移動\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/classification/\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh \n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py \n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n<p>結果の例は以下。<br />\n結果は「Ara macao(コンゴウインコ)」と表示されている。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference on Edge TPU is slow because it includes loading the model into Edge TPU memory.\n12.4ms\n4.2ms\n4.1ms\n4.2ms\n4.2ms\n-------RESULTS--------\nAra macao (Scarlet Macaw): 0.77734\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n\n<p><a id=\"CPUonlydiff\"> </a></p>\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合もCoral USB Acceleratorを接続しておかないとエラーになる。<br />\n接続しなくても実行できるようにするには以下のパッチを適用し、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">-cpu</code>オプションを指定する。</p>\n\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/python/examples/classification/classify_image.py b/python/examples/classification/\n</span><span class=\"gi\">> classify_image.py\n</span><span class=\"gh\">index 75f1d76..44fb798 100644\n</span><span class=\"gd\">--- a/python/examples/classification/classify_image.py\n</span><span class=\"gi\">+++ b/python/examples/classification/classify_image.py\n</span><span class=\"p\">@@ -12,7 +12,7 @@</span>\n<span class=\"err\">#</span> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n # See the License for the specific language governing permissions and\n # limitations under the License.\n<span class=\"gd\">-r\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span><span class=\"gi\">+\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span>\n    To run this code, you must attach an Edge TPU attached to the host and\n    install the Edge TPU runtime (`libedgetpu.so`) and `tflite_runtime`. For\n<span class=\"p\">@@ -64,9 +64,12 @@</span> def load_labels(path, encoding='utf-8'):\n       return {index: line.strip() for index, line in enumerate(lines)}\n\n\n<span class=\"gd\">-def make_interpreter(model_file):\n</span><span class=\"gi\">+def make_interpreter(model_file, cpu=False):\n</span>   model_file, *device = model_file.split('@')\n<span class=\"gd\">-  return tflite.Interpreter(\n</span><span class=\"gi\">+  if cpu :\n+    return tflite.Interpreter(model_path=model_file)\n+  else :\n+    return tflite.Interpreter(\n</span>       model_path=model_file,\n       experimental_delegates=[\n           tflite.load_delegate(EDGETPU_SHARED_LIB,\n<span class=\"p\">@@ -92,11 +95,19 @@</span> def main():\n   parser.add_argument(\n       '-c', '--count', type=int, default=5,\n       help='Number of times to run inference')\n<span class=\"gi\">+  parser.add_argument(\n+      '--cpu', action='store_true',\n+      help='use cpu only(default:use with TPU)')\n</span>   args = parser.parse_args()\n\n+  if args.cpu :\n<span class=\"gi\">+    print('**** USE CPU ONLY!! ****')\n+  else :\n+    print('**** USE WITH TPU ****')\n+\n</span>   labels = load_labels(args.labels) if args.labels else {}\n\n-  interpreter = make_interpreter(args.model)\n<span class=\"gi\">+  interpreter = make_interpreter(args.model, args.cpu)\n</span>   interpreter.allocate_tensors()\n\n   size = classify.input_size(interpreter)\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"サンプルプログラムの実行その2-detection\">サンプルプログラムの実行(その2) detection</h2>\n\n<h3 id=\"プログラムディレクトリへの移動-1\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/detection\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール-1\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh\n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行-1\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<p>結果の例は以下。<br />\n以下の表示と同時に認識結果の画像が別ウィンドウで表示される。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference is slow because it includes loading the model into Edge TPU memory.\n27.90 ms\n11.59 ms\n11.36 ms\n11.89 ms\n11.10 ms\n-------RESULTS--------\ntie\n  id:     31\n  score:  0.83984375\n  bbox:   BBox(xmin=226, ymin=417, xmax=290, ymax=539)\nperson\n  id:     0\n  score:  0.83984375\n  bbox:   BBox(xmin=2, ymin=5, xmax=507, ymax=590)\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行-1\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションを指定すると、結果画像を保存するとともに、表示を行う。<br />\n指定しなければ認識だけ行う(結果の画像表示もしない)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションによる出力ファイルの形式は指定した拡張子で決定される。jpgやbmpなど。<br />\nrawデータで出力した場合(拡張子rgb)は、以下のコマンドでjpgやbmpに変換できる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.jpg\n</code></pre></div>  </div>\n\n  <p>または</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.bmp\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合でCoral USB Acceleratorを接続していなくてエラーになる場合は<br />\n<a href=\"#CPUonlydiff\">こちら</a>を参照</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "tflite": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その6</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その6</h1>\n      <p>tensorflow lite で色々なSSDモデルを使う手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はソースが大半なので、githubにリポジトリ作った。<br />\n内容は各ディレクトリのREADME.mdを見てチョ。<br />\n<a href=\"https://github.com/ippei8jp/tflite_trial\">https://github.com/ippei8jp/tflite_trial</a></p>\n\n<p>順序は <code class=\"language-plaintext highlighter-rouge\">download_models</code> → <code class=\"language-plaintext highlighter-rouge\">mk_tflite_ssd</code> → <code class=\"language-plaintext highlighter-rouge\">images</code> → <code class=\"language-plaintext highlighter-rouge\">ssd</code> が良いと思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その5</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その5</h1>\n      <p>Tensorflow v1.15のインストールとソースからのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はUbuntuだけ。</p>\n\n<h1 id=\"tensorflow-115-のインストール\">Tensorflow 1.15 のインストール</h1>\n\n<p>Tensorflow1系でないと動かない環境とかサンプルとかあるので、<br />\nTensorflow v1.15をインストールする。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_1.15.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_1.15.0\n<span class=\"nb\">cd</span> /work/tf_1.15.0\npyenv <span class=\"nb\">local </span>tf_1.15.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"tensorflow-115-ライブラリのインストール\">Tensorflow 1.15 ライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>1.15\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nGPU使わないので-cpu付きパッケージを選択する</p>\n</blockquote>\n\n<h1 id=\"tensorflow-115-のbuild\">Tensorflow 1.15 のbuild</h1>\n\n<p>Tensorflowのpythonライブラリは<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできるが、\nソースからbuildしないと使えないツールもあるのでbuild環境を整える。</p>\n\n<p>参考: <a href=\"https://www.tensorflow.org/install/source?hl=ja\">ソースからのビルド | Tensorflow</a></p>\n\n<h2 id=\"bazelのインストール\">Bazelのインストール</h2>\n\n<p>Tensorflow をソースからbuildするには<code class=\"language-plaintext highlighter-rouge\">bazel</code>が必要なので、インストールしておく。</p>\n<blockquote>\n  <p>[!NOTE]\nBazelはVer.0.26.1 以下 を使用しないといけない<br />\nVer. 0.26.1はaptでインストールできない</p>\n</blockquote>\n\n<p>参考: <a href=\"https://docs.bazel.build/versions/0.26.0/install-ubuntu.html\">Installing Bazel on Ubuntu</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/bazelbuild/bazel/releases/download/0.26.1/bazel-0.26.1-installer-linux-x86_64.sh\n<span class=\"nb\">chmod</span> +x bazel-0.26.1-installer-linux-x86_64.sh\n./bazel-0.26.1-installer-linux-x86_64.sh <span class=\"nt\">--user</span>\n</code></pre></div></div>\n\n<p>実行ファイルは、<code class=\"language-plaintext highlighter-rouge\">~/bin/bazel</code> になるので、pathが~/binに通ってない場合は、一旦 ログアウトして 再ログイン\n(pathが通ってない場合、configureでエラーになる)</p>\n\n<h2 id=\"必要なpipパッケージのインストール\">必要なpipパッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>six numpy wheel mock <span class=\"s1\">'future>=0.17.1'</span>\npip <span class=\"nb\">install </span>keras_applications <span class=\"nt\">--no-deps</span>\npip <span class=\"nb\">install </span>keras_preprocessing <span class=\"nt\">--no-deps</span>\n</code></pre></div></div>\n\n<h2 id=\"tennsorflowのソースを取得\">tennsorflowのソースを取得</h2>\n\n<p>githubからcloneして V1.15.3 をチェックアウトしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/\ngit clone https://github.com/tensorflow/tensorflow.git\n<span class=\"nb\">cd </span>tensorflow\ngit checkout <span class=\"nt\">-b</span> v1.15.3 refs/tags/v1.15.3\n</code></pre></div></div>\n\n<h1 id=\"buildの設定\">buildの設定</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\n./configure\n<span class=\"c\"># いくつか質問されるので、すべてデフォルト(リターン)を入力</span>\n</code></pre></div></div>\n\n<h1 id=\"buildの実行\">buildの実行</h1>\n<h2 id=\"実行のひな形\">実行のひな形</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build //《対象ディレクトリ》:《ターゲット》\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n※ 対象ディレクトリはカレントディレクトリからの相対パス<br />\n※ ターゲットは対象ディレクトリのBUILDファイルで確認</p>\n</blockquote>\n\n<h2 id=\"例えばこんな感じ\">例えばこんな感じ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel build //tensorflow/lite/toco:toco\nbazel build //tensorflow/python/tools:freeze_graph\nbazel build //tensorflow/tools/graph_transforms:summarize_graph\nbazel build //tensorflow/tools/graph_transforms:transform_graph\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRAMは4GB以上必要かな?<br />\nオプション<code class=\"language-plaintext highlighter-rouge\">--local_ram_resources=2048</code>を指定すると使用するRAMを2GBに限定できる(指定する数値はMB単位)。<br />\n使用するPCのスペックによってかかる時間はマチマチ。<br />\nNativeなUbuntuで4コア8スレッドでも3~4時間程度かかる。<br />\nVirtualboxで1コア使用だと24時間とかかかることも。</p>\n</blockquote>\n\n<h2 id=\"buildしたファイルの実行\">buildしたファイルの実行</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">bazel run</code> で実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nオプションをbazelではなく実行するコマンドに渡すため、<code class=\"language-plaintext highlighter-rouge\">--</code> を入れる必要がある。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel run //tensorflow/lite/toco:toco <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:summarize_graph <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:transform_graph <span class=\"nt\">--</span> «オプション»\n</code></pre></div></div>\n\n<p>絶対パスで実行するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph «オプション»\n</code></pre></div></div>\n\n<p>パスが長いので、以下を設定しておくと便利。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">alias            </span><span class=\"nv\">toco</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">summarize_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">transform_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph'</span>\n</code></pre></div></div>\n\n<h2 id=\"おまけ\">おまけ</h2>\n\n<p>フツーはこっちがメインだが…(^^ゞ<br />\npipでインストールすれば必要ないが、Tensorflowのpipパッケージを作成するにはこちら。<br />\n(オプション変更したいときとか)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build <span class=\"nt\">--config</span><span class=\"o\">=</span>v1 //tensorflow/tools/pip_package:build_pip_package\n./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg\npip <span class=\"nb\">install</span> /tmp/tensorflow_pkg/tensorflow-1.15.3-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その4</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その4</h1>\n      <p>tensorflowのモデルファイル(*.pbや*.tflite)の可視化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>tensorflowのモデルファイル( <code class=\"language-plaintext highlighter-rouge\">*.pb</code> や <code class=\"language-plaintext highlighter-rouge\">*.tflite</code> )を可視化する方法について。<br />\n<code class=\"language-plaintext highlighter-rouge\">tensorboard</code> を使う方法などもあるが、最もお手軽と思われる <code class=\"language-plaintext highlighter-rouge\">netron</code> を使用する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれやらなくても、<a href=\"https://lutzroeder.github.io/netron/\">https://lutzroeder.github.io/netron/</a> にアクセスすれば使える。</p>\n</blockquote>\n\n<h1 id=\"netron-の-インストール\">netron の インストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code>をインストールする。<br />\n<code class=\"language-plaintext highlighter-rouge\">netron</code> はtensorflowのバージョンに依存しない(そもそもtensorflow自体に依存してない)のでTensorflow1系、Tenorflow2系 どちらの環境にインストールしてもよい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>netron\n</code></pre></div></div>\n\n<h1 id=\"netron-の-実行\">netron の 実行</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code> を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>netron <span class=\"nt\">--host</span> 0.0.0.0 <span class=\"o\">[</span><span class=\"nt\">--port</span> xxxx]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--host</code> オプションを指定しないとlocalhostからしか接続できないので、他のマシンから接続するときは指定する。<br />\n<code class=\"language-plaintext highlighter-rouge\">--port</code> オプションのデフォルトは8080なので、変更したいときは指定する。</p>\n\n<h1 id=\"モデルファイルの表示\">モデルファイルの表示</h1>\n\n<p>ブラウザ(Winマシンからで可)で実行したマシンのポート8008(またはオプションで指定したxxxx)に接続。<br />\n例:<code class=\"language-plaintext highlighter-rouge\">http://ncc-1701u.local:8080/</code></p>\n\n<p>表示された画面でOpen Model…をクリックして表示するモデルファイルを選ぶ。<br />\nしばらく待つと表示される。<br />\nモデルファイルはブラウザからアップロードするので、ブラウザから参照できる場所になければならない(サーバ側にあってもダメ)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">*.pb</code> ファイルが大きいとうまく表示できないみたい。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その3</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その3</h1>\n      <p>Tensorflow 2.2.0をインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Edge-TPUを直接操作するわけではないが、Tensorflowで作成されたモデルファイルをtflite用に変換する準備として<br />\ntensorflowをインストールする。<br />\nここではVersion 2.2.0を使用する。</p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<p>coral環境に追加インストールでも良いが、今回は別の環境を用意する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_2.2.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_2.2.0\n<span class=\"nb\">cd</span> /work/tf_2.2.0\npyenv <span class=\"nb\">local </span>tf_2.2.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"tensorflow-220-のインストール\">tensorflow 2.2.0 のインストール</h1>\n\n<p>インストールするパッケージはGPUを使わないので-cpu付きパッケージを選択する。<br />\nTensorflowはバージョンによって機能差が激しいので、インストールするバージョンを指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>2.2.0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その2</h1>\n      <p>Google Coral USB Accelerator で SSD(Single Shot MultiBox Detector)を実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n一部を除き、基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<h1 id=\"tflite-の-モデルファイルをedgetpu使用モデルに変換する方法\">tflite の モデルファイルをEdgeTPU使用モデルに変換する方法</h1>\n<p>通常のtfliteのモデルファイルはCPUのみ(またはCPU+GPU)を使用するように構成されていて、\nそのまま実行してもEdge-TPUは使用されない。<br />\nそこで、Edge-TPU使用モデルに変換するため、edgetpu_compilerを使用する必要がある。<br />\n(ただし、Ubuntuのみ。RasPi不可。)</p>\n\n<h2 id=\"edgetpu_compiler-のインストール\">edgetpu_compiler のインストール</h2>\n\n<p>CPU使用モデルからEdge-TPU使用モデルに変換するツール<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code>をインストールする。<br />\naptリポジトリの登録はTPUライブラリインストール時に行っているので不要(以下ではコメントアウトしてある)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -</span>\n<span class=\"c\"># echo \"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list</span>\n<span class=\"c\"># sudo apt update</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>edgetpu-compiler\n</code></pre></div></div>\n\n<h2 id=\"使用方法\">使用方法</h2>\n<p>基本的に以下。<br />\ntfliteファイルを喰わせるとファイル名に<code class=\"language-plaintext highlighter-rouge\">_edgetpu</code>を付加したファイルが作成される。<br />\nこれがEdge-TPU使用するモデルファイル。<br />\n詳細は<a href=\"https://coral.ai/docs/edgetpu/compiler/\">Edge TPU Compiler</a> を参照。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>edgetpu_compiler [options] model...\n</code></pre></div></div>\n\n<h1 id=\"事前準備\">事前準備</h1>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n\n<p>openCVをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"ssdを実行してみる\">SSDを実行してみる</h1>\n\n<h2 id=\"作業用ディレクトリの作成移動\">作業用ディレクトリの作成&移動</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral/ssd/\n<span class=\"nb\">cd</span> /work/coral/ssd/\n</code></pre></div></div>\n\n<h2 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h2>\n\n<p>用意されているSSDのモデルをダウンロードし、Edge-TPU使用モデルを作成する。<br />\n実行が終了すると、<code class=\"language-plaintext highlighter-rouge\">models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite</code> ができる。</p>\n\n<ul>\n  <li>ダウンロード元: <a href=\"https://www.tensorflow.org/lite/models/object_detection/overview\">Object detection</a>\nの 「Get Started」の「Download starter model and labels」</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl <span class=\"nt\">-O</span> https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip\nunzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip \n<span class=\"nb\">mv </span>detect.tflite coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># リネームしなくてもいいけど、後でわからなくならないようにリネームしておく</span>\n<span class=\"nb\">mv </span>labelmap.txt coco_ssd_mobilenet_v1_1.0_quant.labels   <span class=\"c\"># 同上</span>\nedgetpu_compiler coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># EdgeTPU使用モデルに変換</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"テスト用画像の準備\">テスト用画像の準備</h2>\n\n<p>適当な画像を<code class=\"language-plaintext highlighter-rouge\">image</code>ディレクトリに用意しておく。<br />\n使用できるファイル形式は<code class=\"language-plaintext highlighter-rouge\">jpg</code>と<code class=\"language-plaintext highlighter-rouge\">mp4</code></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>images\n<span class=\"nb\">cd </span>images/\n<span class=\"c\"># 適当な画像ファイルをダウンロードする</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"ssdのプログラムソース\">SSDのプログラムソース</h2>\n\n<p>以下の内容を<code class=\"language-plaintext highlighter-rouge\">object_detection_demo_ssd.py</code>として保存しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">tflite_runtime.interpreter</span> <span class=\"k\">as</span> <span class=\"n\">tflite</span>\n\n<span class=\"c1\"># shared library\n</span><span class=\"n\">EDGETPU_SHARED_LIB</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n  <span class=\"s\">'Linux'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.so.1'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Darwin'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.1.dylib'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Windows'</span><span class=\"p\">:</span> <span class=\"s\">'edgetpu.dll'</span>\n<span class=\"p\">}[</span><span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">system</span><span class=\"p\">()]</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># interpreter の生成\n</span><span class=\"k\">def</span> <span class=\"nf\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">):</span>\n    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"o\">=</span><span class=\"n\">model_file</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span>\n                <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">model_file</span><span class=\"p\">,</span>\n                <span class=\"n\">experimental_delegates</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n                    <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">load_delegate</span><span class=\"p\">(</span><span class=\"n\">EDGETPU_SHARED_LIB</span><span class=\"p\">)</span>\n                <span class=\"p\">])</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    \n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">output_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_output_details</span><span class=\"p\">()</span>\n    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n\n    <span class=\"n\">tflite_results1</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Locations (Top, Left, Bottom, Right)\n</span>    <span class=\"n\">tflite_results2</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Classes (0=Person)\n</span>    <span class=\"n\">tflite_results3</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Scores\n</span>    <span class=\"n\">tflite_results4</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Number of detections\n</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">tflite_results4</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])):</span>\n        <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        \n        <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>        <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n\n        <span class=\"n\">prob</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results3</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">prob</span> <span class=\"o\">>=</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'Class=</span><span class=\"si\">{</span><span class=\"n\">class_name</span><span class=\"si\">:</span><span class=\"mi\">15</span><span class=\"si\">}</span><span class=\"s\">    Probability=</span><span class=\"si\">{</span><span class=\"n\">prob</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    Location=(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)-(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n            <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span>    <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span>   <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span>  <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 表示色\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 対象物の枠とラベルの描画\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"n\">bottom</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">20</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"o\">+</span><span class=\"mi\">160</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"s\">\"{} ({:.3f})\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">class_name</span><span class=\"p\">,</span> <span class=\"n\">prob</span><span class=\"p\">),</span>\n                        <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># interpreterの構築\n</span>    <span class=\"n\">interpreter</span> <span class=\"o\">=</span> <span class=\"n\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">allocate_tensors</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">input_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()</span>\n    \n    <span class=\"c1\"># 入力データ\n</span>    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">org_frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>                 <span class=\"c1\"># オリジナルのフレームレート\n</span>    <span class=\"n\">org_frame_time</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span> <span class=\"o\">/</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>                <span class=\"c1\"># オリジナルのフレーム時間\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">org_frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルの読み込み\n</span>        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルがない場合\n</span>        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># フレーム数\n</span>    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 実行時間測定用変数の初期化\n</span>    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n    <span class=\"c1\"># フレーム測定用タイマ\n</span>    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># モデルの入力サイズ\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># 画像の前処理 =============================================================================\n</span>        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                          <span class=\"c1\"># 前処理開始時刻\n</span>        \n        <span class=\"c1\"># 画像の読み込み\n</span>        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレームを作成\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># モデル入力用にリサイズ\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>   <span class=\"c1\"># input size of coco ssd mobilenet?\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">]]</span>                          <span class=\"c1\"># BGR -> RGB\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">in_frame</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>                 <span class=\"c1\"># 3D -> 4D\n</span>        \n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>     <span class=\"c1\"># 前処理にかかった時間\n</span>        \n        <span class=\"c1\"># 推論実行 =============================================================================\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"c1\"># 推論本体\n</span>        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">set_tensor</span><span class=\"p\">(</span><span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">],</span> <span class=\"n\">in_frame</span><span class=\"p\">)</span>\n        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">invoke</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>                          <span class=\"c1\"># 推論処理にかかった時間\n</span>        \n        <span class=\"c1\"># 検出結果の解析 =============================================================================\n</span>        <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                               <span class=\"c1\"># 解析処理開始時刻\n</span>        <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n        <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>                    <span class=\"c1\"># 解析処理にかかった時間\n</span>        \n        <span class=\"c1\"># 結果の表示 =============================================================================\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 表示処理開始時刻\n</span>        \n        <span class=\"c1\"># 測定データの表示\n</span>        <span class=\"n\">frame_number_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'frame_number   : </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span>\n        <span class=\"k\">if</span> <span class=\"n\">frame_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span>  <span class=\"s\">'Frame time     : ---'</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Frame time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms    </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> fps'</span>\n        <span class=\"n\">inf_time_message</span>        <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Inference time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">render_time_message</span>     <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Rendering time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">parsing_time_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'parse time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        \n        <span class=\"c1\"># 結果の書き込み\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_number_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>     <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>   <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像の保存\n</span>        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>                 <span class=\"c1\"># 表示処理にかかった時間\n</span>        \n        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"c1\"># フレーム処理終了 =============================================================================\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_key_code</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"make_interpretermodel_file\">make_interpreter(model_file)</h3>\n\n<p>interpreter(認識エンジン)を構築する処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>モデルファイル内に<code class=\"language-plaintext highlighter-rouge\">\"edgetpu-custom-op\"</code>という文字列が含まれていたらTPU使用モデルと判定してTPU使用のための共有ライブラリをダウンロードして初期化する。<br />\nそうでなければCPUのみ使用モデルなので、 共有ライブラリなしで初期化する。</p>\n\n<p>もっと単純にモデルファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>が含まれていたらTPU使用モデルと判定しても良いかもしれない(<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code> は出力ファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>を付加するので)。</p>\n\n<h3 id=\"parse_resultinterpreter-frame-labels_map-args\">parse_result(interpreter, frame, labels_map, args)</h3>\n\n<p>認識結果の解析と結果の表示(検出枠とラベルの描画)</p>\n\n<p>認識結果から検出した座標、クラスID、スコアを取得し、出力画像に描画している。</p>\n\n<p>出力データの構成は<a href=\"https://www.tensorflow.org/lite/models/object_detection/overview#output\">ここ</a>を参照。</p>\n\n<p>どうやらこのモデルは検出個数が10個に設定されているようだ。</p>\n\n<h3 id=\"main\">main()</h3>\n\n<p>メインルーチン</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>タイミング調整部分は、認識処理が速かった場合に結果表示画像の表示時間を実際の入力画像の表示時間に合わせるため、ちょっと小細工を入れてある。</p>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--help</span>\nusage: object_detection_demo_ssd.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT <span class=\"o\">[</span><span class=\"nt\">-l</span> LABELS]\n                                    <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> LABELS, <span class=\"nt\">--labels</span> LABELS\n                        Optional. Labels mapping file\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合edge-tpu使用\">静止画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合edge-tpu使用\">動画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n再生が終了するか、画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n<h2 id=\"静止画の場合cpuのみ\">静止画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合cpuのみ\">動画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その1</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その1</h1>\n      <p>Google Coral USB Acceleratorのインストールメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<p>参考サイト:\n<a href=\"https://qiita.com/rhene/items/7b34f60b73645d430789\">RaspberryPi 4でCoral USB TPU Accelerator(EdgeTPU)をとりあえず使う</a></p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<h2 id=\"edgetpu用ライブラリのインストール\">EdgeTPU用ライブラリのインストール</h2>\n\n<p>下記コマンドを実行して、EdgeTPU用ライブラリ(ドライバ類)をインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/coral-edgetpu.list\ncurl https://packages.cloud.google.com/apt/doc/apt-key.gpg | <span class=\"nb\">sudo </span>apt-key add -\n\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># 通常版をインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libedgetpu1-std\n<span class=\"c\"># または、最大クロック版</span>\n<span class=\"c\"># sudo apt install libedgetpu1-max</span>\n</code></pre></div></div>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 coral\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral\n<span class=\"nb\">cd</span> /work/coral\npyenv <span class=\"nb\">local </span>coral \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<p>numpyのinstallで失敗するので、以下を実行しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n</code></pre></div></div>\n\n<h2 id=\"tfliteモジュールのインストール\">TFLiteモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install  </span>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nどれをインストールするかは<a href=\"https://www.tensorflow.org/lite/guide/python\">Python quickstart</a>で確認<br />\n========= 例えば、ubuntu/raspbianのときはpythonのバージョンに応じて以下のどれかを指定 ==============</p>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (x86-64)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl</td>\n      </tr>\n    </tbody>\n  </table>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (ARM 32)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl</td>\n      </tr>\n    </tbody>\n  </table>\n</blockquote>\n\n<h2 id=\"coral-usb-acceleratorの接続と確認\">Coral USB Acceleratorの接続と確認</h2>\n\n<p>USBポートに Coral USB Accelerator を接続する</p>\n\n<p>認識されたことを確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下の表示があったら正常に認識されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>«省略»\nBus XXX Device YYY: ID 1a6e:089a Global Unichip Corp. \n«省略»\n</code></pre></div></div>\n\n<h1 id=\"動作確認サンプルプログラム\">動作確認(サンプルプログラム)</h1>\n\n<h2 id=\"サンプルソースのインストール\">サンプルソースのインストール</h2>\n\n<p>Githubからソースをダウンロードする</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/\ngit<span class=\"k\">**</span> clone https://github.com/google-coral/tflite.git\n</code></pre></div></div>\n\n<h2 id=\"サンプルプログラムの実行その1-classification\">サンプルプログラムの実行(その1) classification</h2>\n\n<h3 id=\"プログラムディレクトリへの移動\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/classification/\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh \n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py \n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n<p>結果の例は以下。<br />\n結果は「Ara macao(コンゴウインコ)」と表示されている。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference on Edge TPU is slow because it includes loading the model into Edge TPU memory.\n12.4ms\n4.2ms\n4.1ms\n4.2ms\n4.2ms\n-------RESULTS--------\nAra macao (Scarlet Macaw): 0.77734\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n\n<p><a id=\"CPUonlydiff\"> </a></p>\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合もCoral USB Acceleratorを接続しておかないとエラーになる。<br />\n接続しなくても実行できるようにするには以下のパッチを適用し、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">-cpu</code>オプションを指定する。</p>\n\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/python/examples/classification/classify_image.py b/python/examples/classification/\n</span><span class=\"gi\">> classify_image.py\n</span><span class=\"gh\">index 75f1d76..44fb798 100644\n</span><span class=\"gd\">--- a/python/examples/classification/classify_image.py\n</span><span class=\"gi\">+++ b/python/examples/classification/classify_image.py\n</span><span class=\"p\">@@ -12,7 +12,7 @@</span>\n<span class=\"err\">#</span> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n # See the License for the specific language governing permissions and\n # limitations under the License.\n<span class=\"gd\">-r\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span><span class=\"gi\">+\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span>\n    To run this code, you must attach an Edge TPU attached to the host and\n    install the Edge TPU runtime (`libedgetpu.so`) and `tflite_runtime`. For\n<span class=\"p\">@@ -64,9 +64,12 @@</span> def load_labels(path, encoding='utf-8'):\n       return {index: line.strip() for index, line in enumerate(lines)}\n\n\n<span class=\"gd\">-def make_interpreter(model_file):\n</span><span class=\"gi\">+def make_interpreter(model_file, cpu=False):\n</span>   model_file, *device = model_file.split('@')\n<span class=\"gd\">-  return tflite.Interpreter(\n</span><span class=\"gi\">+  if cpu :\n+    return tflite.Interpreter(model_path=model_file)\n+  else :\n+    return tflite.Interpreter(\n</span>       model_path=model_file,\n       experimental_delegates=[\n           tflite.load_delegate(EDGETPU_SHARED_LIB,\n<span class=\"p\">@@ -92,11 +95,19 @@</span> def main():\n   parser.add_argument(\n       '-c', '--count', type=int, default=5,\n       help='Number of times to run inference')\n<span class=\"gi\">+  parser.add_argument(\n+      '--cpu', action='store_true',\n+      help='use cpu only(default:use with TPU)')\n</span>   args = parser.parse_args()\n\n+  if args.cpu :\n<span class=\"gi\">+    print('**** USE CPU ONLY!! ****')\n+  else :\n+    print('**** USE WITH TPU ****')\n+\n</span>   labels = load_labels(args.labels) if args.labels else {}\n\n-  interpreter = make_interpreter(args.model)\n<span class=\"gi\">+  interpreter = make_interpreter(args.model, args.cpu)\n</span>   interpreter.allocate_tensors()\n\n   size = classify.input_size(interpreter)\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"サンプルプログラムの実行その2-detection\">サンプルプログラムの実行(その2) detection</h2>\n\n<h3 id=\"プログラムディレクトリへの移動-1\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/detection\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール-1\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh\n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行-1\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<p>結果の例は以下。<br />\n以下の表示と同時に認識結果の画像が別ウィンドウで表示される。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference is slow because it includes loading the model into Edge TPU memory.\n27.90 ms\n11.59 ms\n11.36 ms\n11.89 ms\n11.10 ms\n-------RESULTS--------\ntie\n  id:     31\n  score:  0.83984375\n  bbox:   BBox(xmin=226, ymin=417, xmax=290, ymax=539)\nperson\n  id:     0\n  score:  0.83984375\n  bbox:   BBox(xmin=2, ymin=5, xmax=507, ymax=590)\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行-1\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションを指定すると、結果画像を保存するとともに、表示を行う。<br />\n指定しなければ認識だけ行う(結果の画像表示もしない)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションによる出力ファイルの形式は指定した拡張子で決定される。jpgやbmpなど。<br />\nrawデータで出力した場合(拡張子rgb)は、以下のコマンドでjpgやbmpに変換できる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.jpg\n</code></pre></div>  </div>\n\n  <p>または</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.bmp\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合でCoral USB Acceleratorを接続していなくてエラーになる場合は<br />\n<a href=\"#CPUonlydiff\">こちら</a>を参照</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Edge-TPU": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その6</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その6</h1>\n      <p>tensorflow lite で色々なSSDモデルを使う手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はソースが大半なので、githubにリポジトリ作った。<br />\n内容は各ディレクトリのREADME.mdを見てチョ。<br />\n<a href=\"https://github.com/ippei8jp/tflite_trial\">https://github.com/ippei8jp/tflite_trial</a></p>\n\n<p>順序は <code class=\"language-plaintext highlighter-rouge\">download_models</code> → <code class=\"language-plaintext highlighter-rouge\">mk_tflite_ssd</code> → <code class=\"language-plaintext highlighter-rouge\">images</code> → <code class=\"language-plaintext highlighter-rouge\">ssd</code> が良いと思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その5</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その5</h1>\n      <p>Tensorflow v1.15のインストールとソースからのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はUbuntuだけ。</p>\n\n<h1 id=\"tensorflow-115-のインストール\">Tensorflow 1.15 のインストール</h1>\n\n<p>Tensorflow1系でないと動かない環境とかサンプルとかあるので、<br />\nTensorflow v1.15をインストールする。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_1.15.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_1.15.0\n<span class=\"nb\">cd</span> /work/tf_1.15.0\npyenv <span class=\"nb\">local </span>tf_1.15.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"tensorflow-115-ライブラリのインストール\">Tensorflow 1.15 ライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>1.15\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nGPU使わないので-cpu付きパッケージを選択する</p>\n</blockquote>\n\n<h1 id=\"tensorflow-115-のbuild\">Tensorflow 1.15 のbuild</h1>\n\n<p>Tensorflowのpythonライブラリは<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできるが、\nソースからbuildしないと使えないツールもあるのでbuild環境を整える。</p>\n\n<p>参考: <a href=\"https://www.tensorflow.org/install/source?hl=ja\">ソースからのビルド | Tensorflow</a></p>\n\n<h2 id=\"bazelのインストール\">Bazelのインストール</h2>\n\n<p>Tensorflow をソースからbuildするには<code class=\"language-plaintext highlighter-rouge\">bazel</code>が必要なので、インストールしておく。</p>\n<blockquote>\n  <p>[!NOTE]\nBazelはVer.0.26.1 以下 を使用しないといけない<br />\nVer. 0.26.1はaptでインストールできない</p>\n</blockquote>\n\n<p>参考: <a href=\"https://docs.bazel.build/versions/0.26.0/install-ubuntu.html\">Installing Bazel on Ubuntu</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/bazelbuild/bazel/releases/download/0.26.1/bazel-0.26.1-installer-linux-x86_64.sh\n<span class=\"nb\">chmod</span> +x bazel-0.26.1-installer-linux-x86_64.sh\n./bazel-0.26.1-installer-linux-x86_64.sh <span class=\"nt\">--user</span>\n</code></pre></div></div>\n\n<p>実行ファイルは、<code class=\"language-plaintext highlighter-rouge\">~/bin/bazel</code> になるので、pathが~/binに通ってない場合は、一旦 ログアウトして 再ログイン\n(pathが通ってない場合、configureでエラーになる)</p>\n\n<h2 id=\"必要なpipパッケージのインストール\">必要なpipパッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>six numpy wheel mock <span class=\"s1\">'future>=0.17.1'</span>\npip <span class=\"nb\">install </span>keras_applications <span class=\"nt\">--no-deps</span>\npip <span class=\"nb\">install </span>keras_preprocessing <span class=\"nt\">--no-deps</span>\n</code></pre></div></div>\n\n<h2 id=\"tennsorflowのソースを取得\">tennsorflowのソースを取得</h2>\n\n<p>githubからcloneして V1.15.3 をチェックアウトしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/\ngit clone https://github.com/tensorflow/tensorflow.git\n<span class=\"nb\">cd </span>tensorflow\ngit checkout <span class=\"nt\">-b</span> v1.15.3 refs/tags/v1.15.3\n</code></pre></div></div>\n\n<h1 id=\"buildの設定\">buildの設定</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\n./configure\n<span class=\"c\"># いくつか質問されるので、すべてデフォルト(リターン)を入力</span>\n</code></pre></div></div>\n\n<h1 id=\"buildの実行\">buildの実行</h1>\n<h2 id=\"実行のひな形\">実行のひな形</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build //《対象ディレクトリ》:《ターゲット》\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n※ 対象ディレクトリはカレントディレクトリからの相対パス<br />\n※ ターゲットは対象ディレクトリのBUILDファイルで確認</p>\n</blockquote>\n\n<h2 id=\"例えばこんな感じ\">例えばこんな感じ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel build //tensorflow/lite/toco:toco\nbazel build //tensorflow/python/tools:freeze_graph\nbazel build //tensorflow/tools/graph_transforms:summarize_graph\nbazel build //tensorflow/tools/graph_transforms:transform_graph\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRAMは4GB以上必要かな?<br />\nオプション<code class=\"language-plaintext highlighter-rouge\">--local_ram_resources=2048</code>を指定すると使用するRAMを2GBに限定できる(指定する数値はMB単位)。<br />\n使用するPCのスペックによってかかる時間はマチマチ。<br />\nNativeなUbuntuで4コア8スレッドでも3~4時間程度かかる。<br />\nVirtualboxで1コア使用だと24時間とかかかることも。</p>\n</blockquote>\n\n<h2 id=\"buildしたファイルの実行\">buildしたファイルの実行</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">bazel run</code> で実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nオプションをbazelではなく実行するコマンドに渡すため、<code class=\"language-plaintext highlighter-rouge\">--</code> を入れる必要がある。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel run //tensorflow/lite/toco:toco <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:summarize_graph <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:transform_graph <span class=\"nt\">--</span> «オプション»\n</code></pre></div></div>\n\n<p>絶対パスで実行するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph «オプション»\n</code></pre></div></div>\n\n<p>パスが長いので、以下を設定しておくと便利。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">alias            </span><span class=\"nv\">toco</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">summarize_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">transform_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph'</span>\n</code></pre></div></div>\n\n<h2 id=\"おまけ\">おまけ</h2>\n\n<p>フツーはこっちがメインだが…(^^ゞ<br />\npipでインストールすれば必要ないが、Tensorflowのpipパッケージを作成するにはこちら。<br />\n(オプション変更したいときとか)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build <span class=\"nt\">--config</span><span class=\"o\">=</span>v1 //tensorflow/tools/pip_package:build_pip_package\n./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg\npip <span class=\"nb\">install</span> /tmp/tensorflow_pkg/tensorflow-1.15.3-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その4</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その4</h1>\n      <p>tensorflowのモデルファイル(*.pbや*.tflite)の可視化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>tensorflowのモデルファイル( <code class=\"language-plaintext highlighter-rouge\">*.pb</code> や <code class=\"language-plaintext highlighter-rouge\">*.tflite</code> )を可視化する方法について。<br />\n<code class=\"language-plaintext highlighter-rouge\">tensorboard</code> を使う方法などもあるが、最もお手軽と思われる <code class=\"language-plaintext highlighter-rouge\">netron</code> を使用する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれやらなくても、<a href=\"https://lutzroeder.github.io/netron/\">https://lutzroeder.github.io/netron/</a> にアクセスすれば使える。</p>\n</blockquote>\n\n<h1 id=\"netron-の-インストール\">netron の インストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code>をインストールする。<br />\n<code class=\"language-plaintext highlighter-rouge\">netron</code> はtensorflowのバージョンに依存しない(そもそもtensorflow自体に依存してない)のでTensorflow1系、Tenorflow2系 どちらの環境にインストールしてもよい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>netron\n</code></pre></div></div>\n\n<h1 id=\"netron-の-実行\">netron の 実行</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code> を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>netron <span class=\"nt\">--host</span> 0.0.0.0 <span class=\"o\">[</span><span class=\"nt\">--port</span> xxxx]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--host</code> オプションを指定しないとlocalhostからしか接続できないので、他のマシンから接続するときは指定する。<br />\n<code class=\"language-plaintext highlighter-rouge\">--port</code> オプションのデフォルトは8080なので、変更したいときは指定する。</p>\n\n<h1 id=\"モデルファイルの表示\">モデルファイルの表示</h1>\n\n<p>ブラウザ(Winマシンからで可)で実行したマシンのポート8008(またはオプションで指定したxxxx)に接続。<br />\n例:<code class=\"language-plaintext highlighter-rouge\">http://ncc-1701u.local:8080/</code></p>\n\n<p>表示された画面でOpen Model…をクリックして表示するモデルファイルを選ぶ。<br />\nしばらく待つと表示される。<br />\nモデルファイルはブラウザからアップロードするので、ブラウザから参照できる場所になければならない(サーバ側にあってもダメ)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">*.pb</code> ファイルが大きいとうまく表示できないみたい。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その3</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その3</h1>\n      <p>Tensorflow 2.2.0をインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Edge-TPUを直接操作するわけではないが、Tensorflowで作成されたモデルファイルをtflite用に変換する準備として<br />\ntensorflowをインストールする。<br />\nここではVersion 2.2.0を使用する。</p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<p>coral環境に追加インストールでも良いが、今回は別の環境を用意する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_2.2.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_2.2.0\n<span class=\"nb\">cd</span> /work/tf_2.2.0\npyenv <span class=\"nb\">local </span>tf_2.2.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"tensorflow-220-のインストール\">tensorflow 2.2.0 のインストール</h1>\n\n<p>インストールするパッケージはGPUを使わないので-cpu付きパッケージを選択する。<br />\nTensorflowはバージョンによって機能差が激しいので、インストールするバージョンを指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>2.2.0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その2</h1>\n      <p>Google Coral USB Accelerator で SSD(Single Shot MultiBox Detector)を実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n一部を除き、基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<h1 id=\"tflite-の-モデルファイルをedgetpu使用モデルに変換する方法\">tflite の モデルファイルをEdgeTPU使用モデルに変換する方法</h1>\n<p>通常のtfliteのモデルファイルはCPUのみ(またはCPU+GPU)を使用するように構成されていて、\nそのまま実行してもEdge-TPUは使用されない。<br />\nそこで、Edge-TPU使用モデルに変換するため、edgetpu_compilerを使用する必要がある。<br />\n(ただし、Ubuntuのみ。RasPi不可。)</p>\n\n<h2 id=\"edgetpu_compiler-のインストール\">edgetpu_compiler のインストール</h2>\n\n<p>CPU使用モデルからEdge-TPU使用モデルに変換するツール<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code>をインストールする。<br />\naptリポジトリの登録はTPUライブラリインストール時に行っているので不要(以下ではコメントアウトしてある)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -</span>\n<span class=\"c\"># echo \"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list</span>\n<span class=\"c\"># sudo apt update</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>edgetpu-compiler\n</code></pre></div></div>\n\n<h2 id=\"使用方法\">使用方法</h2>\n<p>基本的に以下。<br />\ntfliteファイルを喰わせるとファイル名に<code class=\"language-plaintext highlighter-rouge\">_edgetpu</code>を付加したファイルが作成される。<br />\nこれがEdge-TPU使用するモデルファイル。<br />\n詳細は<a href=\"https://coral.ai/docs/edgetpu/compiler/\">Edge TPU Compiler</a> を参照。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>edgetpu_compiler [options] model...\n</code></pre></div></div>\n\n<h1 id=\"事前準備\">事前準備</h1>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n\n<p>openCVをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"ssdを実行してみる\">SSDを実行してみる</h1>\n\n<h2 id=\"作業用ディレクトリの作成移動\">作業用ディレクトリの作成&移動</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral/ssd/\n<span class=\"nb\">cd</span> /work/coral/ssd/\n</code></pre></div></div>\n\n<h2 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h2>\n\n<p>用意されているSSDのモデルをダウンロードし、Edge-TPU使用モデルを作成する。<br />\n実行が終了すると、<code class=\"language-plaintext highlighter-rouge\">models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite</code> ができる。</p>\n\n<ul>\n  <li>ダウンロード元: <a href=\"https://www.tensorflow.org/lite/models/object_detection/overview\">Object detection</a>\nの 「Get Started」の「Download starter model and labels」</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl <span class=\"nt\">-O</span> https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip\nunzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip \n<span class=\"nb\">mv </span>detect.tflite coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># リネームしなくてもいいけど、後でわからなくならないようにリネームしておく</span>\n<span class=\"nb\">mv </span>labelmap.txt coco_ssd_mobilenet_v1_1.0_quant.labels   <span class=\"c\"># 同上</span>\nedgetpu_compiler coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># EdgeTPU使用モデルに変換</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"テスト用画像の準備\">テスト用画像の準備</h2>\n\n<p>適当な画像を<code class=\"language-plaintext highlighter-rouge\">image</code>ディレクトリに用意しておく。<br />\n使用できるファイル形式は<code class=\"language-plaintext highlighter-rouge\">jpg</code>と<code class=\"language-plaintext highlighter-rouge\">mp4</code></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>images\n<span class=\"nb\">cd </span>images/\n<span class=\"c\"># 適当な画像ファイルをダウンロードする</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"ssdのプログラムソース\">SSDのプログラムソース</h2>\n\n<p>以下の内容を<code class=\"language-plaintext highlighter-rouge\">object_detection_demo_ssd.py</code>として保存しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">tflite_runtime.interpreter</span> <span class=\"k\">as</span> <span class=\"n\">tflite</span>\n\n<span class=\"c1\"># shared library\n</span><span class=\"n\">EDGETPU_SHARED_LIB</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n  <span class=\"s\">'Linux'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.so.1'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Darwin'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.1.dylib'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Windows'</span><span class=\"p\">:</span> <span class=\"s\">'edgetpu.dll'</span>\n<span class=\"p\">}[</span><span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">system</span><span class=\"p\">()]</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># interpreter の生成\n</span><span class=\"k\">def</span> <span class=\"nf\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">):</span>\n    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"o\">=</span><span class=\"n\">model_file</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span>\n                <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">model_file</span><span class=\"p\">,</span>\n                <span class=\"n\">experimental_delegates</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n                    <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">load_delegate</span><span class=\"p\">(</span><span class=\"n\">EDGETPU_SHARED_LIB</span><span class=\"p\">)</span>\n                <span class=\"p\">])</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    \n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">output_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_output_details</span><span class=\"p\">()</span>\n    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n\n    <span class=\"n\">tflite_results1</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Locations (Top, Left, Bottom, Right)\n</span>    <span class=\"n\">tflite_results2</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Classes (0=Person)\n</span>    <span class=\"n\">tflite_results3</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Scores\n</span>    <span class=\"n\">tflite_results4</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Number of detections\n</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">tflite_results4</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])):</span>\n        <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        \n        <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>        <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n\n        <span class=\"n\">prob</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results3</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">prob</span> <span class=\"o\">>=</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'Class=</span><span class=\"si\">{</span><span class=\"n\">class_name</span><span class=\"si\">:</span><span class=\"mi\">15</span><span class=\"si\">}</span><span class=\"s\">    Probability=</span><span class=\"si\">{</span><span class=\"n\">prob</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    Location=(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)-(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n            <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span>    <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span>   <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span>  <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 表示色\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 対象物の枠とラベルの描画\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"n\">bottom</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">20</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"o\">+</span><span class=\"mi\">160</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"s\">\"{} ({:.3f})\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">class_name</span><span class=\"p\">,</span> <span class=\"n\">prob</span><span class=\"p\">),</span>\n                        <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># interpreterの構築\n</span>    <span class=\"n\">interpreter</span> <span class=\"o\">=</span> <span class=\"n\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">allocate_tensors</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">input_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()</span>\n    \n    <span class=\"c1\"># 入力データ\n</span>    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">org_frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>                 <span class=\"c1\"># オリジナルのフレームレート\n</span>    <span class=\"n\">org_frame_time</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span> <span class=\"o\">/</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>                <span class=\"c1\"># オリジナルのフレーム時間\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">org_frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルの読み込み\n</span>        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルがない場合\n</span>        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># フレーム数\n</span>    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 実行時間測定用変数の初期化\n</span>    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n    <span class=\"c1\"># フレーム測定用タイマ\n</span>    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># モデルの入力サイズ\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># 画像の前処理 =============================================================================\n</span>        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                          <span class=\"c1\"># 前処理開始時刻\n</span>        \n        <span class=\"c1\"># 画像の読み込み\n</span>        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレームを作成\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># モデル入力用にリサイズ\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>   <span class=\"c1\"># input size of coco ssd mobilenet?\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">]]</span>                          <span class=\"c1\"># BGR -> RGB\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">in_frame</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>                 <span class=\"c1\"># 3D -> 4D\n</span>        \n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>     <span class=\"c1\"># 前処理にかかった時間\n</span>        \n        <span class=\"c1\"># 推論実行 =============================================================================\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"c1\"># 推論本体\n</span>        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">set_tensor</span><span class=\"p\">(</span><span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">],</span> <span class=\"n\">in_frame</span><span class=\"p\">)</span>\n        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">invoke</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>                          <span class=\"c1\"># 推論処理にかかった時間\n</span>        \n        <span class=\"c1\"># 検出結果の解析 =============================================================================\n</span>        <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                               <span class=\"c1\"># 解析処理開始時刻\n</span>        <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n        <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>                    <span class=\"c1\"># 解析処理にかかった時間\n</span>        \n        <span class=\"c1\"># 結果の表示 =============================================================================\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 表示処理開始時刻\n</span>        \n        <span class=\"c1\"># 測定データの表示\n</span>        <span class=\"n\">frame_number_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'frame_number   : </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span>\n        <span class=\"k\">if</span> <span class=\"n\">frame_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span>  <span class=\"s\">'Frame time     : ---'</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Frame time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms    </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> fps'</span>\n        <span class=\"n\">inf_time_message</span>        <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Inference time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">render_time_message</span>     <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Rendering time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">parsing_time_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'parse time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        \n        <span class=\"c1\"># 結果の書き込み\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_number_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>     <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>   <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像の保存\n</span>        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>                 <span class=\"c1\"># 表示処理にかかった時間\n</span>        \n        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"c1\"># フレーム処理終了 =============================================================================\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_key_code</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"make_interpretermodel_file\">make_interpreter(model_file)</h3>\n\n<p>interpreter(認識エンジン)を構築する処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>モデルファイル内に<code class=\"language-plaintext highlighter-rouge\">\"edgetpu-custom-op\"</code>という文字列が含まれていたらTPU使用モデルと判定してTPU使用のための共有ライブラリをダウンロードして初期化する。<br />\nそうでなければCPUのみ使用モデルなので、 共有ライブラリなしで初期化する。</p>\n\n<p>もっと単純にモデルファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>が含まれていたらTPU使用モデルと判定しても良いかもしれない(<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code> は出力ファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>を付加するので)。</p>\n\n<h3 id=\"parse_resultinterpreter-frame-labels_map-args\">parse_result(interpreter, frame, labels_map, args)</h3>\n\n<p>認識結果の解析と結果の表示(検出枠とラベルの描画)</p>\n\n<p>認識結果から検出した座標、クラスID、スコアを取得し、出力画像に描画している。</p>\n\n<p>出力データの構成は<a href=\"https://www.tensorflow.org/lite/models/object_detection/overview#output\">ここ</a>を参照。</p>\n\n<p>どうやらこのモデルは検出個数が10個に設定されているようだ。</p>\n\n<h3 id=\"main\">main()</h3>\n\n<p>メインルーチン</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>タイミング調整部分は、認識処理が速かった場合に結果表示画像の表示時間を実際の入力画像の表示時間に合わせるため、ちょっと小細工を入れてある。</p>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--help</span>\nusage: object_detection_demo_ssd.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT <span class=\"o\">[</span><span class=\"nt\">-l</span> LABELS]\n                                    <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> LABELS, <span class=\"nt\">--labels</span> LABELS\n                        Optional. Labels mapping file\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合edge-tpu使用\">静止画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合edge-tpu使用\">動画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n再生が終了するか、画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n<h2 id=\"静止画の場合cpuのみ\">静止画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合cpuのみ\">動画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その1</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その1</h1>\n      <p>Google Coral USB Acceleratorのインストールメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<p>参考サイト:\n<a href=\"https://qiita.com/rhene/items/7b34f60b73645d430789\">RaspberryPi 4でCoral USB TPU Accelerator(EdgeTPU)をとりあえず使う</a></p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<h2 id=\"edgetpu用ライブラリのインストール\">EdgeTPU用ライブラリのインストール</h2>\n\n<p>下記コマンドを実行して、EdgeTPU用ライブラリ(ドライバ類)をインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/coral-edgetpu.list\ncurl https://packages.cloud.google.com/apt/doc/apt-key.gpg | <span class=\"nb\">sudo </span>apt-key add -\n\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># 通常版をインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libedgetpu1-std\n<span class=\"c\"># または、最大クロック版</span>\n<span class=\"c\"># sudo apt install libedgetpu1-max</span>\n</code></pre></div></div>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 coral\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral\n<span class=\"nb\">cd</span> /work/coral\npyenv <span class=\"nb\">local </span>coral \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<p>numpyのinstallで失敗するので、以下を実行しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libatlas-base-dev\n</code></pre></div></div>\n\n<h2 id=\"tfliteモジュールのインストール\">TFLiteモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install  </span>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nどれをインストールするかは<a href=\"https://www.tensorflow.org/lite/guide/python\">Python quickstart</a>で確認<br />\n========= 例えば、ubuntu/raspbianのときはpythonのバージョンに応じて以下のどれかを指定 ==============</p>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (x86-64)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_x86_64.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_x86_64.whl</td>\n      </tr>\n    </tbody>\n  </table>\n\n  <table>\n    <thead>\n      <tr>\n        <th> </th>\n        <th>Linux (ARM 32)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr>\n        <td>3.5</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp35-cp35m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.6</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp36-cp36m-linux_armv7l.whl</td>\n      </tr>\n      <tr>\n        <td>3.7</td>\n        <td>https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl</td>\n      </tr>\n    </tbody>\n  </table>\n</blockquote>\n\n<h2 id=\"coral-usb-acceleratorの接続と確認\">Coral USB Acceleratorの接続と確認</h2>\n\n<p>USBポートに Coral USB Accelerator を接続する</p>\n\n<p>認識されたことを確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n\n<p>以下の表示があったら正常に認識されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>«省略»\nBus XXX Device YYY: ID 1a6e:089a Global Unichip Corp. \n«省略»\n</code></pre></div></div>\n\n<h1 id=\"動作確認サンプルプログラム\">動作確認(サンプルプログラム)</h1>\n\n<h2 id=\"サンプルソースのインストール\">サンプルソースのインストール</h2>\n\n<p>Githubからソースをダウンロードする</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/\ngit<span class=\"k\">**</span> clone https://github.com/google-coral/tflite.git\n</code></pre></div></div>\n\n<h2 id=\"サンプルプログラムの実行その1-classification\">サンプルプログラムの実行(その1) classification</h2>\n\n<h3 id=\"プログラムディレクトリへの移動\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/classification/\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh \n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py \n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n<p>結果の例は以下。<br />\n結果は「Ara macao(コンゴウインコ)」と表示されている。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference on Edge TPU is slow because it includes loading the model into Edge TPU memory.\n12.4ms\n4.2ms\n4.1ms\n4.2ms\n4.2ms\n-------RESULTS--------\nAra macao (Scarlet Macaw): 0.77734\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python classify_image.py <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--model</span> models/mobilenet_v2_1.0_224_inat_bird_quant.tflite  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--labels</span> models/inat_bird_labels.txt  <span class=\"se\">\\</span>\n\t\t<span class=\"nt\">--input</span> images/parrot.jpg \n</code></pre></div></div>\n\n<p><a id=\"CPUonlydiff\"> </a></p>\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合もCoral USB Acceleratorを接続しておかないとエラーになる。<br />\n接続しなくても実行できるようにするには以下のパッチを適用し、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">-cpu</code>オプションを指定する。</p>\n\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/python/examples/classification/classify_image.py b/python/examples/classification/\n</span><span class=\"gi\">> classify_image.py\n</span><span class=\"gh\">index 75f1d76..44fb798 100644\n</span><span class=\"gd\">--- a/python/examples/classification/classify_image.py\n</span><span class=\"gi\">+++ b/python/examples/classification/classify_image.py\n</span><span class=\"p\">@@ -12,7 +12,7 @@</span>\n<span class=\"err\">#</span> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n # See the License for the specific language governing permissions and\n # limitations under the License.\n<span class=\"gd\">-r\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span><span class=\"gi\">+\"\"\"Example using TF Lite to classify a given image using an Edge TPU.\n</span>\n    To run this code, you must attach an Edge TPU attached to the host and\n    install the Edge TPU runtime (`libedgetpu.so`) and `tflite_runtime`. For\n<span class=\"p\">@@ -64,9 +64,12 @@</span> def load_labels(path, encoding='utf-8'):\n       return {index: line.strip() for index, line in enumerate(lines)}\n\n\n<span class=\"gd\">-def make_interpreter(model_file):\n</span><span class=\"gi\">+def make_interpreter(model_file, cpu=False):\n</span>   model_file, *device = model_file.split('@')\n<span class=\"gd\">-  return tflite.Interpreter(\n</span><span class=\"gi\">+  if cpu :\n+    return tflite.Interpreter(model_path=model_file)\n+  else :\n+    return tflite.Interpreter(\n</span>       model_path=model_file,\n       experimental_delegates=[\n           tflite.load_delegate(EDGETPU_SHARED_LIB,\n<span class=\"p\">@@ -92,11 +95,19 @@</span> def main():\n   parser.add_argument(\n       '-c', '--count', type=int, default=5,\n       help='Number of times to run inference')\n<span class=\"gi\">+  parser.add_argument(\n+      '--cpu', action='store_true',\n+      help='use cpu only(default:use with TPU)')\n</span>   args = parser.parse_args()\n\n+  if args.cpu :\n<span class=\"gi\">+    print('**** USE CPU ONLY!! ****')\n+  else :\n+    print('**** USE WITH TPU ****')\n+\n</span>   labels = load_labels(args.labels) if args.labels else {}\n\n-  interpreter = make_interpreter(args.model)\n<span class=\"gi\">+  interpreter = make_interpreter(args.model, args.cpu)\n</span>   interpreter.allocate_tensors()\n\n   size = classify.input_size(interpreter)\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"サンプルプログラムの実行その2-detection\">サンプルプログラムの実行(その2) detection</h2>\n\n<h3 id=\"プログラムディレクトリへの移動-1\">プログラムディレクトリへの移動</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/coral/tflite/python/examples/detection\n</code></pre></div></div>\n\n<h3 id=\"関連モジュールのインストール-1\">関連モジュールのインストール</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./install_requirements.sh\n</code></pre></div></div>\n\n<h3 id=\"edgetpu使用のサンプル実行-1\">EdgeTPU使用のサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<p>結果の例は以下。<br />\n以下の表示と同時に認識結果の画像が別ウィンドウで表示される。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>----INFERENCE TIME----\nNote: The first inference is slow because it includes loading the model into Edge TPU memory.\n27.90 ms\n11.59 ms\n11.36 ms\n11.89 ms\n11.10 ms\n-------RESULTS--------\ntie\n  id:     31\n  score:  0.83984375\n  bbox:   BBox(xmin=226, ymin=417, xmax=290, ymax=539)\nperson\n  id:     0\n  score:  0.83984375\n  bbox:   BBox(xmin=2, ymin=5, xmax=507, ymax=590)\n</code></pre></div></div>\n\n<h3 id=\"cpuのみのサンプル実行-1\">CPUのみのサンプル実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python detect_image.py <span class=\"se\">\\</span>\n<span class=\"nt\">--model</span> models/mobilenet_ssd_v2_coco_quant_postprocess.tflite <span class=\"se\">\\</span>\n<span class=\"nt\">--input</span> images/grace_hopper.bmp <span class=\"se\">\\</span>\n<span class=\"nt\">--labels</span> models/coco_labels.txt <span class=\"se\">\\</span>\n<span class=\"nt\">--output</span> result.jpg\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションを指定すると、結果画像を保存するとともに、表示を行う。<br />\n指定しなければ認識だけ行う(結果の画像表示もしない)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">--output</code>オプションによる出力ファイルの形式は指定した拡張子で決定される。jpgやbmpなど。<br />\nrawデータで出力した場合(拡張子rgb)は、以下のコマンドでjpgやbmpに変換できる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.jpg\n</code></pre></div>  </div>\n\n  <p>または</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>convert result.rgb result.bmp\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nCPUのみで実行する場合でCoral USB Acceleratorを接続していなくてエラーになる場合は<br />\n<a href=\"#CPUonlydiff\">こちら</a>を参照</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Coral USB Accelerator": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その6</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その6</h1>\n      <p>tensorflow lite で色々なSSDモデルを使う手順</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はソースが大半なので、githubにリポジトリ作った。<br />\n内容は各ディレクトリのREADME.mdを見てチョ。<br />\n<a href=\"https://github.com/ippei8jp/tflite_trial\">https://github.com/ippei8jp/tflite_trial</a></p>\n\n<p>順序は <code class=\"language-plaintext highlighter-rouge\">download_models</code> → <code class=\"language-plaintext highlighter-rouge\">mk_tflite_ssd</code> → <code class=\"language-plaintext highlighter-rouge\">images</code> → <code class=\"language-plaintext highlighter-rouge\">ssd</code> が良いと思う。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その5</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その5</h1>\n      <p>Tensorflow v1.15のインストールとソースからのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>今回はUbuntuだけ。</p>\n\n<h1 id=\"tensorflow-115-のインストール\">Tensorflow 1.15 のインストール</h1>\n\n<p>Tensorflow1系でないと動かない環境とかサンプルとかあるので、<br />\nTensorflow v1.15をインストールする。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_1.15.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_1.15.0\n<span class=\"nb\">cd</span> /work/tf_1.15.0\npyenv <span class=\"nb\">local </span>tf_1.15.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"tensorflow-115-ライブラリのインストール\">Tensorflow 1.15 ライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>1.15\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nGPU使わないので-cpu付きパッケージを選択する</p>\n</blockquote>\n\n<h1 id=\"tensorflow-115-のbuild\">Tensorflow 1.15 のbuild</h1>\n\n<p>Tensorflowのpythonライブラリは<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできるが、\nソースからbuildしないと使えないツールもあるのでbuild環境を整える。</p>\n\n<p>参考: <a href=\"https://www.tensorflow.org/install/source?hl=ja\">ソースからのビルド | Tensorflow</a></p>\n\n<h2 id=\"bazelのインストール\">Bazelのインストール</h2>\n\n<p>Tensorflow をソースからbuildするには<code class=\"language-plaintext highlighter-rouge\">bazel</code>が必要なので、インストールしておく。</p>\n<blockquote>\n  <p>[!NOTE]\nBazelはVer.0.26.1 以下 を使用しないといけない<br />\nVer. 0.26.1はaptでインストールできない</p>\n</blockquote>\n\n<p>参考: <a href=\"https://docs.bazel.build/versions/0.26.0/install-ubuntu.html\">Installing Bazel on Ubuntu</a></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/bazelbuild/bazel/releases/download/0.26.1/bazel-0.26.1-installer-linux-x86_64.sh\n<span class=\"nb\">chmod</span> +x bazel-0.26.1-installer-linux-x86_64.sh\n./bazel-0.26.1-installer-linux-x86_64.sh <span class=\"nt\">--user</span>\n</code></pre></div></div>\n\n<p>実行ファイルは、<code class=\"language-plaintext highlighter-rouge\">~/bin/bazel</code> になるので、pathが~/binに通ってない場合は、一旦 ログアウトして 再ログイン\n(pathが通ってない場合、configureでエラーになる)</p>\n\n<h2 id=\"必要なpipパッケージのインストール\">必要なpipパッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>six numpy wheel mock <span class=\"s1\">'future>=0.17.1'</span>\npip <span class=\"nb\">install </span>keras_applications <span class=\"nt\">--no-deps</span>\npip <span class=\"nb\">install </span>keras_preprocessing <span class=\"nt\">--no-deps</span>\n</code></pre></div></div>\n\n<h2 id=\"tennsorflowのソースを取得\">tennsorflowのソースを取得</h2>\n\n<p>githubからcloneして V1.15.3 をチェックアウトしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/\ngit clone https://github.com/tensorflow/tensorflow.git\n<span class=\"nb\">cd </span>tensorflow\ngit checkout <span class=\"nt\">-b</span> v1.15.3 refs/tags/v1.15.3\n</code></pre></div></div>\n\n<h1 id=\"buildの設定\">buildの設定</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\n./configure\n<span class=\"c\"># いくつか質問されるので、すべてデフォルト(リターン)を入力</span>\n</code></pre></div></div>\n\n<h1 id=\"buildの実行\">buildの実行</h1>\n<h2 id=\"実行のひな形\">実行のひな形</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build //《対象ディレクトリ》:《ターゲット》\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n※ 対象ディレクトリはカレントディレクトリからの相対パス<br />\n※ ターゲットは対象ディレクトリのBUILDファイルで確認</p>\n</blockquote>\n\n<h2 id=\"例えばこんな感じ\">例えばこんな感じ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel build //tensorflow/lite/toco:toco\nbazel build //tensorflow/python/tools:freeze_graph\nbazel build //tensorflow/tools/graph_transforms:summarize_graph\nbazel build //tensorflow/tools/graph_transforms:transform_graph\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nRAMは4GB以上必要かな?<br />\nオプション<code class=\"language-plaintext highlighter-rouge\">--local_ram_resources=2048</code>を指定すると使用するRAMを2GBに限定できる(指定する数値はMB単位)。<br />\n使用するPCのスペックによってかかる時間はマチマチ。<br />\nNativeなUbuntuで4コア8スレッドでも3~4時間程度かかる。<br />\nVirtualboxで1コア使用だと24時間とかかかることも。</p>\n</blockquote>\n\n<h2 id=\"buildしたファイルの実行\">buildしたファイルの実行</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">bazel run</code> で実行する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nオプションをbazelではなく実行するコマンドに渡すため、<code class=\"language-plaintext highlighter-rouge\">--</code> を入れる必要がある。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/tf_1.15/tensorflow\nbazel run //tensorflow/lite/toco:toco <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:summarize_graph <span class=\"nt\">--</span> «オプション»\nbazel run //tensorflow/tools/graph_transforms:transform_graph <span class=\"nt\">--</span> «オプション»\n</code></pre></div></div>\n\n<p>絶対パスで実行するには以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph «オプション»\n/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph «オプション»\n</code></pre></div></div>\n\n<p>パスが長いので、以下を設定しておくと便利。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">alias            </span><span class=\"nv\">toco</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/lite/toco/toco'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">summarize_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/summarize_graph'</span>\n<span class=\"nb\">alias </span><span class=\"nv\">transform_graph</span><span class=\"o\">=</span><span class=\"s1\">'/work/tf_1.15/tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph'</span>\n</code></pre></div></div>\n\n<h2 id=\"おまけ\">おまけ</h2>\n\n<p>フツーはこっちがメインだが…(^^ゞ<br />\npipでインストールすれば必要ないが、Tensorflowのpipパッケージを作成するにはこちら。<br />\n(オプション変更したいときとか)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bazel build <span class=\"nt\">--config</span><span class=\"o\">=</span>v1 //tensorflow/tools/pip_package:build_pip_package\n./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg\npip <span class=\"nb\">install</span> /tmp/tensorflow_pkg/tensorflow-1.15.3-cp37-cp37m-linux_x86_64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その4</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その4</h1>\n      <p>tensorflowのモデルファイル(*.pbや*.tflite)の可視化</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>tensorflowのモデルファイル( <code class=\"language-plaintext highlighter-rouge\">*.pb</code> や <code class=\"language-plaintext highlighter-rouge\">*.tflite</code> )を可視化する方法について。<br />\n<code class=\"language-plaintext highlighter-rouge\">tensorboard</code> を使う方法などもあるが、最もお手軽と思われる <code class=\"language-plaintext highlighter-rouge\">netron</code> を使用する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれやらなくても、<a href=\"https://lutzroeder.github.io/netron/\">https://lutzroeder.github.io/netron/</a> にアクセスすれば使える。</p>\n</blockquote>\n\n<h1 id=\"netron-の-インストール\">netron の インストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code>をインストールする。<br />\n<code class=\"language-plaintext highlighter-rouge\">netron</code> はtensorflowのバージョンに依存しない(そもそもtensorflow自体に依存してない)のでTensorflow1系、Tenorflow2系 どちらの環境にインストールしてもよい。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>netron\n</code></pre></div></div>\n\n<h1 id=\"netron-の-実行\">netron の 実行</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">netron</code> を実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>netron <span class=\"nt\">--host</span> 0.0.0.0 <span class=\"o\">[</span><span class=\"nt\">--port</span> xxxx]\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--host</code> オプションを指定しないとlocalhostからしか接続できないので、他のマシンから接続するときは指定する。<br />\n<code class=\"language-plaintext highlighter-rouge\">--port</code> オプションのデフォルトは8080なので、変更したいときは指定する。</p>\n\n<h1 id=\"モデルファイルの表示\">モデルファイルの表示</h1>\n\n<p>ブラウザ(Winマシンからで可)で実行したマシンのポート8008(またはオプションで指定したxxxx)に接続。<br />\n例:<code class=\"language-plaintext highlighter-rouge\">http://ncc-1701u.local:8080/</code></p>\n\n<p>表示された画面でOpen Model…をクリックして表示するモデルファイルを選ぶ。<br />\nしばらく待つと表示される。<br />\nモデルファイルはブラウザからアップロードするので、ブラウザから参照できる場所になければならない(サーバ側にあってもダメ)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">*.pb</code> ファイルが大きいとうまく表示できないみたい。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その3</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その3</h1>\n      <p>Tensorflow 2.2.0をインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Edge-TPUを直接操作するわけではないが、Tensorflowで作成されたモデルファイルをtflite用に変換する準備として<br />\ntensorflowをインストールする。<br />\nここではVersion 2.2.0を使用する。</p>\n\n<h1 id=\"環境の準備\">環境の準備</h1>\n\n<p>pyenv + virtualenvを使用しているものとして記載する。</p>\n\n<h2 id=\"専用のpython環境用意しておく\">専用のPython環境用意しておく</h2>\n\n<p>coral環境に追加インストールでも良いが、今回は別の環境を用意する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.7 tf_2.2.0\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成とpython環境設定\">作業ディレクトリの作成とpython環境設定</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tf_2.2.0\n<span class=\"nb\">cd</span> /work/tf_2.2.0\npyenv <span class=\"nb\">local </span>tf_2.2.0 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h1 id=\"tensorflow-220-のインストール\">tensorflow 2.2.0 のインストール</h1>\n\n<p>インストールするパッケージはGPUを使わないので-cpu付きパッケージを選択する。<br />\nTensorflowはバージョンによって機能差が激しいので、インストールするバージョンを指定しておくのが無難。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>tensorflow-cpu<span class=\"o\">==</span>2.2.0\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Google Coral USB Accelerator を使う その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Google Coral USB Accelerator を使う その2</h1>\n      <p>Google Coral USB Accelerator で SSD(Single Shot MultiBox Detector)を実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Ubuntu/RaspberryPiでGoogle Coral USB Acceleratorを使用できるようにしてみる。<br />\n一部を除き、基本的にともに同じ手順で大丈夫(なハズ…)</p>\n\n<h1 id=\"tflite-の-モデルファイルをedgetpu使用モデルに変換する方法\">tflite の モデルファイルをEdgeTPU使用モデルに変換する方法</h1>\n<p>通常のtfliteのモデルファイルはCPUのみ(またはCPU+GPU)を使用するように構成されていて、\nそのまま実行してもEdge-TPUは使用されない。<br />\nそこで、Edge-TPU使用モデルに変換するため、edgetpu_compilerを使用する必要がある。<br />\n(ただし、Ubuntuのみ。RasPi不可。)</p>\n\n<h2 id=\"edgetpu_compiler-のインストール\">edgetpu_compiler のインストール</h2>\n\n<p>CPU使用モデルからEdge-TPU使用モデルに変換するツール<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code>をインストールする。<br />\naptリポジトリの登録はTPUライブラリインストール時に行っているので不要(以下ではコメントアウトしてある)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -</span>\n<span class=\"c\"># echo \"deb https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list</span>\n<span class=\"c\"># sudo apt update</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>edgetpu-compiler\n</code></pre></div></div>\n\n<h2 id=\"使用方法\">使用方法</h2>\n<p>基本的に以下。<br />\ntfliteファイルを喰わせるとファイル名に<code class=\"language-plaintext highlighter-rouge\">_edgetpu</code>を付加したファイルが作成される。<br />\nこれがEdge-TPU使用するモデルファイル。<br />\n詳細は<a href=\"https://coral.ai/docs/edgetpu/compiler/\">Edge TPU Compiler</a> を参照。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>edgetpu_compiler [options] model...\n</code></pre></div></div>\n\n<h1 id=\"事前準備\">事前準備</h1>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n\n<p>openCVをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"ssdを実行してみる\">SSDを実行してみる</h1>\n\n<h2 id=\"作業用ディレクトリの作成移動\">作業用ディレクトリの作成&移動</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/coral/ssd/\n<span class=\"nb\">cd</span> /work/coral/ssd/\n</code></pre></div></div>\n\n<h2 id=\"モデルファイルのダウンロード\">モデルファイルのダウンロード</h2>\n\n<p>用意されているSSDのモデルをダウンロードし、Edge-TPU使用モデルを作成する。<br />\n実行が終了すると、<code class=\"language-plaintext highlighter-rouge\">models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite</code> ができる。</p>\n\n<ul>\n  <li>ダウンロード元: <a href=\"https://www.tensorflow.org/lite/models/object_detection/overview\">Object detection</a>\nの 「Get Started」の「Download starter model and labels」</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>models\n<span class=\"nb\">cd </span>models\ncurl <span class=\"nt\">-O</span> https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip\nunzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip \n<span class=\"nb\">mv </span>detect.tflite coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># リネームしなくてもいいけど、後でわからなくならないようにリネームしておく</span>\n<span class=\"nb\">mv </span>labelmap.txt coco_ssd_mobilenet_v1_1.0_quant.labels   <span class=\"c\"># 同上</span>\nedgetpu_compiler coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"c\"># EdgeTPU使用モデルに変換</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"テスト用画像の準備\">テスト用画像の準備</h2>\n\n<p>適当な画像を<code class=\"language-plaintext highlighter-rouge\">image</code>ディレクトリに用意しておく。<br />\n使用できるファイル形式は<code class=\"language-plaintext highlighter-rouge\">jpg</code>と<code class=\"language-plaintext highlighter-rouge\">mp4</code></p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>images\n<span class=\"nb\">cd </span>images/\n<span class=\"c\"># 適当な画像ファイルをダウンロードする</span>\n<span class=\"nb\">cd</span> ../\n</code></pre></div></div>\n\n<h2 id=\"ssdのプログラムソース\">SSDのプログラムソース</h2>\n\n<p>以下の内容を<code class=\"language-plaintext highlighter-rouge\">object_detection_demo_ssd.py</code>として保存しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">#!/usr/bin/env python\n</span><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span> <span class=\"k\">as</span> <span class=\"n\">log</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">,</span> <span class=\"n\">SUPPRESS</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">tflite_runtime.interpreter</span> <span class=\"k\">as</span> <span class=\"n\">tflite</span>\n\n<span class=\"c1\"># shared library\n</span><span class=\"n\">EDGETPU_SHARED_LIB</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n  <span class=\"s\">'Linux'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.so.1'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Darwin'</span><span class=\"p\">:</span> <span class=\"s\">'libedgetpu.1.dylib'</span><span class=\"p\">,</span>\n  <span class=\"s\">'Windows'</span><span class=\"p\">:</span> <span class=\"s\">'edgetpu.dll'</span>\n<span class=\"p\">}[</span><span class=\"n\">platform</span><span class=\"p\">.</span><span class=\"n\">system</span><span class=\"p\">()]</span>\n\n<span class=\"c1\"># コマンドラインパーサの構築\n</span><span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">add_help</span><span class=\"o\">=</span><span class=\"bp\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument_group</span><span class=\"p\">(</span><span class=\"s\">'Options'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-h'</span><span class=\"p\">,</span> <span class=\"s\">'--help'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'help'</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">SUPPRESS</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">'Show this help message and exit.'</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-m\"</span><span class=\"p\">,</span> <span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to an .xml file with a trained model.\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-i\"</span><span class=\"p\">,</span> <span class=\"s\">\"--input\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Required. Path to a image/video file. (Specify 'cam' to work with camera)\"</span><span class=\"p\">,</span> <span class=\"n\">required</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-l\"</span><span class=\"p\">,</span> <span class=\"s\">\"--labels\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Labels mapping file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--save\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save result to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--log\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. Save log to specified file\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--no_disp\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Optional. without image display\"</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># interpreter の生成\n</span><span class=\"k\">def</span> <span class=\"nf\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">):</span>\n    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"o\">=</span><span class=\"n\">model_file</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">Interpreter</span><span class=\"p\">(</span>\n                <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">model_file</span><span class=\"p\">,</span>\n                <span class=\"n\">experimental_delegates</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n                    <span class=\"n\">tflite</span><span class=\"p\">.</span><span class=\"n\">load_delegate</span><span class=\"p\">(</span><span class=\"n\">EDGETPU_SHARED_LIB</span><span class=\"p\">)</span>\n                <span class=\"p\">])</span>\n\n<span class=\"c1\"># 結果の解析と表示\n</span><span class=\"k\">def</span> <span class=\"nf\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    \n    <span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[:</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n    <span class=\"n\">output_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_output_details</span><span class=\"p\">()</span>\n    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n\n    <span class=\"n\">tflite_results1</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Locations (Top, Left, Bottom, Right)\n</span>    <span class=\"n\">tflite_results2</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Classes (0=Person)\n</span>    <span class=\"n\">tflite_results3</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Scores\n</span>    <span class=\"n\">tflite_results4</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_tensor</span><span class=\"p\">(</span><span class=\"n\">output_details</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">])</span>  <span class=\"c1\"># Number of detections\n</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">tflite_results4</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])):</span>\n        <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_height</span>\n        <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"n\">tflite_results1</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">][</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">input_width</span>\n        \n        <span class=\"c1\"># ラベルが定義されていればラベルを読み出し、なければclass ID\n</span>        <span class=\"n\">class_id</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results2</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">astype</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">labels_map</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">labels_map</span><span class=\"p\">)</span> <span class=\"o\">></span> <span class=\"n\">class_id</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"n\">labels_map</span><span class=\"p\">[</span><span class=\"n\">class_id</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">class_name</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">class_id</span><span class=\"p\">)</span>\n\n        <span class=\"n\">prob</span> <span class=\"o\">=</span> <span class=\"n\">tflite_results3</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">prob</span> <span class=\"o\">>=</span> <span class=\"mf\">0.5</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'Class=</span><span class=\"si\">{</span><span class=\"n\">class_name</span><span class=\"si\">:</span><span class=\"mi\">15</span><span class=\"si\">}</span><span class=\"s\">    Probability=</span><span class=\"si\">{</span><span class=\"n\">prob</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">    Location=(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)-(</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n            <span class=\"n\">top</span>    <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">top</span>    <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">left</span>   <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">left</span>   <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">bottom</span> <span class=\"o\">*</span> <span class=\"n\">img_height</span>  <span class=\"o\">/</span> <span class=\"n\">input_height</span><span class=\"p\">)</span>\n            <span class=\"n\">right</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">right</span>  <span class=\"o\">*</span> <span class=\"n\">img_width</span> <span class=\"o\">/</span> <span class=\"n\">input_width</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 表示色\n</span>            <span class=\"k\">if</span> <span class=\"n\">class_id</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># class_id = 1のときは緑\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># それ以外のときは赤\n</span>                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n            <span class=\"c1\"># 対象物の枠とラベルの描画\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"n\">bottom</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">rectangle</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">20</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"o\">+</span><span class=\"mi\">160</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"p\">),</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"s\">\"{} ({:.3f})\"</span><span class=\"p\">.</span><span class=\"nb\">format</span><span class=\"p\">(</span><span class=\"n\">class_name</span><span class=\"p\">,</span> <span class=\"n\">prob</span><span class=\"p\">),</span>\n                        <span class=\"p\">(</span><span class=\"n\">left</span><span class=\"p\">,</span> <span class=\"n\">top</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">basicConfig</span><span class=\"p\">(</span><span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s\">\"[ %(levelname)s ] %(message)s\"</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    <span class=\"n\">no_disp</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">no_disp</span>\n    \n    <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">labels</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s\">\".labels\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">)</span>  <span class=\"p\">:</span>\n        <span class=\"n\">model_label</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># ------------- 1. Plugin initialization for specified device and load extensions library if specified -------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Creating Inference Engine...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># interpreterの構築\n</span>    <span class=\"n\">interpreter</span> <span class=\"o\">=</span> <span class=\"n\">make_interpreter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">allocate_tensors</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">input_details</span> <span class=\"o\">=</span> <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">get_input_details</span><span class=\"p\">()</span>\n    \n    <span class=\"c1\"># 入力データ\n</span>    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span> <span class=\"o\">==</span> <span class=\"s\">'cam'</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">input_stream</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">assert</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">),</span> <span class=\"s\">\"Specified input file doesn't exist\"</span>\n    \n    <span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"n\">input_stream</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 幅と高さを取得\n</span>    <span class=\"n\">img_width</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n    <span class=\"n\">img_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n    <span class=\"n\">disp_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"mi\">90</span>      <span class=\"c1\"># 情報表示領域分を追加\n</span>    <span class=\"c1\"># フレームレート(1フレームの時間単位はミリ秒)の取得\n</span>    <span class=\"n\">org_frame_rate</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">))</span>                 <span class=\"c1\"># オリジナルのフレームレート\n</span>    <span class=\"n\">org_frame_time</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span> <span class=\"o\">/</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>                <span class=\"c1\"># オリジナルのフレーム時間\n</span>    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フォーマット\n</span>        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter_fourcc</span><span class=\"p\">(</span><span class=\"s\">'m'</span><span class=\"p\">,</span> <span class=\"s\">'p'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'v'</span><span class=\"p\">)</span>\n        <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoWriter</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">,</span> <span class=\"n\">org_frame_rate</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"n\">disp_height</span><span class=\"p\">))</span>\n    \n    <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s\">'w'</span><span class=\"p\">)</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number, frame_time, preprocess_time, inf_time, parse_time, render_time, wait_time</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>     <span class=\"c1\"># 見出し行\n</span>    \n    <span class=\"k\">if</span> <span class=\"n\">model_label</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルの読み込み\n</span>        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_label</span><span class=\"p\">,</span> <span class=\"s\">'r'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">x</span><span class=\"p\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">f</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"c1\"># ラベルファイルがない場合\n</span>        <span class=\"n\">labels_map</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># フレーム数\n</span>    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_COUNT</span><span class=\"p\">))</span>\n    <span class=\"n\">number_input_frames</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">!=</span> <span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">number_input_frames</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"k\">else</span> <span class=\"n\">number_input_frames</span>\n    \n    <span class=\"c1\"># ----------------------------------------------- 6. Doing inference -----------------------------------------------\n</span>    <span class=\"n\">log</span><span class=\"p\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s\">\"Starting inference...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"To close the application, press 'CTRL+C' here or switch to the output window and press ESC key\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 実行時間測定用変数の初期化\n</span>    <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n    <span class=\"c1\"># フレーム測定用タイマ\n</span>    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># モデルの入力サイズ\n</span>    <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">,</span> <span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'shape'</span><span class=\"p\">]</span>\n    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># 画像の前処理 =============================================================================\n</span>        <span class=\"n\">preprocess_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                          <span class=\"c1\"># 前処理開始時刻\n</span>        \n        <span class=\"c1\"># 画像の読み込み\n</span>        <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">ret</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        \n        <span class=\"c1\"># 表示用領域を含んだフレームを作成\n</span>        <span class=\"n\">pad_img</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">disp_height</span><span class=\"p\">,</span> <span class=\"n\">img_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># モデル入力用にリサイズ\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">input_width</span><span class=\"p\">,</span> <span class=\"n\">input_height</span><span class=\"p\">))</span>   <span class=\"c1\"># input size of coco ssd mobilenet?\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">in_frame</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span><span class=\"mi\">1</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">]]</span>                          <span class=\"c1\"># BGR -> RGB\n</span>        <span class=\"n\">in_frame</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">expand_dims</span><span class=\"p\">(</span><span class=\"n\">in_frame</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>                 <span class=\"c1\"># 3D -> 4D\n</span>        \n        <span class=\"n\">preprocess_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">preprocess_time</span> <span class=\"o\">=</span> <span class=\"n\">preprocess_end</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>     <span class=\"c1\"># 前処理にかかった時間\n</span>        \n        <span class=\"c1\"># 推論実行 =============================================================================\n</span>        <span class=\"n\">inf_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                                 <span class=\"c1\"># 推論処理開始時刻\n</span>        <span class=\"c1\"># 推論本体\n</span>        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">set_tensor</span><span class=\"p\">(</span><span class=\"n\">input_details</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s\">'index'</span><span class=\"p\">],</span> <span class=\"n\">in_frame</span><span class=\"p\">)</span>\n        <span class=\"n\">interpreter</span><span class=\"p\">.</span><span class=\"n\">invoke</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">inf_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">inf_time</span> <span class=\"o\">=</span> <span class=\"n\">inf_end</span> <span class=\"o\">-</span> <span class=\"n\">inf_start</span>                          <span class=\"c1\"># 推論処理にかかった時間\n</span>        \n        <span class=\"c1\"># 検出結果の解析 =============================================================================\n</span>        <span class=\"n\">parse_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                               <span class=\"c1\"># 解析処理開始時刻\n</span>        <span class=\"n\">parse_result</span><span class=\"p\">(</span><span class=\"n\">interpreter</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">labels_map</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">)</span>\n        <span class=\"n\">parse_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">parse_time</span> <span class=\"o\">=</span> <span class=\"n\">parse_end</span> <span class=\"o\">-</span> <span class=\"n\">parse_start</span>                    <span class=\"c1\"># 解析処理にかかった時間\n</span>        \n        <span class=\"c1\"># 結果の表示 =============================================================================\n</span>        <span class=\"n\">render_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 表示処理開始時刻\n</span>        \n        <span class=\"c1\"># 測定データの表示\n</span>        <span class=\"n\">frame_number_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'frame_number   : </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span>\n        <span class=\"k\">if</span> <span class=\"n\">frame_time</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span>  <span class=\"s\">'Frame time     : ---'</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">frame_time_message</span>  <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Frame time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms    </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> fps'</span>\n        <span class=\"n\">inf_time_message</span>        <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Inference time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">render_time_message</span>     <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'Rendering time : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        <span class=\"n\">parsing_time_message</span>    <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'parse time     : </span><span class=\"si\">{</span><span class=\"p\">(</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> ms'</span>\n        \n        <span class=\"c1\"># 結果の書き込み\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_number_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">inf_time_message</span><span class=\"p\">,</span>     <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">parsing_time_message</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">45</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">render_time_message</span><span class=\"p\">,</span>  <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">60</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">,</span> <span class=\"n\">frame_time_message</span><span class=\"p\">,</span>   <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">img_height</span> <span class=\"o\">+</span> <span class=\"mi\">75</span><span class=\"p\">),</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_COMPLEX</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示用領域に画像をコピー\n</span>        <span class=\"n\">pad_img</span><span class=\"p\">[:</span><span class=\"n\">img_height</span><span class=\"p\">,</span> <span class=\"p\">:</span><span class=\"n\">img_width</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">frame</span>\n        \n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">\"Detection Results\"</span><span class=\"p\">,</span> <span class=\"n\">pad_img</span><span class=\"p\">)</span>        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'frame_number: </span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像の保存\n</span>        <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 保存が設定されているときは画像を保存\n</span>            <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pad_img</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">render_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">render_time</span> <span class=\"o\">=</span> <span class=\"n\">render_end</span> <span class=\"o\">-</span> <span class=\"n\">render_start</span>                 <span class=\"c1\"># 表示処理にかかった時間\n</span>        \n        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"c1\"># ESCキー\n</span>            <span class=\"k\">break</span>\n        <span class=\"n\">wait_end</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">wait_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_end</span> <span class=\"o\">-</span> <span class=\"n\">wait_start</span>\n        \n        <span class=\"c1\"># フレーム処理終了 =============================================================================\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>         <span class=\"c1\"># 1フレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n            <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_number</span><span class=\"si\">:</span><span class=\"mi\">5</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">frame_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">preprocess_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">inf_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">parse_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">render_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_key_code</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">wait_time</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    \n    <span class=\"c1\"># 後片付け\n</span>    <span class=\"k\">if</span> <span class=\"n\">writer</span><span class=\"p\">:</span>\n        <span class=\"n\">writer</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">log_f</span> <span class=\"p\">:</span>\n        <span class=\"n\">log_f</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">()</span> <span class=\"ow\">or</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"make_interpretermodel_file\">make_interpreter(model_file)</h3>\n\n<p>interpreter(認識エンジン)を構築する処理</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># CPU/TPU使用の識別\n</span>    <span class=\"c1\"># 「ファイル名に\"_edgetpu\"が含まれていたら」の識別方法もアリかもしれない\n</span>    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">model_file</span><span class=\"p\">,</span> <span class=\"s\">\"rb\"</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"c1\"># モデルデータを読み込む\n</span>        <span class=\"n\">tfdata</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"c1\"># モデルファイル中に\"edgetpu-custom-op\"が含まれていたらTPU使用モデル\n</span>        <span class=\"n\">cpu</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"sa\">b</span><span class=\"s\">\"edgetpu-custom-op\"</span> <span class=\"ow\">in</span> <span class=\"n\">tfdata</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">cpu</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE CPU ONLY!! ****'</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'**** USE WITH TPU ****'</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>モデルファイル内に<code class=\"language-plaintext highlighter-rouge\">\"edgetpu-custom-op\"</code>という文字列が含まれていたらTPU使用モデルと判定してTPU使用のための共有ライブラリをダウンロードして初期化する。<br />\nそうでなければCPUのみ使用モデルなので、 共有ライブラリなしで初期化する。</p>\n\n<p>もっと単純にモデルファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>が含まれていたらTPU使用モデルと判定しても良いかもしれない(<code class=\"language-plaintext highlighter-rouge\">edgetpu_compiler</code> は出力ファイル名に<code class=\"language-plaintext highlighter-rouge\">\"_edgetpu\"</code>を付加するので)。</p>\n\n<h3 id=\"parse_resultinterpreter-frame-labels_map-args\">parse_result(interpreter, frame, labels_map, args)</h3>\n\n<p>認識結果の解析と結果の表示(検出枠とラベルの描画)</p>\n\n<p>認識結果から検出した座標、クラスID、スコアを取得し、出力画像に描画している。</p>\n\n<p>出力データの構成は<a href=\"https://www.tensorflow.org/lite/models/object_detection/overview#output\">ここ</a>を参照。</p>\n\n<p>どうやらこのモデルは検出個数が10個に設定されているようだ。</p>\n\n<h3 id=\"main\">main()</h3>\n\n<p>メインルーチン</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"c1\"># タイミング調整 =============================================================================\n</span>        <span class=\"n\">wait_start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">no_disp</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 表示しない場合は無駄な待ち時間を確保しない\n</span>            <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># フレーム先頭からここまでの時間\n</span>            <span class=\"n\">cur_total_time</span> <span class=\"o\">=</span> <span class=\"n\">wait_start</span> <span class=\"o\">-</span> <span class=\"n\">preprocess_start</span>\n            <span class=\"c1\"># フレーム間処理の待ち時間(フレームが1枚だけの場合は永久待ち)\n</span>            <span class=\"k\">if</span> <span class=\"n\">number_input_frames</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">org_frame_time</span> <span class=\"o\"><</span> <span class=\"n\">cur_total_time</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間がここまでの時間より短ければ最短時間\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"mi\">1</span> \n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># オリジナルフレーム時間とここまでの時間の差(msec単位に変換して小数点以下切り上げ)\n</span>                    <span class=\"n\">wait_key_code</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">ceil</span><span class=\"p\">((</span><span class=\"n\">org_frame_time</span> <span class=\"o\">-</span> <span class=\"n\">cur_total_time</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n        <span class=\"n\">key</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"n\">wait_key_code</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>タイミング調整部分は、認識処理が速かった場合に結果表示画像の表示時間を実際の入力画像の表示時間に合わせるため、ちょっと小細工を入れてある。</p>\n\n<h2 id=\"ヘルプ表示\">ヘルプ表示</h2>\n\n<p>使用できるオプションはヘルプ表示で。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--help</span>\nusage: object_detection_demo_ssd.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"nt\">-m</span> MODEL <span class=\"nt\">-i</span> INPUT <span class=\"o\">[</span><span class=\"nt\">-l</span> LABELS]\n                                    <span class=\"o\">[</span><span class=\"nt\">--save</span> SAVE] <span class=\"o\">[</span><span class=\"nt\">--log</span> LOG] <span class=\"o\">[</span><span class=\"nt\">--no_disp</span><span class=\"o\">]</span>\n\noptional arguments:\n  <span class=\"nt\">--save</span> SAVE           Optional. Save result to specified file\n  <span class=\"nt\">--log</span> LOG             Optional. Save log to specified file\n  <span class=\"nt\">--no_disp</span>             Optional. without image display\n\nOptions:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            Show this <span class=\"nb\">help </span>message and exit.\n  <span class=\"nt\">-m</span> MODEL, <span class=\"nt\">--model</span> MODEL\n                        Required. Path to an .xml file with a trained model.\n  <span class=\"nt\">-i</span> INPUT, <span class=\"nt\">--input</span> INPUT\n                        Required. Path to a image/video file. <span class=\"o\">(</span>Specify <span class=\"s1\">'cam'</span>\n                        to work with camera<span class=\"o\">)</span>\n  <span class=\"nt\">-l</span> LABELS, <span class=\"nt\">--labels</span> LABELS\n                        Optional. Labels mapping file\n</code></pre></div></div>\n\n<h2 id=\"静止画の場合edge-tpu使用\">静止画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合edge-tpu使用\">動画の場合(Edge-TPU使用)</h2>\n\n<p>以下のコマンドを実行すると、認識結果画像が表示される。<br />\n再生が終了するか、画像が表示されたウィンドウでESCキーを押すと終了する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant_edgetpu.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n<h2 id=\"静止画の場合cpuのみ\">静止画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite <span class=\"nt\">--input</span> images/cat.jpg\n</code></pre></div></div>\n\n<h2 id=\"動画の場合cpuのみ\">動画の場合(CPUのみ)</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python object_detection_demo_ssd.py <span class=\"nt\">--model</span> models/coco_ssd_mobilenet_v1_1.0_quant.tflite  <span class=\"nt\">--input</span> images/testvideo3.mp4 \n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "WSL": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSB</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSB</h1>\n      <p>WSLでUSBを使った時のメモ(バージョン 2.5.7.0)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLのバージョンが2.5.7.0でカーネルバージョンが6.6.87.1-1になってカーネルの再ビルドしなくても\n色々なUSBデバイスが使えるようになったので試してみた時のメモ。</p>\n\n<p>参考:<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb\" target=\"_blank\">USB デバイスを接続する</a></p>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"windows側の準備\">windows側の準備</h2>\n<h3 id=\"usbipd-winのインストール\">usbipd-winのインストール</h3>\n<p><a href=\"https://github.com/dorssel/usbipd-win/releases\" target=\"_blank\">usbipd-winのgithub</a>からダウンロード(使用したのは5.10)<br />\nインストールはファイルをダウンロードして実行するだけ。<br />\nWindowsTerminarが開いている場合は一旦すべて閉じる(PATHの変更を有効にするため)</p>\n\n<h2 id=\"ubuntu側の準備\">Ubuntu側の準備</h2>\n<h3 id=\"systemdの有効化\">systemdの有効化</h3>\n\n<p>systemdを有効にするため、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に以下の設定を追加。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<h3 id=\"仮想usbホストコントローラインタフェースのインストール\">仮想USBホストコントローラインタフェースのインストール</h3>\n<p>ネットワーク経由でUSBデバイスを共有することを可能にするため、仮想USBホストコントローラインタフェース(vhci-hcd)をインストール\n(ドライバの組み込み)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/modules-load.d/usb.conf</code> (ファイル名は何でも可)を以下の内容で作成し、WSLの再起動。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vhci-hcd\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nお試しで1回だけ読み込むなら以下。この場合は再起動不要(というか再起動したら消える)。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo modprobe vhci-hcd\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"usbユーティリティのインストール\">USBユーティリティのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">lsusb</code>とか使いたいので、インストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>usbutils\n</code></pre></div></div>\n\n<h3 id=\"仮想マシンの再起動\">仮想マシンの再起動</h3>\n<p>設定を有効にするため、仮想マシンを再起動する。<br />\n開いているすべての仮想マシンを閉じた後、Windwos側で <code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行し、<br />\n<code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>ですべて仮想マシンのSTATEが<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていることを確認し仮想マシンを再度実行。</p>\n\n<h4 id=\"systemdが起動していることを確認する\">systemdが起動していることを確認する</h4>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>systemctl\n</code></pre></div></div>\n<p>起動していればサービス一覧が表示される。<br />\n起動していなければ以下のようなメッセージが表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>System has not been booted with systemd as init system (PID 1). Can't operate.\nFailed to connect to bus: ホストが落ちています\n</code></pre></div></div>\n\n<h4 id=\"vhci-hcdが組み込まれていることを確認する\">vhci-hcdが組み込まれていることを確認する</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsmod\n</code></pre></div></div>\n<p>表示の中に<code class=\"language-plaintext highlighter-rouge\">vhci_hcd</code>があることを確認。<br />\nなければ組み込みの設定を確認。</p>\n\n<h1 id=\"usbカメラを使ってみる\">USBカメラを使ってみる</h1>\n<p>今回は エレコムの UCAM-DLA200HBK を使用。<br />\nかなり古いカメラなのでもう売ってないけど…<br />\nUVC仕様のカメラなら基本的に同じはず。</p>\n\n<h2 id=\"ubuntu側の準備-1\">Ubuntu側の準備</h2>\n<p>今回はカメラなので、自身にvideoグループを追加<br />\n(要 再ログイン、シャットダウンは不要)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> video\n</code></pre></div></div>\n\n<h3 id=\"guvcviewのインストール\">guvcviewのインストール</h3>\n<p>表示ツールは何でもいいけど、とりあえずguvcviewで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>guvcview \n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-1\">Windows側の準備</h2>\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行\">Ubuntu側の実行</h2>\n\n<p>USB機器が割り当てられたことを確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 002: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n</code></pre></div></div>\n\n<p>デバイスノードも確認しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> <span class=\"nt\">-la</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1\n</code></pre></div></div>\n\n<p>実際に表示してみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">LANG</code>が<code class=\"language-plaintext highlighter-rouge\">ja_JP.UTF8</code>とかのままだと文字化けしてしまうので、Cに変更して実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示されるが、何も表示されない\nコンソールには「V4L2_CORE: Could not grab image (select timeout): リソースが一時的に利用できません」と表示され続ける</p>\n\n<p>GuvcviewウィンドウのVideo Controls をクリックし、</p>\n<ul>\n  <li>Frame Rate を15/1 fps</li>\n  <li>Rsolution を 160x120</li>\n  <li>Camera Output を MJPEG<br />\nにすると表示されるけど、あまり実用的ではない…</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nこれらのパラメータが選択できるかは使用するカメラによる。<br />\nPCのスペック等によって、もうちょっと大きいサイズでも表示できることがある。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n日本語で表示するには、例えば以下のように日本語フォントをインストールして\nLANGを指定せずに実行すれば良い。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"windows側の後始末\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n<h2 id=\"ということで\">ということで</h2>\n<p>あまり実用的とは言い難い結果となってしまった。</p>\n\n<h1 id=\"usbカメラをubuntu-pcからエクスポートしてみる\">USBカメラをUbuntu PCからエクスポートしてみる</h1>\n<p>試しに、Ubuntu PCからUSBカメラをエクスポートしてWSLで表示してみる。</p>\n\n<blockquote>\n  <p>[!NOTE]\n「Netive UbuntuあるならWSL使わんでも良いやん」という気もするが…</p>\n</blockquote>\n\n<h2 id=\"navive-ubuntuの準備\">Navive Ubuntuの準備</h2>\n\n<h3 id=\"カメラを接続\">カメラを接続</h3>\n<p>USBカメラを接続し、認識されているか確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 003 Device 006: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>デバイスノードの確認。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ。<br />\nカメラが他にも接続されているので2×2表示されてるけど…<br />\n今回接続されたのは2と3のはず(今はこれを使わないので気にしない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1  /dev/video2  /dev/video3\n</code></pre></div></div>\n\n<p>必要ならguvcviewをインストールして試してみてちょ。</p>\n\n<h3 id=\"linux-toolsのインストール\">linux-toolsのインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div></div>\n<p>usbipを実行してみる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div></div>\n\n<p>※ linux-tools-≪バージョン≫-generic をインストールしろと言われたら従う。例えば</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-6.5.0-41-generic\n</code></pre></div></div>\n\n<h3 id=\"ドライバの組み込みとdaemonの起動\">ドライバの組み込みとdaemonの起動</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbip-host        <span class=\"c\"># ドライバ組み込み</span>\n<span class=\"nb\">sudo </span>usbipd <span class=\"nt\">-D</span>                  <span class=\"c\"># daemon起動</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n起動時に自動で組み込み&実行したいときはsystemdでサービス登録するとできそうだけど、<br />\n本筋じゃないのでやめとく。<br />\n<a href=\"https://github.com/furbrain/systemd-usbip/blob/master/usbipd.service\" target=\"_blank\">ここ</a>\nとか参考になるかも。</p>\n</blockquote>\n\n<h3 id=\"接続されているデバイスを表示\">接続されているデバイスを表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip list <span class=\"nt\">--local</span>         <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<p>こんな感じで表示される</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\n - busid 3-11 (056e:700a)\n   Elecom Co., Ltd : unknown product (056e:700a)\n・・・\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n表示される製品名等が不明確な場合は<code class=\"language-plaintext highlighter-rouge\">lsusb</code>の結果と突き合わせてみると良い。<br />\n(IDはどちらも表示されているので、これを頼りに)</p>\n</blockquote>\n\n<h3 id=\"バインド\">バインド</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip <span class=\"nb\">bind</span> <span class=\"nt\">--busid</span> 3-11    <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<h2 id=\"wsl-ubuntuでの操作\">WSL Ubuntuでの操作</h2>\n\n<h3 id=\"linux-toolsのインストール-1\">linux-toolsのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">usbip</code>はWindows側でインストールしたusbipd-winに含まれているのでインストール不要。<br />\n別途aptでインストールしても使えるけど結構メンドクサイ。<br />\n使いたくなることもあるかもしれんので、手順は残しておく。</p>\n\n<blockquote>\n  <p>[!NOTE]</p>\n\n  <p>usbipが入っているパッケージをインストール</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div>  </div>\n  <p>usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>たぶんこんなメッセージが出る</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>WARNING: usbip not found for kernel 6.6.87.1-microsoft\n\n  You may need to install the following packages for this specific kernel:\n    linux-tools-6.6.87.1-microsoft-standard-WSL2\n    linux-cloud-tools-6.6.87.1-microsoft-standard-WSL2\n\n  You may also want to install one of the following packages to keep up to date:\n    linux-tools-standard-WSL2\n    linux-cloud-tools-standard-WSL2\n</code></pre></div>  </div>\n  <p>しかし、指定されたパッケージをインストールしようとしても「そんなもんはない」と怒られる。<br />\nしかたないのでゴマカシ。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /usr/lib/linux-tools\n\n<span class=\"nb\">ls</span> <span class=\"nt\">-la</span>\n合計 12\ndrwxr-xr-x  3 root root 4096  6月  6 13:11 <span class=\"nb\">.</span>\ndrwxr-xr-x 65 root root 4096  6月  6 13:11 ..\ndrwxr-xr-x  2 root root 4096  6月  6 13:11 6.8.0-60-generic    ← これを覚えておく\n</code></pre></div>  </div>\n  <p>isbipを実行した時のメッセージとlsしたときのディレクトリ名から以下のようなシンボリックリンクを作成する<br />\n(カーネルバージョンが変わると変更しないといけないので注意)</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ln</span> <span class=\"nt\">-s</span> 6.8.0-60-generic 6.6.87.1-microsoft-standard-WSL2\n</code></pre></div>  </div>\n\n  <p>再度usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>USAGEが表示されたらOK。<br />\nまたWARNINGが表示されたらシンボリックリンクの名前が間違っていると思うので、再確認。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nusbipコマンドへのpathを設定してもsudoで実行するときは無効なので、設定せずfullpathで指定する</p>\n</blockquote>\n\n<h3 id=\"アタッチ可能なバス番号を調べる\">アタッチ可能なバス番号を調べる</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip list <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫\n</code></pre></div></div>\n<p>こんな感じで表示される(BUSIDは例。以下同じ)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Exportable USB devices\n======================\n - ≪UbuntuPCのIPアドレス≫\n       3-11: Elecom Co., Ltd : unknown product (056e:700a)\n           : /sys/devices/pci0000:00/0000:00:14.0/usb3/3-11\n           : Miscellaneous Device / ? / Interface Association (ef/02/01)\n</code></pre></div></div>\n<h3 id=\"アタッチする\">アタッチする</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip attach <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫ <span class=\"nt\">--busid</span> 3-11\n</code></pre></div></div>\n\n<h3 id=\"確認\">確認</h3>\n<p>アタッチできたか確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 001 Device 003: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>前と同様にguvcviewを実行してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示され、画像が表示される。<br />\nそれなりに大きなサイズに切り替えても表示できている。</p>\n\n<h3 id=\"後片付け\">後片付け</h3>\n<p>usbipのポートの確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip port\n</code></pre></div></div>\n<p>こんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Imported USB devices\n====================\nPort 00: <Port in Use> at High Speed(480Mbps)\n       Elecom Co., Ltd : unknown product (056e:700a)\n       1-1 -> unknown host, remote port and remote busid\n           -> remote bus/dev 003/006\n</code></pre></div></div>\n<p>ポートは0であることが分かる。</p>\n\n<p>デタッチする</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo /mnt/c/Program\\ Files/usbipd-win/WSL/usbip detach --port 0\n</code></pre></div></div>\n\n<h3 id=\"まとめ\">まとめ</h3>\n<p>ということで、どうも、USBIPD-WINの転送速度が遅いようだ。</p>\n\n<h1 id=\"bluetoothを使ってみる\">Bluetoothを使ってみる</h1>\n<p>カメラはビミョーな結果だったので、今度はBluetoothで試してみる。\n使用したのは Buffalo BSBT4D09BK(4.0+EDR/LEのアダプタ、中身はCSR製)。<br />\nこれも結構古いのでもう売ってない。  中身がCSRのアダプタなら動く可能性高い。<br />\nRealtekのも使えそうだけど、試してないのでなんとも…</p>\n\n<h2 id=\"ubuntu側の準備-2\">Ubuntu側の準備</h2>\n<p>今回はBluetoothなのでBluetooth関連のライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>bluez\n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-2\">Windows側の準備</h2>\n<p>USBipd-win</p>\n\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行-1\">Ubuntu側の実行</h2>\n\n<h3 id=\"usb機器が割り当てられたことを確認する\">USB機器が割り当てられたことを確認する。</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 003: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)\n</code></pre></div></div>\n\n<h3 id=\"動かしてみる\">動かしてみる</h3>\n<p>ローカルデバイスの一覧表示をしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>hcitool dev\n</code></pre></div></div>\n<p>例えばこんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Devices:\n        hci0    XX:XX:XX:XX:XX:XX\n</code></pre></div></div>\n\n<p>スキャンしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bluetoothctl\n</code></pre></div></div>\n<p>bluetoothctlが起動され、プロンプトが<code class=\"language-plaintext highlighter-rouge\">[bluetooth]#</code>になる。<br />\nスキャンしてデバイス一覧を見てみる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>scan on\n≪スキャンされたデバイスが表示される≫\n≪しばらく待つ≫\nscan off\n≪表示が止まる≫\n\nlist\n≪スキャンされたデバイスが表示される≫\n\nexit\n≪終了してshellに戻る≫\n</code></pre></div></div>\n\n<h3 id=\"pythonで動かしてみる\">pythonで動かしてみる。</h3>\n<p>pyenvでpythonをインストールする場合は\n<a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a>\n の注意書きにあるように、コンパイル前に以下を実行しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<p>新しくプログラム作るのは面倒なので以前作った <br />\n<a href=\"/memoBlog/2025/04/21/Buildozer_3.html\" target=\"_blank\">AndroidでpythonでBLE</a> <br />\nを実行してみる。</p>\n\n<p>必要なモジュール類をインストールして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libmtdev-dev\npip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<p>実行</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">python</span> <span class=\"n\">kivy_ble</span><span class=\"p\">.</span><span class=\"n\">py</span>\n</code></pre></div></div>\n\n<p>動いた。メデタシメデタシ。</p>\n\n<h2 id=\"windows側の後始末-1\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n<p>USB接続のSDカードリーダを使えばRaspberryPiのブート用SDカードをWSLにマウントして操作することも可能なはず。<br />\nメンドクサくなってきたので試すのはやめておくけど。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2 メモ(改訂版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2 メモ(改訂版)</h1>\n      <p>WSL2のディストリビューションインストール~初期設定に関するメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"インストール\">インストール</h1>\n<p>WSL自体はインストール済みとします。<br />\n(インストール方法はぐぐってちょ)</p>\n\n<p>ディストリビューションのインストールはコマンドプロンプト等で行います。</p>\n\n<h2 id=\"インストール可能なディストリビューション\">インストール可能なディストリビューション</h2>\n<p>オンラインでインストールできるディストリビューションの一覧は以下で表示できます。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--online</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"新しいディストリビューションのインストール\">新しいディストリビューションのインストール</h2>\n<p>表示されたディストリビューションからインストールしたいディストリビューションを選んでインストールします。<br />\n以下は Ubuntu-24.04 をインストールする例。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--install</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>インストールが終了したら自動的にディストリビューションが起動してユーザアカウントとパスワードの設定が行われますので、\n使用したいユーザ名とパスワードを設定してください。</p>\n\n<h1 id=\"セットアップ\">セットアップ</h1>\n\n<p>引き続きセットアップを行います。</p>\n\n<h2 id=\"アップデート\">アップデート</h2>\n<p>まずはアップデート</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nubuntu 24.04以降なら<code class=\"language-plaintext highlighter-rouge\">sudo apt -U upgrade</code> でもOK。</p>\n</blockquote>\n\n<h2 id=\"日本語化\">日本語化</h2>\n<p>日本語化のため、以下のインストール/設定を行います。</p>\n\n<ul>\n  <li>日本語ランゲージパックのインストール</li>\n  <li>ロケールの設定</li>\n  <li>日本語manページのインストール</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>language-pack-ja <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>update-locale <span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF8 <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>manpages-ja manpages-ja-dev \n</code></pre></div></div>\n\n<h2 id=\"クローンしたあとのデフォルトユーザを設定\">クローンしたあとのデフォルトユーザを設定</h2>\n\n<p>クローンした環境ではデフォルトでrootでログインしてしまうので、<br />\n現在のユーザをデフォルトユーザに設定しておきます。<br />\n(マスタで設定しておけば、クローンする毎に設定しなくて済むので)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span>  /etc/wsl.conf <span class=\"o\"><<</span> <span class=\"no\">__EOF__</span><span class=\"sh\">\n\n[user]\ndefault=</span><span class=\"nv\">$USER</span><span class=\"sh\">\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nPATHにWindowsのPATHを引き継がせない設定<br />\n仮想マシン起動語、PATHにWindows環境のPATHが引き継がれます。<br />\nWindows環境のPATHを引き継がせないようにすることもできます。</p>\n\n  <p>設定方法は <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に 以下の設定を追加します。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>interop]\nappendWindowsPath <span class=\"o\">=</span> <span class=\"nb\">false</span>\n</code></pre></div>  </div>\n\n  <p>参考: <a href=\"https://zenn.dev/o2z/articles/zenn-20210524-01\" target=\"_blank\">WSL2でWindowsのPATH設定が引き継がれるのを解除する</a></p>\n\n  <p>なお、下の .bashrcの設定 ではWindowsのPATHを引き継いだうえで、\nWINDOWSディレクトリ下、VS Code格納ディレクトリ下以外のPATHを削除して不要なPATHを残さないようにしています。</p>\n</blockquote>\n\n<h2 id=\"ミニミニスクリプト\">ミニミニスクリプト</h2>\n<p>ちょっとした不便を解消するミニミニスクリプトを作成しておきます。</p>\n\n<p>以下はExplorerと秀丸をシンボリックリンクでも実体を追いかけて開いてくれるスクリプト</p>\n\n<blockquote>\n  <p>[!NOTE]\nたとえば、<code class=\"language-plaintext highlighter-rouge\">explorer.exe /lib</code>と実行するとエクスプローラでは<code class=\"language-plaintext highlighter-rouge\">/lib</code>を開けません。<br />\n以下のスクリプトを作成した後、<code class=\"language-plaintext highlighter-rouge\">explorer /lib</code>と実行すると\n<code class=\"language-plaintext highlighter-rouge\">/lib</code>の実体である<code class=\"language-plaintext highlighter-rouge\">/usr/lib</code>が開かれます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">~/bin</code>にpathを通すには、作成後再ログイン必要。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> ~/bin\n\n<span class=\"nb\">tee</span> <span class=\"nt\">-a</span>  ~/bin/explorer <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n#!/usr/bin/env bash\n/mnt/c/WINDOWS/explorer.exe </span><span class=\"si\">$(</span>wslpath <span class=\"nt\">-w</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"sh\">\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">tee</span> <span class=\"nt\">-a</span>  ~/bin/hidemaru <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n#!/usr/bin/env bash\nEDITOR=\"/mnt/c/Program Files (x86)/Hidemaru/Hidemaru.exe\"\n\"</span><span class=\"k\">${</span><span class=\"nv\">EDITOR</span><span class=\"k\">}</span><span class=\"sh\">\" </span><span class=\"si\">$(</span>wslpath <span class=\"nt\">-w</span> <span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"sh\">&\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">chmod</span> +x ~/bin/<span class=\"k\">*</span>\n</code></pre></div></div>\n\n<h2 id=\"bashrcの設定\">.bashrcの設定</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に必要な変更/追加を行います。<br />\n以下は私の好みの設定なので、好みに合わせて変更してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.bashrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\n\n\n# プロンプトの設定\n# PS1=\"</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\nPS1=\"</span><span class=\"se\">\\[\\e</span><span class=\"sh\">[36m</span><span class=\"se\">\\]</span><span class=\"nv\">$WSL_DISTRO_NAME</span><span class=\"se\">\\[\\e</span><span class=\"sh\">[0m</span><span class=\"se\">\\]</span><span class=\"sh\">:</span><span class=\"se\">\\w\\$</span><span class=\"sh\"> \"\n\n# キーバインドの設定\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-n\": history-search-forward'\nbind '\"</span><span class=\"se\">\\C</span><span class=\"sh\">-p\": history-search-backward'\n\n# ディレクトリスタックの表示改善\nfunction pushd() {\n    command pushd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction popd() {\n    command popd </span><span class=\"nv\">$*</span><span class=\"sh\"> > /dev/null\n    command dirs -v\n}\nfunction dirs() {\n    command dirs -v\n}\n\n# 表示色変更\nexport LS_COLORS='di=01;32:ln=01;36:ex=01;31:'\nexport GREP_COLORS='mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'\n\n# lessのオプション\nexport LESS=\"-iMRq\"\n\n# grepのオプション指定(GREP_OPTIONS)は廃止されたのでaliasで設定\n# export GREP_OPTIONS=\"--exclude-dir .git\"\nalias grep='grep --exclude-dir .git'\n\n# WindowsのPATHのうち、\"WINDOWS\"を含むディレクトリ、\"VS Code\"を含むディレクトリ以外を削除\nexport PATH=</span><span class=\"si\">$(</span><span class=\"nb\">echo</span> <span class=\"nv\">$PATH</span> | python3 <span class=\"nt\">-c</span> <span class=\"s1\">'import re,sys;PPP=sys.stdin.readline();print(\":\".join([a for a in PPP.split(\":\") if re.match(r\"^(?!\\/mnt)\", a) or re.match(r\"(^/mnt.*WINDOWS.*$|^/mnt.*VS Code.*$)\", a)]))'</span><span class=\"si\">)</span><span class=\"sh\">\n\n# for pyenv\nexport PYENV_ROOT=/proj/.pyenv    #環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$PYENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    # 仮想環境名をプロンプトに表示しない場合は以下を有効化\n    # export VIRTUAL_ENV_DISABLE_PROMPT=1\n    eval \"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"sh\">\"          # pyenv 2.0以降で必要\n    eval \"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"sh\">\"\n    eval \"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"sh\">\"\n    export PYTHON_CONFIGURE_OPTS=\"</span><span class=\"se\">\\</span><span class=\"sh\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"sh\">\n    \"\nfi\n\n# for nodenv\nexport NODENV_ROOT=/proj/.nodenv    # 環境に合わせて修正してね\nif [ -e </span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\"> ]; then\n    export PATH=</span><span class=\"nv\">$NODENV_ROOT</span><span class=\"sh\">/bin:</span><span class=\"nv\">$PATH</span><span class=\"sh\">\n    eval \"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"sh\">\"\nfi\n\n# __pycache__ディレクトリの生成を抑制する\nexport PYTHONDONTWRITEBYTECODE=1\n\n<< '__COMMENT__'\n# この部分はミラーモードでは使えないし、WSLgサポートされたので特に必要ないのでコメントアウト\n# NATモードでは使えるが、hostコマンドインストール必要。(sudo apt install bind9-host)\n# HOSTのIPアドレス取得\n# export HOST_IP_ADDR=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span><span class=\"si\">)</span><span class=\"sh\">\n# HOSTのIPアドレス取得(アドレスが2つ以上返ってきたときは1個目だけ取り出す)\nexport HOST_IP_ADDR=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-n</span> 1p<span class=\"si\">)</span><span class=\"sh\">\n\n# DISPLAY変数が未定義(SSHログイン等)ならDISPLAYを設定する\nif [ -v </span><span class=\"nv\">$DISPLAY</span><span class=\"sh\"> ]; then\n    export DISPLAY=</span><span class=\"k\">${</span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"k\">}</span><span class=\"sh\">:0.0\nfi\necho DISPLAY=\"</span><span class=\"nv\">$DISPLAY</span><span class=\"sh\">\"\n__COMMENT__\n\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<p>変更した内容を有効にするには、再ログインするか、<code class=\"language-plaintext highlighter-rouge\">source ~/.bashrc</code>してください。</p>\n\n<h2 id=\"readlinebash等の設定\">readline(bash等)の設定</h2>\n\n<ul>\n  <li>beepを鳴らさない設定</li>\n  <li>ブラケットペーストモードを無効化する設定(コメントアウト)<br />\n無効化したければ<code class=\"language-plaintext highlighter-rouge\">enable-bracketed-paste</code> の行を有効にします</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalではブラケットペーストモードを無効にすると確認ダイアログでチェックできるようになりますが、\nブラケットペーストモードを有効にすると確認ダイアログは出ず入力欄で確認できるようになります。<br />\nTeraterm のように二重チェックにならないので有効にしてもストレスは少ないと思い無効にしていません。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo tee</span> <span class=\"nt\">-a</span>  /etc/inputrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\nset bell-style visible\n# set enable-bracketed-paste off\n</span><span class=\"no\">__EOF__\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalの場合、beepを鳴らさない設定は <br />\n設定→各仮想環境の設定画面→詳細設定→ベル通知スタイル<br />\nからも変更できる。</p>\n</blockquote>\n\n<h2 id=\"vimの設定\">vimの設定</h2>\n\n<p>私はシンプルな1色表示が好きなのでsyntax highlightを無効にしておきます。<br />\nまた、<code class=\"language-plaintext highlighter-rouge\">sudo vi</code>実行時にも同じように動作するように、<code class=\"language-plaintext highlighter-rouge\">/root</code>にもコピーしておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">/etc/vim/vimrc</code>または<code class=\"language-plaintext highlighter-rouge\">/etc/vim/vimrc.local</code>に記述するとシステム全体で有効なはずですが、\nなぜかうまくいかないので自分とrootの設定を書き換えておきます。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">tee</span> <span class=\"nt\">-a</span> ~/.vimrc <span class=\"o\"><<</span> <span class=\"sh\">'</span><span class=\"no\">__EOF__</span><span class=\"sh\">'\nsyntax off\n</span><span class=\"no\">__EOF__\n\n</span><span class=\"nb\">sudo cp</span> ~/.vimrc /root/\n\n</code></pre></div></div>\n\n<h2 id=\"一旦リブート\">一旦リブート</h2>\n\n<p>ここまでの設定を反映するため、念のためリブートしておきます。</p>\n\n<p>まず、ディストリビューションを停止します。<br />\n<code class=\"language-plaintext highlighter-rouge\">exit</code>コマンドやCTRL-Dでシェルを終了します。<br />\nこれだけではディストリビューションは終了していません。<br />\n(<code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>で「Running」になっている)<br />\nコマンドプロンプト等から以下のコマンドでディストリビューションを終了します。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>で「Stopped」になっていることを確認し、再度ディストリビューションを起動します。<br />\nこのとき、既に実行中のWindowsTerminalのドロップダウンメニューには新しいディストリビューションは表示されません。<br />\nあたらしくWindowsTerminalを開くとそのウィンドウのドロップダウンメニューには表示されますので、そこから実行します。</p>\n\n<p>引き続きセットアップを行います。</p>\n\n<h2 id=\"ワークディレクトリの作成\">ワークディレクトリの作成</h2>\n\n<p>ホームに色々置くのが嫌いなので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo chown</span> <span class=\"nv\">$USER</span>:<span class=\"nv\">$USER</span> /proj /work\n</code></pre></div></div>\n\n<h2 id=\"デフォルトshをbashに変更\">デフォルトshをbashに変更</h2>\n\n<p>なんとなくいつも変更してるので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /usr/bin <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh <span class=\"o\">&&</span> <span class=\"se\">\\</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<h2 id=\"ツール類インストール\">ツール類インストール</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ifconfig</code>とか<code class=\"language-plaintext highlighter-rouge\">route</code>とかを使いたいので。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n\n<h3 id=\"必要なツール類をインストール\">必要なツール類をインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev <span class=\"se\">\\</span>\n                    libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\n                    xz-utils tk-dev libffi-dev liblzma-dev python3-openssl git\n</code></pre></div></div>\n\n<h3 id=\"pyenvのインストール-1\">pyenvのインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/yyuu/pyenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span> <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv  <span class=\"o\">&&</span> <span class=\"se\">\\</span>\ngit clone https://github.com/pyenv/pyenv-update.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div></div>\n\n<p>pyenvを有効にするため、再ログイン(.bashrcに必要な処理は記載済み)。</p>\n\n<h3 id=\"pythonのインストール\">pythonのインストール</h3>\n\n<p>使いたいpythonのバージョンはそのシチュエーションで変わるので、<br />\nインストールするのはマスタからクローンした環境で行う方がいいかも。</p>\n\n<h4 id=\"インストール可能なバージョンを確認\">インストール可能なバージョンを確認</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install</span> <span class=\"nt\">--list</span> | less\n</code></pre></div></div>\n\n<h4 id=\"インストール-1\">インストール</h4>\n\n<p>インストールが終わったらpip他をアップデートしておく。<br />\n(「pip 古いでぇ~」とうるさいので言われる前にやっとく)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.12.4\npyenv shell 3.12.4\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h1 id=\"仮想環境の複製\">仮想環境の複製</h1>\n\n<p>それまでの状態を保持した状態で新しい仮想環境を作成できます。<br />\n今までは一旦tarファイルにエクスポートしてからインポートしていましたが、\nvhdxファイルから直接インポートできるようになりました。</p>\n\n<h2 id=\"仮想hddファイルvhdxを探す\">仮想HDDファイル(.vhdx)を探す</h2>\n<p>インストールしたディストリビューションを含む各仮想環境の名前とパスの一覧は\n以下をコマンドプロンプト等で実行すると表示できる。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">reg</span><span class=\"w\"> </span><span class=\"nx\">query</span><span class=\"w\"> </span><span class=\"nx\">HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Lxss</span><span class=\"w\"> </span><span class=\"nx\">/s</span><span class=\"w\"> </span><span class=\"err\">^</span><span class=\"w\">\n</span><span class=\"o\">|</span><span class=\"w\"> </span><span class=\"n\">findstr</span><span class=\"w\"> </span><span class=\"s2\">\"BasePath DistributionName HKEY_CURRENT_USER\"</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n1行目末の<code class=\"language-plaintext highlighter-rouge\">^</code>は次行に続くことを示す。linuxの<code class=\"language-plaintext highlighter-rouge\">\\</code>と同じ</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">HKEY_CURRENT_USER</code>を検索しているのは区切り位置を見やすくするため</p>\n</blockquote>\n\n<h2 id=\"仮想環境をクローンする\">仮想環境をクローンする</h2>\n\n<p>クローンする仮想環境を停止する</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>確認(Stoppedになっていることを確認)</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\"> </span><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">-l</span><span class=\"w\"> </span><span class=\"nt\">-v</span><span class=\"w\">\n</span><span class=\"err\">・・・・・</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"仮想環境をクローンする-1\">仮想環境をクローンする</h2>\n<p>クローン先に移動しておく</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">cd</span><span class=\"w\"> </span><span class=\"nx\">F:\\WSL_VMs</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>クローンを作成するには以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"err\">≪クローンの名前≫</span><span class=\"w\"> </span><span class=\"err\">≪クローンの保存先≫</span><span class=\"w\"> </span><span class=\"err\">≪クローン元の</span><span class=\"nx\">vhdx</span><span class=\"err\">ファイル≫</span><span class=\"w\"> </span><span class=\"nt\">--vhd</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>例えば、</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04-temp1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">\\Ubuntu-24.04-temp1</span><span class=\"w\"> </span><span class=\"o\">%</span><span class=\"nx\">LOCALAPPDATA</span><span class=\"o\">%</span><span class=\"nx\">\\Packages\\CanonicalGroupLimited.Ubuntu24.04LTS_79rhkp1fndgsc\\LocalState\\\\ext4.vhdx</span><span class=\"w\"> </span><span class=\"nt\">--vhd</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>クローンが完了したらクローンした仮想環境を実行します。</p>\n\n<h3 id=\"削除\">削除</h3>\n<p>不要になった仮想環境は削除する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"err\">«削除する仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-24.04-2</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h1 id=\"wsl2上のサーバプログラムへのアクセス\">WSL2上のサーバプログラムへのアクセス</h1>\n<p>参考:<a href=\"https://www.atmarkit.co.jp/ait/articles/1909/09/news020.html\" target=\"_blank\">Linuxがほぼそのまま動くようになった「WSL2」のネットワーク機能</a></p>\n\n<table>\n  <thead>\n    <tr>\n      <th>向き</th>\n      <th>可否</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>HOST → WSL2</td>\n      <td>localhost でアクセスできる</td>\n    </tr>\n    <tr>\n      <td>WSL2 → HOST</td>\n      <td>localhost でアクセスできない。<br /> IPアドレス指定ならアクセスできる。</td>\n    </tr>\n  </tbody>\n</table>\n\n<p>Windows11の場合は、ネットワークをミラーモードに設定するとどちらもlocalhostでアクセスできます。<br />\nそれどころか、外部PCからWSLの仮想環境内に直接アクセスできます。<br />\nただし、ポート番号はWindows、各仮想環境で共通で使用されるので、\n他で使用していないポート番号を使用しなければなりません。<br />\nミラーモードに設定するには、<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%\\.wslconfig</code> に以下のように設定します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[wsl2]\nnetworkingMode=mirrored\n</code></pre></div></div>\n<p>参考:<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/networking#mirrored-mode-networking\" target=\"_blank\">WSL を使用したネットワーク アプリケーションへのアクセス/ミラー モードのネットワーク</a></p>\n\n<h1 id=\"virtualboxとの共存\">Virtualboxとの共存</h1>\n\n<p>参考:<a href=\"https://zenn.dev/yuni_hutsuka/articles/46923a0b345619\" target=\"_blank\">【REPORT】Ubuntu Desktop on VirtualBox と wsl2 の共存</a></p>\n\n<p>要は「Windows ハイパーバイザープラットフォームを有効化する」だけど、設定箇所にたどり着くのがメンドクサイので\n上の参考サイトを見てね。</p>\n\n<h1 id=\"なんかのときに使うかも\">なんかのときに使うかも</h1>\n\n<h2 id=\"仮想ディスクが肥大化した場合の対処方法\">仮想ディスクが肥大化した場合の対処方法</h2>\n<p><del><a href=\"https://qiita.com/386jp/items/e469333c5a74789db46d\" target=\"_blank\">WSL2を使っているパソコンのディスク容量が枯渇したときにやってみるべきこと</a></del><br />\nこっちの方が分かりやすかった。<br />\n<a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1271vhdexpcmd/vhdexpcmd.html\" target=\"_blank\">仮想ディスクをコマンドラインから拡大/縮小する</a></p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>PS: XXXX> diskpart                                                 ← コマンド起動\n\nMicrosoft DiskPart バージョン 10.0.19041.964\n\nCopyright (C) Microsoft Corporation.\nコンピューター: XXXXXX\n\nDISKPART> select vdisk file=\"f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\" ← 圧縮したいvhdxファイル\n\nDiskPart により、仮想ディスク ファイルが選択されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   20 GB\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART> compact vdisk                                            ← 縮小の実行\n\n  100% 完了しました                       ← ちょっと時間がかかる\n\nDiskPart により、仮想ディスク ファイルは正常に圧縮されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   12 GB                      ← 小さくなった\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART>exit                                                      ← 終了\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSBデバイスを使う(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSBデバイスを使う(その3)</h1>\n      <p>WSLでUSBデバイスを使う(その3:USBカメラ編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>で\nWSLカーネル v6.6.36.3 をビルドしたのでもうv5.15.153は使わなくて良くなったのですが、\nやっぱりカーネル入れ替えずにUSBカメラ使いたい衝動にかられ、手順をまとめてみました。<br />\n(その2でUSBストレージ編を書こうと思っていたので、その2は欠番、その3になりました)</p>\n\n<p>参考:<br />\n<a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a><br />\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a></p>\n\n<h1 id=\"開発環境の準備\">開発環境の準備</h1>\n<p>開発環境の準備については、\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>\nの「Linuxカーネルのビルド環境の構築」を参照してください。</p>\n\n<h1 id=\"カーネルモジュールのビルド\">カーネルモジュールのビルド</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<p>たとえば、以下。 どこでも良いけど、以下の手順はこのディレクトリで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /proj/wsl_kernel <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /proj/wsl_kernel\n</code></pre></div></div>\n\n<h2 id=\"カーネルソースの取得\">カーネルソースの取得</h2>\n<p>作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)にカーネルソースをダウンロードします。<br />\ngitリポジトリをcloneするか、リリースソースをダウンロードして展開します。</p>\n\n<h3 id=\"gitでcloneする場合\">gitでcloneする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/microsoft/WSL2-Linux-Kernel.git\n\n<span class=\"c\"># 目的のタグをチェックアウト</span>\ngit <span class=\"nt\">-C</span> WSL2-Linux-Kernel checkout <span class=\"nt\">-b</span> WSL-5.15.153.1 refs/tags/linux-msft-wsl-5.15.153.1\n\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> WSL2-Linux-Kernel linux\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nclone済みなら念のため<code class=\"language-plaintext highlighter-rouge\">git pull</code>して最新状態にしておく</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nブランチ作る必要ないけど、念のため。</p>\n</blockquote>\n\n<h3 id=\"リリースソースzipをダウンロードする場合\">リリースソース(zip)をダウンロードする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-5.15.153.1.zip\nunzip linux-msft-wsl-5.15.153.1.zip\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> linux-msft-wsl-5.15.153.1 linux\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nunzipはデフォルトではインストールされていないのでインストール必要。</p>\n</blockquote>\n\n<h2 id=\"スクリプトdockerfileの入手\">スクリプト&Dockerfileの入手</h2>\n<blockquote>\n  <p>[!NOTE]\nGistに必要なスクリプト&<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>を置いておいたので以下のページの<code class=\"language-plaintext highlighter-rouge\">DownloadZIP</code>ボタンからダウンロードして\n作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)に展開してください。<br />\n<a href=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021\" target=\"_blank\">Gist:WSLカーネルビルド環境</a></p>\n\n  <p>または以下のコマンドで取得できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021/archive/main.zip\nunzip <span class=\"nt\">-j</span> main.zip\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージを作成起動確認\">Dockerイメージを作成~起動確認</h2>\n<p>Dockerイメージを作成~起動確認は\n<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>\nのDockerイメージを作成~起動確認 を参照してください。<br />\n作成済みならスキップしてください。</p>\n\n<h2 id=\"カーネルモジュールのビルド-1\">カーネルモジュールのビルド</h2>\n\n<p>カーネルソースの取得、Dockeイメージのビルドが終わったら、以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_multimedia.sh\n</code></pre></div></div>\n\n<p>実行には数十分~1時間程度かかります(PCのスペックによる)。</p>\n\n<p>実行完了後、<code class=\"language-plaintext highlighter-rouge\">out</code>ディレクトリに<code class=\"language-plaintext highlighter-rouge\">linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb</code>ができます。<br />\nこれを使用するディストリビューションから見えるフォルダ(ディストリビューション内でなくWindowsのディレクトリでも可)にコピーします。</p>\n\n<h3 id=\"カーネルビルド用スクリプト\">カーネルビルド用スクリプト</h3>\n\n<p>用意したスクリプトの概要は以下の通りです。</p>\n\n<h4 id=\"build_functionssh\">build_functions.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_functions.sh</code>はビルドに関わる処理を関数化したものをまとめたファイルです。<br />\n以下のスクリプトからインクルードして使用します。</p>\n\n<p>Dockerコンテナを使用するので、あらかじめDockerイメージを作成しておく必要があります。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_functions.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_multimediash\">build_wsl_multimedia.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_multimedia.sh</code>はマルチメディア関連のカーネルモジュールのビルドを行います。<br />\n<code class=\"language-plaintext highlighter-rouge\">build_wsl_usb-storage.sh</code>の<code class=\"language-plaintext highlighter-rouge\">ADD_CONFIG</code>変数の設定値を変更しただけです。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_multimedia.sh\"></script>\n</dev>\n\n<p>その他は<a href=\"/memoBlog/2024/07/11/wsl_kernel_build.html\" target=\"_blank\">WSLのカーネルをビルドする</a>を参照してください。</p>\n\n<h1 id=\"実行環境の準備\">実行環境の準備</h1>\n<p>実行環境の準備は <a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a>\nと同じです。<br />\n使用するUSBデバイスがUSBカメラに変わるだけです。</p>\n\n<h2 id=\"実行ディストリビューションの準備\">実行ディストリビューションの準備</h2>\n\n<p>デフォルト状態ではカーネルモジュールのインストール先(<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/</code>)が書き込みできないので、\noverlayfsで書き込みできるファイルシステムをマウントします。</p>\n\n<p>まず、マウントする(実際に書き込むための)ディレクトリを用意します。<br />\nupperとworkの2つが必要です。workにはなにも書き込まないでください。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> /modules_overlay/upper/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n<span class=\"nb\">sudo mkdir</span> <span class=\"nt\">-p</span> /modules_overlay/work/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n</code></pre></div></div>\n\n<p>次にお試しマウントしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>mount <span class=\"nt\">-t</span> overlay overlay <span class=\"nt\">-o</span> <span class=\"se\">\\</span>\n    <span class=\"nv\">lowerdir</span><span class=\"o\">=</span>/usr/lib/modules/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>,<span class=\"se\">\\</span>\n    <span class=\"nv\">upperdir</span><span class=\"o\">=</span>/modules_overlay/upper/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>,<span class=\"se\">\\</span>\n    <span class=\"nv\">workdir</span><span class=\"o\">=</span>/modules_overlay/work/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span> <span class=\"se\">\\</span>\n    /usr/lib/modules/<span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n</code></pre></div></div>\n\n<p>マウントできたか確認するため、ファイルを作成してみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo </span>hogehoge | <span class=\"nb\">sudo tee</span> /usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt</code>が出来ていること(内容が正しいこと)と、\n<code class=\"language-plaintext highlighter-rouge\">/modules_overlay/upper/5.15.153.1-microsoft-standard-WSL2/test.txt</code>に同じファイルがあることを確認します。</p>\n\n<p>終わったら削除しておきましょう。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo rm</span> /usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt\n</code></pre></div></div>\n\n<p>再起動したときに自動的にマウントされるように、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に先ほどのマウントコマンドを\n<code class=\"language-plaintext highlighter-rouge\">command=</code>に指定します。<br />\n以下は書き込んだ後の<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>の例。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\ncommand=mount -t overlay overlay -o \\\n    lowerdir=/usr/lib/modules/$(uname -r),\\\n    upperdir=/modules_overlay/upper/$(uname -r),\\\n    workdir=/modules_overlay/work/$(uname -r) \\\n    /usr/lib/modules/$(uname -r)\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>が正常に変更できたか確認するにはWSLの再起動が必要です(ウィンドウ閉じただけではダメ)。</p>\n\n<h2 id=\"カーネルモジュールのインストール\">カーネルモジュールのインストール</h2>\n\n<p>先ほど作成した<code class=\"language-plaintext highlighter-rouge\">linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb</code>を使用して\n以下のように実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb\n</code></pre></div></div>\n\n<h1 id=\"usbカメラを繋いでみる\">USBカメラを繋いでみる</h1>\n\n<p>実行手順は\n実行環境の準備は <a href=\"/memoBlog/2024/07/03/wsl_usb_1.html\" target=\"_blank\">WSLでUSBデバイスを使う(その1)</a>\nの「USB-Serialデバイスを接続」を参照してください。</p>\n\n<p>USBカメラのを接続したときのログはこんな感じ</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[22183.171276] vhci_hcd vhci_hcd.0: pdev(0) rhport(0) sockfd(3)\n[22183.171281] vhci_hcd vhci_hcd.0: devid(196610) speed(3) speed_str(high-speed)\n[22183.171334] vhci_hcd vhci_hcd.0: Device attached\n[22183.550422] usb 1-1: new high-speed USB device number 3 using vhci_hcd\n[22183.700457] usb 1-1: SetAddress Request (3) to port 0\n[22183.786408] usb 1-1: New USB device found, idVendor=056e, idProduct=700a, bcdDevice= 1.00\n[22183.786412] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0\n[22183.786414] usb 1-1: Product: Venus USB2.0 Camera\n[22183.786416] usb 1-1: Manufacturer: Vimicro Corp.\n[22183.799190] usb 1-1: Found UVC 1.00 device Venus USB2.0 Camera (056e:700a)\n[22183.844401] input: Venus USB2.0 Camera: Venus USB2 as /devices/platform/vhci_hcd.0/usb1/1-1/1-1:1.0/input/input1\n</code></pre></div></div>\n\n<h2 id=\"画出し確認\">画出し確認</h2>\n\n<p>pythonのopwnCVでもguvcviewでもお好きな方でどうぞ。</p>\n\n<p>データ転送帯域が足りなくて画像が表示できない場合は、解像度を落としたり、\nフォーマットをYUYV等からMKPEGに変更したりしてデータ量を少なくして試してみてください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLのカーネルをビルドする</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLのカーネルをビルドする</h1>\n      <p>WSLのカーネルをビルドする手順(Docker使用)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLでUSBストレージ(USBメモリなど)を使う方法を書こうと手順をまとめている間に、カーネル v6.6.36.3 がリリースされてしまいました。<br />\nこのバージョンは自前でビルドしなくてもUSBストレージ関連のドライバが入っています(Builtinモジュールではなくロードモジュールとして)。<br />\nで、バイナリリリースされてしまえば何もしなくてもUSBストレージが使えるようになる(ハズ)ですが、\n今日の段階はまだバイナリリリースされてないので自前でビルドしてみることにしました。<br />\n以下はその時のメモ。<br />\nで、手順は以下のサイトのDockerを使用して開発環境を構築する方法を <del>パクった</del>  参考にしました。<br />\n(もともとカーネル差し替えずにドライバ組み込む手順を調べてて参考にしたサイト)</p>\n\n<p>参照:<a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">カーネルモジュールのビルドと使用</a></p>\n\n<h1 id=\"準備の準備\">準備の準備</h1>\n\n<h2 id=\"wslディストリビューションでsystemdの有効化\">WSLディストリビューションでsystemdの有効化</h2>\n\n<p>systemdの方がDockerのサービスの操作とかやりやすい(情報が多い?)のでsystemdを有効化しておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストールしたタイミングによっては既に有効化されているかも。</p>\n</blockquote>\n\n<p> \n使用するディストリビューションを起動し、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下の設定を行います。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdを有効にするか否かはディストリビューション毎の設定</p>\n</blockquote>\n\n<p>設定後、WSLをシャットダウン(コマンドプロンプト等から<code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行)し、<br />\n再度ディストリビューションを起動します。</p>\n\n<p>参考:<a href=\"https://qiita.com/curacao/items/fb9adaf1c097b1acd6a8\" target=\"_blank\">WSL2でsystemctlを使う方法</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdが動作しているか確認するには、<code class=\"language-plaintext highlighter-rouge\">systemctl is-system-running</code> を実行します。<br />\n<code class=\"language-plaintext highlighter-rouge\">running</code>(起動中) <code class=\"language-plaintext highlighter-rouge\">degraded</code>(起動中だが失敗したサービスなどが存在) と表示されれば動作しています。<br />\n<code class=\"language-plaintext highlighter-rouge\">offline</code> と表示されれば起動していません。<br />\nその他使い方についてはぐぐってちょ。</p>\n</blockquote>\n\n<h1 id=\"linuxカーネルのビルド環境の構築\">Linuxカーネルのビルド環境の構築</h1>\n\n<h2 id=\"dockerの準備\">Dockerの準備</h2>\n\n<p>コンパイル環境はDockerコンテナを使用するので、Dockerをインストールします。<br />\nWindows上で使用できるDocker Desktop for Windowsでも良いのですが、ディストリビューション上にDockerをインストールすることにします。</p>\n\n<blockquote>\n  <p>[!NOTE]\nDocker Desktop for Windows を使用する場合は「WSL統合」でDockerを統合したディストリビューションで作業することになるようです。<br />\n試してないから分からんけど….</p>\n</blockquote>\n\n<p>インストール方法は先人の知恵を拝借→<a href=\"https://zenn.dev/thyt_lab/articles/fee07c278fcaa8\" target=\"_blank\">WSL(Ubuntu)にDocker環境を構築する</a><br />\nこのページの通りに実行すればDockerがインストールできます。</p>\n\n<p>また、Dockerをsudoなしで実行できるように、dockerグループを追加しておきます。<br />\n追加しなくてもsudoで実行できますが、作成されたファイルのオーナーがrootになってしまって面倒なのでおススメしません。</p>\n\n<p>以下、私が実際に行ったコマンドです。上記サイトの手順ほとんどそのままです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># apt keyring ファイル格納ディレクトリを作成</span>\n<span class=\"nb\">sudo install</span> <span class=\"nt\">-m</span> 0755 <span class=\"nt\">-d</span> /etc/apt/keyrings\n\n<span class=\"c\"># 鍵ファイルの作成&リード属性付与</span>\ncurl <span class=\"nt\">-fsSL</span> https://download.docker.com/linux/ubuntu/gpg | <span class=\"nb\">sudo </span>gpg <span class=\"nt\">--dearmor</span> <span class=\"nt\">-o</span> /etc/apt/keyrings/docker.gpg\n<span class=\"nb\">sudo chmod </span>a+r /etc/apt/keyrings/docker.gpg\n\n<span class=\"c\"># aptリポジトリの追加</span>\n<span class=\"nb\">echo</span>   <span class=\"s2\">\"deb [arch=\"</span><span class=\"si\">$(</span>dpkg <span class=\"nt\">--print-architecture</span><span class=\"si\">)</span><span class=\"s2\">\" signed-by=/etc/apt/keyrings/docker.gpg] </span><span class=\"se\">\\</span><span class=\"s2\">\n        https://download.docker.com/linux/ubuntu </span><span class=\"se\">\\</span><span class=\"s2\">\n        \"</span><span class=\"si\">$(</span><span class=\"nb\">.</span> /etc/os-release <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"s2\">\"</span><span class=\"nv\">$VERSION_CODENAME</span><span class=\"s2\">\"</span><span class=\"si\">)</span><span class=\"s2\">\" stable\"</span> <span class=\"se\">\\</span>\n        | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/docker.list\n\n<span class=\"c\"># 追加したリポジトリも含めてaptデータベースの更新</span>\n<span class=\"nb\">sudo </span>apt update\n\n<span class=\"c\"># Dockerのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n\n<span class=\"c\"># 自身にdockerグループを追加</span>\n<span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> docker\n</code></pre></div></div>\n\n<p>dockerグループの追加を有効にするため、<strong>ここで一旦ログアウトして再ログイン</strong></p>\n\n<p>dockerグループが追加されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">groups</span>\n</code></pre></div></div>\n\n<p>以下のようにdockerグループが追加されていればOK。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>XXXX adm cdrom <span class=\"nb\">sudo </span>dip plugdev lxd docker\n</code></pre></div></div>\n\n<h3 id=\"dockerのテスト\">Dockerのテスト</h3>\n\n<p>Dockerが正常にインストールできたか確認するため、hello-worldを実行します。<br />\n実行後、コンテナを削除するように<code class=\"language-plaintext highlighter-rouge\">--rm</code>オプションを指定。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">--rm</span> hello-world\n</code></pre></div></div>\n\n<p>以下のように表示されればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・・\nHello from Docker!\nThis message shows that your installation appears to be working correctly.\n・・・・\n</code></pre></div></div>\n\n<p>使用したhello-worldイメージはもう使わないので削除しておきます。</p>\n\n<p>まずコンテナが残ってないか確認します。<br />\n<code class=\"language-plaintext highlighter-rouge\">-a</code>をつけるのを忘れずに!</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n\n<p>以下のようにヘッダ行だけ表示されればコンテナは残っていません(OKです)。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nもしコンテナが残っていたら(rmオプション付け忘れなど)以下のように表示されます。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES\nae8523f06af4   hello-world   \"/hello\"   13 seconds ago   Exited (0) 10 seconds ago             romantic_booth\n</code></pre></div>  </div>\n  <p>この場合は以下のコマンドで削除します(CONTAINER IDやNAMEは上で表示されたものを使用)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CONTAINER ID で指定</span>\ndocker <span class=\"nb\">rm </span>ae8523f06af4\n<span class=\"c\"># または NAME で指定</span>\ndocker <span class=\"nb\">rm </span>romantic_booth\n</code></pre></div>  </div>\n</blockquote>\n\n<p>イメージを確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<p>結果はこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>REPOSITORY    TAG       IMAGE ID       CREATED         SIZE\nhello-world   latest    d2c94e258dcb   14 months ago   13.3kB\n</code></pre></div></div>\n\n<p>イメージを削除します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image <span class=\"nb\">rm </span>hello-world\n</code></pre></div></div>\n\n<p>結果はこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Untagged: hello-world:latest\nUntagged: hello-world@sha256:94323f3e5e09a8b9515d74337010375a456c909543e1ff1538f5116d38ab3989\nDeleted: sha256:d2c94e258dcb3c5ac2798d32e1249e42ef01cba4841c2234249495f87264ac5a\nDeleted: sha256:ac28800ec8bb38d5c35b49d45a6ac4777544941199075dff8c4eb63e093aa81e\n</code></pre></div></div>\n\n<p>削除されたことを確認します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<p>結果はこんな感じでヘッダ行だけ表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>REPOSITORY   TAG       IMAGE ID   CREATED   SIZE\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nカーネル入れ替えたり、なんやかんやしてるうちにDockerが起動しなくなることがありました。<br />\nそのときは <code class=\"language-plaintext highlighter-rouge\">systemctl status docker</code> を実行して <code class=\"language-plaintext highlighter-rouge\">Active</code>の表示を確認します。\n<code class=\"language-plaintext highlighter-rouge\">failed</code>になっていたら起動に失敗しています。<br />\n原因の調査方法はいろいろありますが、私が遭遇したパターンでは\n<code class=\"language-plaintext highlighter-rouge\">sudo dockerd --debug</code> を実行してエラーメッセージを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">networks have same bridge name</code> と出ている場合は\n<code class=\"language-plaintext highlighter-rouge\">/var/lib/docker/network</code>ディレクトリを消して(不安ならリネームして)、\n<code class=\"language-plaintext highlighter-rouge\">sudo systemctl start docker</code> を実行します。<br />\nこの後、 <code class=\"language-plaintext highlighter-rouge\">systemctl status docker</code> を実行して \n<code class=\"language-plaintext highlighter-rouge\">Active</code>の表示が<code class=\"language-plaintext highlighter-rouge\">active (running)</code>になっていればOKのはず。</p>\n\n</blockquote>\n\n<h1 id=\"カーネルのビルド\">カーネルのビルド</h1>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<p>たとえば、以下。 どこでも良いけど、以下の手順はこのディレクトリで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /proj/wsl_kernel <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /proj/wsl_kernel\n</code></pre></div></div>\n\n<h2 id=\"カーネルソースの取得\">カーネルソースの取得</h2>\n<p>作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)にカーネルソースをダウンロードします。<br />\ngitリポジトリをcloneするか、リリースソースをダウンロードして展開します。</p>\n\n<h3 id=\"gitでcloneする場合\">gitでcloneする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/microsoft/WSL2-Linux-Kernel.git\n\n<span class=\"c\"># 目的のタグをチェックアウト</span>\ngit <span class=\"nt\">-C</span> WSL2-Linux-Kernel checkout <span class=\"nt\">-b</span> WSL-6.6.36.3 refs/tags/linux-msft-wsl-6.6.36.3\n\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> WSL2-Linux-Kernel linux\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nclone済みなら念のため<code class=\"language-plaintext highlighter-rouge\">git pull</code>して最新状態にしておく</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nブランチ作る必要ないけど、念のため。</p>\n</blockquote>\n\n<h3 id=\"リリースソースzipをダウンロードする場合\">リリースソース(zip)をダウンロードする場合</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-6.6.36.3.zip\nunzip linux-msft-wsl-6.6.36.3.zip\n<span class=\"c\"># linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> linux-msft-wsl-6.6.36.3 linux\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nunzipはデフォルトではインストールされていないのでインストール必要。</p>\n</blockquote>\n\n<h2 id=\"スクリプトdockerfileの入手\">スクリプト&Dockerfileの入手</h2>\n<blockquote>\n  <p>[!NOTE]\nGistに必要なスクリプト&<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>を置いておいたので以下のページの<code class=\"language-plaintext highlighter-rouge\">DownloadZIP</code>ボタンからダウンロードして\n作業ディレクトリ(<code class=\"language-plaintext highlighter-rouge\">/proj/wsl_kernel</code>)に展開してください。<br />\n<a href=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021\" target=\"_blank\">Gist:WSLカーネルビルド環境</a></p>\n\n  <p>または以下のコマンドで取得できます。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wget https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021/archive/main.zip\nunzip <span class=\"nt\">-j</span> main.zip\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージを作成\">Dockerイメージを作成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>は上のサイトからダウンロードしてください。<br />\n<code class=\"language-plaintext highlighter-rouge\">Dockerfile</code>があるディレクトリで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker build <span class=\"nt\">-t</span> wslkernelbuilder:2.0 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<p>Dockerfileの内容は以下の通り。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=Dockerfile\"></script>\n</dev>\n\n<h2 id=\"dockerコンテナの起動確認\">Dockerコンテナの起動確認</h2>\n<p>上で作成したDockerイメージでコンテナを起動できることを確認します。<br />\nこのスクリプトは上のDockerイメージでDockerコンテナを起動し、シェルを実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_interactive.sh\n</code></pre></div></div>\n<p>プロンプトが以下のように変わればOKです(最後のディレクトリはlinuxのリンク先の実体のディレクトリ名になります)。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>builder [ /usr/src/WSL2-Linux-Kernel ]$\n</code></pre></div></div>\n<p>適当なコマンドを入力して遊んでみてください(カレントディレクトリのファイルは消さないように)。<br />\n最後は<code class=\"language-plaintext highlighter-rouge\">exit</code>で終了します。<br />\n起動時に<code class=\"language-plaintext highlighter-rouge\">--rm</code>しているので、終了時コンテナは削除されます。<br />\nなので、<code class=\"language-plaintext highlighter-rouge\">/usr/src</code>ディレクトリ以外にファイルを作っても終了後はなくなります。<br />\nもちろん<code class=\"language-plaintext highlighter-rouge\">tdnf install</code>(marinerなのでaptではない)でインストールしたアプリケーションもきれいさっぱりなくなります。<br />\n<code class=\"language-plaintext highlighter-rouge\">/usr/src</code>ディレクトリはスクリプトを起動したディレクトリをマウントしていますので、\nここに作成したファイルはコンテナ終了後も残ります(逆に削除するとホストからも削除されます)。</p>\n\n<h2 id=\"カーネルのビルド-1\">カーネルのビルド</h2>\n\n<p>カーネルソースの取得、Dockeイメージのビルドが終わったら、以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash build_wsl_kernel.sh\n</code></pre></div></div>\n\n<p>実行には1時間とか2時間とかのオーダーの時間がかかりますので、お茶でも飲んで気長に待ってください。</p>\n\n<p>実行完了後、<code class=\"language-plaintext highlighter-rouge\">out</code>ディレクトリに<code class=\"language-plaintext highlighter-rouge\">bzImage</code>と<code class=\"language-plaintext highlighter-rouge\">linux-module-6.6.36.3-microsoft-standard-wsl2_6.6.36.3-3_amd64.deb</code>ができます。<br />\nこれらを使用するPCのWindowsから見えるフォルダ(例えば、<code class=\"language-plaintext highlighter-rouge\">c:\\WSL_KERNEL\\</code>)にコピーします。</p>\n\n<h3 id=\"カーネルビルド用スクリプト\">カーネルビルド用スクリプト</h3>\n\n<p>用意したスクリプトの概要は以下の通りです。</p>\n\n<h4 id=\"build_functionssh\">build_functions.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_functions.sh</code>はビルドに関わる処理を関数化したものをまとめたファイルです。<br />\n以下のスクリプトからインクルードして使用します。</p>\n\n<p>Dockerコンテナを使用するので、あらかじめDockerイメージを作成しておく必要があります。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_functions.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_kernelsh\">build_wsl_kernel.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_kernel.sh</code>はカーネルのビルドを行います。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_kernel.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_interactivesh\">build_wsl_interactive.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_interactive.sh</code>はコンテナ内でインタラクティブにビルド操作をしたい場合に使用します。<br />\nたとえば、新しくモジュールを有効化したいとき、<code class=\"language-plaintext highlighter-rouge\">make menuconfig</code>して<code class=\"language-plaintext highlighter-rouge\">make</code>するような場合です。<br />\n実行するとコンテナ内のシェルが起動するので、実行したいコマンドを実行してください。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_interactive.sh\"></script>\n</dev>\n\n<h4 id=\"build_wsl_usb-storagesh\">build_wsl_usb-storage.sh</h4>\n<p><code class=\"language-plaintext highlighter-rouge\">build_wsl_usb-storage.sh</code>はUSBストレージのカーネルモジュールのビルドを行います。<br />\nバージョン6.6.<em>ではすでに有効になっているので、使用しません。<br />\nバージョン5.15.</em>で標準カーネルのままカーネルモジュールをビルドして使用するときに使用します。<br />\n6.6.*でも他のモジュールを有効化するときに参考になるかもと残しています。</p>\n\n<p><a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">参照先</a>\nの処理を少し書き換えただけです。</p>\n\n<p>outディレクトリに作成された<code class=\"language-plaintext highlighter-rouge\">linux-module-usb-storage-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64</code>を使用するディストリビューションにコピーし、\n以下のように実行しますが、インストール先の<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/</code>が書き込み禁止のため\nあらかじめここにoverlayfsをマウントしておく必要があります。<br />\nマウント方法やその他使用方法は\n<a href=\"https://qiita.com/qawsed477/items/11e4248861fdf8c6a585?fbclid=IwZXh0bgNhZW0CMTAAAR1xXTBXfWFXYm0xDQBugh52dR0LuLYyxMRHjeuj4BidPo9gNW-OJfKAgjA_aem_k3Z0rVIUqWAtPxAia200VQ\" target=\"_blank\">参照先</a>\nを参照してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> linux-module-usb-storage-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64\n</code></pre></div></div>\n<p>標準カーネルを使用することを前提にしているので、カーネルの差し替えは必要ありません。</p>\n\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021.js?file=build_wsl_usb-storage.sh\"></script>\n</dev>\n\n<blockquote>\n  <p>[!NOTE]\nこのスクリプトは使用するWSLカーネルで実行されているディストリビューションで実行してください。<br />\nそうしないとBTFの確認(<code class=\"language-plaintext highlighter-rouge\">check_btf</code>関数)が失敗します。</p>\n</blockquote>\n\n<h1 id=\"差し替えたカーネルで実行\">差し替えたカーネルで実行</h1>\n\n<h2 id=\"wslの停止\">WSLの停止</h2>\n<p>WSL実行中の場合はすべてのウィンドウを閉じます。<br />\nさらにWSLを完全に終了するために以下のコマンドを実行します。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--shutdown</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>念のため、すべて停止していることを確認を確認)</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>結果はこんな感じで<code class=\"language-plaintext highlighter-rouge\">STATE</code>がすべて<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  NAME              STATE           VERSION\n* Ubuntu-20.04-1    Stopped         2\n  ubuntu-22.04-2    Stopped         2\n  test_6_6          Stopped         2\n</code></pre></div></div>\n\n<h2 id=\"差し替えカーネルの設定\">差し替えカーネルの設定</h2>\n\n<p>差し替えカーネルを設定するため、<code class=\"language-plaintext highlighter-rouge\">%USERPROFILE%\\.wslconfig</code> に以下を追記(なければ新規作成)します。<br />\nここで指定しているのは先にコピーしたbzImageファイルのパスです。<br />\nただし、フォルダ区切りの<code class=\"language-plaintext highlighter-rouge\">\\</code>は<code class=\"language-plaintext highlighter-rouge\">\\\\</code>に置き換える必要があります。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[wsl2]\nkernel=c:\\\\WSL_KERNEL\\\\bzImage\n</code></pre></div></div>\n\n<h2 id=\"差し替えカーネルでの起動\">差し替えカーネルでの起動</h2>\n<p>通常通り、ディストリビューションを起動します。<br />\n起動後、ディストリビューション内のシェルで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">uname</span> <span class=\"nt\">-r</span>\n</code></pre></div></div>\n<p>結果が<code class=\"language-plaintext highlighter-rouge\">6.6.36.3-microsoft-standard-WSL2</code>と差し替えたカーネルのバージョンになっていることを確認します。</p>\n\n<h2 id=\"カーネルモジュールのインストール\">カーネルモジュールのインストール</h2>\n\n<p>次に先ほどコピーしたカーネルモジュールをインストールします。</p>\n<blockquote>\n  <p>[!NOTE]\nカーネルモジュールのインストールはカーネル差し替え後に行ってください。<br />\n差し替え前が標準カーネルだった場合、インストール先がリードオンリーのため、インストールに失敗します。</p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>dpkg <span class=\"nt\">-i</span> /mnt/c/WSL_KERNEL/linux-module-6.6.36.3-microsoft-standard-wsl2_6.6.36.3-3_amd64.deb\n</code></pre></div></div>\n\n<p>インストールされると、<code class=\"language-plaintext highlighter-rouge\">/usr/lib/modules/6.6.36.3-microsoft-standard-WSL2/</code>以下に各種ファイルが作成されます。</p>\n\n<p>インストールしたモジュールを読み込むため、ディストリビューションを再起動します。<br />\nWSLを完全に終了するために以下のコマンドを実行します。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--shutdown</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>念のため、すべて停止していることを確認(<code class=\"language-plaintext highlighter-rouge\">STATE</code>が<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていることを確認)</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  NAME              STATE           VERSION\n* Ubuntu-20.04-1    Stopped         2\n  ubuntu-22.04-2    Stopped         2\n  test_6_6          Stopped         2\n</code></pre></div></div>\n\n<p>再度カーネルモジュールをインストールしたディストリビューションを起動し、\n起動したディストリビューションでモジュールが読み込まれていることを確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsmod\n</code></pre></div></div>\n<p>以下のように、いくつかのモジュールが読み込まれていることを確認します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Module                  Size  Used by\nintel_rapl_msr         16384  0\nintel_rapl_common      36864  1 intel_rapl_msr\ncrc32c_intel           16384  0\nconfigfs               61440  0\nip_tables              32768  0\nautofs4                53248  0\n</code></pre></div></div>\n\n<h1 id=\"おわり\">おわり</h1>\n<p>この状態でカーネルの差し替えは完了です。<br />\nusbipd-win を使用すれば、USBシリアルやUSBストレージ、USBカメラも使えるようになります。\nただし、モジュールvhci-hcd(USB 仮想ホストコントローラインターフェース)が読み込まれていないので、\n以下のコマンドで読み込んでおく必要があります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe vhci-hcd\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n起動時にモジュールを読み込むには、通常<code class=\"language-plaintext highlighter-rouge\">/etc/modules</code>に設定しておけば良いのですが、\n試してみましたがうまくいきませんでした。<br />\n<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下のように記述しておくとうまくいくかもしれません。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\ncommand=modprobe vhci-hcd\n</code></pre></div>  </div>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSBデバイスを使う(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSBデバイスを使う(その1)</h1>\n      <p>WSLでUSBデバイスを使う(その1:準備&USB-Serial編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLでUSBを使う方法。あちこちに情報があるけど、なんとなく自分なりにまとめておく。<br />\n<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb\" target=\"_blank\">本家の説明</a></p>\n\n<p>ますは、準備とLinuxカーネルのビルドが必要ないUSB-Serialデバイスから。</p>\n\n<h1 id=\"wsl側の準備\">WSL側の準備</h1>\n\n<h2 id=\"wslのバージョン\">WSLのバージョン</h2>\n<p>使用したWSLのバージョンは以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>wsl <span class=\"nt\">--version</span>\n\nWSL バージョン: 2.2.4.0\nカーネル バージョン: 5.15.153.1-2\nWSLg バージョン: 1.0.61\nMSRDC バージョン: 1.2.5326\nDirect3D バージョン: 1.611.1-81528511\nDXCore バージョン: 10.0.26091.1-240325-1447.ge-release\nWindows バージョン: 10.0.19045.4529\n</code></pre></div></div>\n\n<p>使用したディストリビューションは「Ubuntu 22.04 LTS」</p>\n\n<h2 id=\"wslディストリビューションでsystemdの有効化\">WSLディストリビューションでsystemdの有効化</h2>\n\n<blockquote>\n  <p>[!NOTE]\nインストールしたタイミングによっては既に有効化されているかも。</p>\n</blockquote>\n\n<p>USBのホットプラグ処理は systemd + udev がよしなに行ってくれるみたいなので、systemdを有効化しておく。<br />\n使用するディストリビューションを起動し、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>に以下の設定を行う。</p>\n\n<p>デフォルト(古いデフォルト?)のSystemVinitだとバカチョンで動かなかった…udevサービス再起動とかやったら動いたけど。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdを有効にするか否かはディストリビューション毎の設定</p>\n</blockquote>\n\n<p>設定後、WSLをシャットダウン(コマンドプロンプト等から<code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行)し、<br />\n再度ディストリビューションを起動する。</p>\n\n<p>参考:<a href=\"https://qiita.com/curacao/items/fb9adaf1c097b1acd6a8\" target=\"_blank\">WSL2でsystemctlを使う方法</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nsystemdが動作しているか確認するには、<code class=\"language-plaintext highlighter-rouge\">systemctl is-system-running</code> を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">running</code>(起動中) <code class=\"language-plaintext highlighter-rouge\">degraded</code>(起動中だが失敗したサービスなどが存在) と表示されれば動作している。<br />\n<code class=\"language-plaintext highlighter-rouge\">offline</code> と表示されれば起動していない。<br />\nその他使い方についてはぐぐってちょ。</p>\n</blockquote>\n\n<h2 id=\"必要なパッケージをインストール\">必要なパッケージをインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic hwdata\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nlinux-tools-generic : usbipコマンド等が入る<br />\nhwdata : USB ID等のデータベースが入る<br />\nlinux-tools-generic インストールしたら自動でhwdata入るけど….<br />\n参考にしたサイトにこう書いてあったので。<br />\nlinux-tools-virtualと書いてあるサイトもあるけど、ubuntu 22.04だとchangelogとcopyrightしか違わないみたい。<br />\n </p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /usr/lib/linux-tools\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> 5.15.0-113-generic <span class=\"si\">$(</span><span class=\"nb\">uname</span> <span class=\"nt\">-r</span><span class=\"si\">)</span>\n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあちこちに<code class=\"language-plaintext highlighter-rouge\">sudo update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20</code>\nでコマンドのバージョン管理を行う例が書かれているけど、なんとなくシンボリックリンクを張る方がしっくりするのでこっちにした。</p>\n\n  <p>本来、usbipを実行すると <code class=\"language-plaintext highlighter-rouge\">/usr/bin/usbip</code> が <code class=\"language-plaintext highlighter-rouge\">/usr/lib/linux-tools/≪カーネルバージョン≫/usbip</code><br />\nを起動してくれるらしいのだけど、WSL環境では≪カーネルバージョン≫がカスタマイズバージョンでうまく働かないので<br />\n/usr/lib/linux-tools/≪カーネルバージョン≫をインストールされているバージョンに飛ばしてやればいい。<br />\nカーネルバージョンが変更されたら動かなくなるけど、そのときは、新しいカーネルバージョン名のシンボリックリンクを作ってやればよい。<br />\nもちろん、linux-tools-genericのアップデートが必要か判断して、必要ならアップデートする。</p>\n</blockquote>\n\n<h1 id=\"windows側の準備\">windows側の準備</h1>\n<h2 id=\"usbipd-win-のインストール\">usbipd-win のインストール</h2>\n<p>まずはUSBをTCP/IP経由で接続させるためのツール、usbipd-win をwindowsにインストールする。<br />\nインストールするには、<a href=\"https://github.com/dorssel/usbipd-win/releases\" target=\"_blank\">ダウンロードページ</a>  から\n最新版(以下の手順で使用したのは4.2.0)のmsiファイルをダウンロードして実行するだけ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストール時PATHが変更されるので、既に開いているコマンドプロンプトorPowerShellは一旦閉じて再実行する。</p>\n</blockquote>\n\n<h1 id=\"usbデバイスの操作\">USBデバイスの操作</h1>\n<p>WSLで使用したいUSBデバイスはあらかじめPCに接続しておく。</p>\n\n<p>以下の処理はコマンドプロンプトorPowerShellで行う。<br />\nただし、bind/unbindサブコマンドは管理者権限が必要なので、管理者として開いたコマンドプロンプトorPowerShellで実行する。</p>\n\n<h2 id=\"接続したいデバイスのbusidを調べる\">接続したいデバイスのBusIDを調べる</h2>\n\n<p>以下のコマンドを実行する。<br />\n結果は例。今回は3-4のUSB Serial Converter を使う。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">list</span><span class=\"w\">\n</span><span class=\"err\">≪結果≫</span><span class=\"w\">\n</span><span class=\"n\">Connected:</span><span class=\"w\">\n</span><span class=\"nx\">BUSID</span><span class=\"w\">  </span><span class=\"nx\">VID:PID</span><span class=\"w\">    </span><span class=\"nx\">DEVICE</span><span class=\"w\">                                                        </span><span class=\"nx\">STATE</span><span class=\"w\">\n</span><span class=\"mi\">2</span><span class=\"nt\">-1</span><span class=\"w\">    </span><span class=\"mi\">1</span><span class=\"n\">f75:0918</span><span class=\"w\">  </span><span class=\"nx\">USB</span><span class=\"w\"> </span><span class=\"err\">大容量記憶装置</span><span class=\"w\">                                            </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span><span class=\"mi\">2</span><span class=\"nt\">-2</span><span class=\"w\">    </span><span class=\"mi\">056</span><span class=\"n\">e:700a</span><span class=\"w\">  </span><span class=\"nx\">Venus</span><span class=\"w\"> </span><span class=\"nx\">USB2.0</span><span class=\"w\"> </span><span class=\"nx\">Camera</span><span class=\"w\">                                           </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span><span class=\"mi\">3</span><span class=\"nt\">-4</span><span class=\"w\">    </span><span class=\"mi\">0403</span><span class=\"p\">:</span><span class=\"mi\">6001</span><span class=\"w\">  </span><span class=\"n\">USB</span><span class=\"w\"> </span><span class=\"nx\">Serial</span><span class=\"w\"> </span><span class=\"nx\">Converter</span><span class=\"w\">                                          </span><span class=\"nx\">Not</span><span class=\"w\"> </span><span class=\"nx\">shared</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>ここで表示されたWSLで使用したいUSBデバイスのBUSID(例えば3-4)を覚えておく。</p>\n\n<h2 id=\"デバイスを共有設定する\">デバイスを共有設定する</h2>\n\n<p>管理者として開いたコマンドプロンプトorPowerShellで以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">bind</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">        </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">usbipd: warning: USB filter 'USBPcap' is known to be incompatible with this software; 'bind --force' will be required.</code><br />\nと出た時は、一旦unbindして、–forceオプションを追加して実行<br />\n(うちのPCはWiresharkインストールしてUSBPcap入ってるからだろうなぁ…)</p>\n</blockquote>\n\n<p>実行後、<code class=\"language-plaintext highlighter-rouge\">usbipd list</code>を実行すると、対象デバイスのステータスが Shared または Shared (forced) になっている</p>\n\n<h2 id=\"ディストリビューションの起動\">ディストリビューションの起動</h2>\n\n<p>接続するためのWSLのディストリビューションを起動しておく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n起動してないと<code class=\"language-plaintext highlighter-rouge\">usbipd: error: There is no WSL 2 distribution running; keep a command prompt to a WSL 2 distribution open to leave it running.</code>とエラーになる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nこのとき、複数のディストリビューションが起動していると変なことが起こりそうなので(未確認)\n対象のディストリビューションだけ起動しておくのが良いと思う。</p>\n</blockquote>\n\n<h2 id=\"デバイスを接続する\">デバイスを接続する</h2>\n\n<p>bindしただけではまだWSL側からはUSBデバイスは見えない。</p>\n\n<h3 id=\"windows側から接続する場合\">Windows側から接続する場合</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">attach</span><span class=\"w\"> </span><span class=\"nt\">--wsl</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">             </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"linux側から接続する場合\">linux側から接続する場合</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip attach <span class=\"nt\">-r</span> 172.20.160.1 <span class=\"nt\">-b</span> 3-4    <span class=\"c\"># 172.20.160.1 はWindows側のIPアドレス</span>\n                                            <span class=\"c\"># 3-4は接続するデバイスのBusID</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWindows側のIPアドレスはコマンドプロンプトorPowerShellから<code class=\"language-plaintext highlighter-rouge\">ipconfig</code>コマンドを実行し、<br />\n<code class=\"language-plaintext highlighter-rouge\">Ethernet adapter vEthernet (WSL):</code> に表示されているIPアドレスを使用する。<br />\nでもWSLがミラーネットワークモードになってたらどうなるんだろう???</p>\n</blockquote>\n\n<h2 id=\"デバイス接続を確認する\">デバイス接続を確認する</h2>\n<p>linux側で以下を実行し、接続されたデバイスが表示されていることを確認する。 \n以下のように接続したデバイスが表示されていればOK<br />\n(以下では2行目のFT232 Serial (UART) IC)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n≪結果≫\nBus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub\nBus 001 Device 003: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial <span class=\"o\">(</span>UART<span class=\"o\">)</span> IC\nBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub<span class=\"sb\">```</span>\n</code></pre></div></div>\n\n<h1 id=\"usb-serialデバイスを接続\">USB-Serialデバイスを接続</h1>\n<p>上記操作で接続したUSBデバイスがUSB-Serialデバイス(上記の例では FT232 Serial (UART) IC) であれば、\n<code class=\"language-plaintext highlighter-rouge\">/dev/ttyUSBx</code>(xは数字。通常0から順に割り当てられる)に割り当てられる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> <span class=\"nt\">-la</span> /dev/ttyUSB<span class=\"k\">*</span>\n≪結果≫\ncrw-rw---- 1 root dialout 188, 0  7月  3 11:02 /dev/ttyUSB0\n</code></pre></div></div>\n\n<p>一応、ログを確認してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dmesg\n≪結果≫\n・・・・・・\n<span class=\"o\">[</span>  189.418189] vhci_hcd vhci_hcd.0: pdev<span class=\"o\">(</span>0<span class=\"o\">)</span> rhport<span class=\"o\">(</span>0<span class=\"o\">)</span> sockfd<span class=\"o\">(</span>3<span class=\"o\">)</span>\n<span class=\"o\">[</span>  189.418196] vhci_hcd vhci_hcd.0: devid<span class=\"o\">(</span>196612<span class=\"o\">)</span> speed<span class=\"o\">(</span>2<span class=\"o\">)</span> speed_str<span class=\"o\">(</span>full-speed<span class=\"o\">)</span>\n<span class=\"o\">[</span>  189.418249] vhci_hcd vhci_hcd.0: Device attached\n<span class=\"o\">[</span>  189.690366] vhci_hcd: vhci_device speed not <span class=\"nb\">set</span>\n<span class=\"o\">[</span>  189.760405] usb 1-1: new full-speed USB device number 2 using vhci_hcd\n<span class=\"o\">[</span>  189.840475] vhci_hcd: vhci_device speed not <span class=\"nb\">set</span>\n<span class=\"o\">[</span>  189.910358] usb 1-1: SetAddress Request <span class=\"o\">(</span>2<span class=\"o\">)</span> to port 0\n<span class=\"o\">[</span>  190.135906] usb 1-1: New USB device found, <span class=\"nv\">idVendor</span><span class=\"o\">=</span>0403, <span class=\"nv\">idProduct</span><span class=\"o\">=</span>6001, <span class=\"nv\">bcdDevice</span><span class=\"o\">=</span> 6.00\n<span class=\"o\">[</span>  190.135918] usb 1-1: New USB device strings: <span class=\"nv\">Mfr</span><span class=\"o\">=</span>1, <span class=\"nv\">Product</span><span class=\"o\">=</span>2, <span class=\"nv\">SerialNumber</span><span class=\"o\">=</span>3\n<span class=\"o\">[</span>  190.135921] usb 1-1: Product: FT232R USB UART\n<span class=\"o\">[</span>  190.135923] usb 1-1: Manufacturer: FTDI\n<span class=\"o\">[</span>  190.135924] usb 1-1: SerialNumber: A50285BI\n<span class=\"o\">[</span>  190.511832] usbcore: registered new interface driver ftdi_sio\n<span class=\"o\">[</span>  190.511852] usbserial: USB Serial support registered <span class=\"k\">for </span>FTDI USB Serial Device\n<span class=\"o\">[</span>  190.511881] ftdi_sio 1-1:1.0: FTDI USB Serial Device converter detected\n<span class=\"o\">[</span>  190.511904] usb 1-1: Detected FT232RL\n<span class=\"o\">[</span>  190.521353] usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB0       ← /dev/ttyUSB0が割り当てられたことが分かる\n</code></pre></div></div>\n\n<p>デフォルトで使用できるUSB-Serialデバイスは、\nSilicon Labs社製 CP210x、FTDI社製シリアルコンバータ(FT232)、CH34x(安い中国製Arduinoで使われているらしい)らしい。</p>\n\n<p>/dev/ttyUSBxが割り当てられていない場合は、対応しているUSB-Serialデバイスか、systemdが有効になっているか、等を確認してください。</p>\n\n<blockquote>\n  <p>[!NOTE]\n参考:<a href=\"https://another.maple4ever.net/archives/3221/?fbclid=IwZXh0bgNhZW0CMTAAAR2mnOe2c5FmYg3ig1IQbB1r4Y3t43MLJyqvzAx6tyjuiWCjETjj_x9Rkd0_aem_EpK6sQQOwszToANXZLsfiQ\" target=\"_blank\">Windows WSL2 の Ubuntu 22.04 上から USB-UART 経由で M5Stack に書き込みする</a><br />\n上記サイトではudevルールをplatform.ioのサイトから拝借してきているが、上記の製品なら持ってこなくても可。<br />\n互換品とかでうまく認識しないときは試してみると動くかも(試してないので無責任発言)。</p>\n</blockquote>\n\n<h2 id=\"シリアルポートを使ってみる\">シリアルポートを使ってみる</h2>\n\n<p>シリアルポートを使うツールは色々あると思うけど、とりあえず動いているか確認するならこんな感じ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>pyserial-miniterm <span class=\"nt\">--parity</span> N /dev/ttyUSB0 115200\n</code></pre></div></div>\n\n<p>終了するにはCTRL+]を入力する。</p>\n\n<blockquote>\n  <p>[!NOTE]\nsudoなしで実行するには、自分のアカウントにdialoutグループを追加すればよい。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> dialout\n</code></pre></div>  </div>\n  <p>一旦ログアウトして再ログイン必要。</p>\n</blockquote>\n\n<h2 id=\"デバイスを接続解除する\">デバイスを接続解除する</h2>\n\n<p>WSLをシャットダウンしたら(ディストリビューションのシャットダウンではなくWSL全体)接続解除されるけど、\n手動で接続解除するには以下のコマンドを実行する。</p>\n\n<h3 id=\"windows側から接続解除する場合\">Windows側から接続解除する場合</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\">  </span><span class=\"nx\">detach</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">              </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"linux側から接続解除する場合\">linux側から接続解除する場合</h3>\n<p>linuxから解除するには、まずポート番号を確認する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip port\n≪結果≫\nImported USB devices\n<span class=\"o\">====================</span>\nPort 00: <Port <span class=\"k\">in </span>Use> at Full Speed<span class=\"o\">(</span>12Mbps<span class=\"o\">)</span>\n       Future Technology Devices International, Ltd : FT232 Serial <span class=\"o\">(</span>UART<span class=\"o\">)</span> IC <span class=\"o\">(</span>0403:6001<span class=\"o\">)</span>\n       1-1 -> usbip://172.20.160.1:3240/3-4       ← ホストアドレス\n           -> remote bus/dev 003/004              ← BusID\n           \n</code></pre></div></div>\n\n<p>上記の例ではポート番号は00なので、これをportオプションに指定して以下のように実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip detach <span class=\"nt\">--port</span> 00\n</code></pre></div></div>\n\n<h2 id=\"デバイスを共有解除する\">デバイスを共有解除する</h2>\n\n<p>USBデバイスを共有解除するには、管理者として開いたコマンドプロンプトorPowerShellで以下のコマンドを実行する。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">usbipd</span><span class=\"w\"> </span><span class=\"nx\">unbind</span><span class=\"w\"> </span><span class=\"nt\">--busid</span><span class=\"w\"> </span><span class=\"nx\">3-4</span><span class=\"w\">           </span><span class=\"c\"># 3-4は接続するデバイスのBusID</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nデバイスの共有解除しなければ、PCを再起動しても共有設定されたままになる。<br />\nただし、使用しているUSBポートに別のUSBデバイスを挿入すると共有解除されるが、再度同じUSBデバイスを挿入すれば共有設定される。<br />\n何言ってるか分からんと思うけど、USBデバイス挿抜してみて確かめてみて。</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Visual Studio Code で Jupyter Notebook</title>\n  </head>\n  <body>\n    <header>\n      <h1>Visual Studio Code で Jupyter Notebook</h1>\n      <p>Visual Studio Code で Jupyter Notebookを実行する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>Visual Studio CodeでJupyter Notebookを実行する。</p>\n\n<p>サンプルプログラムがJupyter Notebookだったりするとブラウザで動かすのめんどいので、Visual Studio Codeで動かしてみた。<br />\n参考:このあたりかな? <a href=\"https://codeaid.jp/vscode-jupyter/\" target=\"_blank\">Visual Studio CodeでJupyter Notebookを使う方法</a></p>\n\n<p>以下では、<a href=\"https://www.koi.mashykom.com/tensorflow.html\" target=\"_blank\">SSD と YOLO を用いた物体検出</a> の「Object Detection APIを用いた物体検出」を参考に進めてみる。</p>\n\n<h1 id=\"前準備\">前準備</h1>\n<p>作業ディレクトリとツール類のインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Tensorflow\n<span class=\"nb\">cd</span> /work/Tensorflow\n\n<span class=\"c\"># pyenvの仮想環境作成と切り替え</span>\npyenv virtualenv 3.7.10 tensorflow\npyenv <span class=\"nb\">local </span>tensorflow\n<span class=\"c\"># お約束</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># Protocol buffers コンパイラのインストール(Jupyter Notebookの実行には関係ない)</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>protobuf-compiler\n\n<span class=\"c\"># Jupyter Notebook のモジュールインストール</span>\npip <span class=\"nb\">install </span>notebook\n</code></pre></div></div>\n\n<h1 id=\"modelsリポジトリのクローン\">modelsリポジトリのクローン</h1>\n<p>実行するプログラムの準備</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/tensorflow/models.git\n</code></pre></div></div>\n\n<h1 id=\"visual-studio-codeの起動\">Visual Studio Codeの起動</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models/\ncode <span class=\"nb\">.</span>\n</code></pre></div></div>\n<p><strong>*** Visual Studio Code起動 ***</strong></p>\n\n<h1 id=\"visual-studio-codeでの作業\">Visual Studio Codeでの作業</h1>\n<p>以下、Visual Studio Codeで作業する</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>拡張機能から「Jupyter」と「Python」を選択し、対象マシンにインストール</p>\n\n<h2 id=\"使用するpythonを選択その1\">使用するpythonを選択その1</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n<ul>\n  <li>Python: インタプリター選択\n    <ul>\n      <li>これはどこで有効なんだろうか?念のため設定しておこう。</li>\n    </ul>\n  </li>\n  <li>Jupyter: Select interpreter to start jupyter server\n    <ul>\n      <li>たぶん、Jupyter Notebookそのものを実行するためのPython<br />\njupyter-notebookモジュールがインストールされている必要がある</li>\n    </ul>\n  </li>\n</ul>\n\n<h2 id=\"対象ファイルをオープン\">対象ファイルをオープン</h2>\n<p>エクスプローラから<br />\n<code class=\"language-plaintext highlighter-rouge\">research/object_detection/colab_tutorials/object_detection_tutorial.ipynb</code>\nを開く<br />\n<code class=\"language-plaintext highlighter-rouge\">a notebook could execute harmful code when opened. ~</code>\nと言われるので、<code class=\"language-plaintext highlighter-rouge\">Trust</code> をクリック</p>\n\n<h2 id=\"使用するpythonを選択その2\">使用するpythonを選択その2</h2>\n\n<p>コマンドパレットから以下のコマンドを選び、使用するPythonを選択する<br />\n(ipynbファイルを開かないと選べない)</p>\n\n<p>コマンドパレットを表示するには、メニューの表示→コマンドパレットを選択する。</p>\n\n<ul>\n  <li>Jupyter: Select a Kernel\n    <ul>\n      <li>たぶん、Notebook内のpythonスクリプトを実行するためのPython<br />\nシステムコマンド(!を行頭につけて指定)として実行したり、<code class=\"language-plaintext highlighter-rouge\">%%bash</code> で指定したCode cell で実行した<br />\npython スクリプト(pipコマンドなども含む)を実行した場合もこのバージョンが使用される</li>\n      <li>ipykernelモジュールをインストールしておく必要があるが、入ってなければVSCodeからインストールできるので気にしなくても大丈夫。<br />\n(Jupyter Notebook のモジュールがインストールされていれば同時にインストールされている)</li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nその1、その2で選択するバージョンはそれぞれ異なるバージョンを設定できるが、<br />\n上でpyenvで選択したバージョンで統一しておくのが混乱しなくて良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSelect a Kernel の設定内容は以下のファイルに保存されるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.vscode-server/data/User/globalStorage/ms-toolsai.jupyter/kernelSpecPaths.json</code><br />\nこの設定はシステム(ターゲットマシン)で1つのようなので、他のプロジェクトで設定を変更した場合は再度確認しておくのが良いと思う。</p>\n</blockquote>\n\n<h2 id=\"エラーになる部分の対策\">エラーになる部分の対策</h2>\n\n<h3 id=\"その1\">その1</h3>\n<p>「Get tensorflow/models or cd to parent directory of the repository.」\nの下のCode cellの最後に以下を追加</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n<span class=\"n\">cwd</span><span class=\"o\">=</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getcwd</span><span class=\"p\">()</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research/slim\"</span><span class=\"p\">)</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">insert</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">cwd</span> <span class=\"o\">+</span> <span class=\"s\">\"/models/research\"</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"その2\">その2</h3>\n<p>以下のcellを削除(エラーになる)<br />\n(おそらく、その1で追加している処理に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>%%bash \ncd models/research\npip install .\n</code></pre></div></div>\n\n<h3 id=\"その3\">その3</h3>\n<p>「Instance Segmentation」以下はエラーになる(RCNNのモデル形状が変更された?)ので削除しておく。<br />\n(手順の本筋に関係ないので)</p>\n\n<h2 id=\"実行\">実行</h2>\n<p>最初のCode cell(Installの下)で▶(Run)をクリック<br />\nあとは、続くcellで▶(Run)をクリックしていく。</p>\n\n<p>または、ツールバーの⏩(Run all cells)をクリックする</p>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<h2 id=\"ipynbファイルをpythonファイルにエクスポートする\">ipynbファイルをpythonファイルにエクスポートする。</h2>\n\n<p>Visual Studio Codeのエクスプローラペインで対象のipynbファイルを右クリックして<br />\n<code class=\"language-plaintext highlighter-rouge\">Convert a Notebook to Python Script</code>を選択すると、変換結果が新しいファイルとしてエディタに開かれる。<br />\nこれを名前を付けて保存する。</p>\n\n<p>または、コマンドラインから以下のコマンドを実行する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>jupyter nbconvert «対象ファイル».ipynb <span class=\"nt\">--to</span> python\n</code></pre></div></div>\n<p>デフォルトの出力ファイル名は«対象ファイル名».py(拡張子をipynb→pyに変えたもの)になる。</p>\n\n<p>ただし、単独で動かす場合は <code class=\"language-plaintext highlighter-rouge\">get_ipython()</code> で始まる行(システムコマンドを実行する部分)はエラーになるので、コメントアウトしておくこと。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Keras on tensorflow2 で SSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>Keras on tensorflow2 で SSD</h1>\n      <p>Tensorflow2上のKerasでSSDを実行を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>※ 2021.05.21 kerasをtensorflow.kerasに変更</p>\n\n<h1 id=\"概要\">概要</h1>\n\n<p>Kerasを使ってSSDを実行してみようと思ったら、Tensorflow1.x上の情報ばかり出てきて、Tensorflow2で実行するのに手間取ったのでメモ。<br />\n(最終的にopenVINOに持っていきたいなぁ、と思って試し始めたんだけど、openVINOにサクッと変換できるのはcaffeだった😅)<br />\nということで、やったけど 続きはないかも。実行遅いし…😩💨</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p><a href=\"https://smilerobo.com/papero/tips_keras_tf_ssd/\" target=\"_blank\">【実験】学習済のSSDを使ってPaPeRo i に複数種類の物体を数えさせる</a>\nを参考に、KerasをTensorflow2で動かしてみる。</p>\n\n<p>Pythonは3.8を使用した(念のため明記しておく)。</p>\n\n<p>Anaconda使ってないし、Paperoじゃないので、そのまんまじゃないけど、<br />\nとりあえずSSDを動かしてみよう。</p>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n\n<p>まずは、python仮想環境の準備をする。<br />\npyenv環境前提。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースディレクトリとpython仮想環境の準備</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/keras2/\n<span class=\"nb\">cd</span> /work/keras2/\npyenv virtualenv 3.8.8 keras2\npyenv <span class=\"nb\">local </span>keras2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># pythonモジュールのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n<span class=\"c\"># kerasはtensorflow内を直接参照にしたので不要  </span>\n<span class=\"c\"># pip install keras</span>\npip <span class=\"nb\">install </span>matplotlib\npip <span class=\"nb\">install </span>imageio\n</code></pre></div></div>\n\n<p>インストールされているpythonモジュールは以下の通り</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.2\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.4.0\ngoogle-auth==1.30.0\ngoogle-auth-oauthlib==0.4.4\ngoogle-pasta==0.2.0\ngrpcio==1.34.1\nh5py==3.1.0\nidna==2.10\nimageio==2.9.0\nkeras-nightly==2.5.0.dev2021032900\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.4.2\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.2.52\nopt-einsum==3.3.0\nPillow==8.2.0\nprotobuf==3.17.0\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nsix==1.15.0\ntensorboard==2.5.0\ntensorboard-data-server==0.6.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.5.0\ntensorflow-estimator==2.5.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==2.0.1\nwrapt==1.12.1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nKeras修正以前の状態は以下</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.1\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.3.3\ngoogle-auth==1.28.0\ngoogle-auth-oauthlib==0.4.3\ngoogle-pasta==0.2.0\ngrpcio==1.32.0\nh5py==2.10.0\nidna==2.10\nimageio==2.9.0\nKeras==2.4.3\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.3.4\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.1.48\nopt-einsum==3.3.0\nPillow==8.1.2\nprotobuf==3.15.6\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nPyYAML==5.4.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nscipy==1.6.1\nsix==1.15.0\ntensorboard==2.4.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.4.1\ntensorflow-estimator==2.4.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==1.0.1\nwrapt==1.12.1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"patchファイルの準備\">patchファイルの準備</h2>\n\n<p>参照先には色々手順が書いてあるが、めんどくさいので パッチファイル用意した(足りない修正もあるし)。<br />\n以下の内容を<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code> <code class=\"language-plaintext highlighter-rouge\">ssd_keras_2.patch</code>のファイル名で保存しておく。</p>\n\n<h3 id=\"ssd_keraspatch\">ssd_keras.patch</h3>\n\n<p>参照先の情報によるpatch</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/ssd.py b/ssd.py\nindex c0049d8..656cd83 100644\n</span><span class=\"gd\">--- a/ssd.py\n</span><span class=\"gi\">+++ b/ssd.py\n</span><span class=\"p\">@@ -2,14 +2,15 @@</span>\n \n import keras.backend as K\n from keras.layers import Activation\n<span class=\"gd\">-from keras.layers import AtrousConvolution2D\n</span><span class=\"gi\">+#from keras.layers import AtrousConvolution2D\n</span> from keras.layers import Convolution2D\n from keras.layers import Dense\n from keras.layers import Flatten\n from keras.layers import GlobalAveragePooling2D\n from keras.layers import Input\n from keras.layers import MaxPooling2D\n<span class=\"gd\">-from keras.layers import merge\n</span><span class=\"gi\">+#from keras.layers import merge\n+from keras.layers.merge import concatenate\n</span> from keras.layers import Reshape\n from keras.layers import ZeroPadding2D\n from keras.models import Model\n<span class=\"p\">@@ -34,109 +35,115 @@</span> def SSD300(input_shape, num_classes=21):\n     input_tensor = input_tensor = Input(shape=input_shape)\n     img_size = (input_shape[1], input_shape[0])\n     net['input'] = input_tensor\n<span class=\"gd\">-    net['conv1_1'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    net['conv1_1'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_1')(net['input'])\n<span class=\"gd\">-    net['conv1_2'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    \n+    net['conv1_2'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_2')(net['conv1_1'])\n<span class=\"gd\">-    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+\n+    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool1')(net['conv1_2'])\n     # Block 2\n<span class=\"gd\">-    net['conv2_1'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+    net['conv2_1'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_1')(net['pool1'])\n<span class=\"gd\">-    net['conv2_2'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+\n+    net['conv2_2'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_2')(net['conv2_1'])\n<span class=\"gd\">-    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool2')(net['conv2_2'])\n<span class=\"gi\">+\n</span>     # Block 3\n<span class=\"gd\">-    net['conv3_1'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_1'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_1')(net['pool2'])\n<span class=\"gd\">-    net['conv3_2'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_2'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_2')(net['conv3_1'])\n<span class=\"gd\">-    net['conv3_3'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_3'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_3')(net['conv3_2'])\n<span class=\"gd\">-    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool3')(net['conv3_3'])\n     # Block 4\n<span class=\"gd\">-    net['conv4_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_1')(net['pool3'])\n<span class=\"gd\">-    net['conv4_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_2')(net['conv4_1'])\n<span class=\"gd\">-    net['conv4_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_3')(net['conv4_2'])\n<span class=\"gd\">-    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool4')(net['conv4_3'])\n<span class=\"gd\">-    # Block 5\n-    net['conv5_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+# Block 5\n+    net['conv5_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_1')(net['pool4'])\n<span class=\"gd\">-    net['conv5_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_2')(net['conv5_1'])\n<span class=\"gd\">-    net['conv5_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_3')(net['conv5_2'])\n<span class=\"gd\">-    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), border_mode='same',\n</span><span class=\"gi\">+    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), padding='same',\n</span>                                 name='pool5')(net['conv5_3'])\n     # FC6\n<span class=\"gd\">-    net['fc6'] = AtrousConvolution2D(1024, 3, 3, atrous_rate=(6, 6),\n-                                     activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['fc6'] = Convolution2D(1024, (3, 3), dilation_rate=(6, 6),\n+                                     activation='relu', padding='same',\n</span>                                      name='fc6')(net['pool5'])\n     # x = Dropout(0.5, name='drop6')(x)\n     # FC7\n<span class=\"gd\">-    net['fc7'] = Convolution2D(1024, 1, 1, activation='relu',\n-                               border_mode='same', name='fc7')(net['fc6'])\n</span><span class=\"gi\">+    net['fc7'] = Convolution2D(1024, (1, 1), activation='relu',\n+                               padding='same', name='fc7')(net['fc6'])\n</span>     # x = Dropout(0.5, name='drop7')(x)\n     # Block 6\n<span class=\"gd\">-    net['conv6_1'] = Convolution2D(256, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv6_1'] = Convolution2D(256, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv6_1')(net['fc7'])\n<span class=\"gd\">-    net['conv6_2'] = Convolution2D(512, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+\n+\n+    net['conv6_2'] = Convolution2D(512, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv6_2')(net['conv6_1'])\n<span class=\"gd\">-    # Block 7\n-    net['conv7_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+        # Block 7\n+    net['conv7_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv7_1')(net['conv6_2'])\n     net['conv7_2'] = ZeroPadding2D()(net['conv7_1'])\n<span class=\"gd\">-    net['conv7_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='valid',\n</span><span class=\"gi\">+    net['conv7_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='valid',\n</span>                                    name='conv7_2')(net['conv7_2'])\n     # Block 8\n<span class=\"gd\">-    net['conv8_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv8_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv8_1')(net['conv7_2'])\n<span class=\"gd\">-    net['conv8_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['conv8_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv8_2')(net['conv8_1'])\n     # Last Pool\n     net['pool6'] = GlobalAveragePooling2D(name='pool6')(net['conv8_2'])\n     # Prediction from conv4_3\n     net['conv4_3_norm'] = Normalize(20, name='conv4_3_norm')(net['conv4_3'])\n     num_priors = 3\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv4_3_norm_mbox_loc')(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_loc'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_loc_flat')\n<span class=\"p\">@@ -144,7 +151,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv4_3_norm_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_conf'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_conf_flat')\n<span class=\"p\">@@ -155,16 +162,16 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv4_3_norm_mbox_priorbox'] = priorbox(net['conv4_3_norm'])\n     # Prediction from fc7\n     num_priors = 6\n<span class=\"gd\">-    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, 3, 3,\n-                                        border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, (3, 3),\n+                                        padding='same',\n</span>                                         name='fc7_mbox_loc')(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_loc_flat')\n     net['fc7_mbox_loc_flat'] = flatten(net['fc7_mbox_loc'])\n     name = 'fc7_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, 3, 3,\n-                                         border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, (3, 3),\n+                                         padding='same',\n</span>                                          name=name)(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_conf_flat')\n     net['fc7_mbox_conf_flat'] = flatten(net['fc7_mbox_conf'])\n<span class=\"p\">@@ -174,7 +181,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['fc7_mbox_priorbox'] = priorbox(net['fc7'])\n     # Prediction from conv6_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv6_2_mbox_loc')(net['conv6_2'])\n     net['conv6_2_mbox_loc'] = x\n     flatten = Flatten(name='conv6_2_mbox_loc_flat')\n<span class=\"p\">@@ -182,7 +189,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv6_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv6_2'])\n     net['conv6_2_mbox_conf'] = x\n     flatten = Flatten(name='conv6_2_mbox_conf_flat')\n<span class=\"p\">@@ -193,7 +200,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv6_2_mbox_priorbox'] = priorbox(net['conv6_2'])\n     # Prediction from conv7_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv7_2_mbox_loc')(net['conv7_2'])\n     net['conv7_2_mbox_loc'] = x\n     flatten = Flatten(name='conv7_2_mbox_loc_flat')\n<span class=\"p\">@@ -201,7 +208,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv7_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv7_2'])\n     net['conv7_2_mbox_conf'] = x\n     flatten = Flatten(name='conv7_2_mbox_conf_flat')\n<span class=\"p\">@@ -212,7 +219,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv7_2_mbox_priorbox'] = priorbox(net['conv7_2'])\n     # Prediction from conv8_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv8_2_mbox_loc')(net['conv8_2'])\n     net['conv8_2_mbox_loc'] = x\n     flatten = Flatten(name='conv8_2_mbox_loc_flat')\n<span class=\"p\">@@ -220,7 +227,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv8_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv8_2'])\n     net['conv8_2_mbox_conf'] = x\n     flatten = Flatten(name='conv8_2_mbox_conf_flat')\n<span class=\"p\">@@ -241,7 +248,7 @@</span> def SSD300(input_shape, num_classes=21):\n     priorbox = PriorBox(img_size, 276.0, max_size=330.0, aspect_ratios=[2, 3],\n                         variances=[0.1, 0.1, 0.2, 0.2],\n                         name='pool6_mbox_priorbox')\n<span class=\"gd\">-    if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+    if K.image_data_format() == 'channels_last':\n</span>         target_shape = (1, 1, 256)\n     else:\n         target_shape = (256, 1, 1)\n<span class=\"p\">@@ -249,42 +256,47 @@</span> def SSD300(input_shape, num_classes=21):\n                                     name='pool6_reshaped')(net['pool6'])\n     net['pool6_mbox_priorbox'] = priorbox(net['pool6_reshaped'])\n     # Gather all predictions\n<span class=\"gd\">-    net['mbox_loc'] = merge([net['conv4_3_norm_mbox_loc_flat'],\n</span><span class=\"gi\">+    net['mbox_loc'] = concatenate([net['conv4_3_norm_mbox_loc_flat'],\n</span>                              net['fc7_mbox_loc_flat'],\n                              net['conv6_2_mbox_loc_flat'],\n                              net['conv7_2_mbox_loc_flat'],\n                              net['conv8_2_mbox_loc_flat'],\n                              net['pool6_mbox_loc_flat']],\n<span class=\"gd\">-                            mode='concat', concat_axis=1, name='mbox_loc')\n-    net['mbox_conf'] = merge([net['conv4_3_norm_mbox_conf_flat'],\n</span><span class=\"gi\">+                            axis=1,\n+                                  name='mbox_loc')\n+    net['mbox_conf'] = concatenate([net['conv4_3_norm_mbox_conf_flat'],\n</span>                               net['fc7_mbox_conf_flat'],\n                               net['conv6_2_mbox_conf_flat'],\n                               net['conv7_2_mbox_conf_flat'],\n                               net['conv8_2_mbox_conf_flat'],\n                               net['pool6_mbox_conf_flat']],\n<span class=\"gd\">-                             mode='concat', concat_axis=1, name='mbox_conf')\n-    net['mbox_priorbox'] = merge([net['conv4_3_norm_mbox_priorbox'],\n</span><span class=\"gi\">+                              axis=1,\n+                              name='mbox_conf')\n+    net['mbox_priorbox'] = concatenate([net['conv4_3_norm_mbox_priorbox'],\n</span>                                   net['fc7_mbox_priorbox'],\n                                   net['conv6_2_mbox_priorbox'],\n                                   net['conv7_2_mbox_priorbox'],\n                                   net['conv8_2_mbox_priorbox'],\n                                   net['pool6_mbox_priorbox']],\n<span class=\"gd\">-                                 mode='concat', concat_axis=1,\n</span><span class=\"gi\">+                                 axis=1,\n</span>                                  name='mbox_priorbox')\n     if hasattr(net['mbox_loc'], '_keras_shape'):\n         num_boxes = net['mbox_loc']._keras_shape[-1] // 4\n     elif hasattr(net['mbox_loc'], 'int_shape'):\n<span class=\"gd\">-        num_boxes = K.int_shape(net['mbox_loc'])[-1] // 4\n</span><span class=\"gi\">+        num_boxes = net['mbox_loc'].int_shape()[-1] // 4\n+    elif hasattr(net['mbox_loc'], 'get_shape'):\n+        num_boxes = net['mbox_loc'].get_shape()[-1] // 4\n</span>     net['mbox_loc'] = Reshape((num_boxes, 4),\n                               name='mbox_loc_final')(net['mbox_loc'])\n     net['mbox_conf'] = Reshape((num_boxes, num_classes),\n                                name='mbox_conf_logits')(net['mbox_conf'])\n     net['mbox_conf'] = Activation('softmax',\n                                   name='mbox_conf_final')(net['mbox_conf'])\n<span class=\"gd\">-    net['predictions'] = merge([net['mbox_loc'],\n</span><span class=\"gi\">+    net['predictions'] = concatenate([net['mbox_loc'],\n</span>                                net['mbox_conf'],\n                                net['mbox_priorbox']],\n<span class=\"gd\">-                               mode='concat', concat_axis=2,\n</span><span class=\"gi\">+                               axis=2,\n+                               #axis = 0,\n</span>                                name='predictions')\n     model = Model(net['input'], net['predictions'])\n     return model\n<span class=\"gh\">diff --git a/ssd_layers.py b/ssd_layers.py\nindex 5e10478..41ee510 100644\n</span><span class=\"gd\">--- a/ssd_layers.py\n</span><span class=\"gi\">+++ b/ssd_layers.py\n</span><span class=\"p\">@@ -29,7 +29,8 @@</span> class Normalize(Layer):\n         Add possibility to have one scale for all features.\n     \"\"\"\n     def __init__(self, scale, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n+\n</span>             self.axis = 3\n         else:\n             self.axis = 1\n<span class=\"p\">@@ -41,7 +42,7 @@</span> class Normalize(Layer):\n         shape = (input_shape[self.axis],)\n         init_gamma = self.scale * np.ones(shape)\n         self.gamma = K.variable(init_gamma, name='{}_gamma'.format(self.name))\n<span class=\"gd\">-        self.trainable_weights = [self.gamma]\n</span><span class=\"gi\">+        self._trainable_weights = [self.gamma]\n</span> \n     def call(self, x, mask=None):\n         output = K.l2_normalize(x, self.axis)\n<span class=\"p\">@@ -81,7 +82,7 @@</span> class PriorBox(Layer):\n     \"\"\"\n     def __init__(self, img_size, min_size, max_size=None, aspect_ratios=None,\n                  flip=True, variances=[0.1], clip=True, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n</span>             self.waxis = 2\n             self.haxis = 1\n         else:\n<span class=\"p\">@@ -108,7 +109,7 @@</span> class PriorBox(Layer):\n         self.clip = True\n         super(PriorBox, self).__init__(**kwargs)\n \n<span class=\"gd\">-    def get_output_shape_for(self, input_shape):\n</span><span class=\"gi\">+    def compute_output_shape(self, input_shape):\n</span>         num_priors_ = len(self.aspect_ratios)\n         layer_width = input_shape[self.waxis]\n         layer_height = input_shape[self.haxis]\n<span class=\"gh\">diff --git a/ssd_utils.py b/ssd_utils.py\nindex 0a9ffb1..4fc7a49 100644\n</span><span class=\"gd\">--- a/ssd_utils.py\n</span><span class=\"gi\">+++ b/ssd_utils.py\n</span><span class=\"p\">@@ -1,7 +1,8 @@</span>\n \"\"\"Some utils for SSD.\"\"\"\n \n import numpy as np\n<span class=\"gd\">-import tensorflow as tf\n</span><span class=\"gi\">+import tensorflow.compat.v1 as tf\n+tf.disable_v2_behavior()\n</span> \n \n class BBoxUtility(object):\n<span class=\"gh\">diff --git a/testing_utils/videotest.py b/testing_utils/videotest.py\nindex 0cbae3c..7b2ff4f 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest.py\n</span><span class=\"p\">@@ -3,13 +3,14 @@</span>\n import cv2\n import keras\n from keras.applications.imagenet_utils import preprocess_input\n<span class=\"gd\">-from keras.backend.tensorflow_backend import set_session\n</span><span class=\"gi\">+# from keras.backend.tensorflow_backend import set_session\n</span> from keras.models import Model\n from keras.preprocessing import image \n import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-from scipy.misc import imread, imresize\n</span><span class=\"gi\">+# from scipy.misc import imread, imresize\n+from imageio import imread\n</span> from timeit import default_timer as timer\n \n import sys\n<span class=\"p\">@@ -84,8 +85,8 @@</span> class VideoTest(object):\n             \"trying to open a webcam, make sure you video_path is an integer!\"))\n         \n         # Compute aspect ratio of video     \n<span class=\"gd\">-        vidw = vid.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)\n-        vidh = vid.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)\n</span><span class=\"gi\">+        vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)\n+        vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)\n</span>         vidar = vidw/vidh\n         \n         # Skip frames until reaching start_frame\n<span class=\"gh\">diff --git a/testing_utils/videotest_example.py b/testing_utils/videotest_example.py\nindex fb4d873..27ec148 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest_example.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest_example.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import os\n+# GPU不使用を設定\n+os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n+\n</span> import keras\n import pickle\n from videotest import VideoTest\n<span class=\"p\">@@ -9,16 +13,38 @@</span> from ssd import SSD300 as SSD\n input_shape = (300,300,3)\n \n # Change this if you run with other classes than VOC\n<span class=\"gd\">-class_names = [\"background\", \"aeroplane\", \"bicycle\", \"bird\", \"boat\", \"bottle\", \"bus\", \"car\", \"cat\", \"chair\", \"cow\", \"diningtable\", \"dog\", \"horse\", \"motorbike\", \"person\", \"pottedplant\", \"sheep\", \"sofa\", \"train\", \"tvmonitor\"];\n</span><span class=\"gi\">+class_names = [ \n+                \"background\", \n+                \"aeroplane\", \n+                \"bicycle\", \n+                \"bird\", \n+                \"boat\", \n+                \"bottle\", \n+                \"bus\", \n+                \"car\", \n+                \"cat\", \n+                \"chair\", \n+                \"cow\", \n+                \"diningtable\", \n+                \"dog\", \n+                \"horse\", \n+                \"motorbike\", \n+                \"person\", \n+                \"pottedplant\", \n+                \"sheep\", \n+                \"sofa\", \n+                \"train\", \n+                \"tvmonitor\"\n+            ];\n</span> NUM_CLASSES = len(class_names)\n \n model = SSD(input_shape, num_classes=NUM_CLASSES)\n \n # Change this path if you want to use your own trained weights\n<span class=\"gd\">-model.load_weights('../weights_SSD300.hdf5') \n</span><span class=\"gi\">+model.load_weights('../../weights_SSD300.hdf5') \n</span>         \n vid_test = VideoTest(class_names, model, input_shape)\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('path/to/your/video.mkv')\n</span><span class=\"gi\">+vid_test.run('../../testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h3 id=\"ssd_keras_2patch\">ssd_keras_2.patch</h3>\n\n<p>keras修正対応</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras_2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd.py ssd_keras.tmp/ssd.py\n</span><span class=\"gd\">--- ssd_keras/ssd.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd.py\t2021-05-21 07:06:44.970000000 +0900\n</span><span class=\"p\">@@ -1,19 +1,17 @@</span>\n \"\"\"Keras implementation of SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.layers import Activation\n-#from keras.layers import AtrousConvolution2D\n-from keras.layers import Convolution2D\n-from keras.layers import Dense\n-from keras.layers import Flatten\n-from keras.layers import GlobalAveragePooling2D\n-from keras.layers import Input\n-from keras.layers import MaxPooling2D\n-#from keras.layers import merge\n-from keras.layers.merge import concatenate\n-from keras.layers import Reshape\n-from keras.layers import ZeroPadding2D\n-from keras.models import Model\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.keras.layers import Activation\n+from tensorflow.keras.layers import Convolution2D\n+from tensorflow.keras.layers import Dense\n+from tensorflow.keras.layers import Flatten\n+from tensorflow.keras.layers import GlobalAveragePooling2D\n+from tensorflow.keras.layers import Input\n+from tensorflow.keras.layers import MaxPooling2D\n+from tensorflow.keras.layers import concatenate\n+from tensorflow.keras.layers import Reshape\n+from tensorflow.keras.layers import ZeroPadding2D\n+from tensorflow.keras.models import Model\n</span> \n from ssd_layers import Normalize\n from ssd_layers import PriorBox\n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd_layers.py ssd_keras.tmp/ssd_layers.py\n</span><span class=\"gd\">--- ssd_keras/ssd_layers.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd_layers.py\t2021-05-21 06:31:11.780000000 +0900\n</span><span class=\"p\">@@ -1,8 +1,8 @@</span>\n \"\"\"Some special pupropse layers for SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.engine.topology import InputSpec\n-from keras.engine.topology import Layer\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.python.keras.engine.input_spec import InputSpec\n+from tensorflow.python.keras.engine.base_layer import Layer\n</span> import numpy as np\n import tensorflow as tf\n \n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest.py ssd_keras.tmp/testing_utils/videotest.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest.py\t2021-05-21 07:08:24.680000000 +0900\n</span><span class=\"p\">@@ -1,15 +1,13 @@</span>\n \"\"\" A class for testing a SSD model on a video file or webcam \"\"\"\n \n import cv2\n<span class=\"gd\">-import keras\n-from keras.applications.imagenet_utils import preprocess_input\n-# from keras.backend.tensorflow_backend import set_session\n-from keras.models import Model\n-from keras.preprocessing import image \n</span><span class=\"gi\">+import tensorflow.keras as keras\n+from tensorflow.keras.applications.imagenet_utils import preprocess_input\n+from tensorflow.keras.models import Model\n+from tensorflow.keras.preprocessing import image \n</span> import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-# from scipy.misc import imread, imresize\n</span> from imageio import imread\n from timeit import default_timer as timer\n \n<span class=\"p\">@@ -179,6 +177,7 @@</span>\n             cv2.putText(to_draw, fps, (3,10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0,0,0), 1)\n             \n             cv2.imshow(\"SSD result\", to_draw)\n<span class=\"gd\">-            cv2.waitKey(10)\n-            \n-        \n</span><span class=\"gi\">+            key = cv2.waitKey(1)\n+            if key == 27:\n+                # ESCキー\n+                break\n</span><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest_example.py ssd_keras.tmp/testing_utils/videotest_example.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest_example.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest_example.py\t2021-05-21 07:04:24.320000000 +0900\n</span><span class=\"p\">@@ -2,7 +2,7 @@</span>\n # GPU不使用を設定\n os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n \n<span class=\"gd\">-import keras\n</span><span class=\"gi\">+import tensorflow.keras as keras\n</span> import pickle\n from videotest import VideoTest\n \n<span class=\"p\">@@ -47,4 +47,4 @@</span>\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('../../testvideo3.mp4')\n</span><span class=\"gi\">+vid_test.run('../../images/testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h2 id=\"学習済み重みファイルのダウンロード\">学習済み重みファイルのダウンロード</h2>\n\n<p>参照先の記載にしたがって、重み学習済み重みファイルをダウンロードする。</p>\n\n<p>wgetでは取得できなかったので、ブラウザで↓ここ から weights_SSD300.hdf5 をダウンロード。<br />\n<a href=\"https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA\" target=\"_blank\">https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA</a><br />\nで、ZIPファイルをカレントディレクトリに解凍しておく。</p>\n\n<h2 id=\"ソースのダウンロードパッチをあてる\">ソースのダウンロード&パッチをあてる</h2>\n\n<p>githubからソースをダウンロードする。<br />\nこのままではエラーになるので、先ほど作成したパッチファイル<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code>でパッチをあてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/rykov8/ssd_keras.git\n<span class=\"nb\">cd </span>ssd_keras\npatch <span class=\"nt\">-p1</span> < ../ssd_keras.patch \n<span class=\"c\"># Keras修正対応パッチ</span>\npatch <span class=\"nt\">-p1</span> < ../ssd_keras_2.patch \n</code></pre></div></div>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>testing_utils/\npython videotest_example.py\n</code></pre></div></div>\n\n<p>おー。<br />\nしかし遅い…. <br />\nKerasは遅いみたい。。。orz…</p>\n\n<h1 id=\"こんなんもある\">こんなんもある</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50\" target=\"_blank\">「Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>PyPiからopenVINOをインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>PyPiからopenVINOをインストール</h1>\n      <p>PyPiで配布されているopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>openVINOを使いたいが、SDKをインストールするのは面倒というズボラさんのためのTips😅<br />\nNCS2を使うためのドライバをインストールするにはSDK必要だが(WSLだとそもそもNCS2は使えないけど)、CPUだけでさくっと使いたいときなんかは有効かな?<br />\nあと、SDKインストール済みだけど、別のバージョン試したいときとか。</p>\n\n<p>対象はWindwos(試してないけど)、Ubuntu(x86_64 の 18.04、20.04)。(macOSも対象らしいけど使ったことないのでよーわからん😅)<br />\nPython は3.6、3.7、3.8<br />\nRasoberryPiは現在のところ対象外。</p>\n\n<h1 id=\"pypiのページ\">PyPiのページ</h1>\n\n<p>PyPiは以下にページがある。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino/\" target=\"_blank\">openvino · PyPI</a></li>\n</ul>\n\n<p>ただし、現状はUbuntuでPython3.8を使用する場合は以下を使用(Ubuntu Python3.7は両方用意されているらしい)。</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/openvino-ubuntu20/\" target=\"_blank\">openvino-ubuntu20 · PyPI</a></li>\n</ul>\n\n<h1 id=\"pythonモジュールのインストール\">pythonモジュールのインストール</h1>\n<p>上記ページに記載された通りだが、大抵openCVも必要になるので、インストールしておく。 <br />\n最近はopenCVも<code class=\"language-plaintext highlighter-rouge\">pip</code>コマンドイッパツでインストールできるのでラクチン😊</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># openVINOのインストール</span>\npip <span class=\"nb\">install </span>openvino\n<span class=\"c\"># またはこちら</span>\n<span class=\"c\"># pip install openvino-ubuntu20</span>\n\n<span class=\"c\"># openCVのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<p>インストールすると、現状、以下のモジュールがインストールされる(ubuntuでpython3.7/3.8の場合)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>numpy==1.20.1\nopencv-python==4.5.1.48\nopenvino==2021.2\ntbb==2020.3.254\n</code></pre></div></div>\n\n<h1 id=\"実行前の準備\">実行前の準備</h1>\n\n<p>openVINOモジュールは<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>の設定が必要なので、\nシステムのpythonを使用するときは上記ページに記載された通りに<code class=\"language-plaintext highlighter-rouge\">LD_LIBRARY_PATH</code>を設定する。<br />\nただし、pyenvを使用している場合は、以下のように設定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">LD_LIBRARY_PATH</span><span class=\"k\">}</span>:<span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/versions/<span class=\"sb\">`</span>pyenv version-name<span class=\"sb\">`</span>/lib\n</code></pre></div></div>\n\n<p>pyenvで環境を切り替えることを考えると、<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>で設定するより、スクリプト実行ラッパで設定した方が無難かも。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2でX-serverへの表示</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2でX-serverへの表示</h1>\n      <p>WindowsTerminal上のWSL2コンソールからGUIプログラムを起動する場合の設定メモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>MobaXtermを使えば何もしなくてもGUIプログラムを表示できるけど、\nWindowsTerminalなどから表示したい場合に対応してみた。</p>\n\n<h1 id=\"windows側の設定\">Windows側の設定</h1>\n<p>VcXsrvをインストールして起動しておく。<br />\n参考:<a href=\"/memoBlog/2019/11/26/VcXsrv.html\" target=\"_blank\">WindowsでX-serve</a></p>\n\n<h1 id=\"linux側の設定\">Linux側の設定</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">.bashrc</code>に以下を追加</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># HOSTのIPアドレス取得</span>\n<span class=\"c\"># export HOST_IP_ADDR=$(host `hostname`.mshome.net | sed -r 's/.*address (.*)$/\\1/')</span>\n<span class=\"c\"># HOSTのIPアドレス取得(アドレスが2つ以上返ってきたときは1個目だけ取り出す)</span>\n<span class=\"nb\">export </span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"o\">=</span><span class=\"si\">$(</span>host <span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net | <span class=\"nb\">sed</span> <span class=\"nt\">-r</span> <span class=\"s1\">'s/.*address (.*)$/\\1/'</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-n</span> 1p<span class=\"si\">)</span>\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">HOST_IP_ADDR</span><span class=\"k\">}</span>:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n他の用途でホストのIPアドレス(名前でなく)を使いたいときのために別に変数作っておいた。<br />\n以下のように名前で書いて指定しても良い。<br />\nマシン名は<code class=\"language-plaintext highlighter-rouge\">hostname</code>コマンドで得られるので、別のマシンに移動しても変更の必要はない。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">hostname</span><span class=\"sb\">`</span>.mshome.net:0.0\n</code></pre></div>  </div>\n  <p><code class=\"language-plaintext highlighter-rouge\">.mshome.net</code>ドメインを指定するとホスト側のIPアドレスが得られるらしい。<br />\nドメインなしだと<code class=\"language-plaintext highlighter-rouge\">localhost</code>になっちゃうから注意。<br />\nぐぐると<code class=\"language-plaintext highlighter-rouge\">/etc/resolv.conf</code>を<code class=\"language-plaintext highlighter-rouge\">awk</code>でごちょごちょやるのが流行っているが<br />\n本来の設定値ではない(結果的に同じだけど)のでちゃんと設定しておくことにする。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nドメイン<code class=\"language-plaintext highlighter-rouge\">mshome.net</code>はHyper-Vのネットワークのドメインらしい。<br />\n要はWSL-Windows間の仮想ネットワークのドメイン名みたい。<br />\nちなみに、WSL2上から<code class=\"language-plaintext highlighter-rouge\">nslookup <<ホストのIPアドレス>></code>とやったら出てきた。</p>\n</blockquote>\n\n<h1 id=\"x-windowを使用するプログラムを起動\">X-Windowを使用するプログラムを起動</h1>\n<p>なんか起動してちょ。\nとりあえず<code class=\"language-plaintext highlighter-rouge\">xeyes</code>とか。<br />\nちなみに、<code class=\"language-plaintext highlighter-rouge\">xeyes</code> は <code class=\"language-plaintext highlighter-rouge\">sudo apt install x11-apps</code>でインストールできる。</p>\n\n<h1 id=\"wslからのgui表示が行えない場合の対処\">WSLからのGUI表示が行えない場合の対処</h1>\n\n<h2 id=\"原因\">原因</h2>\n<p>WSLのネットワークがパブリックネットワークになっており、<br />\nWSLネットワークからの接続要求がファイアウォールで はじかれている。</p>\n\n<h2 id=\"ファイアウォールの設定変更による回避\">ファイアウォールの設定変更による回避</h2>\n\n<p>VcXsrvをパブリックネットワークからの接続も受け付けるようにする \n以下手順。</p>\n\n<ul>\n  <li>コントロール パネル  →  Windows Defender ファイアウォール</li>\n  <li>左側上から2番目「Windows Defender ファイアウォールを介したアプリまたは機能を許可」をクリック</li>\n  <li>名前の欄から「VcXsrv windows xserver」を探す</li>\n  <li>その横のチェックボックスの「パブリック」側(右側)にもチェックを入れる(プライベート側は既にチェックが入っているはず。そっちはそのまま)。</li>\n  <li>OKボタンをクリックして終了</li>\n  <li>コントロールパネルは閉じてOK</li>\n</ul>\n\n<h2 id=\"ちなみに\">ちなみに</h2>\n\n<p>以下のような回避方法もある。</p>\n\n<h3 id=\"display変数を変更して回避\">DISPLAY変数を変更して回避</h3>\n<p>一旦WSLネットワークから外に出て接続すれば接続できる。<br />\n具体的には、DISPLAY変数をWSL側のIPアドレス(172.xxx.xxx.xxx)ではなく、<br />\nWi-Fiやイーサネットに割り当てられたアドレス(一般に 192.168.xxx.xxx)を指定する。<br />\n → WSL側から自動的にアドレスを取得できないのであまりおススメできない。<br />\n    VcXsrvがちゃんと動いているかを確認するには有効な手段かも。</p>\n\n<h3 id=\"根本的回避\">根本的回避</h3>\n<p><a href=\"https://daizo3.tumblr.com/post/150523393217/%E5%82%99%E5%BF%98%E9%8C%B2-%E5%85%88%E6%97%A5%E3%81%AE%E7%B6%9A%E3%81%8D-%E8%AD%98%E5%88%A5%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF-%E3%82%92%E3%83%97%E3%83%A9%E3%82%A4%E3%83%99%E3%83%BC%E3%83%88%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AB%E3%81%99%E3%82%8B\">備忘録 - (先日の続き) 識別されていないネットワーク をプライベートネットワークにする</a><br />\nによると、<br />\n<a href=\"https://www.atmarkit.co.jp/ait/articles/1012/24/news127.html\">Windowsで、「識別されていないネットワーク」の種類を「パブリック ネットワーク」から「プライベート ネットワーク」に変更する</a><br />\nの「レジストリによる設定」に記載された方法でも出来るらしいけど(こっちの方が根本的解決な気がする)、<br />\nレジストリ弄るのは気が引けるので、小手先対処にて。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Ubuntu20.04 on WSL2 で openVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>Ubuntu20.04 on WSL2 で openVINO</h1>\n      <p>WSL2上のUbuntu20.04でopenVINOをインストールしたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"環境構築\">環境構築</h1>\n\n<p>WSL環境ではNCS2は使えないが、CPU演算での実行は可能。<br />\n以下インストール~デモ実行までのメモ。</p>\n\n<p>基本は以下を参考に。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/06/16/openVINO_ubuntu_2.html\">openVINO フルパッケージをubuntuにインストール(改訂版)</a></li>\n  <li><a href=\"/memoBlog/2020/10/18/openVINO_ubuntu_3.html\">openVINO フルパッケージ(2021.1)をインストール(追加)</a></li>\n</ul>\n\n<p>WSLのインストールメモはこちら:<a href=\"/memoBlog/2021/03/03/WSL_memo.html\">WSL2 メモ</a><br />\nUbuntuは20.04。<br />\n今回はopenVINO 2021.2を使用した。</p>\n\n<h2 id=\"pyenvの仮想環境を作成\">pyenvの仮想環境を作成</h2>\n<p>まずは、pythonの環境を準備。<br />\n以下ではpythonは3.7.10を使用。(3.8を使えばTensorflow2を使えるらしい(?))</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv virtualenv 3.7.10 openVINO\npyenv <span class=\"nb\">local </span>openVINO \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n\n<h2 id=\"必要なパッケージのインストール\">必要なパッケージのインストール</h2>\n\n<p>ubuntuのライブラリ類をインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libcairo2-dev libpango1.0-dev libglib2.0-dev libgtk2.0-dev libswscale-dev libavcodec-dev libavformat-dev \n<span class=\"c\"># 他にもあるかもしれんけど、とりあえずこれだけ。</span>\n</code></pre></div></div>\n\n<p>WSLでは以下も必要(グラフィック系処理が入ってないので)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libgtk-3-0\n</code></pre></div></div>\n<h2 id=\"ダウンロードしたopenvinoアーカイブの展開とインストール\">ダウンロードしたopenVINOアーカイブの展開とインストール</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/mnt/f/Download/</code>にダウンロードしたファイルがあるとして。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\n<span class=\"nb\">tar </span>xzvf /mnt/f/Download/l_openvino_toolkit_p_2021.2.185.tgz \n<span class=\"nb\">cd </span>l_openvino_toolkit_p_2021.2.185/\n<span class=\"nb\">sudo</span> <span class=\"nt\">-E</span> ./install_GUI.sh \n<span class=\"c\"># なぜかXwindow設定しててもテキストベースになる...</span>\n<span class=\"c\"># てきとーに答えていく。</span>\n</code></pre></div></div>\n\n<p>スクリプト終了したら、以下に従い進めていく。<br />\n<a href=\"https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html\">https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_linux.html</a></p>\n\n<h2 id=\"後半のコマンド一覧と注意事項\">後半のコマンド一覧と注意事項</h2>\n\n<ul>\n  <li>環境変数の設定とpythonモジュールのインストール</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># このコマンド、~/.bashrcにも書いておくこと</span>\n<span class=\"nb\">source</span> /opt/intel/openvino_2021/bin/setupvars.sh\n\n<span class=\"c\"># このコマンド実行すると、pyenvでなくsystemのpipでモジュールがインストールされるので実行しない</span>\n<span class=\"c\"># しかも、systemのpip3が壊れる...すごい罠😡</span>\n<span class=\"c\"># cd /opt/intel/openvino_2021/deployment_tools/model_optimizer/install_prerequisites/</span>\n<span class=\"c\"># sudo -E ./install_prerequisites.sh </span>\n\n<span class=\"c\"># 代わりに以下を実行(上記スクリプトは結局これを実行しているだけなので)</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\npython 3.7で実行すると、</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version >= \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われるけど、無視して良い。<br />\nこれはPython3.8未満か以上で異なるバージョンのTensorflowがインストールされるように設定されているため。<br />\nちなみに、python 3.8でやると</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Ignoring tensorflow: markers <span class=\"s1\">'python_version < \"3.8\"'</span> don<span class=\"s1\">'t match your environment\n</span></code></pre></div>  </div>\n  <p>と言われる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nもし、<code class=\"language-plaintext highlighter-rouge\">install_prerequisites.sh</code>を実行してしまい、pip3が壊れてしまった場合は\n以下で復旧する(一旦アンインストールしてから再インストール)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove python3-pip \n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip \n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"デモ実行\">デモ実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino_2021/deployment_tools/demo\n<span class=\"nb\">sudo cp</span> /work/.python-version <span class=\"nb\">.</span>\n\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/demo1.log\n\n<span class=\"c\"># このデモはグラフィック表示可能環境で実行する必要がある。  </span>\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> /work/tmp/dem2.log\n</code></pre></div></div>\n\n<h1 id=\"別の仮想環境を用意する場合\">別の仮想環境を用意する場合</h1>\n\n<p>別の仮想環境を用意するときは以下で新しい仮想環境下にモジュールをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/model_optimizer/requirements.txt\npip <span class=\"nb\">install</span> <span class=\"nt\">-r</span> /opt/intel/openvino_2021/deployment_tools/open_model_zoo/tools/downloader/requirements.in\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSL2 メモ</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSL2 メモ</h1>\n      <p>WSL2に関するメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <blockquote>\n  <p>[!NOTE]\n<strong><a href=\"https:///memoBlog/2024/07/24/WSL_memo2.html\" target=\"_blank\">改訂版</a>があります。</strong></p>\n</blockquote>\n\n<h1 id=\"インストール\">インストール</h1>\n<h2 id=\"wsl2のインストール\">WSL2のインストール</h2>\n<p>参考: <a href=\"https://itengine.seesaa.net/article/479688577.html\" target=\"_blank\">WSL2をインストールしてみた</a></p>\n\n<h2 id=\"virtualboxとの共存\">Virtualboxとの共存</h2>\n<p>参考: <a href=\"https://qiita.com/hibohiboo/items/c17459e0af84d2059d21\" target=\"_blank\">Vagrant + Virtualbox 6.1.16 と WSL2 を同時に動かしたメモ</a></p>\n\n<h1 id=\"セットアップ\">セットアップ</h1>\n\n<h2 id=\"アップデート\">アップデート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade \n</code></pre></div></div>\n\n<h2 id=\"日本語化\">日本語化</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 日本語ランゲージパック</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>language-pack-ja\n<span class=\"c\"># ロケールの設定</span>\n<span class=\"nb\">sudo </span>update-locale <span class=\"nv\">LANG</span><span class=\"o\">=</span>ja_JP.UTF8\n<span class=\"c\"># 日本語manページのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>manpages-ja manpages-ja-dev\n</code></pre></div></div>\n\n<h2 id=\"beepを消す\">BEEPを消す</h2>\n<p>鬱陶しいのでBEEPを消しておく。<br />\n参考: <a href=\"https://linuxfan.info/bow-stop-beep\" target=\"_blank\">Bash on Windowsでビープ音を消す方法</a></p>\n\n<ul>\n  <li>ターミナルのbeepを消して画面フラッシュにする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"set bell-style visible\"</span> <span class=\"o\">>></span> ~/.inputrc\n</code></pre></div>    </div>\n  </li>\n  <li>vimのbeepを消す\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"set visualbell t_vb=\"</span> <span class=\"o\">>></span> ~/.vimrc\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsTerminalの場合、<code class=\"language-plaintext highlighter-rouge\">settings.json</code>に各プロファイルの設定に\n以下の設定を追加すればbash、vim、その他一括して変更できる。</p>\n  <div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\"> </span><span class=\"nl\">\"bellStyle\"</span><span class=\"w\"> </span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visual\"</span><span class=\"err\">,</span><span class=\"w\">\n</span></code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"デフォルトshをbashに変更\">デフォルトshをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n<h2 id=\"ツール類インストール\">ツール類インストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>net-tools\n</code></pre></div></div>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> /proj /work\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n<p>参考:<a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a></p>\n\n<h2 id=\"nodenvのインストール\">nodenvのインストール</h2>\n<p>参考:<a href=\"/memoBlog/2019/06/28/nodenv.html\" target=\"_blank\">nodenvのインストール</a></p>\n\n<h2 id=\"bashrcの設定\">.bashrcの設定</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\[\\e</span><span class=\"s2\">[36m</span><span class=\"se\">\\]</span><span class=\"nv\">$WSL_DISTRO_NAME</span><span class=\"se\">\\[\\e</span><span class=\"s2\">[0m</span><span class=\"se\">\\]</span><span class=\"s2\">:</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n        <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n        <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># for pyenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># 仮想環境名をプロンプトに表示しない場合は以下を有効化</span>\n    <span class=\"nb\">export </span><span class=\"nv\">VIRTUAL_ENV_DISABLE_PROMPT</span><span class=\"o\">=</span>1\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># for nodenv</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv    <span class=\"c\"># 環境に合わせて修正してね</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># DISPLAY変数が未定義(MobaXterm使用でない)ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-v</span> <span class=\"nv\">$DISPLAY</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n<span class=\"k\">fi\n</span><span class=\"nb\">echo </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"nv\">$DISPLAY</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n\n<h1 id=\"起動時の初期ディレクトリをホームディレクトリにするための設定\">起動時の初期ディレクトリをホームディレクトリにするための設定</h1>\n\n<p>起動時の初期ディレクトリがホームディレクトリにならないので(SSHの場合は大丈夫なはず)、以下の方法で指定する。</p>\n\n<h3 id=\"windows-terminalのsettingjsonでの設定\">Windows TerminalのSetting.jsonでの設定</h3>\n<p><a href=\"https://ryotatake.hatenablog.com/entry/2019/08/15/windows_terminal_wsl\" target=\"_blank\">Windows Terminal + WSLでターミナル起動時のディレクトリをホームディレクトリにする</a></p>\n\n<h3 id=\"wtexeのコマンドラインで指定する場合\">wt.exeのコマンドラインで指定する場合</h3>\n\n<p>settings.jsonで設定してない場合や設定とは別のディレクトリを指定する場合は-dオプションで指定する。<br />\nホームディレクトリを指定する場合は以下。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">C:\\Users\\</span><span class=\"err\"><<ユーザ名>></span><span class=\"nx\">\\AppData\\Local\\Microsoft\\WindowsApps\\wt.exe</span><span class=\"w\"> </span><span class=\"nt\">-p</span><span class=\"w\"> </span><span class=\"s2\">\"«環境登録名»\"</span><span class=\"w\"> </span><span class=\"nt\">-d</span><span class=\"w\"> </span><span class=\"s2\">\"\\\\wsl</span><span class=\"err\">$</span><span class=\"s2\">\\«仮想環境名»\\home\\<<ユーザ名>>\"</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ -p で指定するのは仮想環境名ではなく、WindowsTerminal に登録した環境名(ドロップダウンリストに表示される名前)。 -d で指定するのは仮想環境名。同一でない場合は間違えないように注意。</p>\n\n<h3 id=\"wsl-コマンドで起動する場合\">wsl コマンドで起動する場合</h3>\n\n<p>使用中のターミナルを使って起動する場合はwslコマンドで起動する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">c:\\WINDOWS\\system32\\wsl.exe</span><span class=\"w\"> </span><span class=\"nx\">~</span><span class=\"w\"> </span><span class=\"nt\">-d</span><span class=\"w\"> </span><span class=\"s2\">\"仮想環境名\"</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ wsl コマンドのパラメータに <code class=\"language-plaintext highlighter-rouge\">~</code> を追加</p>\n\n<h1 id=\"pathにwindowsのpathを引き継がせない設定\">PATHにWindowsのPATHを引き継がせない設定</h1>\n<p>仮想マシン起動語、PATHにWindows環境のPATHが引き継がれる。<br />\n便利な半面、コマンド名補完でサーチに行くと かなりの時間をくってしまい 不便。<br />\nWindowsのコマンドを仮想マシン上から起動することはあまりない(私の場合)ので、、<br />\nWindows環境のPATHを引き継がせないようにする。</p>\n\n<p>設定方法は <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に 以下の設定を追加する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>interop]\nappendWindowsPath <span class=\"o\">=</span> <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<p>参考: <a href=\"https://zenn.dev/o2z/articles/zenn-20210524-01\" target=\"_blank\">WSL2でWindowsのPATH設定が引き継がれるのを解除する</a></p>\n\n<h1 id=\"guiアプリを使用する\">GUIアプリを使用する</h1>\n<p>参考: <a href=\"https://qiita.com/vega77/items/f00323e8ce64bfa1fdd6\" target=\"_blank\">WSL2でGUIアプリを起動</a></p>\n\n<h1 id=\"wsl2上のサーバプログラムへのアクセス\">WSL2上のサーバプログラムへのアクセス</h1>\n<p>参考:<a href=\"https://www.atmarkit.co.jp/ait/articles/1909/09/news020.html\" target=\"_blank\">Linuxがほぼそのまま動くようになった「WSL2」のネットワーク機能</a></p>\n\n<table>\n  <thead>\n    <tr>\n      <th>向き</th>\n      <th>可否</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>HOST → WSL2</td>\n      <td>localhost でアクセスできる</td>\n    </tr>\n    <tr>\n      <td>WSL2 → HOST</td>\n      <td>localhost でアクセスできない。<br /> IPアドレス指定ならアクセスできる。</td>\n    </tr>\n  </tbody>\n</table>\n\n<h1 id=\"仮想マシンの複製\">仮想マシンの複製</h1>\n\n<h2 id=\"手順\">手順</h2>\n<p>仮想マシンは元になる仮想マシンをエクスポートして、別のディレクトリにインポートすれば複製できる。</p>\n\n<h3 id=\"仮想マシン一覧の確認\">仮想マシン一覧の確認</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--list</span><span class=\"w\"> </span><span class=\"nt\">--verbose</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>対象の仮想マシンが停止していることを確認。<br />\n停止してない場合はそれぞれのターミナルを終了するか、以下のコマンドで。<br />\nターミナルを終了してから実際に仮想マシンが停止するまで少し時間がかかる(数十秒くらい?)。</p>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--terminate</span><span class=\"w\"> </span><span class=\"err\">«対象の仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"エクスポート\">エクスポート</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--export</span><span class=\"w\"> </span><span class=\"err\">«エクスポート元仮想環境名»</span><span class=\"w\"> </span><span class=\"err\">«エクスポートファイル名»</span><span class=\"o\">.</span><span class=\"nf\">tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<p>例</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--export</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04</span><span class=\"w\"> </span><span class=\"nx\">F:\\WSL_VMs\\_Backup\\Ubuntu-20.04.tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"インポート\">インポート</h3>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"err\">«新しい仮想環境名»</span><span class=\"w\"> </span><span class=\"err\">«インストール先ディレクトリ»</span><span class=\"w\"> </span><span class=\"err\">«エクスポートファイル名»</span><span class=\"o\">.</span><span class=\"nf\">tar</span><span class=\"w\">\n</span></code></pre></div></div>\n<p>※ インストール先ディレクトリは自動で作成される</p>\n\n<p>例:</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--import</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04-1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">/Ubuntu-20.04-1</span><span class=\"w\"> </span><span class=\"o\">.</span><span class=\"nx\">\\_Backup\\Ubuntu-20.04.tar</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h3 id=\"削除\">削除</h3>\n<p>不要になった仮想環境は削除する。</p>\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"err\">«削除する仮想環境名»</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">wsl</span><span class=\"w\"> </span><span class=\"nt\">--unregister</span><span class=\"w\"> </span><span class=\"nx\">Ubuntu-20.04-2</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h2 id=\"参考\">参考</h2>\n<ul>\n  <li>同一ディストリビューションの複製<br />\n<a href=\"https://qiita.com/souyakuchan/items/9f95043cf9c4eda2e1cc\" target=\"_blank\">WSL 上で同一ディストリビューションの環境を複数インストール・管理する</a></li>\n  <li>仮想環境をCドライブ以外に変更する<br />\n<a href=\"https://nosubject.io/windowsdocker-desktop-move-disk-image/\" target=\"_blank\">[Windows] Docker Desktop の ディスク領域 を Cドライブから別のドライブへ移動する方法</a></li>\n</ul>\n\n<h2 id=\"インポートした環境のデフォルトユーザを変更する\">インポートした環境のデフォルトユーザを変更する</h2>\n<p>インポートした環境では、デフォルトユーザがrootになっているため、自分に変更しておく。<br />\n方法は2つ。  <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>のほうがお手軽かな? エクスポート元で書いておけば逐一書かなくてもいいし。<br />\n両方設定した場合は<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>の設定が優先される(らしい)。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>で指定する方法。<br />\nインポートした環境を起動して、 <code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code>を以下の内容で作成\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>user]\n<span class=\"nv\">default</span><span class=\"o\">=</span>«デフォルトユーザ名» \n</code></pre></div>    </div>\n    <p>参考:<a href=\"https://github.com/Microsoft/WSL/issues/3974#issuecomment-576782860\" target=\"_blank\">github Microsoft/WSL/issues/3974</a>\n参考:<a href=\"https://roy-n-roy.github.io/Windows/WSL%EF%BC%86%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A/wslconfig/\" target=\"_blank\">wsl.conf と .wslconfig - roy-n-roy メモ</a></p>\n  </li>\n  <li>レジストリで設定する方法\n    <ul>\n      <li>Windowsでレジストリエディタを起動</li>\n      <li><strong><em>コンピューター\\HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Lxss</em></strong> 下の<br />\n各エントリで <strong><em>DistributionName</em></strong> が対象の名前になっているエントリを探す</li>\n      <li>そのエントリの<strong><em>DefaultUid</em></strong> を 対象のユーザIDに変更する。<br />\n対象のユーザIDはコピー元の<strong><em>DefaultUid</em></strong> に合わせれば良い。 あるいは、一旦ログインして/etc/passwd で調べる。 (大抵、1000( = 0x3e8 )のはず)</li>\n    </ul>\n  </li>\n</ul>\n\n<p>参考:<a href=\"https://roy-n-roy.github.io/Windows/WSL%EF%BC%86%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A/centos/#wsl\" target=\"_blank\">WSLでCentOS/Fedoraを利用する - roy-n-roy メモ</a></p>\n\n<h1 id=\"なんかのときに使うかも\">なんかのときに使うかも</h1>\n\n<p>試してないけど、メモっておく。</p>\n<ul>\n  <li>仮想ディスクが肥大化した場合の対処方法<br />\n<del><a href=\"https://qiita.com/386jp/items/e469333c5a74789db46d\" target=\"_blank\">WSL2を使っているパソコンのディスク容量が枯渇したときにやってみるべきこと</a></del><br />\nこっちの方が分かりやすかった。<br />\n<a href=\"https://www.atmarkit.co.jp/fwin2k/win2ktips/1271vhdexpcmd/vhdexpcmd.html\">仮想ディスクをコマンドラインから拡大/縮小する</a></li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>PS: XXXX> diskpart                                                 ← コマンド起動\n\nMicrosoft DiskPart バージョン 10.0.19041.964\n\nCopyright (C) Microsoft Corporation.\nコンピューター: XXXXXX\n\nDISKPART> select vdisk file=\"f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\" ← 圧縮したいvhdxファイル\n\nDiskPart により、仮想ディスク ファイルが選択されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   20 GB\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART> compact vdisk                                            ← 縮小の実行\n\n  100% 完了しました                       ← ちょっと時間がかかる\n\nDiskPart により、仮想ディスク ファイルは正常に圧縮されました。\n\nDISKPART> detail vdisk                                             ← 縮小前の状態確認\n\nデバイスの種類 ID: 0 (不明)\nベンダー ID: {00000000-0000-0000-0000-000000000000} (不明)\n状態: 追加済み\n仮想サイズ:  256 GB\n物理サイズ:   12 GB                      ← 小さくなった\nファイル名: f:\\WSL_VMs\\openvino_2021_3\\ext4.vhdx\n子: いいえ\n親ファイル名:\n関連付けられたディスク番号: 見つかりません。\n\nDISKPART>exit                                                      ← 終了\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>git の差分比較ツールにWinMergeを使用する</title>\n  </head>\n  <body>\n    <header>\n      <h1>git の差分比較ツールにWinMergeを使用する</h1>\n      <p>git の差分比較ツールに WinMerge を使用する方法</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows上のgit-の差分比較ツールに-winmerge-を使用する方法\">Windows上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows限定だが、git の差分比較ツールに WinMerge を使用する方法のメモ<br />\n参考: <a href=\"https://qiita.com/kobake@github/items/fb317b4fdacad718a4b2?fbclid=IwAR1eO6ENMKDeeY3PmGJWrKLf_n1rgC8NVPBF60xKMiG02yAFgCFS6ceC7IE\">git の差分比較・マージを WinMerge で行う</a><br />\n↑参考というよりパクリだが(^^ゞ</p>\n\n<p>git の差分比較の <code class=\"language-plaintext highlighter-rouge\">git diff</code> で見ると見難いので、WinmMergeを使えるようにしてみた。<br />\n普段はVS Code 使ってるけど…</p>\n\n<p>手順は、 <code class=\"language-plaintext highlighter-rouge\">C:\\Users\\〇〇\\.gitconfig</code> に以下を追記するだけ。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n[difftool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -f \\\"*.*\\\" -e -u -r \\\"$LOCAL\\\" \\\"$REMOTE\\\"\n[merge]\n    tool = WinMerge\n[mergetool \"WinMerge\"]\n    path = C:/Program Files/WinMerge/WinMergeU.exe\n    cmd = \\\"C:/Program Files/WinMerge/WinMergeU.exe\\\" -e -u \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$MERGED\\\"\n[alias]\n    windiff = difftool -y -d -t WinMerge\n    winmerge = mergetool -y -t WinMerge\n</code></pre></div></div>\n\n<p>差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力すれば良い。</p>\n\n<p>差分はファイル書き換えても自動的にアップデートされなので、都度<code class=\"language-plaintext highlighter-rouge\">git windiff</code> する必要がある。<br />\n(あくまでスナップショットでの比較を表示してるだけ)</p>\n\n<p>比較対象の指定とか、マージとかもできるみたいだけど、使ってないので、詳しくは↑の参考先を見てね。(^^ゞ</p>\n\n<h1 id=\"wsl上のgit-の差分比較ツールに-winmerge-を使用する方法\">WSL上のgit の差分比較ツールに WinMerge を使用する方法</h1>\n\n<p>Windows上の場合とほぼ同じ。<code class=\"language-plaintext highlighter-rouge\">~/.gitconfig</code>に以下を追加しておき、差分比較したいときに <code class=\"language-plaintext highlighter-rouge\">git windiff</code> と入力する。<br />\nマージは使わないので、diffだけ設定。<br />\n(上の方法をwslpathでLinux上のpath→Windows上のpath 変換してるだけ、かな?)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[diff]\n    tool = WinMerge\n\n[difftool]\n    prompt = false\n\n[difftool \"WinMerge\"]\n    cmd = '/mnt/c/Program Files/WinMerge/WinMergeU.exe' -e -r -u -wl -dl Local -wr -dr Remote \\\"`wslpath -wa $LOCAL`\\\" \\\"`wslpath -wa $REMOTE`\\\"\n    trustExitCode = false\n\n[alias]\n    windiff = difftool -y -d --no-symlinks -t WinMerge\n</code></pre></div></div>\n<p>参考:<a href=\"https://qiita.com/forest1/items/334b5d756b5696c63331\">WSL(Ubuntu 18.04)環境のgitでWinMergeを使う方法</a></p>\n\n<p>参考先ではUbuntu18.04となっているが、20.04でも問題なし。<br />\nまた、<code class=\"language-plaintext highlighter-rouge\">/mnt/c/Users/username</code>以下で作業と書いてあるが、どこで作業しても大丈夫。テンポラリパスの変更も不要。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "wireshark": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える(その2)</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順はWiresharkで色々操作しないといけないのがめんどっちいので、スクリプトで自動化してみた。</p>\n\n<p>WiresharkのCUI版である、tsharkを使うと出来るらしいとの情報があったので、試してみたときのメモ。<br />\n今回はRaspberryPiだけ。Windowsは対応してません。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<p><a href=\"/memoBlog/2020/08/30/wireshark_1.html\">WiresharkでUSBパケットをキャプチャするときの注意事項</a> \nの準備は出来ているものとする。(Wiresharkは入ってなくても大丈夫。もちろん 入ってても良いよ。)</p>\n\n<p>tsharkは以下のコマンドイッパツでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tshark \n</code></pre></div></div>\n\n<p>で、あとは以下のスクリプトを\n<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの<code class=\"language-plaintext highlighter-rouge\">json_read.py</code>と同じディレクトリに作成し、実行するだけ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cap.sh\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\">#!/usr/bin/env bash</span>\n\n<span class=\"c\"># 第一引数でキャプチャ期間(sec)</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-z</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n  <span class=\"c\"># 引数なしだと2secに設定</span>\n  <span class=\"nv\">period</span><span class=\"o\">=</span>2\n<span class=\"k\">else</span>\n  <span class=\"c\"># 引数のチェック</span>\n  <span class=\"k\">if </span><span class=\"nb\">expr</span> <span class=\"s2\">\"</span><span class=\"nv\">$1</span><span class=\"s2\">\"</span> : <span class=\"s1\">'[0-9]*'</span> <span class=\"o\">></span> /dev/null <span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># 数値</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nv\">$1</span> <span class=\"nt\">-lt</span> 1 <span class=\"o\">]</span> <span class=\"p\">;</span> <span class=\"k\">then</span>\n      <span class=\"c\"># 1未満の数値</span>\n      <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n      <span class=\"nb\">exit\n    </span><span class=\"k\">else</span>\n      <span class=\"c\"># 1以上の数値(OK)</span>\n      <span class=\"nv\">period</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">1</span><span class=\"k\">}</span>\n    <span class=\"k\">fi\n  else</span>\n    <span class=\"c\"># 数値でない</span>\n    <span class=\"nb\">echo</span> <span class=\"s2\">\"1以上の数字を指定してください\"</span>\n    <span class=\"nb\">exit\n  </span><span class=\"k\">fi\nfi</span>\n\n<span class=\"c\"># 現在時刻</span>\n<span class=\"nv\">cur_time</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">date</span> <span class=\"s2\">\"+%y%m%d_%H%M%S\"</span><span class=\"sb\">`</span>\n<span class=\"c\"># ファイル名生成</span>\n<span class=\"nv\">fname_base</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span>_<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># USBパケットキャプチャ</span>\n<span class=\"nb\">echo</span> <span class=\"s2\">\"Capture USB packets for </span><span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span><span class=\"s2\"> second from </span><span class=\"k\">${</span><span class=\"nv\">cur_time</span><span class=\"k\">}</span><span class=\"s2\">\"</span>\ntshark <span class=\"nt\">-i</span> usbmon1 <span class=\"nt\">-w</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-a</span> duration:<span class=\"k\">${</span><span class=\"nv\">period</span><span class=\"k\">}</span>\n\n<span class=\"c\"># バス番号、デバイス番号の抽出</span>\n<span class=\"nv\">tmp_str</span><span class=\"o\">=</span><span class=\"sb\">`</span>lsusb | <span class=\"nb\">grep </span>WebCam<span class=\"sb\">`</span>\n<span class=\"nv\">bus_and_dev</span><span class=\"o\">=(</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">tmp_str</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"s/Bus </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">Device </span><span class=\"se\">\\(</span><span class=\"s2\">.*</span><span class=\"se\">\\)</span><span class=\"s2\">: ID.*/</span><span class=\"se\">\\1</span><span class=\"s2\"> </span><span class=\"se\">\\2</span><span class=\"s2\">/g\"</span><span class=\"sb\">`</span><span class=\"o\">)</span>\n<span class=\"nv\">bus</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[0]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">dev</span><span class=\"o\">=</span><span class=\"sb\">`</span><span class=\"nb\">echo</span> <span class=\"k\">${</span><span class=\"nv\">bus_and_dev</span><span class=\"p\">[1]</span><span class=\"k\">}</span> | <span class=\"nb\">sed</span> <span class=\"s1\">'s/0*\\([0-9]*[0-9]$\\)/\\1/g'</span><span class=\"sb\">`</span>\n<span class=\"nv\">endpoint</span><span class=\"o\">=</span>1\n<span class=\"nv\">addr</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">bus</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">dev</span><span class=\"k\">}</span>.<span class=\"k\">${</span><span class=\"nv\">endpoint</span><span class=\"k\">}</span>\n<span class=\"c\"># echo ${addr}</span>\n\n<span class=\"c\"># JSONファイルをエクスポート</span>\n<span class=\"nb\">echo </span>JSON data save to <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json...\ntshark <span class=\"nt\">-r</span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.pcapng <span class=\"nt\">-Y</span> <span class=\"s2\">\"usb.src==</span><span class=\"se\">\\\"</span><span class=\"k\">${</span><span class=\"nv\">addr</span><span class=\"k\">}</span><span class=\"se\">\\\"</span><span class=\"s2\">\"</span> <span class=\"nt\">-T</span> json <span class=\"o\">></span> <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json\n\n<span class=\"c\"># JSON->CSV 変換</span>\npython json_read.py <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.json <span class=\"k\">${</span><span class=\"nv\">fname_base</span><span class=\"k\">}</span>.csv\n\n</code></pre></div></div>\n\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。キャプチャ時間を秒で設定する。省略時は2秒。<br />\n出力されるファイル名は実行時の時刻で作成された文字列に各拡張子を付加したもの。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash cap.sh <span class=\"o\">[</span>キャプチャ時間<span class=\"o\">(</span>sec<span class=\"o\">)]</span>\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>なんかパラメータチェックが一番長いなぁ…😅</p>\n\n<p>33行目でパケットキャプチャ実行。</p>\n\n<p>35~41行目で対象USB機器のアドレス(バス番号、デバイス番号)を取得している。<br />\n36行目の<code class=\"language-plaintext highlighter-rouge\">grep</code>のパラメータは対象となるUSB機器に合わせて変更してちょ。<br />\nエンドポイント番号は対象機器によって固定なので、調べてね。\n分からなかったら、キャプチャしたデータをWiresharkで読み込んで確認してちょ。</p>\n\n<p>46行目でキャプチャしたファイルをJSONファイルにエクスポート。</p>\n\n<p>49行目でJSON→CSV変換。</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>これで<a href=\"/memoBlog/2020/08/30/wireshark_2.html\">WiresharkでUSBパケットを解析するときのニッチな要求に応える</a> \nの手順をスクリプトイッパツで完了できる。<br />\nま、特定環境でしか試してないから、どんな環境でも使えるとは限らないけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットを解析するときのニッチな要求に応える</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットを解析するときのニッチな要求に応える</h1>\n      <p>WiresharkでUSBパケットを解析するときのニッチな要求に応えたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要--背景\">概要 & 背景</h1>\n\n<p>WiresharkでUSBパケットをキャプチャしたとき、実際に転送されてるデータの中身が見たいというニッチな要求があった。<br />\n(送ったデータがちゃんとUSBバスに出てるよね~、という確認がしたいなどの用途)</p>\n\n<p>Wiresharkのセーブデータ渡して「Wiresharkで見てね~」と言ったら「見方が分からん!」と…<br />\nで、Excelで一覧表にしてあげようと思い、エクスポートできんかな~と探してみるも、適当な機能が見つからず…<br />\nしかたなく、変換スクリプトかましてCSVに出力してExcelで読み込んでみよう、と試した時のメモ。</p>\n\n<p>今回はisochronous転送のデータの中身をダンプしている。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<ol>\n  <li>最初に解析したいパケットをキャプチャしておく(これをやらなきゃ始まらん…)。</li>\n  <li>必要なら表示フィルタで解析したいパケットだけ選び出す。</li>\n  <li>それらのパケットの一部だけ(最初の1秒だけ など)解析したい場合はそのパケット群を選択する。<br />\n   RaspberryPiでのやり方が分からん…Windows版なら他のアプリ同様、先頭で左クリック→最後でshift押しながら左クリックでOK。<br />\n   どうしても出来なかったら、RaspberryPiでキャプチャしたのを保存して、そのファイル(pcapngファイル)をWindowsにコピーして、\n   Windows上のWiresharkで読み込んでくだされ…😅</li>\n  <li>メニューの「ファイル」→「パケット解析をエクスポート」→「JSONとして」を選択</li>\n  <li>ファイル操作ダイアログが表示される\n    <ul>\n      <li>真ん中の「ファイル名」を入力</li>\n      <li>左下の「パケットの範囲」で\n        <ul>\n          <li>「表示されたパケット」を選択</li>\n          <li>「すべてのパケット」または「選択されたパケットのみ」を選択<br />\n (ここで「範囲」を選んで入力すれば選択しなくてもいいのかな?試してないので不明)</li>\n        </ul>\n      </li>\n      <li>「保存」をクリック</li>\n    </ul>\n  </li>\n</ol>\n\n<p>これでJSONファイルが保存される。</p>\n\n<h1 id=\"csvファイルに変換\">CSVファイルに変換</h1>\n\n<p>さぁ、このJSONファイルを読み込んで必要な部分を取り出すスクリプトを書けばOKじゃん?と思ったが、<br />\nそうは問屋がおろしてくれない😢<br />\nじつはWiresharkがエクスポートするJSONファイルはJSONファイルの文法からはずれた部分があるのだ…<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">/_source/layers/usb</code> の配下に複数のキー<code class=\"language-plaintext highlighter-rouge\">usb</code>があって、すべてのUSBデータを読み込めない。<br />\n(JSONの仕様では同一階層に複数の同じキーの存在を許さない。pythonのJSONモジュールでは複数あるデータのうち、一つだけが読み込まれる)<br />\nここが配列になってればOKだと気が付いて、チカラワザで変換する処理を追加してみた。</p>\n\n<p>で、pyshonで書いたスクリプトがこちら。<br />\nWindows/RaspberryPi どっちでも大丈夫と思うけど、Windowsでしか試してない。<br />\npythonは3.6以降が必要。3.7.7で動作確認。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  json_read.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"c1\"># テンポラリファイル名\n</span><span class=\"n\">tmp_file</span> <span class=\"o\">=</span> <span class=\"s\">'tmp.json'</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">usage</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'==== USAGE ========================='</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'    </span><span class=\"si\">{</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s\"> <JSON file> <CSV file>'</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'===================================='</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">3</span> <span class=\"p\">:</span>\n    <span class=\"n\">json_file</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"n\">csv_file</span>  <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n<span class=\"k\">else</span> <span class=\"p\">:</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span> <span class=\"s\">'Error: JSON file not exist!!'</span><span class=\"p\">)</span>\n    <span class=\"n\">usage</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># \"usb\" キーが複数あるので、これをリストに変換したJSONファイルを作成する\n# かなり力技...\n</span><span class=\"k\">def</span> <span class=\"nf\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_json</span><span class=\"p\">,</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_tmp</span><span class=\"p\">:</span>\n        <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        \n        <span class=\"k\">while</span> <span class=\"n\">line</span><span class=\"p\">:</span>\n            <span class=\"n\">line_number</span> <span class=\"o\">=</span> <span class=\"n\">line_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>           <span class=\"c1\"># 行番号\n</span>            <span class=\"c1\"># line = line.rstrip('\\r\\n')              # CRLFを削除\n</span>            <span class=\"k\">if</span> <span class=\"n\">find_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">'\"usb\": '</span><span class=\"p\">,</span> <span class=\"s\">''</span><span class=\"p\">)</span>      <span class=\"c1\"># key名称 \"usb\"を削除\n</span>                <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'START: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          \"usb_data\": [</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">+</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'{'</span><span class=\"p\">)</span>\n                <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"n\">brackets</span> <span class=\"o\">-</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">count</span><span class=\"p\">(</span><span class=\"s\">'}'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">brackets</span> <span class=\"o\"><</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># print(f'END: {line_number} {line}')\n</span>                    <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'          ]</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb.iso.numdesc\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">f_pos</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">tell</span><span class=\"p\">()</span>\n                    <span class=\"n\">next_line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>        <span class=\"c1\"># 次の行を読み込んで\n</span>                    <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"n\">f_pos</span><span class=\"p\">)</span>                   <span class=\"c1\"># ファイル位置を戻す\n</span>                    <span class=\"k\">if</span> <span class=\"n\">next_line</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'          \"usb\":'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                        <span class=\"n\">find_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n                        <span class=\"n\">brackets</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                    <span class=\"c1\"># 括弧の数\n</span>            <span class=\"n\">f_tmp</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">line</span><span class=\"p\">)</span>\n            <span class=\"n\">line</span> <span class=\"o\">=</span> <span class=\"n\">f_json</span><span class=\"p\">.</span><span class=\"n\">readline</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># JSONファイルの修正\n</span><span class=\"n\">modify_json</span><span class=\"p\">(</span><span class=\"n\">json_file</span><span class=\"p\">,</span> <span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># パケット解析用変数\n</span><span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n<span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"c1\"># JSONファイルの読み込み\n</span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n    <span class=\"n\">json_load</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print(json_load)\n</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">csv_file</span><span class=\"p\">,</span> <span class=\"s\">'w'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f_csv</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># ヘッダの出力\n</span>    <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s\">'PacketNo,Date,Relative_time,Delta_time,Packet Size,Video Stream Size,Video Stream offset,Frame No,Stream No,Stream Data</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">json_data</span> <span class=\"ow\">in</span> <span class=\"n\">json_load</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># フレームデータ\n</span>        <span class=\"n\">frame_data</span>          <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"frame\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_index</span>         <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.number\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_epoc</span>     <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_epoch\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_delta</span>    <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_delta_displayed\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_relative</span> <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.time_relative\"</span><span class=\"p\">]</span>\n        <span class=\"n\">frame_time_dt</span>       <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">fromtimestamp</span><span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">frame_time_epoc</span><span class=\"p\">))</span>\n        <span class=\"n\">frame_time</span>          <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_time_dt</span><span class=\"p\">)</span>\n        <span class=\"n\">frame_len</span>           <span class=\"o\">=</span> <span class=\"n\">frame_data</span><span class=\"p\">[</span><span class=\"s\">\"frame.len\"</span><span class=\"p\">]</span>\n        <span class=\"c1\"># print(f'{frame_index},\"\\'{frame_time}\",{frame_len},', end='')\n</span>        <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">frame_index</span><span class=\"si\">}</span><span class=\"s\">,\"</span><span class=\"se\">\\'</span><span class=\"si\">{</span><span class=\"n\">frame_time</span><span class=\"si\">}</span><span class=\"s\">\",</span><span class=\"si\">{</span><span class=\"n\">frame_time_relative</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_time_delta</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_len</span><span class=\"si\">}</span><span class=\"s\">,'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># USBデータ\n</span>        <span class=\"n\">usb_datas</span>  <span class=\"o\">=</span> <span class=\"n\">json_data</span><span class=\"p\">[</span><span class=\"s\">\"_source\"</span><span class=\"p\">][</span><span class=\"s\">\"layers\"</span><span class=\"p\">][</span><span class=\"s\">\"usb\"</span><span class=\"p\">][</span><span class=\"s\">\"usb_data\"</span><span class=\"p\">]</span>\n        <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"k\">for</span> <span class=\"n\">usb_data</span> <span class=\"ow\">in</span> <span class=\"n\">usb_datas</span> <span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">first_flag</span> <span class=\"p\">:</span>\n                <span class=\"n\">first_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f',,,,,', end='')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">',,,,,'</span><span class=\"p\">)</span>\n            <span class=\"n\">iso_len</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_len'</span><span class=\"p\">])</span>\n            <span class=\"n\">iso_off</span>  <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">'usb.iso.iso_off'</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">iso_len</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"n\">usb_data</span><span class=\"p\">[</span><span class=\"s\">\"usb.iso.data\"</span><span class=\"p\">]</span>\n                <span class=\"n\">iso_data</span> <span class=\"o\">=</span> <span class=\"s\">'0x'</span><span class=\"o\">+</span><span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s\">':'</span><span class=\"p\">,</span> <span class=\"s\">',0x'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">stream_number</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number</span> <span class=\"o\">=</span> <span class=\"n\">frame_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">frame_number</span><span class=\"p\">)</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">frame_number_str</span> <span class=\"o\">=</span> <span class=\"s\">''</span>\n                \n                <span class=\"c1\"># print(f'{iso_len},{iso_off},{stream_number},{iso_data}')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">frame_number_str</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">stream_number</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_data</span><span class=\"si\">}</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x02'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">iso_data</span><span class=\"p\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s\">'0x02,0x03'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">stream_number</span> <span class=\"o\">=</span> <span class=\"n\">stream_number</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># print(f'{iso_len},{iso_off},,')\n</span>                <span class=\"n\">f_csv</span><span class=\"p\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">iso_len</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">iso_off</span><span class=\"si\">}</span><span class=\"s\">,,</span><span class=\"se\">\\n</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n\n<span class=\"c1\"># テンポラリファイルの削除\n</span><span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">tmp_file</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<h2 id=\"実行方法\">実行方法</h2>\n<p>以下のコマンドで実行する。(RaspberryPiだと<code class=\"language-plaintext highlighter-rouge\">python3</code>にしてちょ)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python json_read.py «入力JSONファイル» «出力CSVファイル»\n</code></pre></div></div>\n\n<h2 id=\"ちょっと説明\">ちょっと説明</h2>\n\n<p>やっつけスクリプトなので、エラーチェックはかなりいい加減…</p>\n\n<p>関数<code class=\"language-plaintext highlighter-rouge\">modify_json()</code> が 前述のJSONファイルの不具合をチカラワザで修正する処理。</p>\n\n<p>テンポラリファイルとしてカレントディレクトリに<code class=\"language-plaintext highlighter-rouge\">tmp.json</code>を作成するので、注意。\nファイル名を変更したければ、8行目の<code class=\"language-plaintext highlighter-rouge\">tmp_file</code>を変更。<br />\nこのファイルはスクリプトの最後で削除している。<br />\n作成したテンポラリファイルを残しておきたければ最後の<code class=\"language-plaintext highlighter-rouge\">os.remove(tmp_file)</code>をコメントアウト。</p>\n\n<p>71~72行目で修正したJSONファイルを読み込み。</p>\n\n<p>75行目で書き出すCSVファイルをオープン。</p>\n\n<p>78行目~のforループで各JSONレコードを読み込みながら処理。</p>\n\n<p>82,85~86行目でframe.time_epochから時刻文字列を作成。<br />\n時刻は<code class=\"language-plaintext highlighter-rouge\">frame.time</code>を使用する手もあるが、ここはプラットフォームによって変化するらしいので同じ表示にするためにエポックタイムから生成している。<br />\nその他時刻関連データでは、<code class=\"language-plaintext highlighter-rouge\">frame.time_delta_displayed</code>で「前のパケットからの相対時間」、\n<code class=\"language-plaintext highlighter-rouge\">frame.time_relative</code>で「最初のパケットからの相対時間」を取得している。</p>\n\n<p>94行目~のforループがデータを取り出す部分。<br />\nisochronous転送のデータではないデータを取り出したい場合は、所望のデータのキーに置き換えて取り出せば良い。<br />\n<code class=\"language-plaintext highlighter-rouge\">frame_number</code>と<code class=\"language-plaintext highlighter-rouge\">stream_number</code>は私の解析用の補助データなので気にしないでネ。</p>\n\n<p>あとは、エクスポートされたJSONファイルとスクリプトを見比べてちゃぶだい。(^^ゞ</p>\n\n<h1 id=\"おしまい\">おしまい</h1>\n\n<p>あとは、csvファイルをExcelで読み込むなり、pandasとかを使った別のスクリプトで加工するなりしてちょ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WiresharkでUSBパケットをキャプチャするときの注意事項</title>\n  </head>\n  <body>\n    <header>\n      <h1>WiresharkでUSBパケットをキャプチャするときの注意事項</h1>\n      <p>WiresharkでUSBパケットをキャプチャしようとしてちょっとハマったのでメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>WiresharkでUSBパケットをキャプチャするための準備(Linux版)<br />\nWindows版はちょっと異なると思うけど試してないので、ググってね😅。</p>\n\n<h1 id=\"wiresharkのインストール実行\">Wiresharkのインストール&実行</h1>\n\n<p>ふつーに<code class=\"language-plaintext highlighter-rouge\">apt install</code>するだけ。<br />\nWindows版と異なり、USBパケットキャプチャのために別途USBキャプチャプログラムをインストールする必要はない。<br />\nついでに<code class=\"language-plaintext highlighter-rouge\">sudo</code>しなくても実行できるように自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>グループを追加しておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>wireshark\n<span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span> wireshark \n</code></pre></div></div>\n\n<p>ここで一旦ログアウト&再ログイン or 再起動。</p>\n\n<p>このままだとUSBパケットキャプチャのためのプログラム(<code class=\"language-plaintext highlighter-rouge\">usbmon</code>)が動いてないので、動かす必要がある。<br />\n<strong>起動の度に</strong>ターミナルから以下のコマンドを実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbmon\n</code></pre></div></div>\n\n<p>Wiresharkの実行は、ターミナルから<code class=\"language-plaintext highlighter-rouge\">wireshark</code>を実行するか、メニューの「インターネット」→「Wireshark」を選択します。<br />\n(自分に<code class=\"language-plaintext highlighter-rouge\">wireshark</code>`グループを追加してあるので、メニューからでも実行できます)</p>\n\n<p>起動の度に<code class=\"language-plaintext highlighter-rouge\">usbmon</code>を起動するのは面倒な場合は、以下の手順で自動化できます。</p>\n\n<ol>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/udev/rules.d/99-usbmon.rules</code>を以下の内容で作成\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>SUBSYSTEM==\"usbmon\", GROUP=\"wireshark\", MODE=\"640\"\n</code></pre></div>    </div>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">/etc/modules</code> に以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbmon\n</code></pre></div>    </div>\n  </li>\n  <li>リブート</li>\n</ol>\n\n<h1 id=\"wiresharkの使い方\">Wiresharkの使い方</h1>\n\n<p>あちこちのホームページに詳しく解説されているので、ぐぐってちょ(←なんて他力本願…😅)。<br />\nRaspberryPi4の場合、USBのインタフェースはusbmon1とusbmon2があるが、どっちをキャプチャするかは、接続した機器がUSB2.0かUSB3.0による。<br />\nたぶん、usbmon1がUSB2.0(外側/内側)、usbmon2がUSB3.0(内側のみ)だと思う。<br />\n<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)がusbmonYのYにあたるとだと推測。</p>\n\n<h1 id=\"wiresharkでパケット解析\">Wiresharkでパケット解析</h1>\n\n<p>USBのパケットの表示フィルタの書き方がネット上でもなかなか見つからなかったので、簡単なものだけメモ。</p>\n\n<h2 id=\"特定のusb機器のパケットだけ表示\">特定のUSB機器のパケットだけ表示</h2>\n\n<p>実際にはエンドポイントまで指定しているので、複数のエンドポイントを同時に表示したければ、OR(<code class=\"language-plaintext highlighter-rouge\">||</code>)で条件つなげてください。\n(<code class=\"language-plaintext highlighter-rouge\">1.5.*</code>みたいな書き方が出来るのかは不明 )</p>\n\n<p>この例の<code class=\"language-plaintext highlighter-rouge\">1.5.1</code>の<br />\n左の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のバス番号(<code class=\"language-plaintext highlighter-rouge\">Bus XXX</code>の部分の数字)、 <br />\n中央の<code class=\"language-plaintext highlighter-rouge\">5</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb</code>で表示される対象機器のデバイス番号(<code class=\"language-plaintext highlighter-rouge\">Device YYY</code>の部分の数字)(<strong>挿抜の度に変わる</strong>)、 <br />\n右の<code class=\"language-plaintext highlighter-rouge\">1</code>が<code class=\"language-plaintext highlighter-rouge\">lsusb -D /dev/bus/usb/XXX/YYY</code>(XXX、YYYは上記のバス番号、デバイス番号。0は省略不可) で表示される情報の <br />\n<code class=\"language-plaintext highlighter-rouge\">bEndpointAddress</code>で確認できるけど、これは機器内部で固定されてるはず。<br />\nと、難しく調べんでも、一度全部キャプチャしたものを表示して欲しいパケットを探してみてそこのアドレスを見れば分かる。</p>\n\n<p>USBホストの吐合は<code class=\"language-plaintext highlighter-rouge\">\"host\"</code>になる。</p>\n\n<h3 id=\"特定の機器の送信パケットだけ表示\">特定の機器の送信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\"\n</code></pre></div></div>\n<h3 id=\"特定の機器の受信パケットだけ表示\">特定の機器の受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n<h3 id=\"特定の機器の送受信パケットだけ表示\">特定の機器の送受信パケットだけ表示</h3>\n<p>表示フィルタに以下を入力してリターン(以下の1.5.1の部分は対象の機器のものに変更)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usb.src == \"1.5.1\" || usb.dst == \"1.5.1\"\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Jetson nano": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</h1>\n      <p>Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>SDカードのアクセスが遅いのと、USBドライブの方が大容量のメディアを入手しやすいので\nUSBドライブをブートデバイスに変更してみる。</p>\n\n<p>といっても、Jetpack4.5以降ではブートローダがUSBからのブートをサポートしたので、かなり簡単になった。</p>\n\n<p>Jetpack4.4のときのメモは<a href=\"/memoBlog/2020/10/30/Jetson_usb_boot.html\" target=\"_blank\">Jetson nano をUSBドライブからブートできるようにする</a> にあります。</p>\n\n<h1 id=\"ディスクイメージの書き込み\">ディスクイメージの書き込み</h1>\n<p>通常セットアップを行ったSDカードのディスクイメージをUSBドライブにコピーします。\nSDカード→USBドライブ直接でも構いませんし、バックアップとして作成したディスクイメージファイルからでも構いません。</p>\n\n<p>ubuntu PCでディスクイメージファイルからコピーする場合はこんな感じ。<br />\n<code class=\"language-plaintext highlighter-rouge\">/dev/sdc</code> の部分は環境により異なるので注意(間違って他のディスクに上書きしないように!!)。<br />\n<code class=\"language-plaintext highlighter-rouge\">jetpack46_XXXXXXXX.img</code>がディスクイメージファイルのファイル名です。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"nv\">of</span><span class=\"o\">=</span>/dev/sdc <span class=\"k\">if</span><span class=\"o\">=</span>jetpack46_XXXXXXXX.img <span class=\"nv\">bs</span><span class=\"o\">=</span>1M <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div></div>\n\n<h1 id=\"bootデバイス変更のための設定\">BOOTデバイス変更のための設定</h1>\n\n<p>ディスクイメージを書き込んたUSBドライブをSDカードブートした Jetson nano や ubuntu PCに接続し、\n設定ファイルを書き換えます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ディスクのマウント</span>\n<span class=\"nb\">sudo </span>mount /dev/sdc1 /mnt\n<span class=\"nb\">cd</span> /mnt/boot/extlinux/\n<span class=\"c\"># オリジナルファイルのバックアップ</span>\n<span class=\"nb\">sudo cp </span>extlinux.conf extlinux.conf.mmc\n<span class=\"c\"># 編集</span>\n<span class=\"nb\">sudo </span>vi extlinux.conf\n</code></pre></div></div>\n\n<p>以下のように変更します\n具体的には<code class=\"language-plaintext highlighter-rouge\">/mnt/boot/extlinux/extlinux.conf</code> 内の \n<code class=\"language-plaintext highlighter-rouge\">/dev/mmcblk0p1</code>を<code class=\"language-plaintext highlighter-rouge\">/dev/sda1</code>に変更します。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- extlinux.conf.mmc\t2021-09-14 06:02:45.889520568 +0900\n</span><span class=\"gi\">+++ extlinux.conf\t2021-09-14 06:03:29.453873117 +0900\n</span><span class=\"p\">@@ -7,7 +7,7 @@</span>\n       MENU LABEL primary kernel\n       LINUX /boot/Image\n       INITRD /boot/initrd\n<span class=\"gd\">-      APPEND ${cbootargs} loglevel=6 root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 ipv6.disable=1\n</span><span class=\"gi\">+      APPEND ${cbootargs} loglevel=6 root=/dev/sda1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 ipv6.disable=1\n</span> \n # When testing a custom kernel, it is recommended that you create a backup of\n # the original kernel and add a new entry to this file so that the device can\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nrootパラメータはパーティションのUUIDを書いておくのが最近の作法らしいが\n大抵 マウント先は <code class=\"language-plaintext highlighter-rouge\">/dev/sda1</code> なので、お手軽にこっちで指定する。</p>\n</blockquote>\n\n<h1 id=\"ついでに設定\">ついでに設定</h1>\n<p>ついでにパーティションサイズも変更しておくと良いです。</p>\n\n<h1 id=\"boot\">BOOT</h1>\n<p>あとはJetson nano にUSBドライブを接続し、元々ブートに使用していた<strong>SDカードを取り外し</strong>て電源ON。</p>\n\n<p>起動後、USBドライブがrootにマウントされていることを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">mount</code>で確認しても良いけど、いっぱい出てきて鬱陶しいので<code class=\"language-plaintext highlighter-rouge\">df</code>で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">df</span> <span class=\"nt\">-h</span> /\n</code></pre></div></div>\n<p>こんな感じで行頭にマウント元が表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Filesystem      Size  Used Avail Use% Mounted on\n/dev/sda1       108G   13G   91G  13% /\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</h1>\n      <p>Jetson nano にtigerVNCをインストールする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/09/13/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする(Jetpack4.6)</a>\nではVNCにvinoをインストールしましたが、vinoはキー入力/画面描画のレスポンスがかなり遅く、\n結構なストレスになります。<br />\nそこで、代わりに<a href=\"https://tigervnc.org/\">tigerVNC</a>をインストールしてみます。</p>\n\n<p>最初に結論を書いておきますが、レスポンスはvinoより良くなるのですが、クリップボードの共有\n(ホスト/ターゲット間でのコピペ)ができないので、普段使いにはあまり使い勝手が良くありません。<br />\ngithubのリポジトリもずいぶん前から更新されていないみたいなので、今後改善される可能性も低そうです。<br />\nなので、私は使っていません(^^ゞ</p>\n\n<h1 id=\"前準備\">前準備</h1>\n<p>vinoをセットアップしてある場合は停止しておいてください。<br />\n<code class=\"language-plaintext highlighter-rouge\">~/.config/autostart/vino-server.desktop</code> を削除しておけば大丈夫でしょう。<br />\n以下、vinoのセットアップは行っていないものとして記載します。</p>\n\n<h1 id=\"tigervncの設定\">tigerVNCの設定</h1>\n\n<h2 id=\"tiger-vnc-のインストール\">tiger VNC のインストール</h2>\n<p>必要なプログラムをインストールします</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tigervnc-standalone-server tigervnc-scraping-server\n</code></pre></div></div>\n\n<h2 id=\"vncのパスワードの設定\">VNCのパスワードの設定</h2>\n<p>接続パスワードを設定します</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vncpasswd\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">Password:</code>と<code class=\"language-plaintext highlighter-rouge\">Verify:</code>で設定するパスワードを入力<br />\n<code class=\"language-plaintext highlighter-rouge\">Would you like to enter a view-only password (y/n)?</code>には <code class=\"language-plaintext highlighter-rouge\">n</code>を入力<br />\nVNCクライアントから接続する際にこのパスワードを入力します</p>\n\n<h2 id=\"自動loginの設定\">自動loginの設定</h2>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定します</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h2 id=\"解像度の設定\">解像度の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n<h2 id=\"ここで一旦リブートする\">ここで一旦リブートする</h2>\n<p>リブートしないと下の単体テストで「displayがopenできない」とエラーになる模様。</p>\n\n<h2 id=\"手動で動かしてみる画面のミラーリング\">手動で動かしてみる(画面のミラーリング)</h2>\n\n<p>動作確認として、サーバを手動で起動してみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>x0vncserver <span class=\"nt\">-display</span> :0 <span class=\"nt\">-passwordfile</span> ~/.vnc/passwd\n</code></pre></div></div>\n\n<p>サーバが起動したら、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続します。</p>\n\n<p>正常に設定できていればVNCクライアントにデスクトップが表示されます。</p>\n\n<h2 id=\"自動起動の設定\">自動起動の設定</h2>\n<p>逐一<code class=\"language-plaintext highlighter-rouge\">x0vncserver</code>を起動するのは面倒なので、自動で起動するように設定しておきます。</p>\n\n<p>参考: <a href=\"https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f\">https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/systemd/system/x0vncserver.service</code> を以下の内容で作成します。<br />\nただし、<code class=\"language-plaintext highlighter-rouge\">XXXXXXXX</code>の部分は 自分のユーザ名に置き換えてください。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Remote desktop service (VNC)\nAfter=syslog.target\nAfter=network.target remote-fs.target nss-lookup.target\nAfter=x11-common.service \n\n[Service]\nType=forking\nUser=XXXXXXXX\nGroup=XXXXXXXX\nWorkingDirectory=/home/XXXXXXXX\nExecStart=/bin/sh -c 'sleep 10 && /usr/bin/x0vncserver -display :0  -rfbport 5900 -passwordfile /home/XXXXXXXX/.vnc/passwd &'\n\n[Install]\nWantedBy=multi-user.target\n</code></pre></div></div>\n\n<h2 id=\"サービスの起動と確認\">サービスの起動と確認</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl start x0vncserver\n<span class=\"nb\">sudo </span>systemctl status x0vncserver\n</code></pre></div></div>\n\n<p>以下のように出力されることを確認します</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>● x0vncserver.service - Remote desktop service (VNC)\n   Loaded: loaded (/etc/systemd/system/x0vncserver.service; enabled; vendor pres\n   Active: active (running) since Fri 2021-09-03 11:08:07 JST; 8s ago\n  Process: 14646 ExecStart=/bin/sh -c sleep 10 && /usr/bin/x0vncserver -display ・・・・\n Main PID: 14659 (sh)\n    Tasks: 2 (limit: 4172)\n   CGroup: /system.slice/x0vncserver.service\n           ├─14659 /bin/sh -c sleep 10 && /usr/bin/x0vncserver -display :0  ・・・・\n           └─14666 sleep 10\n\n 9月 03 11:08:07 jetson systemd[1]: Starting Remote desktop service (VNC)...\n 9月 03 11:08:07 jetson systemd[1]: Started Remote desktop service (VNC).\n</code></pre></div></div>\n\n<h2 id=\"サービスの有効化\">サービスの有効化</h2>\n<p>起動時に自動実行されるように、サービスの有効化を行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>systemctl <span class=\"nb\">enable </span>x0vncserver\n</code></pre></div></div>\n\n<h2 id=\"リブート\">リブート</h2>\n\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続します。</p>\n\n<p>正常に起動できていればVNCクライアントにデスクトップが表示されます。</p>\n\n<h1 id=\"別のやり方参考\">別のやり方(参考)</h1>\n<p>ディスプレイとは別のデスクトップを表示する場合は以下の手順で。<br />\nここではwindow managerにlxdeを使用していますので、モニタ表示とは異なる見た目になりますし、\nウィンドウマネージャの設定も同じではありません。</p>\n\n<p>参考:<a href=\"https://forums.developer.nvidia.com/t/how-to-setup-tigervnc-on-jetson-nano/174244\">https://forums.developer.nvidia.com/t/how-to-setup-tigervnc-on-jetson-nano/174244</a></p>\n\n<p>一回試しただけ(ちゃんとメモってなかった)なので、抜けとかあるかも。</p>\n\n<h2 id=\"tiger-vnc-のインストール-1\">Tiger VNC のインストール</h2>\n<p>必要なプログラムをインストールします</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>tigervnc-standalone-server\n</code></pre></div></div>\n\n<h2 id=\"vncのパスワードの設定-1\">VNCのパスワードの設定</h2>\n<p>接続パスワードを設定します</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vncpasswd\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">Password:</code>と<code class=\"language-plaintext highlighter-rouge\">Verify:</code>で設定するパスワードを入力<br />\n<code class=\"language-plaintext highlighter-rouge\">Would you like to enter a view-only password (y/n)?</code>には <code class=\"language-plaintext highlighter-rouge\">n</code>を入力<br />\nVNCクライアントから接続する際にこのパスワードを入力します</p>\n\n<h2 id=\"自動loginの設定-1\">自動loginの設定</h2>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定します</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h2 id=\"解像度の設定-1\">解像度の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n\n<h2 id=\"vncxstartup-の作成\">~/.vnc/xstartup の作成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.vnc/xstartup</code> を以下の内容で作成します<br />\nXXXXXXXX は 自分のユーザ名に置き換えてください</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">!</span>/bin/sh\n<span class=\"nb\">export </span><span class=\"nv\">XDG_RUNTIME_DIR</span><span class=\"o\">=</span>/run/user/1000\n<span class=\"nb\">export </span><span class=\"nv\">XKL_XMODMAP_DISABLE</span><span class=\"o\">=</span>1\n<span class=\"nb\">unset </span>SESSION_MANAGER\n<span class=\"nb\">unset </span>DBUS_SESSION_BUS_ADDRESS\nxrdb /home/XXXXXXXX/.Xresources\nxsetroot <span class=\"nt\">-solid</span> grey\ngnome-session &\nstartlxde &\n</code></pre></div></div>\n\n<p>実行属性を付けます</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod </span>755 ~/.vnc/xstartup\n</code></pre></div></div>\n\n<h2 id=\"xresources-ファイルの作成\">.Xresources ファイルの作成</h2>\n<p>.Xresources ファイルを作成します</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">touch</span> ~/.Xresources\n</code></pre></div></div>\n\n<h2 id=\"vncの自動起動の設定\">VNCの自動起動の設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/systemd/system/vncserver@.service</code>を以下の内容で作成します<br />\nXXXXXXXX は 自分のユーザ名に置き換えてください</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Start TigerVNC Server at startup\nAfter=syslog.target network.target\n\n[Service]\nType=forking\nUser=XXXXXXXX\nGroup=XXXXXXXX\nWorkingDirectory=/home/XXXXXXXX\nPIDFile=/home/XXXXXXXX/.vnc/%H:%i.pid\nExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1\nExecStart=/usr/bin/vncserver :%i -depth 24 -geometry 1920x1080 -nolisten tcp\n\nExecStop=/usr/bin/vncserver -kill :%i\n\n[Install]\nWantedBy=multi-user.target\n</code></pre></div></div>\n\n<h2 id=\"リモートからのアクセス許可\">リモートからのアクセス許可</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/vnc.conf</code> に以下を追記してリモートアクセスを許可します</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$localhost = “no”;\n</code></pre></div></div>\n\n<h2 id=\"systemctl-enable-の代わりにシンボリックリンクの作成\">systemctl enable の代わりにシンボリックリンクの作成</h2>\n<p>参照元がこうなってたので。<br />\n<code class=\"language-plaintext highlighter-rouge\">sudo systemctl enable vncserver@</code>でも良い気がするけど。ここのファイル名でポート番号決めてる?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /etc/systemd/system/multi-user.target.wants/\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-s</span> /etc/systemd/system/vncserver@.service vncserver@1.service\n</code></pre></div></div>\n\n<h2 id=\"リブートする\">リブートする</h2>\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5901に接続します。<br />\n(VNCクライアントの接続先に<code class=\"language-plaintext highlighter-rouge\">«JetsonのIPアドレス»:5901</code> を指定します)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をセットアップする(Jetpack4.6)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をセットアップする(Jetpack4.6)</h1>\n      <p>Jetson nano をセットアップする(Jetpack4.6)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>Nvidiaの<a href=\"https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/\">Jetson nano</a>をセットアップしたときのメモ<br />\nJetpack4.4のときのメモは<a href=\"/memoBlog/2020/10/23/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする</a> にあります。</p>\n\n<h1 id=\"参照先\">参照先</h1>\n<ul>\n  <li><a href=\"https://monoist.atmarkit.co.jp/mn/articles/1905/30/news029.html\">「Jetson Nano」の電源を入れて立ち上げる</a>\n    <ul>\n      <li>わりと詳しく書いてある</li>\n    </ul>\n  </li>\n  <li><a href=\"https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit\">Getting Started With Jetson Nano Developer Kit </a>\n    <ul>\n      <li>本家</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"シリアルコンソールの使用\">シリアルコンソールの使用</h1>\n<p>シリアルコンソールが必要なら接続できる。<br />\n特に設定等は必要ない。  <br />\n接続端子は以下を参照</p>\n<ul>\n  <li><a href=\"https://www.jetsonhacks.com/2019/04/19/jetson-nano-serial-console/\">Jetson Nano – Serial Console</a>\nの 「Wiring」の下の「Jetson Nano B01」を参照。</li>\n</ul>\n\n<p>シリアルポートの設定は115200bps/8bit/none/1bit/none</p>\n\n<p>その他、コネクタ類の配置が分かりにくい場合は、\n<a href=\"https://developer.download.nvidia.com/assets/embedded/secure/jetson/Nano/docs/NV_Jetson_Nano_Developer_Kit_User_Guide.pdf?yIbsUqvBKxI1G6r3WW7cOdheZGv2-eSfaFW_kMt3dSgi0NJ7h77OwFHr5b-rquc3IX7Tyrt8FV6IKD4DHqvP4_LzhWt55tb071gqXlNGwBPYCOC5pnEKAla8D-B82bPjhQMykANFyn-EhxZRHC8AIBYWuVwwwXVPWtCOjs34Tg50oBdN0vBNoyUlZMRFXLNJ2to\">JETSON NANO DEVELOPER KIT</a>\nのP22 に<strong>Developer kit module and carrier board: rev B01 top view</strong>として配置図が掲載されているので参照のこと。</p>\n\n<h1 id=\"sdカードの作成firstboot\">SDカードの作成~FirstBoot</h1>\n<p>基本的に参照先の通り。<br />\n<a href=\"https://developer.nvidia.com/embedded/downloads\">https://developer.nvidia.com/embedded/downloads</a>\nから「Jetson Nano Developer Kit SD Card Image」  の Version 「4.6」 をダウンロード<br />\n(他のバージョンが必要ならそのバージョンで)</p>\n\n<p>ファーストブートで設定が終わったら、何はともあれ最新版にアップデート。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ここで一旦リブートしておく。</p>\n\n<h1 id=\"sshでの接続\">SSHでの接続</h1>\n<p>特に設定などは必要ない。<br />\nTeraTermなどで接続すれば良い。\nUbuntuではmDNSが動いているので、«マシン名».localでアクセスできる。</p>\n\n<p>TeraTerm使用時のコマンドは以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\"C:\\Program Files (x86)\\teraterm\\ttermpro.exe\" /auth=password /user=«ユーザ名» /passwd=«パスワード» «JetsonのIPアドレス or マシン名.local»\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nSSHやmDNSは立ち上がるまで少し時間がかかるみたいなので、<br />\n起動後数十秒程度待ってから接続した方が良い。</p>\n</blockquote>\n\n<h2 id=\"ssh接続がタイムアウトする対策\">SSH接続がタイムアウトする対策</h2>\n<p>SSH接続したターミナルを触らずにしばらく置いておくと、タイムアウトしてクローズされてしまう。\nこれを防ぐにはクライアント側からkeep-aliveパケットを定期的に送信してやれば良いらしい。</p>\n\n<p>Teratermの場合、「設定」→「SSH」→「ハートビート(keep-alive)」を「8」とかに設定し、保存。\n次回接続時はこの保存した設定ファイルを読み込む</p>\n\n<h1 id=\"初期設定\">初期設定</h1>\n<h2 id=\"bashrcの修正\">.bashrcの修正</h2>\n<p>.bashrcの修正をお好みで。<br />\n以下は設定例</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># プロンプトの設定</span>\n<span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\w\\$</span><span class=\"s2\"> \"</span>\n\n<span class=\"c\"># キーバインドの設定</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-n\": history-search-forward'</span>\n<span class=\"nb\">bind</span> <span class=\"s1\">'\"\\C-p\": history-search-backward'</span>\n\n<span class=\"c\"># ディレクトリスタックの表示改善</span>\n<span class=\"k\">function </span><span class=\"nb\">pushd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command pushd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">popd</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command popd</span> <span class=\"nv\">$*</span> <span class=\"o\">></span> /dev/null\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n<span class=\"k\">function </span><span class=\"nb\">dirs</span><span class=\"o\">()</span> <span class=\"o\">{</span>\n    <span class=\"nb\">command dirs</span> <span class=\"nt\">-v</span>\n<span class=\"o\">}</span>\n\n<span class=\"c\"># 表示色変更</span>\n<span class=\"nb\">export </span><span class=\"nv\">LS_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'di=01;32:ln=01;36:ex=01;31:'</span>\n<span class=\"nb\">export </span><span class=\"nv\">GREP_COLORS</span><span class=\"o\">=</span><span class=\"s1\">'mt=01;31:ml=:cx=:fn=01;32:ln=32:bn=32:se=36'</span>\n\n<span class=\"c\"># lessのオプション</span>\n<span class=\"nb\">export </span><span class=\"nv\">LESS</span><span class=\"o\">=</span><span class=\"s2\">\"-iMR\"</span>\n\n<span class=\"c\"># reset console size</span>\n<span class=\"k\">case</span> <span class=\"s2\">\"</span><span class=\"nv\">$TERM</span><span class=\"s2\">\"</span> <span class=\"k\">in\n    </span>vt220<span class=\"p\">)</span> resize <span class=\"p\">;;</span>\n<span class=\"k\">esac</span>\n\n<span class=\"c\"># numpy 1.19.5 のimportでcore dumpする対策</span>\n<span class=\"nb\">export </span><span class=\"nv\">OPENBLAS_CORETYPE</span><span class=\"o\">=</span>ARMV8\n\n<span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$PYENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"c\"># Raspbian向け対策(numpyでundefined symbol: PyFPE_jbuf)</span>\n    <span class=\"c\"># export PYTHON_CONFIGURE_OPTS=\"--enable-ipv6\\</span>\n    <span class=\"c\">#     --enable-unicode=ucs4\\</span>\n    <span class=\"c\">#     --enable-shared\\</span>\n    <span class=\"c\">#     --with-dbmliborder=bdb:gdbm\\</span>\n    <span class=\"c\">#     --with-system-expat\\</span>\n    <span class=\"c\">#     --with-system-ffi\\</span>\n    <span class=\"c\">#     --with-fpectl\"</span>\n    <span class=\"c\"># Ubuntu向け対策</span>\n    <span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n     --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n    \"</span>\n\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init <span class=\"nt\">--path</span><span class=\"si\">)</span><span class=\"s2\">\"</span>          <span class=\"c\"># pyenv 2.0以降で必要</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># nodenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">NODENV_ROOT</span><span class=\"o\">=</span>/proj/.nodenv\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-e</span> <span class=\"nv\">$NODENV_ROOT</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$NODENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>nodenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vim\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># venvの仮想環境名を表示するための設定</span>\n    show_virtual_env<span class=\"o\">()</span> <span class=\"o\">{</span>\n      <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"s2\">)\"</span>\n      <span class=\"k\">fi</span>\n    <span class=\"o\">}</span>\n    <span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s1\">'$(show_virtual_env)'</span><span class=\"nv\">$PS1</span>\n<span class=\"k\">fi</span>\n\n<span class=\"c\"># x11からのログイン以外ならDISPLAYを設定する</span>\n<span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then</span>\n    <span class=\"c\"># DISPLAYが未定義なら設定する</span>\n    <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-z</span> <span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0\n    <span class=\"k\">fi\nfi</span>\n</code></pre></div></div>\n\n<h2 id=\"不要なソフトのアンインストール\">不要なソフトのアンインストール</h2>\n<p>使わないのでアンインストールしておく</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt remove libreoffice-<span class=\"k\">*</span>\n<span class=\"nb\">sudo </span>apt remove thunderbird\n</code></pre></div></div>\n\n<h2 id=\"色々使うのでインストール\">色々使うのでインストール</h2>\n<p>なにかと使うのでインストール</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>dconf-editor\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gnome-tweak-tool\n</code></pre></div></div>\n\n<h2 id=\"guiの動作の設定変更をお好みで\">GUIの動作の設定変更をお好みで</h2>\n<!--\n「ウィンドウが勝手に最大化するのをやめる」はOK\n「ウィンドウにマウスを乗せるとフォーカスされるようにする」で \"focus-mode\" は 'mouse' ではなく 'sloppy'\n「デスクトップからゴミ箱とホームを消す」は項目としてないらしい\n「Dockのカスタマイズ」は設定できるけど有効でない?\n「マウスカーソルを大きくする」は設定できるけど有効でない?リブートすると元に戻る?\nwindowの閉じるボタンなどを右に移動するにはgnome-tweaskでWindowsのTitlebar Buttons を設定する → 反映されず\n「CAPSキーをCtrlキーに変更」はOK\n-->\n<h3 id=\"ウィンドウが勝手に最大化するのをやめる\">ウィンドウが勝手に最大化するのをやめる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.mutter auto-maximize\ngsettings get org.gnome.mutter edge-tiling\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.mutter auto-maximize <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.mutter edge-tiling <span class=\"nb\">false</span>\n</code></pre></div></div>\n\n<h3 id=\"ウィンドウにマウスを乗せるとフォーカスされるようにする\">ウィンドウにマウスを乗せるとフォーカスされるようにする</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認</span>\ngsettings get org.gnome.desktop.wm.preferences auto-raise \ngsettings get org.gnome.desktop.wm.preferences focus-mode \ngsettings get org.gnome.desktop.wm.preferences raise-on-click\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences auto-raise <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences focus-mode sloppy\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.wm.preferences raise-on-click <span class=\"nb\">true</span>\n</code></pre></div></div>\n\n<h3 id=\"capsキーをctrlキーに変更\">CAPSキーをCtrlキーに変更</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 現在値確認 </span>\ngsettings get org.gnome.desktop.input-sources xkb-options\n\n<span class=\"c\"># 設定</span>\ngsettings <span class=\"nb\">set </span>org.gnome.desktop.input-sources xkb-options <span class=\"se\">\\[\\'</span>ctrl:nocaps<span class=\"se\">\\'\\]</span>\n\n<span class=\"c\"># 設定を有効にするにはGUIでのlogout&再loginが必要</span>\n\n</code></pre></div></div>\n\n<h2 id=\"ipv6を無効化する\">IPv6を無効化する</h2>\n<p>IPv6を無効化したい場合は、\n/<code class=\"language-plaintext highlighter-rouge\">boot/extlinux/extlinux.conf</code>の<code class=\"language-plaintext highlighter-rouge\">APPEND</code>の行の最後に<code class=\"language-plaintext highlighter-rouge\">ipv6.disable=1</code>を追加してリブートする<br />\n参考: <a href=\"https://www.rough-and-cheap.jp/ubuntu/ubuntu18_04_howto_diseable_ipv6/\" target=\"_blank\">Ubuntu 18.04 で ipv6 を無効にする</a></p>\n<blockquote>\n  <p>[!NOTE]\ngrubではなく、U-Bootなので設定するところが違う</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSysctl の設定ではうまくいかなかった。</p>\n</blockquote>\n\n<h2 id=\"デフォルトshellをbashに変更\">デフォルトshellをbashに変更</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /bin\n<span class=\"nb\">sudo ln</span> <span class=\"nt\">-sf</span> bash sh\n</code></pre></div></div>\n\n<h2 id=\"作業用ディレクトリの作成\">作業用ディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mkdir</span> /proj /work\n<span class=\"nb\">sudo chown</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>:<span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>  /proj /work\n</code></pre></div></div>\n\n<h2 id=\"sambaのインストール\">sambaのインストール</h2>\n<h3 id=\"インストール\">インストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>samba\n</code></pre></div></div>\n\n<h3 id=\"設定ファイル\">設定ファイル</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/samba/smb.conf</code> に以下を追加</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[proj]\npath = /proj\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[work]\npath = /work\nguest ok = no\nwritable = yes\nmap archive = no\nshare modes = yes\ndos filetimes = yes\nforce group = yas-i\nforce create mode = 0664\nforce directory mode = 0665\n\n[homes]\n   comment = Home Directories\n   browseable = no\n\n# By default, the home directories are exported read-only. Change the\n# next parameter to 'no' if you want to be able to write to them.\n;   read only = yes\n    read only = no\n\n# File creation mask is set to 0700 for security reasons. If you want to\n# create files with group=rw permissions, set next parameter to 0775.\n;   create mask = 0700\n    create mask = 0665\n\n# Directory creation mask is set to 0700 for security reasons. If you want to\n# create dirs. with group=rw permissions, set next parameter to 0775.\n;   directory mask = 0700\n    directory mask = 0775\n\n# By default, \\\\server\\username shares can be connected to by anyone\n# with access to the samba server.\n# Un-comment the following parameter to make sure that only \"username\"\n# can connect to \\\\server\\username\n# This might need tweaking when using external authentication schemes\n   valid users = %S\n</code></pre></div></div>\n\n<h3 id=\"ユーザの追加と再起動\">ユーザの追加と再起動</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>smbpasswd <span class=\"nt\">-a</span> <span class=\"sb\">`</span><span class=\"nb\">whoami</span><span class=\"sb\">`</span>\n<span class=\"nb\">sudo </span>service smbd reload\n<span class=\"nb\">sudo </span>service smbd restart\n</code></pre></div></div>\n\n<h2 id=\"vncサーバvinoの設定\">VNCサーバ(vino)の設定</h2>\n<p>参考: <a href=\"https://zenn.dev/tunefs/articles/9774eb8f229e1bf97a8c\">https://zenn.dev/tunefs/articles/9774eb8f229e1bf97a8c</a>\n以下、参考先をベースに説明</p>\n\n<h3 id=\"vinoのインストール\">Vinoのインストール</h3>\n<p>インストール済みなので不要</p>\n\n<h3 id=\"vinoの自動起動の設定\">Vinoの自動起動の設定</h3>\n<p>コピー先ディレクトリは作成済み</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cp</span> /usr/share/applications/vino-server.desktop ~/.config/autostart/\n</code></pre></div></div>\n\n<h3 id=\"vinoのコンフィグレーション\">Vinoのコンフィグレーション</h3>\n<p>実行は以下のみでOK</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.Vino prompt-enabled <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false</span>\n</code></pre></div></div>\n<p>以下は不要</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>set org.gnome.Vino authentication-methods は \"['vnc']\" でなく \"['none']\"   デフォルトと同じなので不要\ngsettings set org.gnome.Vino vnc-password $(echo -n 'thepassword'|base64) は不要\n</code></pre></div></div>\n\n<h3 id=\"自動loginの設定\">自動loginの設定</h3>\n<p>VNCはログインしてないと接続できないので、自動ログインを設定する</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/gdm3/custom.conf</code> を以下のように変更</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLoginEnable</code> の行を有効化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">AutomaticLogin</code> の行を有効化して <code class=\"language-plaintext highlighter-rouge\">user1</code> をloginするユーザ名に変更</li>\n</ul>\n\n<h3 id=\"解像度の設定\">解像度の設定</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/X11/xorg.conf</code> に以下を追加 <br />\n<code class=\"language-plaintext highlighter-rouge\">Virtual 1920 1080</code>の部分は使用する解像度に合わせて変更</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Section \"Screen\"\n   Identifier    \"Default Screen\"\n   Monitor       \"Configured Monitor\"\n   Device        \"Tegra0\"\n   SubSection \"Display\"\n       Depth    24\n       Virtual 1920 1080 # Modify the resolution by editing these values\n   EndSubSection\nEndSection\n</code></pre></div></div>\n\n<h3 id=\"リブートする\">リブートする</h3>\n<p>再起動後、PCからVNCクライアントでJetson nano のポート5900(VNCのデフォルトポートなので省略可)に接続する。</p>\n\n<h3 id=\"設定メニューを表示できるようにする\">設定メニューを表示できるようにする</h3>\n<p>上記だけで設定は完了するが、設定メニュー(Settings)から設定しようとするとエラーになるので、\nそれを修正しておく(やらなくても設定メニュー使わなければ問題ない)。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml</code>に以下のパッチを当てる</li>\n</ul>\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  /tmp/a.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- org.gnome.Vino.gschema.xml.org      2020-10-19 06:21:32.034728957 +0900\n</span><span class=\"gi\">+++ org.gnome.Vino.gschema.xml  2020-10-19 06:22:30.887994965 +0900\n</span><span class=\"p\">@@ -154,5 +154,14 @@</span>\n       </description>\n       <default>true</default>\n     </key>\n<span class=\"gi\">+    <key name='enabled' type='b'>\n+      <summary>Enable remote access to the desktop</summary>\n+        <description>\n+          If true, allows remote access to the desktop via the RFB\n+          protocol. Users on remote machines may then connect to the\n+          desktop using a VNC viewer.\n+        </description>\n+      <default>false</default>\n+    </key>\n</span>   </schema>\n </schemalist>\n</code></pre></div></div>\n\n<ul>\n  <li>パッチを当てるコマンド\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>patch /usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml /tmp/a.patch\n</code></pre></div>    </div>\n  </li>\n  <li>さらにコンパイルが必要\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>glib-compile-schemas /usr/share/glib-2.0/schemas\n</code></pre></div>    </div>\n  </li>\n  <li>これで「settings」から「Desktop Sharing」が実行できるようになる</li>\n</ul>\n\n<h2 id=\"使用率等の確認ツールのインストールと起動\">使用率等の確認ツールのインストールと起動</h2>\n\n<p>pyenvインストール済みのときは念のため<code class=\"language-plaintext highlighter-rouge\">pyenv shell system</code>しておく。<br />\nvenv環境使用時はデアクティベートしておく。<br />\n(sudo付きで実行してるのでsystemのpython3が使用されるハズだけど)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-pip\n<span class=\"nb\">sudo </span>pip3 <span class=\"nb\">install </span>jetson-stats\n<span class=\"nb\">sudo </span>jtop \n</code></pre></div></div>\n<p>一度再起動したあとは、<code class=\"language-plaintext highlighter-rouge\">sudo</code>なしの<code class=\"language-plaintext highlighter-rouge\">jtop</code>のみで実行可能。</p>\n<blockquote>\n  <p>[!NOTE]\njtopは結構CPUパワーを喰うので、性能評価等の間は止めておくのが無難と思われる。</p>\n</blockquote>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"sdカードのイメージファイル化\">SDカードのイメージファイル化</h1>\n<p><a href=\"/memoBlog/2021/07/18/sd_image_2.html\" target=\"_blank\">Raspbian SDカードイメージファイルの作成(改訂版)</a>を参照。</p>\n\n<h1 id=\"イメージのコピーからの起動\">イメージのコピーからの起動</h1>\n<h2 id=\"縮小されたパーティションを拡張する\">縮小されたパーティションを拡張する</h2>\n<p>バックアップはパーティションが縮小されているので、拡張する。<br />\n上記参照先の拡張方法ではうまくいかない(JetsonはパーティションがGPTだから?)。<br />\nなので、GUIツールのgpartedを使用して拡張する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>gparted\n<span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.200:0.0       <span class=\"c\"># sshから実行するときはXserverが起動しているマシンをDISPLAY変数に設定</span>\n<span class=\"nb\">sudo </span>gparted /dev/mmcblk0\n</code></pre></div></div>\n\n<ul>\n  <li>Libparted Warning ダイアログで”Not all of the space available to ~”と出たらFixをクリック</li>\n  <li>Libparted Warning ダイアログで”The backup GPT table is corrupt, but the primary appears OK, so that will be used.”と出たらOKをクリック</li>\n  <li>以降も何度か出るが、以下の操作がすべて終わればbackup GPTが新たに作成されるので問題なし。\n    <ul>\n      <li>(これは、ディスクイメージを縮小したときにgdiskコマンドを実行しなかった場合に出ます)</li>\n    </ul>\n  </li>\n  <li>図の«SDカードのパーティション» を右クリック→「Resize/Move」をクリック\n    <ul>\n      <li>「New size」の欄に上にある「Maximum size」以下の値を入力(「Free space following」 に残したいサイズを入れても可)</li>\n      <li>他の入力欄をクリックして自動計算を反映</li>\n      <li>「Resize」をクリック\n-「Edit」→「Apply All Operations」をクリック</li>\n      <li>「Are you sure you want to apply the pending operations?」と聞かれるので、「Apply」をクリック</li>\n    </ul>\n  </li>\n  <li>処理が完了したら閉じるボタンでプログラム終了</li>\n</ul>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"venvによるpython-仮想環境の構築\">venvによるpython 仮想環境の構築</h1>\n<p>いつもはpyenv + virtualenv で環境構築しているが、この環境ではプリインストールされた opencv を使用できないらしい(core dumpする)。<br />\nなので、system上のpythonを使用してvenvで仮想環境を構築して使用するようにしてみた。<br />\n(これ、↓のnumpyの問題かも。でもtensorflowはpython3.6でないとダメだから、pyenv引っ張ってこなくてもいいか。)</p>\n\n<h2 id=\"venvのインストール\">venvのインストール</h2>\n<p>venv使用のためのプログラムをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>python3-venv\n</code></pre></div></div>\n\n<h2 id=\"仮想環境の構築\">仮想環境の構築</h2>\n<p>仮想環境を構築する。<br />\nここで実行したpythonが仮想環境で実行されるpythonになる。<br />\n<code class=\"language-plaintext highlighter-rouge\">--system-site-packages</code> を付加しておくと元のパッケージも参照される。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> «venv_dir»\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">pip list/freeze</code> でも参照される。pipのバージョンが新しければ、<code class=\"language-plaintext highlighter-rouge\">pip -v list</code>と オプション<code class=\"language-plaintext highlighter-rouge\">-v</code>を付けることで インストール先を見分けることでどちらにインストールされているかが判別できる。</p>\n\n<p>例えばこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/TF2.5\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート\">仮想環境のアクティベート</h2>\n<p>pyenvではlocalで指定してあればディレクトリ移動で自動的に仮想環境を切り替えられたが、<br />\nvenvでは逐一仮想環境をアクティベートしなければならない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> «venv_dir»/bin/bin/activate\n</code></pre></div></div>\n\n<h2 id=\"お約束\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"仮想環境の終了\">仮想環境の終了</h2>\n<p>仮想環境を終了するときは以下のコマンドでデアクティベートする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>deactivate\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">deactivate</code>はアクティベート時に関数として登録されている<br />\n下記のようにdirenvで設定した場合は<code class=\"language-plaintext highlighter-rouge\">deactivate</code>は使えないが、ディレクトリから移動すれば元にもどるので問題ない</p>\n</blockquote>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"direnvのインストールと設定\">direnvのインストールと設定</h1>\n<p>仮想環境管理をvenvで行うようにしたが、venvだと逐一activateしないといけないので、pyenvに慣れたカラダでは なかなか 使いにくい。<br />\nそこで、direnvを使ってpyenvに近い使い勝手を実現してみる。</p>\n\n<p>参考:<a href=\"https://yoshitaku-jp.hatenablog.com/entry/2018/07/29/070000\">direnvを使って、source bin/activateを自動化する</a></p>\n\n<h2 id=\"インストール-1\">インストール</h2>\n<p>インストールは<code class=\"language-plaintext highlighter-rouge\">apt</code>でイッパツ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>direnv\n</code></pre></div></div>\n\n<h2 id=\"初期設定-1\">初期設定</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code> に以下の内容を追記。(上記<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>例では記載済み)<br />\nエディタはvimに設定してあるが、別のものを使いたければ設定変更のこと。<br />\n(direnv 未インストール時は設定はスキップされる)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># direnv 設定</span>\n<span class=\"k\">if </span><span class=\"nb\">type </span>direnv <span class=\"o\">></span> /dev/null 2>&1<span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">EDITOR</span><span class=\"o\">=</span>vim\n    <span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>direnv hook bash<span class=\"si\">)</span><span class=\"s2\">\"</span>\n    \n    <span class=\"c\"># venvの仮想環境名を表示するための設定</span>\n    show_virtual_env<span class=\"o\">()</span> <span class=\"o\">{</span>\n      <span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"nt\">-n</span> <span class=\"s2\">\"</span><span class=\"nv\">$VIRTUAL_ENV</span><span class=\"s2\">\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n        </span><span class=\"nb\">echo</span> <span class=\"s2\">\"(</span><span class=\"si\">$(</span><span class=\"nb\">basename</span> <span class=\"nv\">$VIRTUAL_ENV</span><span class=\"si\">)</span><span class=\"s2\">)\"</span>\n      <span class=\"k\">fi</span>\n    <span class=\"o\">}</span>\n    <span class=\"nv\">PS1</span><span class=\"o\">=</span><span class=\"s1\">'$(show_virtual_env)'</span><span class=\"nv\">$PS1</span>\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">source ~/.bashrc</code> するか、terminalを開きなおす。</p>\n\n<h2 id=\"対象ディレクトリに処理を登録する\">対象ディレクトリに処理を登録する</h2>\n<p>対象ディレクトリに移動して<code class=\"language-plaintext highlighter-rouge\">direnv edit .</code> を実行して中身を作成するか、 <code class=\"language-plaintext highlighter-rouge\">.envrc</code>を直接生成する。</p>\n\n<p>中身は以下の通り<br />\n他にも設定したい環境変数があれば設定しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> «venv_dir»/bin/activate\n</code></pre></div></div>\n<p>例えばこんな感じ</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/TF2.5/bin/activate\n</code></pre></div></div>\n<p><code class=\"language-plaintext highlighter-rouge\">direnv: error .envrc is blocked. Run `direnv allow` to approve its content.</code>と言われたら、以下のように実行する。<br />\n(直接編集した時に言われるらしい)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>direnv allow\n</code></pre></div></div>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"tensorflow2-のインストール\">tensorflow2 のインストール</h1>\n<h2 id=\"仮想環境の構築-1\">仮想環境の構築</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/TF2.5\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート-1\">仮想環境のアクティベート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/TF2.5/bin/activate\n</code></pre></div></div>\n<p>またはdirenvで上記が実行されるように設定しておく</p>\n\n<h2 id=\"お約束-1\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<p>tensorflowをimportしたとき(具体的にはその中でnumpyをimportしたとき)に\n<code class=\"language-plaintext highlighter-rouge\">Illegal instruction (core dumped)</code>が発生する。<br />\nこれを回避するため、以下を<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に設定しておく(上記<code class=\"language-plaintext highlighter-rouge\">.bashrc</code>例では記載済み) 。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">OPENBLAS_CORETYPE</span><span class=\"o\">=</span>ARMV8\n</code></pre></div></div>\n\n<p>tensoorflowはpypiではなく、nvidiaのサイトからダウンロードしてインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>https://developer.download.nvidia.com/compute/redist/jp/v46/tensorflow/tensorflow-2.5.0+nv21.7-cp36-cp36m-linux_aarch64.whl\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nn5pyインストールでエラーになった時は以下の手順で回避する。  <br />\nミソはh5pyのインストール時点でnumpy 1.19.5がインストールされているとエラーになるので、<br />\n一時的にnumpyのそれ以前のバージョンをインストールしてh5pyをインストールし、その後numpyを本来のバージョンに戻す。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libhdf5-serial-dev hdf5-tools libhdf5-dev\npip <span class=\"nb\">install </span>cython\n<span class=\"c\"># numpyのバージョン下げる  </span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">numpy</span><span class=\"o\">==</span>1.19.3\npip <span class=\"nb\">install </span><span class=\"nv\">h5py</span><span class=\"o\">==</span>2.10.0\n<span class=\"c\"># h5pyのインストールのためにインストールしたnumpyを本来のバージョンに更新  </span>\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">numpy</span><span class=\"o\">==</span>1.19.5\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"tensorflowなどのありか\">Tensorflowなどのありか</h2>\n<p>以下に色々まとめられている。<br />\n<a href=\"https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime\">https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime</a></p>\n\n<!-- ---------------------------------------------------------------------- -->\n<h1 id=\"onnx-runtimeのインストール\">onnx-runtimeのインストール</h1>\n<h2 id=\"仮想環境の構築-2\">仮想環境の構築</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python3 <span class=\"nt\">-m</span> venv <span class=\"nt\">--system-site-packages</span> /proj/venvs/onnx\n</code></pre></div></div>\n\n<h2 id=\"仮想環境のアクティベート-2\">仮想環境のアクティベート</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/venvs/onnx/bin/activate\n</code></pre></div></div>\n<p>またはdirenvで上記が実行されるように設定しておく</p>\n\n<h2 id=\"お約束-2\">お約束</h2>\n<p>続いて <code class=\"language-plaintext highlighter-rouge\">pip</code> <code class=\"language-plaintext highlighter-rouge\">setuptool</code> <code class=\"language-plaintext highlighter-rouge\">wheel</code> を最新版にしておく(お約束)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"インストールファイルのダウンロード\">インストールファイルのダウンロード</h2>\n<p><a href=\"https://elinux.org/Jetson_Zoo?fbclid=IwAR1_Mdi9asx0f8RNvzQIR9suJuPFqwF8ev_C6B7lyLLfsGnnIS4G_yFAr0I#ONNX_Runtime\" target=\"_blank\">Jetson Zoo</a>\nから使用環境に対応するインストールファイルをダウンロードする。<br />\n表の下にあるコマンド例の<code class=\"language-plaintext highlighter-rouge\">wget</code>ではうまくダウンロードできないのでブラウザでダウンロードしてコピっておく。<br />\n以下、onnxruntime 1.8.0/Python 3.6 を選択したものとする。</p>\n\n<h2 id=\"インストール-2\">インストール</h2>\n\n<p>システムにインストールされたprotobufのバージョンが古くてエラーになるので、\nあらかじめ最新版にアップデートしておく。<br />\n(venv環境なので、システムのprotobufには影響ない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> protobuf\n</code></pre></div></div>\n\n<p>ダウンロードしたonnx-runtimeをインストールする</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>onnxruntime_gpu-1.8.0-cp36-cp36m-linux_aarch64.whl\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano に pyenv をインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano に pyenv をインストールする</h1>\n      <p>Jetson nano に pyenvをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>systemのpythonを使うのはちょっと嫌なので、仮想環境を使えるようにしておく。<br />\n<code class=\"language-plaintext highlighter-rouge\">venv</code>でもいいけど、やっぱり使い慣れた<code class=\"language-plaintext highlighter-rouge\">pyenv</code>+<code class=\"language-plaintext highlighter-rouge\">vertualenv</code>で。<br />\n基本的に<a href=\"/memoBlog/2019/06/27/pyenv.html\">pyenvのインストール</a>と同じだけど、<br />\nJetpackでインストール済みで、<code class=\"language-plaintext highlighter-rouge\">pip</code>でインストールできないパッケージがあるなど、<br />\nJetson nano 固有の設定等があるので、メモ。</p>\n\n<h1 id=\"手順再掲を含む\">手順(再掲を含む)</h1>\n\n<h2 id=\"pyenvをインストールする\">pyenvをインストールする</h2>\n<ul>\n  <li>必要なパッケージのインストール\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> make build-essential libssl-dev zlib1g-dev libbz2-dev <span class=\"se\">\\</span>\nlibreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev <span class=\"se\">\\</span>\nxz-utils tk-dev libffi-dev liblzma-dev python-openssl git\n</code></pre></div>    </div>\n  </li>\n  <li>pyenvとプラグインをダウンロード\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv    <span class=\"c\">#環境に合わせて修正してね</span>\ngit clone https://github.com/yyuu/pyenv.git            <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>\ngit clone https://github.com/yyuu/pyenv-virtualenv.git <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-virtualenv\ngit clone git://github.com/pyenv/pyenv-update.git      <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/plugins/pyenv-update\n</code></pre></div>    </div>\n  </li>\n  <li>pyenv環境からJetpackでインストール済みのパッケージを参照できるようにしておく。<br />\n(pipでインストールできないみたいなので、お手軽な方法で解決)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/cv2          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/graphsurgeon <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/tensorrt     <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> /usr/lib/python3.6/dist-packages/uff          <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>\n、とやりたいけど、ARM版は非対応らしいので…</p>\n    </blockquote>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>の修正<br />\n以下を追加しておく\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># pyenv 設定</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYENV_ROOT</span><span class=\"o\">=</span>/proj/.pyenv\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span><span class=\"nv\">$PYENV_ROOT</span>/bin:<span class=\"nv\">$PATH</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">eval</span> <span class=\"s2\">\"</span><span class=\"si\">$(</span>pyenv virtualenv-init -<span class=\"si\">)</span><span class=\"s2\">\"</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHON_CONFIGURE_OPTS</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"se\">\\</span><span class=\"s2\">\n --enable-shared</span><span class=\"se\">\\</span><span class=\"s2\">\n\"</span>\n<span class=\"c\">#jetson専用のインストール済みパッケージをコピっておく</span>\n<span class=\"nb\">export </span><span class=\"nv\">PYTHONPATH</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span><span class=\"s2\">/jetson_pythonlib:</span><span class=\"nv\">$PYTHONPATH</span><span class=\"s2\">\"</span>\n</code></pre></div>    </div>\n  </li>\n  <li>ターミナル開きなおし or <code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>を再読み込み</li>\n</ul>\n\n<h2 id=\"ベースとなるpythonのインストール\">ベースとなるpythonのインストール</h2>\n<p>バージョンは3.6.xでないとダメっぽい</p>\n\n<h2 id=\"python-のインストール\">python のインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.6.12\npyenv global 3.6.12\n</code></pre></div></div>\n<p>pip と setuptools のアップデート</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n</code></pre></div></div>\n<h2 id=\"その他\">その他</h2>\n<p>wheelが入ってると仮想環境を変えて同じモジュールをインストールするときに早いので、<br />\nインストールしておきたいが、各仮想環境に逐一インストールするのも面倒なので<br />\n共通に参照できるディレクトリにインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>wheel <span class=\"nt\">-t</span> <span class=\"k\">${</span><span class=\"nv\">PYENV_ROOT</span><span class=\"k\">}</span>/jetson_pythonlib/\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をUSBドライブからブートできるようにする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をUSBドライブからブートできるようにする</h1>\n      <p>Jetson nano をUSBドライブからブートできるようにする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>本稿はJetoack4.4での手順です。<br />\nJetpack4.6のときのメモは<a href=\"/memoBlog/2021/09/14/Jetson_usb_boot.html\" target=\"_blank\">Jetson nano をUSBドライブからブートできるようにする(Jetpack4.6)</a> にあります。</p>\n\n<h1 id=\"概要\">概要</h1>\n<p>SDカードからブートすると、かなりディスクアクセスが遅いのと、ディスク容量を結構喰うので、<br />\nUSBドライブ(HDD/SSD)からブートできるようにする手順。<br />\n例によって、先人の知恵を借りるだけだけど(パクりとも言う)…(^^ゞ</p>\n\n<p>めんどくさそうだったけど、ほとんどスクリプト化されているので、意外と簡単。</p>\n\n<h1 id=\"参考\">参考</h1>\n<ul>\n  <li><a href=\"https://www.miki-ie.com/nvidiajetsonnano/nvidia-jetson-nano-usb-root/\">NVIDIA Jetson Nano USB ディスクをルート構成</a></li>\n  <li><a href=\"https://qiita.com/sgrowd/items/87d65383c0b74306ea7d\">Jetson Nanoの/をUSBドライブにしてSDカードを長生きさせる</a></li>\n  <li><a href=\"https://www.jetsonhacks.com/2019/09/17/jetson-nano-run-from-usb-drive/\">Jetson Nano – Run From USB Drive</a></li>\n</ul>\n\n<h1 id=\"手順を再掲しとく\">手順を再掲しとく</h1>\n\n<ul>\n  <li>SDカードからブート</li>\n  <li>USBドライブを接続&フォーマット</li>\n  <li>USBドライブをマウント</li>\n  <li>ツールのダウンロード\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/JetsonHacksNano/rootOnUSB.git\n<span class=\"nb\">cd </span>rootOnUSB/\n</code></pre></div>    </div>\n  </li>\n  <li>USBドライブからbootするためのinitrdを作成する\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./addUSBToInitramfs.sh\n</code></pre></div>    </div>\n  </li>\n  <li>SDカードからUSBドライブへファイルをコピーする\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./copyRootToUSB.sh <span class=\"nt\">-p</span> «コピー先パーティション»\n  <span class=\"c\"># 例: ./copyRootToUSB.sh -p /dev/sda1</span>\n</code></pre></div>    </div>\n  </li>\n  <li>実際にUSBドライブからブートするための設定\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/boot/extlinux/extlinux.conf</code>のバックアップをとっておく\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo mv</span> /boot/extlinux/extlinux.conf /boot/extlinux/extlinux.conf.org\n</code></pre></div>        </div>\n      </li>\n      <li>USBドライブのUUIDを調べる\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>./diskUUID.sh\n</code></pre></div>        </div>\n        <p>→ <code class=\"language-plaintext highlighter-rouge\">XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</code>として得られる。</p>\n      </li>\n      <li><code class=\"language-plaintext highlighter-rouge\">sample-extlinux.conf</code> の <code class=\"language-plaintext highlighter-rouge\">APPEND</code>の行のUUID部分を以下のように変更する\n        <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    APPEND ${cbootargs} root=UUID=dc21871e-9db4-434c-98b4-713f55f807eb rootwait rootfstype=ext4\n                                     ↓↓↓↓↓\n    APPEND ${cbootargs} root=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rootwait rootfstype=ext4\n</code></pre></div>        </div>\n      </li>\n      <li>変更した<code class=\"language-plaintext highlighter-rouge\">sample-extlinux.conf</code>を<code class=\"language-plaintext highlighter-rouge\">/boot/extlinux/extlinux.conf</code>をコピー\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo cp </span>sample-extlinux.conf /boot/extlinux/extlinux.conf\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>リーブート</li>\n</ul>\n\n<p>リブート完了したらUSBドライブがrootにマウントされていることを確認<br />\n<code class=\"language-plaintext highlighter-rouge\">mount</code>で確認しても良いけど、いっぱい出てきて鬱陶しいので<code class=\"language-plaintext highlighter-rouge\">df</code>で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">df</span> <span class=\"nt\">-h</span> /\n</code></pre></div></div>\n<p>こんな感じで行頭にマウント元が表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Filesystem      Size  Used Avail Use% Mounted on\n/dev/sda1       110G   14G   91G  13% /\n</code></pre></div></div>\n\n<h1 id=\"注意\">注意</h1>\n<p>USBドライブからブートできるようになっても、SDカードは取り外してはいけない。<br />\nu-bootからinitrdをロードするのはSDカードなので。</p>\n\n<p>ということは、<code class=\"language-plaintext highlighter-rouge\">apt update</code>でカーネルアップデートされても古いカーネルが使われちゃうなぁ…<br />\nそれはそのとき考えよう…<br />\nそんなに変わるもんでもないだろう。</p>\n\n<h1 id=\"独り言\">独り言</h1>\n<p>u-bootの環境変数見ると、そのままUSBブート出来そうな感じだったけど、<br />\n実際に<code class=\"language-plaintext highlighter-rouge\">usb start</code>してみたらエラーになる。<br />\nどうやらu-bootにはUSBドライバが入ってないらしい…<br />\nそんな環境変数残しとくな!!</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano のSDカードをバックアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano のSDカードをバックアップする</h1>\n      <p>Jetson nano のSDカードをバックアップする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2020/10/23/Jetson_nano_install.html\">Jetson nano をセットアップする</a> \nでセットアップしたSDカードをバックアップしておけば逐一セットアップ作業を行わなくても環境を復元できます。</p>\n\n<p>ただ、そのままSDカードをイメージファイル化しただけでは復元するSDカードのサイズが微妙に小さい場合などは、復元できなくなってしまいます。<br />\nそこで、バックアップしtイメージファイル内のパーティションサイズを縮小し、イメージファイルを小さくするスクリプトを用意しました。</p>\n\n<p>この作業はubuntu PC上で行います。</p>\n\n<p>この方法、およびスクリプトはRaspberryPi用SDカードでも使用できます。</p>\n\n<h1 id=\"sdカードのバックアップ\">SDカードのバックアップ</h1>\n<blockquote>\n  <p>[!WARNING]\nJetson用SDカードはFATパーティションが存在しないため、<br />\nWindowsPCではバックアップツールがSDカードを認識できず、バックアップできません。</p>\n</blockquote>\n\n<ul>\n  <li>ubuntu PCにバックアップしたいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>SDカードイメージをファイルにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">of</span><span class=\"o\">=</span>«出力ファイル» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n  <li>ubuntu PCからSDカードを抜去</li>\n</ul>\n\n<h1 id=\"ディスクイメージファイルの縮小\">ディスクイメージファイルの縮小</h1>\n\n<p>バックアップしたイメージファイルはSDカード容量と同じサイズになっています。<br />\nディスクイメージを縮小するために <a href=\"/memoBlog/misc/stock/diskimage_shrink.sh\">このスクリプト</a> をダウンロードして実行します。</p>\n\n<p>まず、必要なツールをインストールしておきます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install </span>kpartx\n</code></pre></div></div>\n\n<p>ダウンロードしたスクリプトを実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bash diskimage_shrink.sh «入力イメージファイル» «出力イメージファイル» \n</code></pre></div></div>\n<p>出力イメージファイルが既に存在する場合は、上書きするか聞かれますので、yまたはnで指定してください。</p>\n\n<p>最初に入力イメージファイルから出力イメージファイルへコピーを行います。<br />\nコピーが終了すると、<code class=\"language-plaintext highlighter-rouge\">sudo</code>実行するためのパスワードを聞かれますので、入力してください。<br />\n縮小するパーティションサイズを計算した後、\n現在のパーティションサイズと縮小後のパーティションサイズが表示されます。<br />\n各サイズが正しければ、yを入力してパーティションサイズの修正を行いますが、\n一般的に危険な処理なので、「警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?」と再度確認されます。<br />\nyを入力して実行してください。</p>\n\n<p>その後、さらに ファイルサイズを切り詰めます。</p>\n\n<p>処理が終了すると、以下のメッセージが表示されますので、これにしたがって後の処理を行ってください。<br />\nRaspberryPi用SDカードはMBRパーティションなので<code class=\"language-plaintext highlighter-rouge\">gdisk</code>の処理は不要です。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n</code></pre></div></div>\n\n<h2 id=\"実行例\">実行例</h2>\n<p>実行例を以下に示します。<br />\n入力コマンドは<code class=\"language-plaintext highlighter-rouge\"># =========</code>で囲んであります。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># =========================================================================\n/work2$ bash diskimage_shrink.sh jetson_sd_20201022_2.img XXXX.img\n# =========================================================================\nCopy image file...\n>f+++++++++ jetson_sd_20201022_2.img\n 30,953,963,520 100%   26.97MB/s    0:18:14 (xfr#1, to-chk=0/1)\nGet partition info...\n対象パーティション番号 : 1\nImage file mapping...\n[sudo] <<ユーザ>> のパスワード: «パスワードを入力»\nadd map loop18p1 (253:0): 0 60313600 linear 7:18 28672\nadd map loop18p2 (253:1): 0 256 linear 7:18 2048\nadd map loop18p3 (253:2): 0 896 linear 7:18 4096\nadd map loop18p4 (253:3): 0 1152 linear 7:18 6144\nadd map loop18p5 (253:4): 0 128 linear 7:18 8192\nadd map loop18p6 (253:5): 0 384 linear 7:18 10240\nadd map loop18p7 (253:6): 0 768 linear 7:18 12288\nadd map loop18p8 (253:7): 0 128 linear 7:18 14336\nadd map loop18p9 (253:8): 0 896 linear 7:18 16384\nadd map loop18p10 (253:9): 0 896 linear 7:18 18432\nadd map loop18p11 (253:10): 0 1536 linear 7:18 20480\nadd map loop18p12 (253:11): 0 128 linear 7:18 22528\nadd map loop18p13 (253:12): 0 160 linear 7:18 24576\nadd map loop18p14 (253:13): 0 256 linear 7:18 26624\nLOOP device : /dev/mapper/loop18p1\n現在のパーティションサイズ   : 29450MiB\n縮小後のパーティションサイズ : 15637MiB\nパーティションを縮小しますか? [y/N]: y\nPartition shrinking...\ne2fsck 1.44.1 (24-Mar-2018)\nPass 1: Checking iノードs, blocks, and sizes\nPass 2: Checking ディレクトリ structure\nPass 3: Checking ディレクトリ connectivity\nPass 4: Checking reference counts\nPass 5: Checking グループ summary information\n/dev/mapper/loop18p1: 199065/1881264 files (0.2% non-contiguous), 3701166/7539200 blocks\nresize2fs 1.44.1 (24-Mar-2018)\nResizing the filesystem on /dev/mapper/loop18p1 to 4003167 (4k) blocks.\nBegin pass 2 (max = 55)\nRelocating blocks             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nBegin pass 3 (max = 231)\nScanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nThe filesystem on /dev/mapper/loop18p1 is now 4003167 (4k) blocks long.\n\n警告: 管理者権限がありません。パーミッションに注意してください。\n警告: パーティションを縮小するとデータを失うかもしれませんが、それでも実行しますか?\nはい(Y)/Yes/いいえ(N)/No? y                                               \nTruncate image file size...\nReleas image file mapping...\nloop deleted : /dev/loop18\n******** Done!! ********\n\n\n\n対象ディスクイメージがGPTパーティションの場合は\nこのあと、「gdisk XXXX.img」を実行し、\nb → 適当なファイル名 → r → d → w → y\nと入力してください。\n\n\n「sudo parted -m XXXX.img unit GiB print」と実行すると\n縮小後のパーティションサイズを確認できます(後ろの方にext4と書かれた行)\n\n\n\nこれで期待通りのパーティションサイズになっていることが確認出来たら\n先に入力した「適当なファイル名」のファイルは削除してもかまいません\n\n\n\n# =========================================================================\n/work2$ gdisk XXXX.img \n# =========================================================================\nGPT fdisk (gdisk) version 1.0.3\n\nWarning! Disk size is smaller than the main header indicates! Loading\nsecondary header from the last sector of the disk! You should use 'v' to\nverify disk integrity, and perhaps options on the experts' menu to repair\nthe disk.\nCaution: invalid backup GPT header, but valid main header; regenerating\nbackup header from main header.\n\nWarning! Error 25 reading partition table for CRC check!\nWarning! One or more CRCs don't match. You should repair the disk!\n\nPartition table scan:\n  MBR: protective\n  BSD: not present\n  APM: not present\n  GPT: damaged\n\n****************************************************************************\nCaution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\nverification and recovery are STRONGLY recommended.\n****************************************************************************\n\nCommand (? for help): b\nEnter backup filename to save: backup.gpt\nThe operation has completed successfully.\n\nCommand (? for help): r\n\nRecovery/transformation command (? for help): d\n\nRecovery/transformation command (? for help): w\nCaution! Secondary header was placed beyond the disk's limits! Moving the\nheader, but other problems may occur!\n\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\nPARTITIONS!!\n\nDo you want to proceed? (Y/N): y\nOK; writing new GUID partition table (GPT) to XXXX.img.\nWarning: The kernel is still using the old partition table.\nThe new table will be used at the next reboot or after you\nrun partprobe(8) or kpartx(8)\nThe operation has completed successfully.\n\n\n\n# =========================================================================\n/work2$ sudo parted -m XXXX.img unit GiB print\n# =========================================================================\nBYT;\n/work2/XXXX.img:15.3GiB:file:512:512:gpt::;\n2:0.00GiB:0.00GiB:0.00GiB::TBC:;\n3:0.00GiB:0.00GiB:0.00GiB::RP1:;\n4:0.00GiB:0.00GiB:0.00GiB::EBT:;\n5:0.00GiB:0.00GiB:0.00GiB::WB0:;\n6:0.00GiB:0.01GiB:0.00GiB::BPF:;\n7:0.01GiB:0.01GiB:0.00GiB::BPF-DTB:;\n8:0.01GiB:0.01GiB:0.00GiB::FX:;\n9:0.01GiB:0.01GiB:0.00GiB::TOS:;\n10:0.01GiB:0.01GiB:0.00GiB::DTB:;\n11:0.01GiB:0.01GiB:0.00GiB::LNX:;\n12:0.01GiB:0.01GiB:0.00GiB::EKS:;\n13:0.01GiB:0.01GiB:0.00GiB::BMP:;\n14:0.01GiB:0.01GiB:0.00GiB::RP4:;\n1:0.01GiB:15.3GiB:15.3GiB:ext4:APP:;\n\n\n\n# =========================================================================\n/work2$ ls -la jetson_sd_20201022_2.img y.img \n# =========================================================================\n-rw-r--r-- 1 user  user 30953963520 10月 22 15:42 jetson_sd_20201022_2.img\n-rw-r--r-- 1 user  user 16422139904 10月 25 07:00 y.img\n</code></pre></div></div>\n\n<h1 id=\"新しいsdカードにバックアップを復元\">新しいSDカードにバックアップを復元</h1>\n\n<p>イメージファイルからSDカードへのコピーはWindowsマシンで行っても良いですが、ここではubuntu PCで行う方法について記載します。</p>\n\n<ul>\n  <li>ubuntu PCに新しいSDカードを挿入\n    <ul>\n      <li>マウントする必要はないので、マウントのための認証でキャンセルします<br />\nマウントされちゃたら、以下のコマンドでアンマウント\n        <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>umount «SDカードデバイスのパーティション»\n</code></pre></div>        </div>\n      </li>\n    </ul>\n  </li>\n  <li>バックアップしたイメージファイルをSDカードにコピー\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo dd </span><span class=\"k\">if</span><span class=\"o\">=</span>«入力ファイル» <span class=\"nv\">of</span><span class=\"o\">=</span>«SDカードデバイス» <span class=\"nv\">status</span><span class=\"o\">=</span>progress\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h1 id=\"新しいsdカードのパーティションを拡張\">新しいSDカードのパーティションを拡張</h1>\n\n<p>バックアップした際にパーティションサイズを縮小してあるため、そのままのSDカードではディスクの残り容量がわずかしかありません。<br />\nそこで、パーティションサイズを拡張して容量を増加させます。</p>\n\n<p>この作業はubuntu PCであらかじめ行うか、またはターゲットマシンでブートした後に行います。</p>\n\n<p>パーティション操作プログラム<code class=\"language-plaintext highlighter-rouge\">gparted</code>を使用します。<br />\nインストールされていない場合は、<code class=\"language-plaintext highlighter-rouge\">sudo apt install gparted</code>でインストールしておいてください。</p>\n\n<ul>\n  <li>gpartedを起動\n    <ul>\n      <li>Libparted Warning ダイアログで”Not all of the space available to ~”と出たらFixをクリック</li>\n      <li>Libparted Warning ダイアログで”The backup GPT table is corrupt, but the primary appears OK, so that will be used.”と出たらOKをクリック<br />\n以降も何度か出るが、以下の操作がすべて終わればbackup GPTが新たに作成されるので問題なし。<br />\n(これは、ディスクイメージを縮小したときにgdiskコマンドを実行しなかった場合に出ます)</li>\n      <li>Gparted→デバイスで<code class=\"language-plaintext highlighter-rouge\">«SDカードデバイス»</code>`を選択</li>\n      <li>図の<code class=\"language-plaintext highlighter-rouge\">«SDカードのパーティション»</code> を右クリック→「リサイズ/移動」をクリック\n        <ul>\n          <li>「新しいサイズ」の欄に上にある「最大サイズ」以下の値を入力</li>\n          <li>「リサイズ」をクリック</li>\n        </ul>\n      </li>\n      <li>「編集(E)」→「保留中の全ての操作を適用する(A)」をクリック\n        <ul>\n          <li>「本当に保留中の操作を適用してもよろしいですか?」と聞かれるので、「適用」をクリック</li>\n        </ul>\n      </li>\n      <li>処理が完了したら「閉じる」をクリック</li>\n    </ul>\n  </li>\n  <li>gpartedを終了</li>\n</ul>\n\n<p>ターゲットマシンで実行している場合は、そのまま使用できます。<br />\nubuntuマシンで実行した場合は、SDカードを取り外してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Jetson nano をセットアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Jetson nano をセットアップする</h1>\n      <p>Jetson nano をセットアップする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>本稿はJetoack4.4での手順です。<br />\nJetpack4.6のときのメモは<a href=\"/memoBlog/2021/09/13/Jetson_nano_install.html\" target=\"_blank\">Jetson nano をセットアップする(Jetpack4.6)</a> にあります。</p>\n\n<p>Nvidiaの<a href=\"https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/\">Jetson nano</a>をセットアップしたときのメモ</p>\n\n<h1 id=\"参照先\">参照先</h1>\n<ul>\n  <li><a href=\"https://monoist.atmarkit.co.jp/mn/articles/1905/30/news029.html\">「Jetson Nano」の電源を入れて立ち上げる</a>\n    <ul>\n      <li>わりと詳しく書いてある</li>\n    </ul>\n  </li>\n  <li><a href=\"https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit\">Getting Started With Jetson Nano Developer Kit </a>\n    <ul>\n      <li>本家</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"sdカードの作成\">SDカードの作成</h1>\n<p>参照先の通り。</p>\n\n<p>ただし、参照先のSDカードイメージへのリンクは古いので、は以下から最新版をダウンロードする(古いのも下の方を探せば出てくる)</p>\n<ul>\n  <li><a href=\"https://developer.nvidia.com/embedded/downloads\">Jetson Download Center</a></li>\n</ul>\n\n<p>SDカード書き込みは記事に書かれた balenaEtcher でなく WIN32DiskImager でも大丈夫だが、<br />\nbalenaEtcher は zipファイルを解凍せずにSDカードに書き込めるので便利。<br />\nちなみに、<em>balena</em> はイタリア語で <em>鯨</em> の意味らしい…全然関係ないけど…</p>\n\n<blockquote>\n  <p>[!NOTE]\nインストール先のSDカードは32GB必須みたい。<br />\n16GBだとインストールしただけで「残り少ない」と言われてしまう。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nSDカードスロットが分かりにくいところにある(開発ボード側ではなく、モジュール側の裏側)。<br />\nシリアルコンソール繋いでるとケーブルが邪魔で特に挿抜しにくい…</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\n一度このイメージを書き込んだSDカードは、以後Windowsから認識されなくなる。<br />\nよって、SDフォーマッタやディスクイメージ書き込みツールから新たに書き込みできなくなってしまう。\nこれは書き込んだSDカードにFATのパーティションが存在しないためのよう。<br />\n(RaspberryPiはbootパーティションとしてFATパーティションを持っているので認識されるようだ)</p>\n\n  <p>コントロールパネル→管理ツール→コンピュータの管理を起動して、<br />\n記憶域の下のディスクの管理からSDカード上の不明なパーティションを解放し、<br />\nそこに新たにFATパーティションを作成すればWindowsから認識されるようになる。<br />\nもちろん、他のUbuntuマシンで書き換えちゃうのもアリだけど。。。</p>\n</blockquote>\n\n<h1 id=\"シリアルコンソールの使用\">シリアルコンソールの使用</h1>\n<p>シリアルコンソールが必要なら接続できる。<br />\n特に設定等は必要ない。  <br />\n接続端子は以下を参照</p>\n<ul>\n  <li><a href=\"https://www.jetsonhacks.com/2019/04/19/jetson-nano-serial-console/\">Jetson Nano – Serial Console</a>\nの 「Wiring」の下の「Jetson Nano B01」を参照。</li>\n</ul>\n\n<p>シリアルポートの設定は115200bps/8bit/none/1bit/none</p>\n\n<blockquote>\n  <p>[!WARNING]\nJ41(RaspberryPi互換の40pinヘッダ)のUART端子はコンソールとして動作していないみたい。<br />\ngettyが動いてないみたいなので。  <br />\nたぶん、<code class=\"language-plaintext highlighter-rouge\">/etc/systemd/nvgetty.sh</code> に<code class=\"language-plaintext highlighter-rouge\">ttyTHS2</code>の設定を追加すればできるようになる感じだけど、試してないので詳細不明。<br />\nJ41のUARTを汎用UARTとして使用するには、以下を参照。</p>\n  <ul>\n    <li><a href=\"https://www.jetsonhacks.com/2019/10/10/jetson-nano-uart/\">Jetson Nano – UART</a></li>\n  </ul>\n</blockquote>\n\n<p>その他、コネクタ類の配置が分かりにくい場合は、\n<a href=\"https://developer.download.nvidia.com/assets/embedded/secure/jetson/Nano/docs/NV_Jetson_Nano_Developer_Kit_User_Guide.pdf?yIbsUqvBKxI1G6r3WW7cOdheZGv2-eSfaFW_kMt3dSgi0NJ7h77OwFHr5b-rquc3IX7Tyrt8FV6IKD4DHqvP4_LzhWt55tb071gqXlNGwBPYCOC5pnEKAla8D-B82bPjhQMykANFyn-EhxZRHC8AIBYWuVwwwXVPWtCOjs34Tg50oBdN0vBNoyUlZMRFXLNJ2to\">JETSON NANO DEVELOPER KIT</a>\nのP22 に<strong>Developer kit module and carrier board: rev B01 top view</strong>として配置図が掲載されているので参照のこと。</p>\n\n<h1 id=\"firstboot\">FirstBoot</h1>\n<p>最初のブートでUbuntuのセットアップを行う。<br />\nこれも参照先の通り。<br />\n終わったら、何はともあれ最新版にアップデート。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt upgrade\n</code></pre></div></div>\n\n<p>ここで一旦リブートしておく。</p>\n\n<p>その他こまごました設定はこちらが参考になるかも。</p>\n<ul>\n  <li><a href=\"/memoBlog/2020/05/08/ubuntu_native.html\">UbuntuをNative環境にインストールする(18.04)</a></li>\n</ul>\n\n<p>インストールしたパッケージ\ngnome-tweaks\ndconf-editor\nsamba</p>\n<blockquote>\n  <p>[!NOTE]\nmin/max/closeボタンがウィンドウ右側に移動できない…\nちょっとストレス…</p>\n</blockquote>\n\n<h1 id=\"その他設定\">その他設定</h1>\n<h2 id=\"ウィンドウマネージャをunityからubuntuに変更する\">ウィンドウマネージャをUnityからubuntuに変更する</h2>\n<p>Unityは使いにくくて嫌(個人の見解デス)なので、Ubuntuに変更する(変更しなくても良い)。\n自動ログインしている場合は、一旦ログアウトして、<br />\n再ログインする際に、「サインイン」ボタンの左にある歯車アイコンをクリック→Ubuntuを選択してから<br />\nログインすると、ウィンドウマネージャがUbuntuに変更されている。<br />\n次回ログイン(自動ログインでも)は何もしなくても前回のウィンドウマネージャが選択される。</p>\n<blockquote>\n  <p>[!NOTE]\nUbuntuに変えると min/max/closeボタンがウィンドウ右側に移動できてる。<br />\n結果オーライ😅</p>\n</blockquote>\n\n<h2 id=\"sshでの接続\">SSHでの接続</h2>\n<p>特に設定などは必要ない。<br />\nTeraTermなどで接続すれば良い。\nUbuntuではmDNSが動いているので、«マシン名».localでアクセスできる。</p>\n\n<p>コマンドは以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\"C:\\Program Files (x86)\\teraterm\\ttermpro.exe\" /auth=password /user=«ユーザ名» /passwd=«パスワード» «JetsonのIPアドレス or マシン名.local»\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nSSHやmDNSは立ち上がるまで少し時間がかかるみたいなので、<br />\n起動後数十秒程度待ってから接続した方が良い。</p>\n</blockquote>\n\n<h3 id=\"ssh接続がタイムアウトする対策\">SSH接続がタイムアウトする対策</h3>\n<p>SSH接続したターミナルを触らずにしばらく置いておくと、タイムアウトしてクローズされてしまう。\nこれを防ぐにはクライアント側からkeep-aliveパケットを定期的に送信してやれば良いらしい。</p>\n\n<p>Teratermの場合、「設定」→「SSH」→「ハートビート(keep-alive)」を「8」とかに設定し、保存。\n次回接続時はこの保存した設定ファイルを読み込む</p>\n\n<h3 id=\"シリアルコンソールssh接続でguiウィンドウを表示できるようにする\">シリアルコンソール/SSH接続でGUIウィンドウを表示できるようにする</h3>\n<p>シリアルコンソール/SSH接続でGUIウィンドウを表示できるようにするには、\nWindowsPCなどでX-Serverを動作させておき、<br />\nそこに出力するようにすればよい。<br />\nJetson側は<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加しておく。<br />\nここのIPアドレスはX-Serverが動作しているマシンのIPアドレスに変更すること。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"o\">[</span> <span class=\"s2\">\"</span><span class=\"nv\">$XDG_SESSION_TYPE</span><span class=\"s2\">\"</span> <span class=\"o\">!=</span> <span class=\"s2\">\"x11\"</span> <span class=\"o\">]</span><span class=\"p\">;</span> <span class=\"k\">then\n    </span><span class=\"nb\">export </span><span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XX.XX:0.0\n<span class=\"k\">fi</span>\n</code></pre></div></div>\n\n<h1 id=\"リモートデスクトップの設定\">リモートデスクトップの設定</h1>\n<p>TigerVNC はちょっと動作があやしいので、やめておいて、Desktop Sharing(Vino)を使うことにする。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f#%E6%96%B9%E6%B3%952-desktop-sharingvino%E3%82%92%E4%BD%BF%E3%81%86\">Jetson Nanoにリモートデスクトップ(VNC)環境を用意する</a></li>\n  <li><a href=\"https://www.hackster.io/news/getting-started-with-the-nvidia-jetson-nano-developer-kit-43aa7c298797\">Getting Started with the NVIDIA Jetson Nano Developer Kit</a> の 「Enabling Desktop Sharing」</li>\n</ul>\n\n<p>この手順はウィンドウマネージャがUnityで実行しています。 ウィンドウマネージャをUbuntuに変更していると少し手順が違うかもしれませんので、\nウィンドウマネージャをUbuntuに変更している場合はUnityに戻してから設定してください。<br />\n設定完了後はUbuntuに再変更しても問題ありません。</p>\n\n<p>以下手順の再掲。</p>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">/usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml</code>に以下のパッチを当てる</li>\n</ul>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- org.gnome.Vino.gschema.xml.org      2020-10-19 06:21:32.034728957 +0900\n</span><span class=\"gi\">+++ org.gnome.Vino.gschema.xml  2020-10-19 06:22:30.887994965 +0900\n</span><span class=\"p\">@@ -154,5 +154,14 @@</span>\n       </description>\n       <default>true</default>\n     </key>\n<span class=\"gi\">+    <key name='enabled' type='b'>\n+      <summary>Enable remote access to the desktop</summary>\n+        <description>\n+          If true, allows remote access to the desktop via the RFB\n+          protocol. Users on remote machines may then connect to the\n+          desktop using a VNC viewer.\n+        </description>\n+      <default>false</default>\n+    </key>\n</span>   </schema>\n </schemalist>\n</code></pre></div></div>\n<ul>\n  <li>以下のコマンドを実行(これで「システム設定」に「デスクトップの共有」アイコンが表示されるようになる)\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>glib-compile-schemas /usr/share/glib-2.0/schemas\n</code></pre></div>    </div>\n  </li>\n  <li>GUI画面から「システム設定」→「デスクトップの共有」(ユーザ向けカテゴリの中にある)\n    <ul>\n      <li>「Sharing」カテゴリ\n        <ul>\n          <li>「Allow other users to view your desktop」にチェックを<em>入れる</em></li>\n          <li>「Allow other users to control your desktop」にチェックを<em>入れる</em></li>\n        </ul>\n      </li>\n      <li>「セキュリティ」カテゴリ\n        <ul>\n          <li>「You must confirm each access to this machine」のチェックを<em>はずす</em></li>\n          <li>「Requwire the user to enter this password」にチェックを<em>入れて</em>パスワード設定</li>\n          <li>「Automatically configure UPnP router to open and forward ports」のチェックを<em>はずす</em></li>\n        </ul>\n      </li>\n      <li>「Show Notification Area Icon」カテゴリ\n        <ul>\n          <li>「Only when someone is connected」を選択\n            <blockquote>\n              <p>[!NOTE]\nウィンドウマネージャがUbuntuの時は「設定」で設定する。\n左側の「共有」カテゴリを選択、「画面共有」をクリック</p>\n              <ul>\n                <li>「このスクリーンの操作する接続を許可する」をチェック</li>\n                <li>「アクセスオプション」で「パスワードを要求する」を選択し、パスワード設定</li>\n                <li>「ネットワーク」で「有線接続1」のスライドスイッチで「オン」を選択\n左上のスライドスイッチで「オン」を選択\nで出来ると思うけど、出来なかったらUnityで上の方法で設定した後、再度Ubuntuに切り替えてちょ。</li>\n              </ul>\n            </blockquote>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>「自動起動するアプリケーション」を起動\n    <blockquote>\n      <p>[!NOTE]\n「コンピュータを検索」で「自動」または「session」と入力すると出てくる\n日本語環境だと「startup」で出てこないみたい…</p>\n    </blockquote>\n    <ul>\n      <li>「追加」ボタンをクリック\n        <ul>\n          <li>名前に「Vino」</li>\n          <li>コマンドに「/usr/lib/vino/vino-server」</li>\n          <li>説明に「VNC server」\nー と入力して「追加」をクリック</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>以下のコマンドを実行\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gsettings <span class=\"nb\">set </span>org.gnome.Vino require-encryption <span class=\"nb\">false\n</span>gsettings <span class=\"nb\">set </span>org.gnome.Vino prompt-enabled <span class=\"nb\">false</span>\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\nこれはVinoの暗号化方式がWindowsと互換性がないための措置で、<br />\n暗号化を無効化しているらしい。<br />\ndconf-editorでも設定できる。</p>\n    </blockquote>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nVNC使う場合は自動ログインをONしておかないといけない<br />\n設定箇所はぐぐってちゃぶだい…😅</p>\n</blockquote>\n\n<ul>\n  <li>リブートする</li>\n  <li>ホストPCからRealVNCのVNC ViewerやUltraVNC viewerなどで接続する</li>\n</ul>\n\n<blockquote>\n  <p>[!WARNING]\nVNCは反応速度が鈍いので、ちょっと使いにくい。<br />\n普段はSSHとsambaとホスト側のX-Serverで動かすのが良いかも…</p>\n</blockquote>\n\n<h1 id=\"追加情報\">追加情報</h1>\n<p>ipv6を無効にしたい(ネットワーク環境によっては無効にした方が良い)場合は、<br />\n<a href=\"/memoBlog/2020/05/26/ubuntu_koneta.html\">ubuntu 小ネタ集</a>の\n「ubuntu 18.04 で IPv6を無効にする方法」 にしたがって設定する。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Keras": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Keras on tensorflow2 で SSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>Keras on tensorflow2 で SSD</h1>\n      <p>Tensorflow2上のKerasでSSDを実行を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>※ 2021.05.21 kerasをtensorflow.kerasに変更</p>\n\n<h1 id=\"概要\">概要</h1>\n\n<p>Kerasを使ってSSDを実行してみようと思ったら、Tensorflow1.x上の情報ばかり出てきて、Tensorflow2で実行するのに手間取ったのでメモ。<br />\n(最終的にopenVINOに持っていきたいなぁ、と思って試し始めたんだけど、openVINOにサクッと変換できるのはcaffeだった😅)<br />\nということで、やったけど 続きはないかも。実行遅いし…😩💨</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p><a href=\"https://smilerobo.com/papero/tips_keras_tf_ssd/\" target=\"_blank\">【実験】学習済のSSDを使ってPaPeRo i に複数種類の物体を数えさせる</a>\nを参考に、KerasをTensorflow2で動かしてみる。</p>\n\n<p>Pythonは3.8を使用した(念のため明記しておく)。</p>\n\n<p>Anaconda使ってないし、Paperoじゃないので、そのまんまじゃないけど、<br />\nとりあえずSSDを動かしてみよう。</p>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n\n<p>まずは、python仮想環境の準備をする。<br />\npyenv環境前提。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースディレクトリとpython仮想環境の準備</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/keras2/\n<span class=\"nb\">cd</span> /work/keras2/\npyenv virtualenv 3.8.8 keras2\npyenv <span class=\"nb\">local </span>keras2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># pythonモジュールのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n<span class=\"c\"># kerasはtensorflow内を直接参照にしたので不要  </span>\n<span class=\"c\"># pip install keras</span>\npip <span class=\"nb\">install </span>matplotlib\npip <span class=\"nb\">install </span>imageio\n</code></pre></div></div>\n\n<p>インストールされているpythonモジュールは以下の通り</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.2\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.4.0\ngoogle-auth==1.30.0\ngoogle-auth-oauthlib==0.4.4\ngoogle-pasta==0.2.0\ngrpcio==1.34.1\nh5py==3.1.0\nidna==2.10\nimageio==2.9.0\nkeras-nightly==2.5.0.dev2021032900\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.4.2\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.2.52\nopt-einsum==3.3.0\nPillow==8.2.0\nprotobuf==3.17.0\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nsix==1.15.0\ntensorboard==2.5.0\ntensorboard-data-server==0.6.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.5.0\ntensorflow-estimator==2.5.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==2.0.1\nwrapt==1.12.1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nKeras修正以前の状態は以下</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.1\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.3.3\ngoogle-auth==1.28.0\ngoogle-auth-oauthlib==0.4.3\ngoogle-pasta==0.2.0\ngrpcio==1.32.0\nh5py==2.10.0\nidna==2.10\nimageio==2.9.0\nKeras==2.4.3\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.3.4\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.1.48\nopt-einsum==3.3.0\nPillow==8.1.2\nprotobuf==3.15.6\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nPyYAML==5.4.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nscipy==1.6.1\nsix==1.15.0\ntensorboard==2.4.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.4.1\ntensorflow-estimator==2.4.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==1.0.1\nwrapt==1.12.1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"patchファイルの準備\">patchファイルの準備</h2>\n\n<p>参照先には色々手順が書いてあるが、めんどくさいので パッチファイル用意した(足りない修正もあるし)。<br />\n以下の内容を<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code> <code class=\"language-plaintext highlighter-rouge\">ssd_keras_2.patch</code>のファイル名で保存しておく。</p>\n\n<h3 id=\"ssd_keraspatch\">ssd_keras.patch</h3>\n\n<p>参照先の情報によるpatch</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/ssd.py b/ssd.py\nindex c0049d8..656cd83 100644\n</span><span class=\"gd\">--- a/ssd.py\n</span><span class=\"gi\">+++ b/ssd.py\n</span><span class=\"p\">@@ -2,14 +2,15 @@</span>\n \n import keras.backend as K\n from keras.layers import Activation\n<span class=\"gd\">-from keras.layers import AtrousConvolution2D\n</span><span class=\"gi\">+#from keras.layers import AtrousConvolution2D\n</span> from keras.layers import Convolution2D\n from keras.layers import Dense\n from keras.layers import Flatten\n from keras.layers import GlobalAveragePooling2D\n from keras.layers import Input\n from keras.layers import MaxPooling2D\n<span class=\"gd\">-from keras.layers import merge\n</span><span class=\"gi\">+#from keras.layers import merge\n+from keras.layers.merge import concatenate\n</span> from keras.layers import Reshape\n from keras.layers import ZeroPadding2D\n from keras.models import Model\n<span class=\"p\">@@ -34,109 +35,115 @@</span> def SSD300(input_shape, num_classes=21):\n     input_tensor = input_tensor = Input(shape=input_shape)\n     img_size = (input_shape[1], input_shape[0])\n     net['input'] = input_tensor\n<span class=\"gd\">-    net['conv1_1'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    net['conv1_1'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_1')(net['input'])\n<span class=\"gd\">-    net['conv1_2'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    \n+    net['conv1_2'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_2')(net['conv1_1'])\n<span class=\"gd\">-    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+\n+    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool1')(net['conv1_2'])\n     # Block 2\n<span class=\"gd\">-    net['conv2_1'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+    net['conv2_1'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_1')(net['pool1'])\n<span class=\"gd\">-    net['conv2_2'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+\n+    net['conv2_2'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_2')(net['conv2_1'])\n<span class=\"gd\">-    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool2')(net['conv2_2'])\n<span class=\"gi\">+\n</span>     # Block 3\n<span class=\"gd\">-    net['conv3_1'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_1'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_1')(net['pool2'])\n<span class=\"gd\">-    net['conv3_2'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_2'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_2')(net['conv3_1'])\n<span class=\"gd\">-    net['conv3_3'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_3'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_3')(net['conv3_2'])\n<span class=\"gd\">-    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool3')(net['conv3_3'])\n     # Block 4\n<span class=\"gd\">-    net['conv4_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_1')(net['pool3'])\n<span class=\"gd\">-    net['conv4_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_2')(net['conv4_1'])\n<span class=\"gd\">-    net['conv4_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_3')(net['conv4_2'])\n<span class=\"gd\">-    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool4')(net['conv4_3'])\n<span class=\"gd\">-    # Block 5\n-    net['conv5_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+# Block 5\n+    net['conv5_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_1')(net['pool4'])\n<span class=\"gd\">-    net['conv5_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_2')(net['conv5_1'])\n<span class=\"gd\">-    net['conv5_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_3')(net['conv5_2'])\n<span class=\"gd\">-    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), border_mode='same',\n</span><span class=\"gi\">+    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), padding='same',\n</span>                                 name='pool5')(net['conv5_3'])\n     # FC6\n<span class=\"gd\">-    net['fc6'] = AtrousConvolution2D(1024, 3, 3, atrous_rate=(6, 6),\n-                                     activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['fc6'] = Convolution2D(1024, (3, 3), dilation_rate=(6, 6),\n+                                     activation='relu', padding='same',\n</span>                                      name='fc6')(net['pool5'])\n     # x = Dropout(0.5, name='drop6')(x)\n     # FC7\n<span class=\"gd\">-    net['fc7'] = Convolution2D(1024, 1, 1, activation='relu',\n-                               border_mode='same', name='fc7')(net['fc6'])\n</span><span class=\"gi\">+    net['fc7'] = Convolution2D(1024, (1, 1), activation='relu',\n+                               padding='same', name='fc7')(net['fc6'])\n</span>     # x = Dropout(0.5, name='drop7')(x)\n     # Block 6\n<span class=\"gd\">-    net['conv6_1'] = Convolution2D(256, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv6_1'] = Convolution2D(256, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv6_1')(net['fc7'])\n<span class=\"gd\">-    net['conv6_2'] = Convolution2D(512, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+\n+\n+    net['conv6_2'] = Convolution2D(512, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv6_2')(net['conv6_1'])\n<span class=\"gd\">-    # Block 7\n-    net['conv7_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+        # Block 7\n+    net['conv7_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv7_1')(net['conv6_2'])\n     net['conv7_2'] = ZeroPadding2D()(net['conv7_1'])\n<span class=\"gd\">-    net['conv7_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='valid',\n</span><span class=\"gi\">+    net['conv7_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='valid',\n</span>                                    name='conv7_2')(net['conv7_2'])\n     # Block 8\n<span class=\"gd\">-    net['conv8_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv8_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv8_1')(net['conv7_2'])\n<span class=\"gd\">-    net['conv8_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['conv8_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv8_2')(net['conv8_1'])\n     # Last Pool\n     net['pool6'] = GlobalAveragePooling2D(name='pool6')(net['conv8_2'])\n     # Prediction from conv4_3\n     net['conv4_3_norm'] = Normalize(20, name='conv4_3_norm')(net['conv4_3'])\n     num_priors = 3\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv4_3_norm_mbox_loc')(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_loc'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_loc_flat')\n<span class=\"p\">@@ -144,7 +151,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv4_3_norm_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_conf'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_conf_flat')\n<span class=\"p\">@@ -155,16 +162,16 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv4_3_norm_mbox_priorbox'] = priorbox(net['conv4_3_norm'])\n     # Prediction from fc7\n     num_priors = 6\n<span class=\"gd\">-    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, 3, 3,\n-                                        border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, (3, 3),\n+                                        padding='same',\n</span>                                         name='fc7_mbox_loc')(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_loc_flat')\n     net['fc7_mbox_loc_flat'] = flatten(net['fc7_mbox_loc'])\n     name = 'fc7_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, 3, 3,\n-                                         border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, (3, 3),\n+                                         padding='same',\n</span>                                          name=name)(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_conf_flat')\n     net['fc7_mbox_conf_flat'] = flatten(net['fc7_mbox_conf'])\n<span class=\"p\">@@ -174,7 +181,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['fc7_mbox_priorbox'] = priorbox(net['fc7'])\n     # Prediction from conv6_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv6_2_mbox_loc')(net['conv6_2'])\n     net['conv6_2_mbox_loc'] = x\n     flatten = Flatten(name='conv6_2_mbox_loc_flat')\n<span class=\"p\">@@ -182,7 +189,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv6_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv6_2'])\n     net['conv6_2_mbox_conf'] = x\n     flatten = Flatten(name='conv6_2_mbox_conf_flat')\n<span class=\"p\">@@ -193,7 +200,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv6_2_mbox_priorbox'] = priorbox(net['conv6_2'])\n     # Prediction from conv7_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv7_2_mbox_loc')(net['conv7_2'])\n     net['conv7_2_mbox_loc'] = x\n     flatten = Flatten(name='conv7_2_mbox_loc_flat')\n<span class=\"p\">@@ -201,7 +208,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv7_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv7_2'])\n     net['conv7_2_mbox_conf'] = x\n     flatten = Flatten(name='conv7_2_mbox_conf_flat')\n<span class=\"p\">@@ -212,7 +219,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv7_2_mbox_priorbox'] = priorbox(net['conv7_2'])\n     # Prediction from conv8_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv8_2_mbox_loc')(net['conv8_2'])\n     net['conv8_2_mbox_loc'] = x\n     flatten = Flatten(name='conv8_2_mbox_loc_flat')\n<span class=\"p\">@@ -220,7 +227,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv8_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv8_2'])\n     net['conv8_2_mbox_conf'] = x\n     flatten = Flatten(name='conv8_2_mbox_conf_flat')\n<span class=\"p\">@@ -241,7 +248,7 @@</span> def SSD300(input_shape, num_classes=21):\n     priorbox = PriorBox(img_size, 276.0, max_size=330.0, aspect_ratios=[2, 3],\n                         variances=[0.1, 0.1, 0.2, 0.2],\n                         name='pool6_mbox_priorbox')\n<span class=\"gd\">-    if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+    if K.image_data_format() == 'channels_last':\n</span>         target_shape = (1, 1, 256)\n     else:\n         target_shape = (256, 1, 1)\n<span class=\"p\">@@ -249,42 +256,47 @@</span> def SSD300(input_shape, num_classes=21):\n                                     name='pool6_reshaped')(net['pool6'])\n     net['pool6_mbox_priorbox'] = priorbox(net['pool6_reshaped'])\n     # Gather all predictions\n<span class=\"gd\">-    net['mbox_loc'] = merge([net['conv4_3_norm_mbox_loc_flat'],\n</span><span class=\"gi\">+    net['mbox_loc'] = concatenate([net['conv4_3_norm_mbox_loc_flat'],\n</span>                              net['fc7_mbox_loc_flat'],\n                              net['conv6_2_mbox_loc_flat'],\n                              net['conv7_2_mbox_loc_flat'],\n                              net['conv8_2_mbox_loc_flat'],\n                              net['pool6_mbox_loc_flat']],\n<span class=\"gd\">-                            mode='concat', concat_axis=1, name='mbox_loc')\n-    net['mbox_conf'] = merge([net['conv4_3_norm_mbox_conf_flat'],\n</span><span class=\"gi\">+                            axis=1,\n+                                  name='mbox_loc')\n+    net['mbox_conf'] = concatenate([net['conv4_3_norm_mbox_conf_flat'],\n</span>                               net['fc7_mbox_conf_flat'],\n                               net['conv6_2_mbox_conf_flat'],\n                               net['conv7_2_mbox_conf_flat'],\n                               net['conv8_2_mbox_conf_flat'],\n                               net['pool6_mbox_conf_flat']],\n<span class=\"gd\">-                             mode='concat', concat_axis=1, name='mbox_conf')\n-    net['mbox_priorbox'] = merge([net['conv4_3_norm_mbox_priorbox'],\n</span><span class=\"gi\">+                              axis=1,\n+                              name='mbox_conf')\n+    net['mbox_priorbox'] = concatenate([net['conv4_3_norm_mbox_priorbox'],\n</span>                                   net['fc7_mbox_priorbox'],\n                                   net['conv6_2_mbox_priorbox'],\n                                   net['conv7_2_mbox_priorbox'],\n                                   net['conv8_2_mbox_priorbox'],\n                                   net['pool6_mbox_priorbox']],\n<span class=\"gd\">-                                 mode='concat', concat_axis=1,\n</span><span class=\"gi\">+                                 axis=1,\n</span>                                  name='mbox_priorbox')\n     if hasattr(net['mbox_loc'], '_keras_shape'):\n         num_boxes = net['mbox_loc']._keras_shape[-1] // 4\n     elif hasattr(net['mbox_loc'], 'int_shape'):\n<span class=\"gd\">-        num_boxes = K.int_shape(net['mbox_loc'])[-1] // 4\n</span><span class=\"gi\">+        num_boxes = net['mbox_loc'].int_shape()[-1] // 4\n+    elif hasattr(net['mbox_loc'], 'get_shape'):\n+        num_boxes = net['mbox_loc'].get_shape()[-1] // 4\n</span>     net['mbox_loc'] = Reshape((num_boxes, 4),\n                               name='mbox_loc_final')(net['mbox_loc'])\n     net['mbox_conf'] = Reshape((num_boxes, num_classes),\n                                name='mbox_conf_logits')(net['mbox_conf'])\n     net['mbox_conf'] = Activation('softmax',\n                                   name='mbox_conf_final')(net['mbox_conf'])\n<span class=\"gd\">-    net['predictions'] = merge([net['mbox_loc'],\n</span><span class=\"gi\">+    net['predictions'] = concatenate([net['mbox_loc'],\n</span>                                net['mbox_conf'],\n                                net['mbox_priorbox']],\n<span class=\"gd\">-                               mode='concat', concat_axis=2,\n</span><span class=\"gi\">+                               axis=2,\n+                               #axis = 0,\n</span>                                name='predictions')\n     model = Model(net['input'], net['predictions'])\n     return model\n<span class=\"gh\">diff --git a/ssd_layers.py b/ssd_layers.py\nindex 5e10478..41ee510 100644\n</span><span class=\"gd\">--- a/ssd_layers.py\n</span><span class=\"gi\">+++ b/ssd_layers.py\n</span><span class=\"p\">@@ -29,7 +29,8 @@</span> class Normalize(Layer):\n         Add possibility to have one scale for all features.\n     \"\"\"\n     def __init__(self, scale, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n+\n</span>             self.axis = 3\n         else:\n             self.axis = 1\n<span class=\"p\">@@ -41,7 +42,7 @@</span> class Normalize(Layer):\n         shape = (input_shape[self.axis],)\n         init_gamma = self.scale * np.ones(shape)\n         self.gamma = K.variable(init_gamma, name='{}_gamma'.format(self.name))\n<span class=\"gd\">-        self.trainable_weights = [self.gamma]\n</span><span class=\"gi\">+        self._trainable_weights = [self.gamma]\n</span> \n     def call(self, x, mask=None):\n         output = K.l2_normalize(x, self.axis)\n<span class=\"p\">@@ -81,7 +82,7 @@</span> class PriorBox(Layer):\n     \"\"\"\n     def __init__(self, img_size, min_size, max_size=None, aspect_ratios=None,\n                  flip=True, variances=[0.1], clip=True, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n</span>             self.waxis = 2\n             self.haxis = 1\n         else:\n<span class=\"p\">@@ -108,7 +109,7 @@</span> class PriorBox(Layer):\n         self.clip = True\n         super(PriorBox, self).__init__(**kwargs)\n \n<span class=\"gd\">-    def get_output_shape_for(self, input_shape):\n</span><span class=\"gi\">+    def compute_output_shape(self, input_shape):\n</span>         num_priors_ = len(self.aspect_ratios)\n         layer_width = input_shape[self.waxis]\n         layer_height = input_shape[self.haxis]\n<span class=\"gh\">diff --git a/ssd_utils.py b/ssd_utils.py\nindex 0a9ffb1..4fc7a49 100644\n</span><span class=\"gd\">--- a/ssd_utils.py\n</span><span class=\"gi\">+++ b/ssd_utils.py\n</span><span class=\"p\">@@ -1,7 +1,8 @@</span>\n \"\"\"Some utils for SSD.\"\"\"\n \n import numpy as np\n<span class=\"gd\">-import tensorflow as tf\n</span><span class=\"gi\">+import tensorflow.compat.v1 as tf\n+tf.disable_v2_behavior()\n</span> \n \n class BBoxUtility(object):\n<span class=\"gh\">diff --git a/testing_utils/videotest.py b/testing_utils/videotest.py\nindex 0cbae3c..7b2ff4f 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest.py\n</span><span class=\"p\">@@ -3,13 +3,14 @@</span>\n import cv2\n import keras\n from keras.applications.imagenet_utils import preprocess_input\n<span class=\"gd\">-from keras.backend.tensorflow_backend import set_session\n</span><span class=\"gi\">+# from keras.backend.tensorflow_backend import set_session\n</span> from keras.models import Model\n from keras.preprocessing import image \n import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-from scipy.misc import imread, imresize\n</span><span class=\"gi\">+# from scipy.misc import imread, imresize\n+from imageio import imread\n</span> from timeit import default_timer as timer\n \n import sys\n<span class=\"p\">@@ -84,8 +85,8 @@</span> class VideoTest(object):\n             \"trying to open a webcam, make sure you video_path is an integer!\"))\n         \n         # Compute aspect ratio of video     \n<span class=\"gd\">-        vidw = vid.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)\n-        vidh = vid.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)\n</span><span class=\"gi\">+        vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)\n+        vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)\n</span>         vidar = vidw/vidh\n         \n         # Skip frames until reaching start_frame\n<span class=\"gh\">diff --git a/testing_utils/videotest_example.py b/testing_utils/videotest_example.py\nindex fb4d873..27ec148 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest_example.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest_example.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import os\n+# GPU不使用を設定\n+os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n+\n</span> import keras\n import pickle\n from videotest import VideoTest\n<span class=\"p\">@@ -9,16 +13,38 @@</span> from ssd import SSD300 as SSD\n input_shape = (300,300,3)\n \n # Change this if you run with other classes than VOC\n<span class=\"gd\">-class_names = [\"background\", \"aeroplane\", \"bicycle\", \"bird\", \"boat\", \"bottle\", \"bus\", \"car\", \"cat\", \"chair\", \"cow\", \"diningtable\", \"dog\", \"horse\", \"motorbike\", \"person\", \"pottedplant\", \"sheep\", \"sofa\", \"train\", \"tvmonitor\"];\n</span><span class=\"gi\">+class_names = [ \n+                \"background\", \n+                \"aeroplane\", \n+                \"bicycle\", \n+                \"bird\", \n+                \"boat\", \n+                \"bottle\", \n+                \"bus\", \n+                \"car\", \n+                \"cat\", \n+                \"chair\", \n+                \"cow\", \n+                \"diningtable\", \n+                \"dog\", \n+                \"horse\", \n+                \"motorbike\", \n+                \"person\", \n+                \"pottedplant\", \n+                \"sheep\", \n+                \"sofa\", \n+                \"train\", \n+                \"tvmonitor\"\n+            ];\n</span> NUM_CLASSES = len(class_names)\n \n model = SSD(input_shape, num_classes=NUM_CLASSES)\n \n # Change this path if you want to use your own trained weights\n<span class=\"gd\">-model.load_weights('../weights_SSD300.hdf5') \n</span><span class=\"gi\">+model.load_weights('../../weights_SSD300.hdf5') \n</span>         \n vid_test = VideoTest(class_names, model, input_shape)\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('path/to/your/video.mkv')\n</span><span class=\"gi\">+vid_test.run('../../testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h3 id=\"ssd_keras_2patch\">ssd_keras_2.patch</h3>\n\n<p>keras修正対応</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras_2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd.py ssd_keras.tmp/ssd.py\n</span><span class=\"gd\">--- ssd_keras/ssd.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd.py\t2021-05-21 07:06:44.970000000 +0900\n</span><span class=\"p\">@@ -1,19 +1,17 @@</span>\n \"\"\"Keras implementation of SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.layers import Activation\n-#from keras.layers import AtrousConvolution2D\n-from keras.layers import Convolution2D\n-from keras.layers import Dense\n-from keras.layers import Flatten\n-from keras.layers import GlobalAveragePooling2D\n-from keras.layers import Input\n-from keras.layers import MaxPooling2D\n-#from keras.layers import merge\n-from keras.layers.merge import concatenate\n-from keras.layers import Reshape\n-from keras.layers import ZeroPadding2D\n-from keras.models import Model\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.keras.layers import Activation\n+from tensorflow.keras.layers import Convolution2D\n+from tensorflow.keras.layers import Dense\n+from tensorflow.keras.layers import Flatten\n+from tensorflow.keras.layers import GlobalAveragePooling2D\n+from tensorflow.keras.layers import Input\n+from tensorflow.keras.layers import MaxPooling2D\n+from tensorflow.keras.layers import concatenate\n+from tensorflow.keras.layers import Reshape\n+from tensorflow.keras.layers import ZeroPadding2D\n+from tensorflow.keras.models import Model\n</span> \n from ssd_layers import Normalize\n from ssd_layers import PriorBox\n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd_layers.py ssd_keras.tmp/ssd_layers.py\n</span><span class=\"gd\">--- ssd_keras/ssd_layers.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd_layers.py\t2021-05-21 06:31:11.780000000 +0900\n</span><span class=\"p\">@@ -1,8 +1,8 @@</span>\n \"\"\"Some special pupropse layers for SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.engine.topology import InputSpec\n-from keras.engine.topology import Layer\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.python.keras.engine.input_spec import InputSpec\n+from tensorflow.python.keras.engine.base_layer import Layer\n</span> import numpy as np\n import tensorflow as tf\n \n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest.py ssd_keras.tmp/testing_utils/videotest.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest.py\t2021-05-21 07:08:24.680000000 +0900\n</span><span class=\"p\">@@ -1,15 +1,13 @@</span>\n \"\"\" A class for testing a SSD model on a video file or webcam \"\"\"\n \n import cv2\n<span class=\"gd\">-import keras\n-from keras.applications.imagenet_utils import preprocess_input\n-# from keras.backend.tensorflow_backend import set_session\n-from keras.models import Model\n-from keras.preprocessing import image \n</span><span class=\"gi\">+import tensorflow.keras as keras\n+from tensorflow.keras.applications.imagenet_utils import preprocess_input\n+from tensorflow.keras.models import Model\n+from tensorflow.keras.preprocessing import image \n</span> import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-# from scipy.misc import imread, imresize\n</span> from imageio import imread\n from timeit import default_timer as timer\n \n<span class=\"p\">@@ -179,6 +177,7 @@</span>\n             cv2.putText(to_draw, fps, (3,10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0,0,0), 1)\n             \n             cv2.imshow(\"SSD result\", to_draw)\n<span class=\"gd\">-            cv2.waitKey(10)\n-            \n-        \n</span><span class=\"gi\">+            key = cv2.waitKey(1)\n+            if key == 27:\n+                # ESCキー\n+                break\n</span><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest_example.py ssd_keras.tmp/testing_utils/videotest_example.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest_example.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest_example.py\t2021-05-21 07:04:24.320000000 +0900\n</span><span class=\"p\">@@ -2,7 +2,7 @@</span>\n # GPU不使用を設定\n os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n \n<span class=\"gd\">-import keras\n</span><span class=\"gi\">+import tensorflow.keras as keras\n</span> import pickle\n from videotest import VideoTest\n \n<span class=\"p\">@@ -47,4 +47,4 @@</span>\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('../../testvideo3.mp4')\n</span><span class=\"gi\">+vid_test.run('../../images/testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h2 id=\"学習済み重みファイルのダウンロード\">学習済み重みファイルのダウンロード</h2>\n\n<p>参照先の記載にしたがって、重み学習済み重みファイルをダウンロードする。</p>\n\n<p>wgetでは取得できなかったので、ブラウザで↓ここ から weights_SSD300.hdf5 をダウンロード。<br />\n<a href=\"https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA\" target=\"_blank\">https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA</a><br />\nで、ZIPファイルをカレントディレクトリに解凍しておく。</p>\n\n<h2 id=\"ソースのダウンロードパッチをあてる\">ソースのダウンロード&パッチをあてる</h2>\n\n<p>githubからソースをダウンロードする。<br />\nこのままではエラーになるので、先ほど作成したパッチファイル<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code>でパッチをあてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/rykov8/ssd_keras.git\n<span class=\"nb\">cd </span>ssd_keras\npatch <span class=\"nt\">-p1</span> < ../ssd_keras.patch \n<span class=\"c\"># Keras修正対応パッチ</span>\npatch <span class=\"nt\">-p1</span> < ../ssd_keras_2.patch \n</code></pre></div></div>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>testing_utils/\npython videotest_example.py\n</code></pre></div></div>\n\n<p>おー。<br />\nしかし遅い…. <br />\nKerasは遅いみたい。。。orz…</p>\n\n<h1 id=\"こんなんもある\">こんなんもある</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50\" target=\"_blank\">「Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Tensorflow": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その2)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その2)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(PPO2編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_1.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a>\nではポリシーにDDQNを使用したサンプルを実行してみたが、今回はもう一つのサンプル(PPO2を使用)を試してみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim2\n<span class=\"nb\">cd</span> /work2/donkey_sim2\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv <span class=\"nb\">install </span>3.7.12 \npyenv virtualenv 3.7.12 donkey_sim2\npyenv <span class=\"nb\">local </span>donkey_sim2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>stable-baselines\npip <span class=\"nb\">install </span><span class=\"nv\">tensorflow</span><span class=\"o\">==</span>1.14.0\n\n<span class=\"c\"># 現時点での最新リリース v21.7.24 をcheckoutしておく</span>\ngit clone https://github.com/tawnkramer/gym-donkeycar <span class=\"nt\">-b</span> v21.07.24\n\n<span class=\"c\"># gym-donkeycarライブラリのインストール</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-e</span> gym-donkeycar\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nstable-baselines は tensorflow ~1.14.0 しかサポートしていないので、バージョン指定してインストールする。<br />\ntensorflow 1.14.0 は python ~3.7 しかサポートしていないので、3.7系の最新版を使用している。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ngym-donkeycar は -e (–editable) オプション付きでインストールしているので、編集も可能。 \ngit cloneした先を参照しているので、インストール後もgym-donkeycarを削除しちゃダメ。</p>\n\n  <p>githubから直接インストールする場合は以下。<br />\nこの場合、パッケージは通常のディレクトリにインストールされる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n</code></pre></div>  </div>\n  <p>でも、以下でサンプルプログラム使うので、git cloneもしないとダメ。</p>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a> と同じ</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n\n<p>用意されているサンプルプログラムにパッチをあてようと思ったのだけど、<br />\n<code class=\"language-plaintext highlighter-rouge\">ppo_train.py</code> はやっつけ感満載のイマイチソースなので いっそ全書き換えで。</p>\n\n<p>主な対応内容は、</p>\n<ul>\n  <li>一定間隔でモデルの保存を行うようcallbackクラスの追加</li>\n  <li>シミュレータのリモート実行対応(<code class=\"language-plaintext highlighter-rouge\">--host</code>)</li>\n  <li>学習回数指定オプション(<code class=\"language-plaintext highlighter-rouge\">--step</code>)</li>\n  <li>テスト回数指定オプション(<code class=\"language-plaintext highlighter-rouge\">--test_step</code>)</li>\n  <li>保存したモデルファイルをロードしてからの学習に対応</li>\n  <li></li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ppo.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">signal</span>\n<span class=\"kn\">import</span> <span class=\"nn\">argparse</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">typing</span>\n<span class=\"kn\">from</span> <span class=\"nn\">typing</span> <span class=\"kn\">import</span> <span class=\"n\">Union</span><span class=\"p\">,</span> <span class=\"n\">List</span><span class=\"p\">,</span> <span class=\"n\">Dict</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">,</span> <span class=\"n\">Optional</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">gym</span>\n<span class=\"kn\">import</span> <span class=\"nn\">gym_donkeycar</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines</span> <span class=\"kn\">import</span> <span class=\"n\">PPO2</span>\n<span class=\"c1\"># from stable_baselines.common import set_global_seeds\n</span><span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.policies</span> <span class=\"kn\">import</span> <span class=\"n\">CnnPolicy</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.vec_env</span> <span class=\"kn\">import</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.callbacks</span> <span class=\"kn\">import</span> <span class=\"n\">EventCallback</span>\n<span class=\"kn\">from</span> <span class=\"nn\">stable_baselines.common.base_class</span> <span class=\"kn\">import</span> <span class=\"n\">BaseRLModel</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MyCallback</span><span class=\"p\">(</span><span class=\"n\">EventCallback</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> \n                 <span class=\"n\">eval_env</span><span class=\"p\">:</span> <span class=\"n\">Union</span><span class=\"p\">[</span><span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">Env</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span><span class=\"p\">],</span>\n                 <span class=\"n\">save_freq</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">1000</span><span class=\"p\">,</span>\n                 <span class=\"n\">save_file</span><span class=\"p\">:</span> <span class=\"n\">Optional</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"bp\">None</span><span class=\"p\">,</span>\n                 <span class=\"n\">verbose</span><span class=\"p\">:</span> <span class=\"nb\">int</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">MyCallback</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"n\">verbose</span><span class=\"o\">=</span><span class=\"n\">verbose</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span> <span class=\"o\">=</span> <span class=\"n\">save_file</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">=</span> <span class=\"n\">save_freq</span>\n        \n        <span class=\"c1\"># Convert to VecEnv for consistency\n</span>        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">eval_env</span><span class=\"p\">,</span> <span class=\"n\">VecEnv</span><span class=\"p\">):</span>\n            <span class=\"n\">eval_env</span> <span class=\"o\">=</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">([</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"n\">eval_env</span><span class=\"p\">])</span>\n            \n        <span class=\"k\">assert</span> <span class=\"n\">eval_env</span><span class=\"p\">.</span><span class=\"n\">num_envs</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s\">\"You must pass only one environment for evaluation\"</span>\n        \n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">eval_env</span> <span class=\"o\">=</span> <span class=\"n\">eval_env</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">init_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">model</span><span class=\"p\">:</span> <span class=\"s\">'BaseRLModel'</span><span class=\"p\">)</span> <span class=\"o\">-></span> <span class=\"bp\">None</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#### INIT ####\"</span><span class=\"p\">)</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">EventCallback</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">init_callback</span><span class=\"p\">(</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">_init_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#### _INIT ####\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">def</span> <span class=\"nf\">_on_step</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"o\">-></span> <span class=\"nb\">bool</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">></span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">n_calls</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_freq</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">now</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">now</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">verbose</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">now</span><span class=\"si\">}</span><span class=\"s\"> saving...'</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span> <span class=\"p\">:</span>\n                <span class=\"n\">now_str</span>  <span class=\"o\">=</span> <span class=\"n\">now</span><span class=\"p\">.</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s\">'%y%m%d_%H%M%S'</span><span class=\"p\">)</span>\n                <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">save_file</span>\n                <span class=\"c1\"># filename = os.path.join(os.path.dirname(self.save_file), f'{now_str}_{os.path.basename(self.save_file)}')\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">True</span>\n    \n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Initialize the donkey environment\n</span>    <span class=\"c1\"># where env_name one of:\n</span>    <span class=\"n\">env_list</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-roads-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-avc-sparkfun-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-roboracingleague-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-waveshare-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-minimonaco-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-warren-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-thunderhill-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-circuit-launch-track-v0\"</span><span class=\"p\">,</span>\n    <span class=\"p\">]</span>\n    \n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s\">\"ppo_train\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--sim\"</span><span class=\"p\">,</span>\n        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span>\n        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"sim_path\"</span><span class=\"p\">,</span>\n        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\"</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--model\"</span><span class=\"p\">,</span>     <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"ppo_donkey\"</span><span class=\"p\">,</span>  <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--host\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"127.0.0.1\"</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"simulator address\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--port\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">9091</span><span class=\"p\">,</span>          <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--step\"</span><span class=\"p\">,</span>      <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">,</span>         <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test_step\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">,</span>             <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for tcp\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test\"</span><span class=\"p\">,</span>      <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">,</span>             <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"load the trained model and play\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--env_name\"</span><span class=\"p\">,</span>  <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"name of donkey sim environment\"</span><span class=\"p\">,</span> <span class=\"n\">choices</span><span class=\"o\">=</span><span class=\"n\">env_list</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n    \n    <span class=\"n\">test_step</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test_step</span>\n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span> <span class=\"ow\">and</span> <span class=\"n\">test_step</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"n\">test_step</span> <span class=\"o\">=</span> <span class=\"mi\">1000</span>\n        \n    <span class=\"c1\"># Complement the file extension\n</span>    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s\">\".zip\"</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span> <span class=\"o\">+</span> <span class=\"s\">\".zip\"</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">model_path</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span>\n    \n    <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s\">\"exe_path\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sim</span><span class=\"p\">,</span>\n        <span class=\"s\">\"host\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">host</span><span class=\"p\">,</span>\n        <span class=\"s\">\"port\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">port</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_style\"</span><span class=\"p\">:</span> <span class=\"s\">\"car01\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_rgb\"</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span>\n        <span class=\"s\">\"car_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"me\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"font_size\"</span><span class=\"p\">:</span> <span class=\"mi\">100</span><span class=\"p\">,</span>\n        <span class=\"s\">\"racer_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"PPO\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"country\"</span><span class=\"p\">:</span> <span class=\"s\">\"USA\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"bio\"</span><span class=\"p\">:</span> <span class=\"s\">\"Learning to drive w PPO RL\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"guid\"</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"p\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()),</span>\n        <span class=\"s\">\"max_cte\"</span><span class=\"p\">:</span> <span class=\"mi\">10</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\"># Make an environment test our trained policy\n</span>    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">make</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">env_name</span><span class=\"p\">,</span> <span class=\"n\">conf</span><span class=\"o\">=</span><span class=\"n\">conf</span><span class=\"p\">)</span>\n    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">DummyVecEnv</span><span class=\"p\">([</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"n\">env</span><span class=\"p\">])</span>\n    \n    <span class=\"c1\"># hook terninate signal\n</span>    <span class=\"k\">def</span> <span class=\"nf\">signal_handler</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"catching ctrl+c\"</span><span class=\"p\">)</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGINT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGTERM</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGABRT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">try</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># check model path\n</span>        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">):</span>\n            <span class=\"c1\"># load model\n</span>            <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">PPO2</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">,</span> <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span> \n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">:</span>\n                <span class=\"c1\"># create model\n</span>                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"create new model\"</span><span class=\"p\">)</span>\n                <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">PPO2</span><span class=\"p\">(</span><span class=\"n\">CnnPolicy</span><span class=\"p\">,</span> <span class=\"n\">env</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">raise</span> <span class=\"nb\">ValueError</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"Error: the file </span><span class=\"si\">{</span><span class=\"n\">model_path</span><span class=\"si\">}</span><span class=\"s\"> could not be found\"</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># change throttle lower limit\n</span>        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">action_space</span><span class=\"p\">.</span><span class=\"n\">low</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.1</span>\n        \n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">:</span>\n            <span class=\"c1\"># in training mode\n</span>            \n            <span class=\"n\">callback</span> <span class=\"o\">=</span> <span class=\"n\">MyCallback</span><span class=\"p\">(</span><span class=\"n\">env</span><span class=\"p\">,</span> <span class=\"n\">save_freq</span> <span class=\"o\">=</span> <span class=\"mi\">5000</span><span class=\"p\">,</span> <span class=\"n\">save_file</span> <span class=\"o\">=</span> <span class=\"n\">model_path</span><span class=\"p\">,</span> <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"c1\"># callback = MyCallback(env, save_freq = 10, verbose = 1)\n</span>            \n            <span class=\"c1\"># set up model in learning mode with goal number of timesteps to complete\n</span>            <span class=\"c1\"># model.learn(total_timesteps=10000)\n</span>            <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">learn</span><span class=\"p\">(</span><span class=\"n\">total_timesteps</span><span class=\"o\">=</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">,</span> <span class=\"n\">callback</span><span class=\"o\">=</span><span class=\"n\">callback</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># save model\n</span>            <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">model_path</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stert testing...\"</span><span class=\"p\">)</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">reset</span><span class=\"p\">()</span>\n        <span class=\"n\">prev_done_count</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">test_step</span><span class=\"p\">):</span>\n            <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">_states</span> <span class=\"o\">=</span> <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n            <span class=\"n\">obs</span><span class=\"p\">,</span> <span class=\"n\">rewards</span><span class=\"p\">,</span> <span class=\"n\">dones</span><span class=\"p\">,</span> <span class=\"n\">info</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">(</span><span class=\"n\">action</span><span class=\"p\">)</span>\n            <span class=\"c1\"># print(f\"cnt : {i}    rewards : {rewards[0]}    dones : {dones[0]}    pos : {info[0]['pos']}, CrossTrackError : {info[0]['cte']}, speed : {info[0]['speed']}\")\n</span>            <span class=\"c1\"># print(f\"+++ info: {info} +++\")\n</span>            <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">render</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">dones</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'dones flag detected : </span><span class=\"si\">{</span><span class=\"n\">i</span> <span class=\"o\">-</span> <span class=\"n\">prev_done_count</span><span class=\"si\">}</span><span class=\"s\">  (</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">}</span><span class=\"s\">)'</span><span class=\"p\">)</span>\n                <span class=\"n\">prev_done_count</span> <span class=\"o\">=</span> <span class=\"n\">i</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"done testing\"</span><span class=\"p\">)</span>\n        \n    <span class=\"k\">except</span> <span class=\"nb\">KeyboardInterrupt</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stopping run...\"</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n</code></pre></div></div>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習。<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションに<code class=\"language-plaintext highlighter-rouge\">remote</code>を、実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>examples/reinforcement_learning\npython ppo.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n学習回数を指定するには<code class=\"language-plaintext highlighter-rouge\">--step</code>オプションで指定します。<br />\n指定する回数はエピソード数ではなく、アクション数。<br />\n例えば、<code class=\"language-plaintext highlighter-rouge\">--step=100000</code></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nローカルマシンでシミュレータを実行する場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションにDonkeyCar シミュレータ起動コマンドをフルパスで指定します。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションは不要です。<br />\nシミュレータをあらかじめ起動しておく必要はなく、自動的に起動されます。</p>\n</blockquote>\n\n<p>モデルの保存間隔は<code class=\"language-plaintext highlighter-rouge\">MyCallback</code>のインスタンス生成時に<code class=\"language-plaintext highlighter-rouge\">save_freq = 5000</code>で指定していますので、必要なら変更してください。</p>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンドに<code class=\"language-plaintext highlighter-rouge\">--test</code>を指定するだけです。<br />\nテストを実行するステップ数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--test_step</code>オプションで指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ppo.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--test</span> \n</code></pre></div></div>\n<p>途中で止めたい場合はCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>ほど複雑じゃないので省略。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その1)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その1)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(DDQN編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"https://qiita.com/bathtimefish/items/a9b23681720527c0bd7e?fbclid=IwAR3sbaoBn09U7pFL4AKyEOXMi0wNXyAYi9jODUzO1muYr-N7q6hFG-hDfKs\" target=\"_blank\">DonkeyCar3シミュレーターで強化学習してみる</a>のマネをしてDonkeyCarシミュレータライブラリの中にあるサンプルのddqn.pyを実行してみる。<br />\n参考:<br />\nDQNについてはここが分かりやすかったかな。<br />\n<a href=\"https://www.tcom242242.net/entry/ai-2/%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/%E6%B7%B1%E5%B1%A4%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/%E3%80%90%E6%B7%B1%E5%B1%A4%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92%E3%80%91deep_q_network_%E3%82%92tensorflow%E3%81%A7%E5%AE%9F%E8%A3%85/\" target=\"_blank\">【深層強化学習,入門】Deep Q Network(DQN)の解説とPythonで実装 〜図を使って説明〜 </a><br />\n<a href=\"https://www.tcom242242.net/entry/ai-2/%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92/%e3%80%90%e6%b7%b1%e5%b1%a4%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92%e3%80%91double-q-network/\" target=\"_blank\">【深層強化学習】Double Deep Q Network(DDQN)</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim\n<span class=\"nb\">cd</span> /work2/donkey_sim\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 donkey_sim\npyenv <span class=\"nb\">local </span>donkey_sim \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n\n<span class=\"c\"># 現時点での最新リリース v21.7.24 をcheckoutしておく</span>\ngit clone https://github.com/tawnkramer/gym-donkeycar <span class=\"nt\">-b</span> v21.07.24\n\n<span class=\"c\"># gym-donkeycarライブラリのインストール</span>\npip <span class=\"nb\">install</span> <span class=\"nt\">-e</span> gym-donkeycar\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ngym-donkeycar は -e (–editable) オプション付きでインストールしているので、編集も可能。 \ngit cloneした先を参照しているので、インストール後もgym-donkeycarを削除しちゃダメ。</p>\n\n  <p>githubから直接インストールする場合は以下。<br />\nこの場合、パッケージは通常のディレクトリにインストールされる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n</code></pre></div>  </div>\n  <p>でも、以下でサンプルプログラム使うので、git cloneもしないとダメ。</p>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p>以下のページから実行するプラットフォームに合わせて<code class=\"language-plaintext highlighter-rouge\">DonkeySimXXXX.zip</code>(XXXXはプラットフォーム名)をダウンロードし、<br />\n適当なディレクトリに展開しておきます。<br />\n(Linux/Macの場合は実行属性付けるのを忘れずに)<br />\n<a href=\"https://github.com/tawnkramer/gym-donkeycar/releases\">https://github.com/tawnkramer/gym-donkeycar/releases</a></p>\n\n<p>マシンスペックがそれほど高くない場合は別マシンで実行してリモート接続するのがおススメ。<br />\nSSH接続で実行する場合はリモート必須。</p>\n\n<h2 id=\"patchをあてる\">patchをあてる</h2>\n\n<p>以下のパッチファイルを使用してサンプルプログラムにパッチをあてます。<br />\n内容は、</p>\n<ul>\n  <li>なぜか<code class=\"language-plaintext highlighter-rouge\">gym_donkeycar</code>がimportされてなかった</li>\n  <li>tensorflow 1.13以降2.0未満用の設定をバージョン情報からスキップできるようにした</li>\n  <li>シミュレータのリモート実行対応(hostオプション追加)</li>\n  <li>探索率(ε値)の初期値設定オプションの追加<br />\n探索率(ε値)については<a href=\"https://www.tcom242242.net/entry/ai-2/%E5%BC%B7%E5%8C%96%E5%AD%A6%E7%BF%92/epsilon-greedy/\" target=\"_blank\">ε-greedy行動選択 </a>を参照</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  rl_sample.patch\n</p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/examples/reinforcement_learning/ddqn.py b/examples/reinforcement_learning/ddqn.py\nindex 87c74f0..5c32f49 100755\n</span><span class=\"gd\">--- a/examples/reinforcement_learning/ddqn.py\n</span><span class=\"gi\">+++ b/examples/reinforcement_learning/ddqn.py\n</span><span class=\"p\">@@ -21,6 +21,8 @@</span> from tensorflow.keras.layers import Activation, Conv2D, Dense, Flatten\n from tensorflow.keras.models import Sequential\n from tensorflow.keras.optimizers import Adam\n \n<span class=\"gi\">+import gym_donkeycar\n+\n</span> EPISODES = 10000\n img_rows, img_cols = 80, 80\n # Convert image into Black and white\n<span class=\"p\">@@ -121,6 +123,9 @@</span> class DQNAgent:\n         if self.epsilon > self.epsilon_min:\n             self.epsilon -= (self.initial_epsilon - self.epsilon_min) / self.explore\n \n<span class=\"gi\">+    def set_epsilon(self, epsilon):\n+        self.epsilon = epsilon\n+\n</span>     def train_replay(self):\n         if len(self.memory) < self.train_start:\n             return\n<span class=\"p\">@@ -196,15 +201,17 @@</span> def run_ddqn(args):\n     run a DDQN training session, or test it's result, with the donkey simulator\n     \"\"\"\n \n<span class=\"gd\">-    # only needed if TF==1.13.1\n-    config = tf.ConfigProto()\n-    config.gpu_options.allow_growth = True\n-    sess = tf.Session(config=config)\n-    K.set_session(sess)\n</span><span class=\"gi\">+    tf_ver = tf.__version__.split('.')\n+    if (tf_ver[0] == 1 and tf_ver[1] >= 13) :\n+        # only needed if TF==1.13.1\n+        config = tf.ConfigProto()\n+        config.gpu_options.allow_growth = True\n+        sess = tf.Session(config=config)\n+        K.set_session(sess)\n</span> \n     conf = {\n         \"exe_path\": args.sim,\n<span class=\"gd\">-        \"host\": \"127.0.0.1\",\n</span><span class=\"gi\">+        \"host\": args.host,\n</span>         \"port\": args.port,\n         \"body_style\": \"donkey\",\n         \"body_rgb\": (128, 128, 128),\n<span class=\"p\">@@ -237,6 +244,9 @@</span> def run_ddqn(args):\n     try:\n         agent = DQNAgent(state_size, action_space, train=not args.test)\n \n<span class=\"gi\">+        if args.epsilon > 0 :\n+            agent.set_epsilon(args.epsilon)\n+\n</span>         throttle = args.throttle  # Set throttle as constant value\n \n         episodes = []\n<span class=\"p\">@@ -350,6 +360,7 @@</span> if __name__ == \"__main__\":\n         default=\"manual\",\n         help=\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\",\n     )\n<span class=\"gi\">+    parser.add_argument(\"--host\", type=str, default=\"127.0.0.1\", help=\"simulator address\")\n</span>     parser.add_argument(\"--model\", type=str, default=\"rl_driver.h5\", help=\"path to model\")\n     parser.add_argument(\"--test\", action=\"store_true\", help=\"agent uses learned model to navigate env\")\n     parser.add_argument(\"--port\", type=int, default=9091, help=\"port to use for websockets\")\n<span class=\"p\">@@ -357,6 +368,7 @@</span> if __name__ == \"__main__\":\n     parser.add_argument(\n         \"--env_name\", type=str, default=\"donkey-warehouse-v0\", help=\"name of donkey sim environment\", choices=env_list\n     )\n<span class=\"gi\">+    parser.add_argument(\"--epsilon\", type=float, default=0.0, help=\"initial epsilon value\")\n</span> \n     args = parser.parse_args()\n</code></pre></div></div>\n\n<p>以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>gym-donkeycar/\npatch <span class=\"nt\">-p1</span> < rl_sample.patch \n</code></pre></div></div>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習しないと話にならないので学習します。<br />\n強化学習は教師データが要らないので、準備がラクチン…  でも学習には時間がかかる…<br />\nDonkeyCar シミュレータをリモートマシンで実行する場合、<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションに<code class=\"language-plaintext highlighter-rouge\">remote</code>を、実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>examples/reinforcement_learning\npython ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルマシンでシミュレータを実行する場合は<br />\n<code class=\"language-plaintext highlighter-rouge\">--sim</code>オプションにDonkeyCar シミュレータ起動コマンドをフルパスで指定します。<br />\nこのとき、<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションは不要です。<br />\nシミュレータをあらかじめ起動しておく必要はなく、自動的に起動されます。</p>\n</blockquote>\n\n<p>エピソード毎に学習結果が <code class=\"language-plaintext highlighter-rouge\">rl_driver.h5</code>に保存されるので、任意のタイミングでCTRL-Cで中断できます。<br />\n次回学習を再開する場合は、ログとして表示されている<code class=\"language-plaintext highlighter-rouge\">epsilon: 0.XXXXXXX</code>の部分の最後の値を覚えておいてください。<br />\nこのプログラムではε値は0.02を下回ると固定されるので、ある程度学習が進んだ状態では<code class=\"language-plaintext highlighter-rouge\">0.02</code>だと思っても問題ないでしょう。</p>\n\n<p>学習を再開する場合は以下のように上記コマンドに<code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプションを追加して実行します。<br />\n(<code class=\"language-plaintext highlighter-rouge\">0.XXXXXXX</code>の部分は上で覚えておいた値。ピッタリ同じでなくて大体で可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--epsilon</span><span class=\"o\">=</span>0.XXXXXXX\n</code></pre></div></div>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンドに<code class=\"language-plaintext highlighter-rouge\">--test</code>を指定するだけです。<br />\n<code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプションは指定しません。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python ddqn.py <span class=\"nt\">--sim</span><span class=\"o\">=</span>remote <span class=\"nt\">--host</span><span class=\"o\">=</span>192.168.78.200 <span class=\"nt\">--test</span>\n</code></pre></div></div>\n<p>うまく学習が進んでいれば、コースアウトすることなく周回してくれるハズ。<br />\n学習時と同様、コースアウトすると自動的にスタート位置に戻って再スタートします。<br />\n適当にCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>以下はソースを読んだ時のメモです。<br />\n書いてみたけど、自分で読んでも なにが何だか分からない…😢</p>\n\n<h2 id=\"冒頭部分\">冒頭部分</h2>\n<p>この辺はお約束なので。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"s\">\"\"\"\nfile: ddqn.py\nauthor: Felix Yu\ndate: 2018-09-12\noriginal: https://github.com/flyyufelix/donkey_rl/blob/master/donkey_rl/src/ddqn.py\n\"\"\"</span>\n<span class=\"kn\">import</span> <span class=\"nn\">argparse</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">signal</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">from</span> <span class=\"nn\">collections</span> <span class=\"kn\">import</span> <span class=\"n\">deque</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">gym</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">tensorflow</span> <span class=\"k\">as</span> <span class=\"n\">tf</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras</span> <span class=\"kn\">import</span> <span class=\"n\">backend</span> <span class=\"k\">as</span> <span class=\"n\">K</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.layers</span> <span class=\"kn\">import</span> <span class=\"n\">Activation</span><span class=\"p\">,</span> <span class=\"n\">Conv2D</span><span class=\"p\">,</span> <span class=\"n\">Dense</span><span class=\"p\">,</span> <span class=\"n\">Flatten</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.models</span> <span class=\"kn\">import</span> <span class=\"n\">Sequential</span>\n<span class=\"kn\">from</span> <span class=\"nn\">tensorflow.keras.optimizers</span> <span class=\"kn\">import</span> <span class=\"n\">Adam</span>\n\n</code></pre></div></div>\n<h2 id=\"冒頭部分その2\">冒頭部分その2</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">gym_donkey</code>をimportしないとDonkeyCarシミュレータと接続できないので。<br />\nなぜかオリジナルでは入ってなかった。<br />\n<code class=\"language-plaintext highlighter-rouge\">if __name__ == \"__main__\":</code>付けといた方が良いかもしれんが、とりあえずそのままimportしておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">gym_donkeycar</span>\n\n</code></pre></div></div>\n\n<h2 id=\"パラメータの設定\">パラメータの設定</h2>\n<p>意味は以下の通り。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: center\">変数</th>\n      <th style=\"text-align: left\">意味</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: center\">EPISODES</td>\n      <td style=\"text-align: left\">学習回数</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_rows</td>\n      <td style=\"text-align: left\">入力に使用する画像サイズ(Y)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_cols</td>\n      <td style=\"text-align: left\">入力に使用する画像サイズ(X)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">img_channels</td>\n      <td style=\"text-align: left\">入力に過去何フレーム分のデータを使用するか</td>\n    </tr>\n  </tbody>\n</table>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">EPISODES</span> <span class=\"o\">=</span> <span class=\"mi\">10000</span>\n<span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span> <span class=\"o\">=</span> <span class=\"mi\">80</span><span class=\"p\">,</span> <span class=\"mi\">80</span>\n<span class=\"c1\"># Convert image into Black and white\n</span><span class=\"n\">img_channels</span> <span class=\"o\">=</span> <span class=\"mi\">4</span>  <span class=\"c1\"># We stack 4 frames\n</span></code></pre></div></div>\n\n<h2 id=\"強化学習エージェントクラス\">強化学習エージェントクラス</h2>\n\n<p>強化学習のエージェントを定義したクラスです。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">DQNAgent</span><span class=\"p\">:</span>\n</code></pre></div></div>\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>クラス変数</p>\n\n<table>\n  <thead>\n    <tr>\n      <th style=\"text-align: center\">変数</th>\n      <th style=\"text-align: left\">意味</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td style=\"text-align: center\">t</td>\n      <td style=\"text-align: left\">実行カウンタ(ステータス表示用のみ使用)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">max_Q</td>\n      <td style=\"text-align: left\">Q値の最大値(ステータス表示用のみ使用)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">train</td>\n      <td style=\"text-align: left\">学習モード/テストモード(<code class=\"language-plaintext highlighter-rouge\">--test</code>オプションで指定)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">state_size</td>\n      <td style=\"text-align: left\">モデルの入力層のサイズ。現状未使用</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">action_space</td>\n      <td style=\"text-align: left\">シミュレータの現在のステアリング/スロットル設定値取得用</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">action_size</td>\n      <td style=\"text-align: left\">未使用。たぶん、ステアリング角を何分割するかの定義(15)にすべきだと思う</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">discount_factor</td>\n      <td style=\"text-align: left\">割引率(γ値) (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">learning_rate</td>\n      <td style=\"text-align: left\">学習率 (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">epsilon</td>\n      <td style=\"text-align: left\">現在の探索率(ε値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">initial_epsilon</td>\n      <td style=\"text-align: left\">探索率の最大値  最小率と共に探索率の変更率を計算する(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">epsilon_min</td>\n      <td style=\"text-align: left\">探索率の最小値 学習時の探索率をこれより小さくしない(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">explore</td>\n      <td style=\"text-align: left\">探索率を最小値にするまでの回数(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">batch_size</td>\n      <td style=\"text-align: left\">バッチサイズ (固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">train_start</td>\n      <td style=\"text-align: left\">学習開始タイミング(最初は学習を行わない)(固定値)</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">memory</td>\n      <td style=\"text-align: left\">Experience Buffer</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">model</td>\n      <td style=\"text-align: left\">メインモデル</td>\n    </tr>\n    <tr>\n      <td style=\"text-align: center\">target_model</td>\n      <td style=\"text-align: left\">ターゲットモデル(double DQNなので)</td>\n    </tr>\n  </tbody>\n</table>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state_size</span><span class=\"p\">,</span> <span class=\"n\">action_space</span><span class=\"p\">,</span> <span class=\"n\">train</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">max_Q</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train</span> <span class=\"o\">=</span> <span class=\"n\">train</span>\n\n        <span class=\"c1\"># Get size of state and action\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">state_size</span> <span class=\"o\">=</span> <span class=\"n\">state_size</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_space</span> <span class=\"o\">=</span> <span class=\"n\">action_space</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_size</span> <span class=\"o\">=</span> <span class=\"n\">action_space</span>\n\n        <span class=\"c1\"># These are hyper parameters for the DQN\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">discount_factor</span> <span class=\"o\">=</span> <span class=\"mf\">0.99</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">learning_rate</span> <span class=\"o\">=</span> <span class=\"mf\">1e-4</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1e-6</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">=</span> <span class=\"mf\">1e-6</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span> <span class=\"o\">=</span> <span class=\"mf\">0.02</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"mi\">64</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train_start</span> <span class=\"o\">=</span> <span class=\"mi\">100</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">explore</span> <span class=\"o\">=</span> <span class=\"mi\">10000</span>\n\n        <span class=\"c1\"># Create replay memory using deque\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span> <span class=\"o\">=</span> <span class=\"n\">deque</span><span class=\"p\">(</span><span class=\"n\">maxlen</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Create main model and target model\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">build_model</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">build_model</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># Copy the model to target model\n</span>        <span class=\"c1\"># --> initialize the target model so that the parameters of model & target model to be same\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_target_model</span><span class=\"p\">()</span>\n\n</code></pre></div></div>\n<h3 id=\"モデルの生成\">モデルの生成</h3>\n\n<p>そんなに複雑なモデルではないみたい。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">build_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Sequential</span><span class=\"p\">()</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span>\n            <span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">24</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">,</span> <span class=\"n\">input_shape</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">,</span> <span class=\"n\">img_channels</span><span class=\"p\">))</span>\n        <span class=\"p\">)</span>  <span class=\"c1\"># 80*80*4\n</span>        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">32</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Conv2D</span><span class=\"p\">(</span><span class=\"mi\">64</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">strides</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">),</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"s\">\"same\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Flatten</span><span class=\"p\">())</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Dense</span><span class=\"p\">(</span><span class=\"mi\">512</span><span class=\"p\">))</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Activation</span><span class=\"p\">(</span><span class=\"s\">\"relu\"</span><span class=\"p\">))</span>\n\n        <span class=\"c1\"># 15 categorical bins for Steering angles\n</span>        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">Dense</span><span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">activation</span><span class=\"o\">=</span><span class=\"s\">\"linear\"</span><span class=\"p\">))</span>\n\n        <span class=\"n\">adam</span> <span class=\"o\">=</span> <span class=\"n\">Adam</span><span class=\"p\">(</span><span class=\"n\">lr</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">learning_rate</span><span class=\"p\">)</span>\n        <span class=\"n\">model</span><span class=\"p\">.</span><span class=\"nb\">compile</span><span class=\"p\">(</span><span class=\"n\">loss</span><span class=\"o\">=</span><span class=\"s\">\"mse\"</span><span class=\"p\">,</span> <span class=\"n\">optimizer</span><span class=\"o\">=</span><span class=\"n\">adam</span><span class=\"p\">)</span>\n\n        <span class=\"k\">return</span> <span class=\"n\">model</span>\n\n</code></pre></div></div>\n<h3 id=\"rgbグレースケール変換処理\">RGB→グレースケール変換処理</h3>\n<p>シミュレータの出力はRGB画像、モデルの入力はグレースケール画像なので、その変換を行うための関数。<br />\n<code class=\"language-plaintext highlighter-rouge\">cv2.dst = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)</code> で良い気もするが…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">rgb2gray</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">rgb</span><span class=\"p\">):</span>\n        <span class=\"s\">\"\"\"\n        take a numpy rgb image return a new single channel image converted to greyscale\n        \"\"\"</span>\n        <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">dot</span><span class=\"p\">(</span><span class=\"n\">rgb</span><span class=\"p\">[...,</span> <span class=\"p\">:</span><span class=\"mi\">3</span><span class=\"p\">],</span> <span class=\"p\">[</span><span class=\"mf\">0.299</span><span class=\"p\">,</span> <span class=\"mf\">0.587</span><span class=\"p\">,</span> <span class=\"mf\">0.114</span><span class=\"p\">])</span>\n\n</code></pre></div></div>\n\n<h3 id=\"入力画像前処理\">入力画像前処理</h3>\n<p>シミュレータの出力画像をモデルの入力データに変換する処理。<br />\nRGBからグレースケールに変換し、リサイズを行う。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">process_image</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">obs</span><span class=\"p\">):</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rgb2gray</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n        <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">resize</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">obs</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ターゲットモデルのパラメータ更新\">ターゲットモデルのパラメータ更新</h3>\n\n<p>メインモデルのパラメータをターゲットモデルにコピーする</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">update_target_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span><span class=\"p\">.</span><span class=\"n\">set_weights</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">get_weights</span><span class=\"p\">())</span>\n\n</code></pre></div></div>\n\n<h3 id=\"現在の環境での次の行動を取得する\">現在の環境での次の行動を取得する</h3>\n\n<p>乱数を発生し、ε値以下だったら環境が生成したランダム値(<code class=\"language-plaintext highlighter-rouge\">self.action_space.sample()[0]</code>)を返す。<br />\nそれ以外はメインモデルで予測した結果を返す。<br />\nその際、モデルの出力結果そのままではなく、どのステアリング位置に当たるかの量子化を行って返す。<br />\n(得られるのはステアリング情報だけで、スロットル情報は固定値)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Get action from model using epsilon-greedy policy\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_action</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">rand</span><span class=\"p\">()</span> <span class=\"o\"><=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">action_space</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"c1\"># print(\"Return Max Q Prediction\")\n</span>            <span class=\"n\">q_value</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">)</span>\n\n            <span class=\"c1\"># Convert q array to steering value\n</span>            <span class=\"k\">return</span> <span class=\"n\">linear_unbin</span><span class=\"p\">(</span><span class=\"n\">q_value</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n</code></pre></div></div>\n\n<h3 id=\"状態等の保存\">状態等の保存</h3>\n<p>現在の状態(state)、行動(action)、報酬(reward)、行動後の状態(next_state)、\n終了フラグ(done)をExperience Bufferに保存する。<br />\n(Experience Buffer は Experience Replayに使用するためのデータを保存しておくところ)<br />\n<code class=\"language-plaintext highlighter-rouge\">memory</code> は <code class=\"language-plaintext highlighter-rouge\">collections.dque()</code>で作成しているので、指定サイズを超えたときは古いデータから順に削除される。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">replay_memory</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">next_state</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">((</span><span class=\"n\">state</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">next_state</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">))</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ε値の更新\">ε値の更新</h3>\n\n<p>現在のε値が最小値より大きかったら一定比率で小さくしていく。<br />\n最小値以下になっていたらそのまま。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">update_epsilon</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">></span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">-=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">initial_epsilon</span> <span class=\"o\">-</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon_min</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">explore</span>\n\n</code></pre></div></div>\n\n<h3 id=\"ε値の初期設定\">ε値の初期設定</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">--epsilon</code>オプション追加したので、指定値でε値を変更する処理を追加。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">set_epsilon</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">epsilon</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">=</span> <span class=\"n\">epsilon</span>\n</code></pre></div></div>\n\n<h3 id=\"学習\">学習</h3>\n\n<p>Experience Bufferから任意の経験を取り出し、Q Networkをミニバッチ学習(Experience Replay)</p>\n\n<p>記憶したデータ数が<code class=\"language-plaintext highlighter-rouge\">self.train_start</code>に達するまでは何もしない。<br />\nバッチ学習に使用するデータをExperience Bufferから取り出し、<br />\nそれぞれの配列にバラす(<code class=\"language-plaintext highlighter-rouge\">state_t</code>,<code class=\"language-plaintext highlighter-rouge\">action_t</code>, <code class=\"language-plaintext highlighter-rouge\">reward_t</code>, <code class=\"language-plaintext highlighter-rouge\">state_t1</code>, <code class=\"language-plaintext highlighter-rouge\">terminal</code>)。<br />\n<code class=\"language-plaintext highlighter-rouge\">state_t</code>と<code class=\"language-plaintext highlighter-rouge\">state_t1</code>は<code class=\"language-plaintext highlighter-rouge\">np.concatenate()</code>でndarrayにまとめておく。<br />\n11行目の<code class=\"language-plaintext highlighter-rouge\">self.model.predict(state_t)</code>は<code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>の取得にしか使用されておらず、</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>はステータス表示にしか使用されてなく、無駄な計算なので、削除するのが良いと思われる(無駄な計算なので)。<br />\nその場合、<code class=\"language-plaintext highlighter-rouge\">targets</code>の初期化は<code class=\"language-plaintext highlighter-rouge\">targets = np.zeros((batch_size, 15))</code>で行う。<br />\n(<code class=\"language-plaintext highlighter-rouge\">self.max_Q</code>を参照しているところも削除。あるいは<code class=\"language-plaintext highlighter-rouge\">get_action()</code>で戻り値として返すのも手か。)</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">state_t1</code>を入力としてメインモデルをターゲットモデルを使用して得られた出力から出力期待値を取得し、<br />\n学習を行う<code class=\"language-plaintext highlighter-rouge\">self.model.train_on_batch(state_t, targets)</code>。<br />\nこの辺は\n<a href=\"https://www.tcom242242.net/entry/ai-2/%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92/%e3%80%90%e6%b7%b1%e5%b1%a4%e5%bc%b7%e5%8c%96%e5%ad%a6%e7%bf%92%e3%80%91double-q-network/\" target=\"_blank\">【深層強化学習】Double Deep Q Network(DDQN)</a>\nのソースとかを見ると分かったような分からないような気になれるかも…</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">train_replay</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">)</span> <span class=\"o\"><</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">train_start</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span>\n\n        <span class=\"n\">batch_size</span> <span class=\"o\">=</span> <span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">batch_size</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">))</span>\n        <span class=\"n\">minibatch</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"p\">.</span><span class=\"n\">sample</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">,</span> <span class=\"n\">batch_size</span><span class=\"p\">)</span>\n\n        <span class=\"n\">state_t</span><span class=\"p\">,</span> <span class=\"n\">action_t</span><span class=\"p\">,</span> <span class=\"n\">reward_t</span><span class=\"p\">,</span> <span class=\"n\">state_t1</span><span class=\"p\">,</span> <span class=\"n\">terminal</span> <span class=\"o\">=</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">minibatch</span><span class=\"p\">)</span>\n        <span class=\"n\">state_t</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">concatenate</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">)</span>\n        <span class=\"n\">state_t1</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">concatenate</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"n\">targets</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">max_Q</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n        <span class=\"n\">target_val</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"n\">target_val_</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_model</span><span class=\"p\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">state_t1</span><span class=\"p\">)</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">batch_size</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">terminal</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]:</span>\n                <span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">action_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">reward_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">target_val</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">])</span>\n                <span class=\"n\">targets</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">action_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">reward_t</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">discount_factor</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">target_val_</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">][</span><span class=\"n\">a</span><span class=\"p\">])</span>\n\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">train_on_batch</span><span class=\"p\">(</span><span class=\"n\">state_t</span><span class=\"p\">,</span> <span class=\"n\">targets</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"モデルのロード\">モデルのロード</h3>\n\n<p>モデルの読み込み先はメインモデル。<br />\nこのあと、ターゲットモデルへコピーするので、ここではターゲットモデルは触らない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">load_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">load_weights</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"モデルの保存\">モデルの保存</h3>\n\n<p>メインモデルをファイルに保存する。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Save the model which is under training\n</span>    <span class=\"k\">def</span> <span class=\"nf\">save_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">.</span><span class=\"n\">save_weights</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"ステアリング角モデル出力形式変換\">ステアリング角→モデル出力形式変換</h2>\n\n<p>ステアリング角(-1~1)をモデル出力形式(要素数15の配列のどれか1つに1が入る)に変換する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">linear_bin</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    Convert a value to a categorical array.\n\n    Parameters\n    ----------\n    a : int or float\n        A value between -1 and 1\n\n    Returns\n    -------\n    list of int\n        A list of length 15 with one item set to 1, which represents the linear value, and all other items set to 0.\n    \"\"\"</span>\n    <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    <span class=\"n\">b</span> <span class=\"o\">=</span> <span class=\"nb\">round</span><span class=\"p\">(</span><span class=\"n\">a</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"mi\">2</span> <span class=\"o\">/</span> <span class=\"mi\">14</span><span class=\"p\">))</span>\n    <span class=\"n\">arr</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">zeros</span><span class=\"p\">(</span><span class=\"mi\">15</span><span class=\"p\">)</span>\n    <span class=\"n\">arr</span><span class=\"p\">[</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">b</span><span class=\"p\">)]</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">return</span> <span class=\"n\">arr</span>\n</code></pre></div></div>\n\n<h2 id=\"モデル出力形式ステアリング角変換\">モデル出力形式→ステアリング角変換</h2>\n\n<p>モデル出力のうち、最大値を持つindexに相当するステアリング角を取得する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">linear_unbin</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    Convert a categorical array to value.\n\n    See Also\n    --------\n    linear_bin\n    \"\"\"</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">15</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"nb\">ValueError</span><span class=\"p\">(</span><span class=\"s\">\"Illegal array length, must be 15\"</span><span class=\"p\">)</span>\n    <span class=\"n\">b</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">arr</span><span class=\"p\">)</span>\n    <span class=\"n\">a</span> <span class=\"o\">=</span> <span class=\"n\">b</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"mi\">2</span> <span class=\"o\">/</span> <span class=\"mi\">14</span><span class=\"p\">)</span> <span class=\"o\">-</span> <span class=\"mi\">1</span>\n    <span class=\"k\">return</span> <span class=\"n\">a</span>\n</code></pre></div></div>\n\n<h2 id=\"メインルーチン\">メインルーチン</h2>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">run_ddqn</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">):</span>\n    <span class=\"s\">\"\"\"\n    run a DDQN training session, or test it's result, with the donkey simulator\n    \"\"\"</span>\n</code></pre></div></div>\n\n<h3 id=\"tensorflow-1131でのおまじない\">Tensorflow 1.13.1でのおまじない</h3>\n\n<p>Tensorflow 2 を使用したかったので、処理不要。<br />\nコメントアウトすれば良いのだけれど、なんとなくバージョンで分けてみた。<br />\n1.14以降では要るのかな?要ると思って書いてみた。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">tf_ver</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">__version__</span><span class=\"p\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s\">'.'</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">tf_ver</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">tf_ver</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">>=</span> <span class=\"mi\">13</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># only needed if TF==1.13.1\n</span>        <span class=\"n\">config</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">ConfigProto</span><span class=\"p\">()</span>\n        <span class=\"n\">config</span><span class=\"p\">.</span><span class=\"n\">gpu_options</span><span class=\"p\">.</span><span class=\"n\">allow_growth</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"n\">sess</span> <span class=\"o\">=</span> <span class=\"n\">tf</span><span class=\"p\">.</span><span class=\"n\">Session</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">=</span><span class=\"n\">config</span><span class=\"p\">)</span>\n        <span class=\"n\">K</span><span class=\"p\">.</span><span class=\"n\">set_session</span><span class=\"p\">(</span><span class=\"n\">sess</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"シミュレータ環境の構築\">シミュレータ環境の構築</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">body_style</code> には <code class=\"language-plaintext highlighter-rouge\">donkey</code>、 <code class=\"language-plaintext highlighter-rouge\">bare</code>、<code class=\"language-plaintext highlighter-rouge\">car01</code>、<code class=\"language-plaintext highlighter-rouge\">cybertruck</code>、<code class=\"language-plaintext highlighter-rouge\">f1</code>が使用できるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">body_rgb</code> で 色を指定できるらしい。<br />\n<code class=\"language-plaintext highlighter-rouge\">car_name</code> でシミュレータに表示される名前を指定。複数の車を走らせるときに見分けられるみたい。<br />\n<code class=\"language-plaintext highlighter-rouge\">font_size</code>で名前のフォントサイズを指定。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s\">\"exe_path\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">sim</span><span class=\"p\">,</span>\n        <span class=\"s\">\"host\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">host</span><span class=\"p\">,</span>\n        <span class=\"s\">\"port\"</span><span class=\"p\">:</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">port</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_style\"</span><span class=\"p\">:</span> <span class=\"s\">\"donkey\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"body_rgb\"</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">,</span> <span class=\"mi\">128</span><span class=\"p\">),</span>\n        <span class=\"s\">\"car_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"me\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"font_size\"</span><span class=\"p\">:</span> <span class=\"mi\">100</span><span class=\"p\">,</span>\n        <span class=\"s\">\"racer_name\"</span><span class=\"p\">:</span> <span class=\"s\">\"DDQN\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"country\"</span><span class=\"p\">:</span> <span class=\"s\">\"USA\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"bio\"</span><span class=\"p\">:</span> <span class=\"s\">\"Learning to drive w DDQN RL\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"guid\"</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"p\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()),</span>\n        <span class=\"s\">\"max_cte\"</span><span class=\"p\">:</span> <span class=\"mi\">10</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\"># Construct gym environment. Starts the simulator if path is given.\n</span>    <span class=\"n\">env</span> <span class=\"o\">=</span> <span class=\"n\">gym</span><span class=\"p\">.</span><span class=\"n\">make</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">env_name</span><span class=\"p\">,</span> <span class=\"n\">conf</span><span class=\"o\">=</span><span class=\"n\">conf</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"プログラム終了時のフックルーチンの定義と登録\">プログラム終了時のフックルーチンの定義と登録</h3>\n\n<p>プログラム終了時にシミュレータの終了処理を行うようにフックルーチンを登録する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># not working on windows...\n</span>    <span class=\"k\">def</span> <span class=\"nf\">signal_handler</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"catching ctrl+c\"</span><span class=\"p\">)</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">unwrapped</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGINT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGTERM</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n    <span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"p\">.</span><span class=\"n\">SIGABRT</span><span class=\"p\">,</span> <span class=\"n\">signal_handler</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"パラメータ用変数の定義\">パラメータ用変数の定義</h3>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># Get size of state and action from environment\n</span>    <span class=\"n\">state_size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">img_rows</span><span class=\"p\">,</span> <span class=\"n\">img_cols</span><span class=\"p\">,</span> <span class=\"n\">img_channels</span><span class=\"p\">)</span>\n    <span class=\"n\">action_space</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">action_space</span>  <span class=\"c1\"># Steering and Throttle\n</span></code></pre></div></div>\n\n<h3 id=\"エージェントの生成\">エージェントの生成</h3>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">agent</span> <span class=\"o\">=</span> <span class=\"n\">DQNAgent</span><span class=\"p\">(</span><span class=\"n\">state_size</span><span class=\"p\">,</span> <span class=\"n\">action_space</span><span class=\"p\">,</span> <span class=\"n\">train</span><span class=\"o\">=</span><span class=\"ow\">not</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">test</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"ε値の設定\">ε値の設定</h3>\n\n<p>オプションでε値が指定されていたら設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">epsilon</span> <span class=\"o\">></span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">set_epsilon</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"スロットル値の設定\">スロットル値の設定</h3>\n\n<p>スロットルの設定は固定値(コマンドラインオプションで設定)</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"n\">throttle</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">throttle</span>  <span class=\"c1\"># Set throttle as constant value\n</span>\n        <span class=\"n\">episodes</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n</code></pre></div></div>\n\n<h3 id=\"モデルのロード-1\">モデルのロード</h3>\n\n<p>モデルファイルがあれば読み込む。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">):</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"load the saved model\"</span><span class=\"p\">)</span>\n            <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">load_model</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n\n</code></pre></div></div>\n\n<h3 id=\"学習ループ\">学習ループ</h3>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"k\">for</span> <span class=\"n\">e</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">EPISODES</span><span class=\"p\">):</span>\n\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Episode: \"</span><span class=\"p\">,</span> <span class=\"n\">e</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h4 id=\"スタート位置へ移動\">スタート位置へ移動</h4>\n\n<p><code class=\"language-plaintext highlighter-rouge\">obs</code> ← スタート時のカメラ画像<br />\n<code class=\"language-plaintext highlighter-rouge\">x_t</code> ← <code class=\"language-plaintext highlighter-rouge\">obs</code> をモデルの入力形式に合わせて変換(グレースケール化&リサイズ) <br />\n<code class=\"language-plaintext highlighter-rouge\">s_t</code> ← <code class=\"language-plaintext highlighter-rouge\">x_t</code>を4枚分コピー(入力画像は過去4枚分を使用するので)(ちゃんと<code class=\"language-plaintext highlighter-rouge\">img_channels</code>参照して欲しいけど)</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"n\">done</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"n\">obs</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">reset</span><span class=\"p\">()</span>\n\n            <span class=\"n\">episode_len</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n            <span class=\"n\">x_t</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">process_image</span><span class=\"p\">(</span><span class=\"n\">obs</span><span class=\"p\">)</span>\n\n            <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">stack</span><span class=\"p\">((</span><span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">,</span> <span class=\"n\">x_t</span><span class=\"p\">),</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"c1\"># In Keras, need to reshape\n</span>            <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">s_t</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">])</span>  <span class=\"c1\"># 1*80*80*4\n</span></code></pre></div></div>\n\n<h4 id=\"エピソードループ\">エピソードループ</h4>\n\n<p>終了フラグがセットされるまでループ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>            <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">done</span><span class=\"p\">:</span>\n</code></pre></div></div>\n\n<h5 id=\"現在の状態から行動を予測しシミュレータで実行\">現在の状態から行動を予測し、シミュレータで実行</h5>\n\n<p><code class=\"language-plaintext highlighter-rouge\">steering</code> ← 予測結果<br />\n<code class=\"language-plaintext highlighter-rouge\">env.step()</code>でシミュレータステップ実行<br />\n<code class=\"language-plaintext highlighter-rouge\">x_t1</code> ←ステップ実行後のカメラ画像<br />\n<code class=\"language-plaintext highlighter-rouge\">s_t1</code> ← 現在の入力データの一番古いものを削除し、今回の画像を追加</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"c1\"># Get action for the current state and go one step in environment\n</span>                <span class=\"n\">steering</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">get_action</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">)</span>\n                <span class=\"n\">action</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">steering</span><span class=\"p\">,</span> <span class=\"n\">throttle</span><span class=\"p\">]</span>\n                <span class=\"n\">next_obs</span><span class=\"p\">,</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">,</span> <span class=\"n\">info</span> <span class=\"o\">=</span> <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">step</span><span class=\"p\">(</span><span class=\"n\">action</span><span class=\"p\">)</span>\n\n                <span class=\"n\">x_t1</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">process_image</span><span class=\"p\">(</span><span class=\"n\">next_obs</span><span class=\"p\">)</span>\n\n                <span class=\"n\">x_t1</span> <span class=\"o\">=</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">reshape</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">x_t1</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"mi\">1</span><span class=\"p\">)</span>  <span class=\"c1\"># 1x80x80x1\n</span>                <span class=\"n\">s_t1</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">x_t1</span><span class=\"p\">,</span> <span class=\"n\">s_t</span><span class=\"p\">[:,</span> <span class=\"p\">:,</span> <span class=\"p\">:,</span> <span class=\"p\">:</span><span class=\"mi\">3</span><span class=\"p\">],</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>  <span class=\"c1\"># 1x80x80x4\n</span></code></pre></div></div>\n\n<h5 id=\"experience-bufferに現在の状態を保存\">Experience Bufferに現在の状態を保存</h5>\n\n<p>ε値の更新も</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"c1\"># Save the sample <s, a, r, s'> to the replay memory\n</span>                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">replay_memory</span><span class=\"p\">(</span><span class=\"n\">s_t</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">argmax</span><span class=\"p\">(</span><span class=\"n\">linear_bin</span><span class=\"p\">(</span><span class=\"n\">steering</span><span class=\"p\">)),</span> <span class=\"n\">reward</span><span class=\"p\">,</span> <span class=\"n\">s_t1</span><span class=\"p\">,</span> <span class=\"n\">done</span><span class=\"p\">)</span>\n                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">update_epsilon</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h5 id=\"学習実行\">学習実行</h5>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n                    <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train_replay</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h5 id=\"ループ更新処理とステータス表示\">ループ更新処理とステータス表示</h5>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"n\">s_t</span> <span class=\"o\">=</span> <span class=\"n\">s_t1</span>\n                <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"n\">episode_len</span> <span class=\"o\">=</span> <span class=\"n\">episode_len</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span> <span class=\"o\">%</span> <span class=\"mi\">30</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span>\n                        <span class=\"s\">\"EPISODE\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">e</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"TIMESTEP\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">t</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ ACTION\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">action</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ REWARD\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">reward</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ EPISODE LENGTH\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">episode_len</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"/ Q_MAX \"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">max_Q</span><span class=\"p\">,</span>\n                    <span class=\"p\">)</span>\n</code></pre></div></div>\n<h5 id=\"ループ更新処理とステータス表示-1\">ループ更新処理とステータス表示</h5>\n\n<p><code class=\"language-plaintext highlighter-rouge\">agent.update_target_model()</code>でターゲットモデルの更新\n<code class=\"language-plaintext highlighter-rouge\">episodes.append(e)</code>はデバッグ用?</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>                <span class=\"k\">if</span> <span class=\"n\">done</span><span class=\"p\">:</span>\n\n                    <span class=\"c1\"># Every episode update the target model to be same with model\n</span>                    <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">update_target_model</span><span class=\"p\">()</span>\n\n                    <span class=\"n\">episodes</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n\n                    <span class=\"c1\"># Save model for each episode\n</span>                    <span class=\"k\">if</span> <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">train</span><span class=\"p\">:</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">save_model</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n\n                    <span class=\"k\">print</span><span class=\"p\">(</span>\n                        <span class=\"s\">\"episode:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">e</span><span class=\"p\">,</span>\n                        <span class=\"s\">\"  memory length:\"</span><span class=\"p\">,</span>\n                        <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">memory</span><span class=\"p\">),</span>\n                        <span class=\"s\">\"  epsilon:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">agent</span><span class=\"p\">.</span><span class=\"n\">epsilon</span><span class=\"p\">,</span>\n                        <span class=\"s\">\" episode length:\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">episode_len</span><span class=\"p\">,</span>\n                    <span class=\"p\">)</span>\n</code></pre></div></div>\n<h4 id=\"エピソードループと学習ループの終わり\">エピソードループと学習ループの終わり</h4>\n<p>キーボード割り込み例外と終了処理</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">except</span> <span class=\"nb\">KeyboardInterrupt</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"stopping run...\"</span><span class=\"p\">)</span>\n    <span class=\"k\">finally</span><span class=\"p\">:</span>\n        <span class=\"n\">env</span><span class=\"p\">.</span><span class=\"n\">unwrapped</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"コマンドライン解析処理まわり\">コマンドライン解析処理まわり</h2>\n\n<p>コマンドライン解析処理とメインルーチンへのジャンプ</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n\n    <span class=\"c1\"># Initialize the donkey environment\n</span>    <span class=\"c1\"># where env_name one of:\n</span>    <span class=\"n\">env_list</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-roads-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-avc-sparkfun-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-generated-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-roboracingleague-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-waveshare-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-minimonaco-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-warren-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-thunderhill-track-v0\"</span><span class=\"p\">,</span>\n        <span class=\"s\">\"donkey-circuit-launch-track-v0\"</span><span class=\"p\">,</span>\n    <span class=\"p\">]</span>\n\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">argparse</span><span class=\"p\">.</span><span class=\"n\">ArgumentParser</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s\">\"ddqn\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--sim\"</span><span class=\"p\">,</span>\n        <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span>\n        <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"manual\"</span><span class=\"p\">,</span>\n        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to unity simulator. maybe be left at manual if you would like to start the sim on your own.\"</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--host\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"127.0.0.1\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"simulator address\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--model\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"rl_driver.h5\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"path to model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--test\"</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">\"store_true\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"agent uses learned model to navigate env\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--port\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">9091</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"port to use for websockets\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--throttle\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.3</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"constant throttle for driving\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span>\n        <span class=\"s\">\"--env_name\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"s\">\"donkey-warehouse-v0\"</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"name of donkey sim environment\"</span><span class=\"p\">,</span> <span class=\"n\">choices</span><span class=\"o\">=</span><span class=\"n\">env_list</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"--epsilon\"</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"initial epsilon value\"</span><span class=\"p\">)</span>\n\n    <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n    <span class=\"n\">run_ddqn</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"でもってこんな改造をするとちょびっと計算量が減る\">でもって、こんな改造をするとちょびっと計算量が減る</h2>\n<p>シミュレータに表示される車を変更してるのはご愛敬😅</p>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ddqn.py.old\t2021-12-02 06:25:02.149997073 +0900\n</span><span class=\"gi\">+++ ddqn.py\t2021-12-03 07:14:49.346378878 +0900\n</span><span class=\"p\">@@ -98,9 +98,10 @@</span>\n         return np.dot(rgb[..., :3], [0.299, 0.587, 0.114])\n \n     def process_image(self, obs):\n<span class=\"gd\">-        obs = self.rgb2gray(obs)\n-        obs = cv2.resize(obs, (img_rows, img_cols))\n-        return obs\n</span><span class=\"gi\">+        # obs1 = self.rgb2gray(obs)\n+        obs1 = cv2.dst = cv2.cvtColor(obs, cv2.COLOR_RGB2GRAY)\n+        obs2 = cv2.resize(obs1, (img_rows, img_cols))\n+        return obs2\n</span> \n     def update_target_model(self):\n         self.target_model.set_weights(self.model.get_weights())\n<span class=\"p\">@@ -108,13 +109,17 @@</span>\n     # Get action from model using epsilon-greedy policy\n     def get_action(self, s_t):\n         if np.random.rand() <= self.epsilon:\n<span class=\"gd\">-            return self.action_space.sample()[0]\n</span><span class=\"gi\">+            return self.action_space.sample()[0], 0\n</span>         else:\n             # print(\"Return Max Q Prediction\")\n             q_value = self.model.predict(s_t)\n \n<span class=\"gi\">+            max_q = np.amax(q_value[0])\n+            if self.max_Q < max_q :\n+                self.max_Q = max_q\n+\n</span>             # Convert q array to steering value\n<span class=\"gd\">-            return linear_unbin(q_value[0])\n</span><span class=\"gi\">+            return linear_unbin(q_value[0]), max_q\n</span> \n     def replay_memory(self, state, action, reward, next_state, done):\n         self.memory.append((state, action, reward, next_state, done))\n<span class=\"p\">@@ -136,16 +141,16 @@</span>\n         state_t, action_t, reward_t, state_t1, terminal = zip(*minibatch)\n         state_t = np.concatenate(state_t)\n         state_t1 = np.concatenate(state_t1)\n<span class=\"gd\">-        targets = self.model.predict(state_t)\n-        self.max_Q = np.max(targets[0])\n-        target_val = self.model.predict(state_t1)\n-        target_val_ = self.target_model.predict(state_t1)\n</span><span class=\"gi\">+\n+        targets = np.zeros((batch_size, 15))\n+        q_val = self.model.predict(state_t1)\n+        target_q_val = self.target_model.predict(state_t1)\n</span>         for i in range(batch_size):\n             if terminal[i]:\n                 targets[i][action_t[i]] = reward_t[i]\n             else:\n<span class=\"gd\">-                a = np.argmax(target_val[i])\n-                targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_val_[i][a])\n</span><span class=\"gi\">+                a = np.argmax(q_val[i])\n+                targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_q_val[i][a])\n</span> \n         self.model.train_on_batch(state_t, targets)\n \n<span class=\"p\">@@ -213,8 +218,8 @@</span>\n         \"exe_path\": args.sim,\n         \"host\": args.host,\n         \"port\": args.port,\n<span class=\"gd\">-        \"body_style\": \"donkey\",\n-        \"body_rgb\": (128, 128, 128),\n</span><span class=\"gi\">+        \"body_style\": \"f1\",\n+        \"body_rgb\": (255, 128, 128),\n</span>         \"car_name\": \"me\",\n         \"font_size\": 100,\n         \"racer_name\": \"DDQN\",\n<span class=\"p\">@@ -273,7 +278,7 @@</span>\n             while not done:\n \n                 # Get action for the current state and go one step in environment\n<span class=\"gd\">-                steering = agent.get_action(s_t)\n</span><span class=\"gi\">+                steering, max_Q = agent.get_action(s_t)\n</span>                 action = [steering, throttle]\n                 next_obs, reward, done, info = env.step(action)\n \n<span class=\"p\">@@ -305,7 +310,7 @@</span>\n                         \"/ EPISODE LENGTH\",\n                         episode_len,\n                         \"/ Q_MAX \",\n<span class=\"gd\">-                        agent.max_Q,\n</span><span class=\"gi\">+                        max_Q,\n</span>                     )\n \n                 if done:\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tensorflowの転移学習に関するメモ</title>\n  </head>\n  <body>\n    <header>\n      <h1>tensorflowの転移学習に関するメモ</h1>\n      <p>tensorflowの転移学習を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"tensorflow-1xでのssdの転移学習の例\">tensorflow 1.XでのSSDの転移学習の例</h1>\n\n<p><a href=\"https://github.com/ippei8jp/tf1_TransferLearning\" target=\"_blank\">https://github.com/ippei8jp/tf1_TransferLearning</a></p>\n\n<h1 id=\"tensorflow-2xでのssdの転移学習の例\">tensorflow 2.XでのSSDの転移学習の例</h1>\n\n<p><a href=\"https://github.com/ippei8jp/tf2_TransferLearning\" target=\"_blank\">https://github.com/ippei8jp/tf2_TransferLearning</a></p>\n\n<h1 id=\"pascal-voc-で転移学習\">Pascal VOC で転移学習</h1>\n\n<p>ローカルマシン(Core-i7/Win10/WSL2/Ubuntu20.04/Tensorflow2.4)で試してみた手順が以下。<br />\nかなり時間がかかるけど、GPUなくても24時間もあればそれなりの回数がこなせる(5000回くらい?)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA  To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.</code> と言われているので、これらを有効にしてTensorflowを再構築すればもうちっと速くなるはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nずいぶん前にtensorflow 1.1.0でAVXを有効にしたら、MNISTの学習で実行時間が半分になった記憶もあるが、<br />\ntensorflow 1.6以降でAVXは有効になってて、AVX2,FMAの有無では10%くらいしか違わないらしい。<br />\n参考:<a href=\"https://www.acceluniverse.com/blog/developers/2019/05/tensorflowavx2-fma.html\" target=\"_blank\">TensorFlowのAVX2, FMAの有無で性能の比較をする</a><br />\ntensorflowのbuildに十何時間もかかることを考えたら 「ま、いっか」となっちゃうな…</p>\n</blockquote>\n\n<h2 id=\"実行手順\">実行手順</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">BASE_DIR</span><span class=\"o\">=</span>/work/test\n<span class=\"nv\">MODELS_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>/models\n<span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>/voc\n\n<span class=\"c\"># modelsリポジトリのclone</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">BASE_DIR</span><span class=\"k\">}</span>\ngit clone <span class=\"nt\">--depth</span> 1 https://github.com/tensorflow/models.git\n<span class=\"c\"># object_detectionモジュール未インストールならインストールすること</span>\n\n<span class=\"c\"># Pascal VOC データ取得</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>\nwget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar <span class=\"nt\">-O</span> - | <span class=\"nb\">tar </span>xvf -\n\n<span class=\"c\"># 学習データ(tf-record)の作成</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython create_pascal_tf_record.py <span class=\"nt\">--label_map_path</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"nt\">--data_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/VOCdevkit <span class=\"nt\">--year</span> VOC2007 <span class=\"nt\">--set</span> train <span class=\"nt\">--output_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pascal_train.record\npython create_pascal_tf_record.py <span class=\"nt\">--label_map_path</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"nt\">--data_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/VOCdevkit <span class=\"nt\">--year</span> VOC2007 <span class=\"nt\">--set</span> val <span class=\"nt\">--output_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pascal_val.record\n\n<span class=\"c\"># 元となるモデルのダウンロード</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/\nwget http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8.tar.gz <span class=\"nt\">-O</span> - | <span class=\"nb\">tar </span>xzvf -\n<span class=\"nb\">cp </span>ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/pipeline.config <span class=\"nb\">.</span>\n\n<span class=\"c\"># pipeline.config を編集(下記参照)</span>\n\n<span class=\"c\"># 学習実行</span>\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython model_main_tf2.py <span class=\"nt\">--pipeline_config_path</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--model_dir</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--alsologtostderr</span>\n</code></pre></div></div>\n\n<h3 id=\"object_detectionモジュールのインストール方法\">object_detectionモジュールのインストール方法</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>models/research\nprotoc object_detection/protos/<span class=\"k\">*</span>.proto <span class=\"nt\">--python_out</span><span class=\"o\">=</span><span class=\"nb\">.</span>\n<span class=\"nb\">cp </span>object_detection/packages/tf2/setup.py <span class=\"nb\">.</span> \n<span class=\"c\"># ↑ tf1の場合はtf1ディレクトリを指定する</span>\n\npip <span class=\"nb\">install</span> <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"pipelineconfig-の修正例\">pipeline.config\tの修正例</h3>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/pipeline.config\t2020-07-11 09:16:11.000000000 +0900\n</span><span class=\"gi\">+++ pipeline.config\t2021-05-11 05:22:30.943865000 +0900\n</span><span class=\"p\">@@ -1,6 +1,6 @@</span>\n model {\n   ssd {\n<span class=\"gd\">-    num_classes: 90\n</span><span class=\"gi\">+    num_classes: 20\n</span>     image_resizer {\n       fixed_shape_resizer {\n         height: 320\n<span class=\"p\">@@ -132,7 +132,7 @@</span>\n   }\n }\n train_config {\n<span class=\"gd\">-  batch_size: 128\n</span><span class=\"gi\">+  batch_size: 64\n</span>   data_augmentation_options {\n     random_horizontal_flip {\n     }\n<span class=\"p\">@@ -162,19 +162,19 @@</span>\n     }\n     use_moving_average: false\n   }\n<span class=\"gd\">-  fine_tune_checkpoint: \"PATH_TO_BE_CONFIGURED\"\n-  num_steps: 50000\n</span><span class=\"gi\">+  fine_tune_checkpoint: \"/work/test/voc/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/checkpoint/ckpt-0\"\n+  num_steps: 2000\n</span>   startup_delay_steps: 0.0\n   replicas_to_aggregate: 8\n   max_number_of_boxes: 100\n   unpad_groundtruth_tensors: false\n<span class=\"gd\">-  fine_tune_checkpoint_type: \"classification\"\n</span><span class=\"gi\">+  fine_tune_checkpoint_type: \"detection\"\n</span>   fine_tune_checkpoint_version: V2\n }\n train_input_reader {\n<span class=\"gd\">-  label_map_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+  label_map_path: \"/work/test/models/research/object_detection/data/pascal_label_map.pbtxt\"\n</span>   tf_record_input_reader {\n<span class=\"gd\">-    input_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+    input_path: \"/work/test/voc/pascal_train.record\"\n</span>   }\n }\n eval_config {\n<span class=\"p\">@@ -182,10 +182,10 @@</span>\n   use_moving_averages: false\n }\n eval_input_reader {\n<span class=\"gd\">-  label_map_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+  label_map_path: \"/work/test/models/research/object_detection/data/pascal_label_map.pbtxt\"\n</span>   shuffle: false\n   num_epochs: 1\n   tf_record_input_reader {\n<span class=\"gd\">-    input_path: \"PATH_TO_BE_CONFIGURED\"\n</span><span class=\"gi\">+    input_path: \"/work/test/voc/pascal_val.record\"\n</span>   }\n }\n</code></pre></div></div>\n\n<h2 id=\"学習の中断\">学習の中断</h2>\n\n<p>学習処理を中断したい場合は、CTRL+cを入力する。<br />\nただし、中断した時点でのチェックポイントの保存は行われないので、それまでに保存されたチェックポイントが有効。<br />\nデフォルトではチェックポイントの保存は1000回毎なので、1000回未満で中断すると学習してないのと同じ(たぶん)。</p>\n\n<h2 id=\"追加学習学習の再開\">追加学習/学習の再開</h2>\n\n<p>中断した学習を再開したい場合や設定した学習回数では十分ではなかった場合の追加学習を行うには<br />\n<code class=\"language-plaintext highlighter-rouge\">model_main_tf2.py</code>を再度実行すればOK。<br />\nそれまで実行した学習結果の続きを実行してくれます。<br />\n(特に設定ファイル類を変更する必要はないみたい)</p>\n\n<p>追加学習の場合や学習回数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--num_train_steps</code>オプションで新しい学習回数を指定するか、\n<code class=\"language-plaintext highlighter-rouge\">pipeline.config</code>ファイル内の<code class=\"language-plaintext highlighter-rouge\">num_steps</code>の項目を変更します。</p>\n\n<p>また、デフォルトでは学習結果は1000回毎にセーブされるので、学習回数が1000回未満の場合や端数が出る場合、結果がセーブされません。<br />\nこの場合、<code class=\"language-plaintext highlighter-rouge\">--checkpoint_every_n</code>オプションで何回毎にセーブするかを指定する必要があります。</p>\n\n<p>以下に例を示します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python model_main_tf2.py <span class=\"nt\">--pipeline_config_path</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--model_dir</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--alsologtostderr</span> <span class=\"nt\">--checkpoint_every_n</span><span class=\"o\">=</span>100 <span class=\"nt\">--num_train_steps</span><span class=\"o\">=</span>2300\n</code></pre></div></div>\n<h2 id=\"モデルのエクスポート\">モデルのエクスポート</h2>\n\n<p>学習を行った結果をエクスポートしてsaved_modelを作成します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/\npython exporter_main_v2.py <span class=\"nt\">--trained_checkpoint_dir</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/output_training <span class=\"nt\">--pipeline_config_path</span> <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/pipeline.config <span class=\"nt\">--output_directory</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/inference_voc\n<span class=\"c\"># ラベルファイルもコピーしておく</span>\n<span class=\"nb\">cp</span> <span class=\"k\">${</span><span class=\"nv\">MODELS_DIR</span><span class=\"k\">}</span>/research/object_detection/data/pascal_label_map.pbtxt <span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/inference_voc/\n</code></pre></div></div>\n\n<h1 id=\"学習データtf-recordの確認方法\">学習データ(tf-record)の確認方法</h1>\n<h2 id=\"セットアップ\">セットアップ</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/tfrecord\n<span class=\"nb\">cd</span>  /work/tfrecord\n<span class=\"c\"># 仮想環境の準備</span>\npyenv virtualenv 3.8.9 tfrecord\npyenv <span class=\"nb\">local </span>tfrecord \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n<span class=\"c\"># 必要なモジュールのインストール</span>\npip <span class=\"nb\">install </span><span class=\"nv\">tensorflow</span><span class=\"o\">==</span>2.<span class=\"k\">*</span>\npip <span class=\"nb\">install </span>flask\npip <span class=\"nb\">install </span>pillow\npip <span class=\"nb\">install </span>tqdm\n</code></pre></div></div>\n\n<h2 id=\"リポジトリのclone\">リポジトリのclone</h2>\n\n<p>以下のリポジトリから</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/sulc/tfrecord-viewer.git\n<span class=\"nb\">cd </span>tfrecord-viewer/\n</code></pre></div></div>\n<h2 id=\"viewerの実行\">Viewerの実行</h2>\n\n<p>webサーバを起動する</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfviewer.py «tf-recordファイル» \n</code></pre></div></div>\n\n<p>例:</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfviewer.py /work/test/train.record \n</code></pre></div></div>\n\n<p>ブラウザで以下に接続する(ポート番号は実行環境によって変わるかも)<br />\n<code class=\"language-plaintext highlighter-rouge\">http://localhost:5000/</code></p>\n\n<p>表示下部にサムネイルが表示されるので、クリックすると中央に拡大表示される。</p>\n\n<h2 id=\"元画像データの抽出\">元画像データの抽出</h2>\n\n<p>以下のパッチを当てる<br />\n(元のファイル名がディレクトリ名を含んでいるとファイル作成エラーになるので)</p>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tfrecord_to_imfolder.py b/tfrecord_to_imfolder.py\nindex 81bb764..7a0e269 100644\n</span><span class=\"gd\">--- a/tfrecord_to_imfolder.py\n</span><span class=\"gi\">+++ b/tfrecord_to_imfolder.py\n</span><span class=\"p\">@@ -41,6 +41,7 @@</span> def parse_tfrecord(record):\n     feat = example.features.feature\n\n     filename = feat[args.filename_key].bytes_list.value[0].decode(\"utf-8\")\n<span class=\"gi\">+    filename = os.path.basename(filename)\n</span>     img =  feat[args.image_key].bytes_list.value[0]\n     label = feat[args.class_label_key].bytes_list.value[0].decode(\"utf-8\")\n</code></pre></div></div>\n\n<p>以下のコマンドを実行<br />\n<code class=\"language-plaintext highlighter-rouge\">--class-label-key</code> には他にも指定できるものがあるけど、これくらいしか使わないと思う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfrecord_to_imfolder.py <span class=\"se\">\\</span>\n  <span class=\"nt\">--output_path</span> «ファイル出力ディレクトリ» <span class=\"se\">\\</span>\n  <span class=\"nt\">--class-label-key</span> image/object/class/text <span class=\"se\">\\</span>\n  <span class=\"nt\">-v</span> <span class=\"se\">\\</span>\n   «tf-recordファイル»\n</code></pre></div></div>\n\n<p>実行すると、«ファイル出力ディレクトリ»/«クラス名»/の下に画像ファイルが生成される。<br />\n(画像中に複数のクラスが含まれる場合は、一番最初のクラスが使用される)</p>\n\n<p>例:</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python tfrecord_to_imfolder.py <span class=\"se\">\\</span>\n  <span class=\"nt\">--output_path</span> ./hogehoge <span class=\"se\">\\</span>\n  <span class=\"nt\">--class-label-key</span> image/object/class/text <span class=\"se\">\\</span>\n  <span class=\"nt\">-v</span> <span class=\"se\">\\</span>\n  /work/test/train.record\n</code></pre></div></div>\n\n<h1 id=\"参考になるかもしれないページ\">参考になるかもしれないページ</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8c3197d11f61812546a9?fbclid=IwAR35TFl3mOK9XxXcZChP8wNkxp8cF6HZwnrWiTborZqETz7LJBZ88Dehvvs\">TensorFlowでの物体検出が超手軽にできる「Object Detection Tools」をTensorFlow 2.xに対応しました</a></p>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50?fbclid=IwAR35TFl3mOK9XxXcZChP8wNkxp8cF6HZwnrWiTborZqETz7LJBZ88Dehvvs\">Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Keras on tensorflow2 で SSD</title>\n  </head>\n  <body>\n    <header>\n      <h1>Keras on tensorflow2 で SSD</h1>\n      <p>Tensorflow2上のKerasでSSDを実行を試したときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>※ 2021.05.21 kerasをtensorflow.kerasに変更</p>\n\n<h1 id=\"概要\">概要</h1>\n\n<p>Kerasを使ってSSDを実行してみようと思ったら、Tensorflow1.x上の情報ばかり出てきて、Tensorflow2で実行するのに手間取ったのでメモ。<br />\n(最終的にopenVINOに持っていきたいなぁ、と思って試し始めたんだけど、openVINOにサクッと変換できるのはcaffeだった😅)<br />\nということで、やったけど 続きはないかも。実行遅いし…😩💨</p>\n\n<h1 id=\"手順\">手順</h1>\n\n<p><a href=\"https://smilerobo.com/papero/tips_keras_tf_ssd/\" target=\"_blank\">【実験】学習済のSSDを使ってPaPeRo i に複数種類の物体を数えさせる</a>\nを参考に、KerasをTensorflow2で動かしてみる。</p>\n\n<p>Pythonは3.8を使用した(念のため明記しておく)。</p>\n\n<p>Anaconda使ってないし、Paperoじゃないので、そのまんまじゃないけど、<br />\nとりあえずSSDを動かしてみよう。</p>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n\n<p>まずは、python仮想環境の準備をする。<br />\npyenv環境前提。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースディレクトリとpython仮想環境の準備</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/keras2/\n<span class=\"nb\">cd</span> /work/keras2/\npyenv virtualenv 3.8.8 keras2\npyenv <span class=\"nb\">local </span>keras2 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools\n\n<span class=\"c\"># pythonモジュールのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>tensorflow\n<span class=\"c\"># kerasはtensorflow内を直接参照にしたので不要  </span>\n<span class=\"c\"># pip install keras</span>\npip <span class=\"nb\">install </span>matplotlib\npip <span class=\"nb\">install </span>imageio\n</code></pre></div></div>\n\n<p>インストールされているpythonモジュールは以下の通り</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.2\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.4.0\ngoogle-auth==1.30.0\ngoogle-auth-oauthlib==0.4.4\ngoogle-pasta==0.2.0\ngrpcio==1.34.1\nh5py==3.1.0\nidna==2.10\nimageio==2.9.0\nkeras-nightly==2.5.0.dev2021032900\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.4.2\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.2.52\nopt-einsum==3.3.0\nPillow==8.2.0\nprotobuf==3.17.0\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nsix==1.15.0\ntensorboard==2.5.0\ntensorboard-data-server==0.6.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.5.0\ntensorflow-estimator==2.5.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==2.0.1\nwrapt==1.12.1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nKeras修正以前の状態は以下</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>absl-py==0.12.0\nastunparse==1.6.3\ncachetools==4.2.1\ncertifi==2020.12.5\nchardet==4.0.0\ncycler==0.10.0\nflatbuffers==1.12\ngast==0.3.3\ngoogle-auth==1.28.0\ngoogle-auth-oauthlib==0.4.3\ngoogle-pasta==0.2.0\ngrpcio==1.32.0\nh5py==2.10.0\nidna==2.10\nimageio==2.9.0\nKeras==2.4.3\nKeras-Preprocessing==1.1.2\nkiwisolver==1.3.1\nMarkdown==3.3.4\nmatplotlib==3.3.4\nnumpy==1.19.5\noauthlib==3.1.0\nopencv-python==4.5.1.48\nopt-einsum==3.3.0\nPillow==8.1.2\nprotobuf==3.15.6\npyasn1==0.4.8\npyasn1-modules==0.2.8\npyparsing==2.4.7\npython-dateutil==2.8.1\nPyYAML==5.4.1\nrequests==2.25.1\nrequests-oauthlib==1.3.0\nrsa==4.7.2\nscipy==1.6.1\nsix==1.15.0\ntensorboard==2.4.1\ntensorboard-plugin-wit==1.8.0\ntensorflow==2.4.1\ntensorflow-estimator==2.4.0\ntermcolor==1.1.0\ntyping-extensions==3.7.4.3\nurllib3==1.26.4\nWerkzeug==1.0.1\nwrapt==1.12.1\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"patchファイルの準備\">patchファイルの準備</h2>\n\n<p>参照先には色々手順が書いてあるが、めんどくさいので パッチファイル用意した(足りない修正もあるし)。<br />\n以下の内容を<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code> <code class=\"language-plaintext highlighter-rouge\">ssd_keras_2.patch</code>のファイル名で保存しておく。</p>\n\n<h3 id=\"ssd_keraspatch\">ssd_keras.patch</h3>\n\n<p>参照先の情報によるpatch</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/ssd.py b/ssd.py\nindex c0049d8..656cd83 100644\n</span><span class=\"gd\">--- a/ssd.py\n</span><span class=\"gi\">+++ b/ssd.py\n</span><span class=\"p\">@@ -2,14 +2,15 @@</span>\n \n import keras.backend as K\n from keras.layers import Activation\n<span class=\"gd\">-from keras.layers import AtrousConvolution2D\n</span><span class=\"gi\">+#from keras.layers import AtrousConvolution2D\n</span> from keras.layers import Convolution2D\n from keras.layers import Dense\n from keras.layers import Flatten\n from keras.layers import GlobalAveragePooling2D\n from keras.layers import Input\n from keras.layers import MaxPooling2D\n<span class=\"gd\">-from keras.layers import merge\n</span><span class=\"gi\">+#from keras.layers import merge\n+from keras.layers.merge import concatenate\n</span> from keras.layers import Reshape\n from keras.layers import ZeroPadding2D\n from keras.models import Model\n<span class=\"p\">@@ -34,109 +35,115 @@</span> def SSD300(input_shape, num_classes=21):\n     input_tensor = input_tensor = Input(shape=input_shape)\n     img_size = (input_shape[1], input_shape[0])\n     net['input'] = input_tensor\n<span class=\"gd\">-    net['conv1_1'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    net['conv1_1'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_1')(net['input'])\n<span class=\"gd\">-    net['conv1_2'] = Convolution2D(64, 3, 3,\n</span><span class=\"gi\">+    \n+    net['conv1_2'] = Convolution2D(64, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv1_2')(net['conv1_1'])\n<span class=\"gd\">-    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+\n+    net['pool1'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool1')(net['conv1_2'])\n     # Block 2\n<span class=\"gd\">-    net['conv2_1'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+    net['conv2_1'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_1')(net['pool1'])\n<span class=\"gd\">-    net['conv2_2'] = Convolution2D(128, 3, 3,\n</span><span class=\"gi\">+\n+    net['conv2_2'] = Convolution2D(128, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv2_2')(net['conv2_1'])\n<span class=\"gd\">-    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool2'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool2')(net['conv2_2'])\n<span class=\"gi\">+\n</span>     # Block 3\n<span class=\"gd\">-    net['conv3_1'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_1'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_1')(net['pool2'])\n<span class=\"gd\">-    net['conv3_2'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_2'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_2')(net['conv3_1'])\n<span class=\"gd\">-    net['conv3_3'] = Convolution2D(256, 3, 3,\n</span><span class=\"gi\">+    net['conv3_3'] = Convolution2D(256, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv3_3')(net['conv3_2'])\n<span class=\"gd\">-    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool3'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool3')(net['conv3_3'])\n     # Block 4\n<span class=\"gd\">-    net['conv4_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_1')(net['pool3'])\n<span class=\"gd\">-    net['conv4_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_2')(net['conv4_1'])\n<span class=\"gd\">-    net['conv4_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv4_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv4_3')(net['conv4_2'])\n<span class=\"gd\">-    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), border_mode='same',\n</span><span class=\"gi\">+    net['pool4'] = MaxPooling2D((2, 2), strides=(2, 2), padding='same',\n</span>                                 name='pool4')(net['conv4_3'])\n<span class=\"gd\">-    # Block 5\n-    net['conv5_1'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+# Block 5\n+    net['conv5_1'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_1')(net['pool4'])\n<span class=\"gd\">-    net['conv5_2'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_2'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_2')(net['conv5_1'])\n<span class=\"gd\">-    net['conv5_3'] = Convolution2D(512, 3, 3,\n</span><span class=\"gi\">+    net['conv5_3'] = Convolution2D(512, (3, 3),\n</span>                                    activation='relu',\n<span class=\"gd\">-                                   border_mode='same',\n</span><span class=\"gi\">+                                   padding='same',\n</span>                                    name='conv5_3')(net['conv5_2'])\n<span class=\"gd\">-    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), border_mode='same',\n</span><span class=\"gi\">+    net['pool5'] = MaxPooling2D((3, 3), strides=(1, 1), padding='same',\n</span>                                 name='pool5')(net['conv5_3'])\n     # FC6\n<span class=\"gd\">-    net['fc6'] = AtrousConvolution2D(1024, 3, 3, atrous_rate=(6, 6),\n-                                     activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['fc6'] = Convolution2D(1024, (3, 3), dilation_rate=(6, 6),\n+                                     activation='relu', padding='same',\n</span>                                      name='fc6')(net['pool5'])\n     # x = Dropout(0.5, name='drop6')(x)\n     # FC7\n<span class=\"gd\">-    net['fc7'] = Convolution2D(1024, 1, 1, activation='relu',\n-                               border_mode='same', name='fc7')(net['fc6'])\n</span><span class=\"gi\">+    net['fc7'] = Convolution2D(1024, (1, 1), activation='relu',\n+                               padding='same', name='fc7')(net['fc6'])\n</span>     # x = Dropout(0.5, name='drop7')(x)\n     # Block 6\n<span class=\"gd\">-    net['conv6_1'] = Convolution2D(256, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv6_1'] = Convolution2D(256, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv6_1')(net['fc7'])\n<span class=\"gd\">-    net['conv6_2'] = Convolution2D(512, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+\n+\n+    net['conv6_2'] = Convolution2D(512, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv6_2')(net['conv6_1'])\n<span class=\"gd\">-    # Block 7\n-    net['conv7_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+        # Block 7\n+    net['conv7_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv7_1')(net['conv6_2'])\n     net['conv7_2'] = ZeroPadding2D()(net['conv7_1'])\n<span class=\"gd\">-    net['conv7_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='valid',\n</span><span class=\"gi\">+    net['conv7_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='valid',\n</span>                                    name='conv7_2')(net['conv7_2'])\n     # Block 8\n<span class=\"gd\">-    net['conv8_1'] = Convolution2D(128, 1, 1, activation='relu',\n-                                   border_mode='same',\n</span><span class=\"gi\">+    net['conv8_1'] = Convolution2D(128, (1, 1), activation='relu',\n+                                   padding='same',\n</span>                                    name='conv8_1')(net['conv7_2'])\n<span class=\"gd\">-    net['conv8_2'] = Convolution2D(256, 3, 3, subsample=(2, 2),\n-                                   activation='relu', border_mode='same',\n</span><span class=\"gi\">+    net['conv8_2'] = Convolution2D(256, (3, 3), strides=(2, 2),\n+                                   activation='relu', padding='same',\n</span>                                    name='conv8_2')(net['conv8_1'])\n     # Last Pool\n     net['pool6'] = GlobalAveragePooling2D(name='pool6')(net['conv8_2'])\n     # Prediction from conv4_3\n     net['conv4_3_norm'] = Normalize(20, name='conv4_3_norm')(net['conv4_3'])\n     num_priors = 3\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv4_3_norm_mbox_loc')(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_loc'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_loc_flat')\n<span class=\"p\">@@ -144,7 +151,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv4_3_norm_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv4_3_norm'])\n     net['conv4_3_norm_mbox_conf'] = x\n     flatten = Flatten(name='conv4_3_norm_mbox_conf_flat')\n<span class=\"p\">@@ -155,16 +162,16 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv4_3_norm_mbox_priorbox'] = priorbox(net['conv4_3_norm'])\n     # Prediction from fc7\n     num_priors = 6\n<span class=\"gd\">-    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, 3, 3,\n-                                        border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_loc'] = Convolution2D(num_priors * 4, (3, 3),\n+                                        padding='same',\n</span>                                         name='fc7_mbox_loc')(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_loc_flat')\n     net['fc7_mbox_loc_flat'] = flatten(net['fc7_mbox_loc'])\n     name = 'fc7_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, 3, 3,\n-                                         border_mode='same',\n</span><span class=\"gi\">+    net['fc7_mbox_conf'] = Convolution2D(num_priors * num_classes, (3, 3),\n+                                         padding='same',\n</span>                                          name=name)(net['fc7'])\n     flatten = Flatten(name='fc7_mbox_conf_flat')\n     net['fc7_mbox_conf_flat'] = flatten(net['fc7_mbox_conf'])\n<span class=\"p\">@@ -174,7 +181,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['fc7_mbox_priorbox'] = priorbox(net['fc7'])\n     # Prediction from conv6_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv6_2_mbox_loc')(net['conv6_2'])\n     net['conv6_2_mbox_loc'] = x\n     flatten = Flatten(name='conv6_2_mbox_loc_flat')\n<span class=\"p\">@@ -182,7 +189,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv6_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv6_2'])\n     net['conv6_2_mbox_conf'] = x\n     flatten = Flatten(name='conv6_2_mbox_conf_flat')\n<span class=\"p\">@@ -193,7 +200,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv6_2_mbox_priorbox'] = priorbox(net['conv6_2'])\n     # Prediction from conv7_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv7_2_mbox_loc')(net['conv7_2'])\n     net['conv7_2_mbox_loc'] = x\n     flatten = Flatten(name='conv7_2_mbox_loc_flat')\n<span class=\"p\">@@ -201,7 +208,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv7_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv7_2'])\n     net['conv7_2_mbox_conf'] = x\n     flatten = Flatten(name='conv7_2_mbox_conf_flat')\n<span class=\"p\">@@ -212,7 +219,7 @@</span> def SSD300(input_shape, num_classes=21):\n     net['conv7_2_mbox_priorbox'] = priorbox(net['conv7_2'])\n     # Prediction from conv8_2\n     num_priors = 6\n<span class=\"gd\">-    x = Convolution2D(num_priors * 4, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * 4, (3, 3), padding='same',\n</span>                       name='conv8_2_mbox_loc')(net['conv8_2'])\n     net['conv8_2_mbox_loc'] = x\n     flatten = Flatten(name='conv8_2_mbox_loc_flat')\n<span class=\"p\">@@ -220,7 +227,7 @@</span> def SSD300(input_shape, num_classes=21):\n     name = 'conv8_2_mbox_conf'\n     if num_classes != 21:\n         name += '_{}'.format(num_classes)\n<span class=\"gd\">-    x = Convolution2D(num_priors * num_classes, 3, 3, border_mode='same',\n</span><span class=\"gi\">+    x = Convolution2D(num_priors * num_classes, (3, 3), padding='same',\n</span>                       name=name)(net['conv8_2'])\n     net['conv8_2_mbox_conf'] = x\n     flatten = Flatten(name='conv8_2_mbox_conf_flat')\n<span class=\"p\">@@ -241,7 +248,7 @@</span> def SSD300(input_shape, num_classes=21):\n     priorbox = PriorBox(img_size, 276.0, max_size=330.0, aspect_ratios=[2, 3],\n                         variances=[0.1, 0.1, 0.2, 0.2],\n                         name='pool6_mbox_priorbox')\n<span class=\"gd\">-    if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+    if K.image_data_format() == 'channels_last':\n</span>         target_shape = (1, 1, 256)\n     else:\n         target_shape = (256, 1, 1)\n<span class=\"p\">@@ -249,42 +256,47 @@</span> def SSD300(input_shape, num_classes=21):\n                                     name='pool6_reshaped')(net['pool6'])\n     net['pool6_mbox_priorbox'] = priorbox(net['pool6_reshaped'])\n     # Gather all predictions\n<span class=\"gd\">-    net['mbox_loc'] = merge([net['conv4_3_norm_mbox_loc_flat'],\n</span><span class=\"gi\">+    net['mbox_loc'] = concatenate([net['conv4_3_norm_mbox_loc_flat'],\n</span>                              net['fc7_mbox_loc_flat'],\n                              net['conv6_2_mbox_loc_flat'],\n                              net['conv7_2_mbox_loc_flat'],\n                              net['conv8_2_mbox_loc_flat'],\n                              net['pool6_mbox_loc_flat']],\n<span class=\"gd\">-                            mode='concat', concat_axis=1, name='mbox_loc')\n-    net['mbox_conf'] = merge([net['conv4_3_norm_mbox_conf_flat'],\n</span><span class=\"gi\">+                            axis=1,\n+                                  name='mbox_loc')\n+    net['mbox_conf'] = concatenate([net['conv4_3_norm_mbox_conf_flat'],\n</span>                               net['fc7_mbox_conf_flat'],\n                               net['conv6_2_mbox_conf_flat'],\n                               net['conv7_2_mbox_conf_flat'],\n                               net['conv8_2_mbox_conf_flat'],\n                               net['pool6_mbox_conf_flat']],\n<span class=\"gd\">-                             mode='concat', concat_axis=1, name='mbox_conf')\n-    net['mbox_priorbox'] = merge([net['conv4_3_norm_mbox_priorbox'],\n</span><span class=\"gi\">+                              axis=1,\n+                              name='mbox_conf')\n+    net['mbox_priorbox'] = concatenate([net['conv4_3_norm_mbox_priorbox'],\n</span>                                   net['fc7_mbox_priorbox'],\n                                   net['conv6_2_mbox_priorbox'],\n                                   net['conv7_2_mbox_priorbox'],\n                                   net['conv8_2_mbox_priorbox'],\n                                   net['pool6_mbox_priorbox']],\n<span class=\"gd\">-                                 mode='concat', concat_axis=1,\n</span><span class=\"gi\">+                                 axis=1,\n</span>                                  name='mbox_priorbox')\n     if hasattr(net['mbox_loc'], '_keras_shape'):\n         num_boxes = net['mbox_loc']._keras_shape[-1] // 4\n     elif hasattr(net['mbox_loc'], 'int_shape'):\n<span class=\"gd\">-        num_boxes = K.int_shape(net['mbox_loc'])[-1] // 4\n</span><span class=\"gi\">+        num_boxes = net['mbox_loc'].int_shape()[-1] // 4\n+    elif hasattr(net['mbox_loc'], 'get_shape'):\n+        num_boxes = net['mbox_loc'].get_shape()[-1] // 4\n</span>     net['mbox_loc'] = Reshape((num_boxes, 4),\n                               name='mbox_loc_final')(net['mbox_loc'])\n     net['mbox_conf'] = Reshape((num_boxes, num_classes),\n                                name='mbox_conf_logits')(net['mbox_conf'])\n     net['mbox_conf'] = Activation('softmax',\n                                   name='mbox_conf_final')(net['mbox_conf'])\n<span class=\"gd\">-    net['predictions'] = merge([net['mbox_loc'],\n</span><span class=\"gi\">+    net['predictions'] = concatenate([net['mbox_loc'],\n</span>                                net['mbox_conf'],\n                                net['mbox_priorbox']],\n<span class=\"gd\">-                               mode='concat', concat_axis=2,\n</span><span class=\"gi\">+                               axis=2,\n+                               #axis = 0,\n</span>                                name='predictions')\n     model = Model(net['input'], net['predictions'])\n     return model\n<span class=\"gh\">diff --git a/ssd_layers.py b/ssd_layers.py\nindex 5e10478..41ee510 100644\n</span><span class=\"gd\">--- a/ssd_layers.py\n</span><span class=\"gi\">+++ b/ssd_layers.py\n</span><span class=\"p\">@@ -29,7 +29,8 @@</span> class Normalize(Layer):\n         Add possibility to have one scale for all features.\n     \"\"\"\n     def __init__(self, scale, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n+\n</span>             self.axis = 3\n         else:\n             self.axis = 1\n<span class=\"p\">@@ -41,7 +42,7 @@</span> class Normalize(Layer):\n         shape = (input_shape[self.axis],)\n         init_gamma = self.scale * np.ones(shape)\n         self.gamma = K.variable(init_gamma, name='{}_gamma'.format(self.name))\n<span class=\"gd\">-        self.trainable_weights = [self.gamma]\n</span><span class=\"gi\">+        self._trainable_weights = [self.gamma]\n</span> \n     def call(self, x, mask=None):\n         output = K.l2_normalize(x, self.axis)\n<span class=\"p\">@@ -81,7 +82,7 @@</span> class PriorBox(Layer):\n     \"\"\"\n     def __init__(self, img_size, min_size, max_size=None, aspect_ratios=None,\n                  flip=True, variances=[0.1], clip=True, **kwargs):\n<span class=\"gd\">-        if K.image_dim_ordering() == 'tf':\n</span><span class=\"gi\">+        if K.image_data_format() == 'channels_last':\n</span>             self.waxis = 2\n             self.haxis = 1\n         else:\n<span class=\"p\">@@ -108,7 +109,7 @@</span> class PriorBox(Layer):\n         self.clip = True\n         super(PriorBox, self).__init__(**kwargs)\n \n<span class=\"gd\">-    def get_output_shape_for(self, input_shape):\n</span><span class=\"gi\">+    def compute_output_shape(self, input_shape):\n</span>         num_priors_ = len(self.aspect_ratios)\n         layer_width = input_shape[self.waxis]\n         layer_height = input_shape[self.haxis]\n<span class=\"gh\">diff --git a/ssd_utils.py b/ssd_utils.py\nindex 0a9ffb1..4fc7a49 100644\n</span><span class=\"gd\">--- a/ssd_utils.py\n</span><span class=\"gi\">+++ b/ssd_utils.py\n</span><span class=\"p\">@@ -1,7 +1,8 @@</span>\n \"\"\"Some utils for SSD.\"\"\"\n \n import numpy as np\n<span class=\"gd\">-import tensorflow as tf\n</span><span class=\"gi\">+import tensorflow.compat.v1 as tf\n+tf.disable_v2_behavior()\n</span> \n \n class BBoxUtility(object):\n<span class=\"gh\">diff --git a/testing_utils/videotest.py b/testing_utils/videotest.py\nindex 0cbae3c..7b2ff4f 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest.py\n</span><span class=\"p\">@@ -3,13 +3,14 @@</span>\n import cv2\n import keras\n from keras.applications.imagenet_utils import preprocess_input\n<span class=\"gd\">-from keras.backend.tensorflow_backend import set_session\n</span><span class=\"gi\">+# from keras.backend.tensorflow_backend import set_session\n</span> from keras.models import Model\n from keras.preprocessing import image \n import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-from scipy.misc import imread, imresize\n</span><span class=\"gi\">+# from scipy.misc import imread, imresize\n+from imageio import imread\n</span> from timeit import default_timer as timer\n \n import sys\n<span class=\"p\">@@ -84,8 +85,8 @@</span> class VideoTest(object):\n             \"trying to open a webcam, make sure you video_path is an integer!\"))\n         \n         # Compute aspect ratio of video     \n<span class=\"gd\">-        vidw = vid.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)\n-        vidh = vid.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)\n</span><span class=\"gi\">+        vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)\n+        vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)\n</span>         vidar = vidw/vidh\n         \n         # Skip frames until reaching start_frame\n<span class=\"gh\">diff --git a/testing_utils/videotest_example.py b/testing_utils/videotest_example.py\nindex fb4d873..27ec148 100644\n</span><span class=\"gd\">--- a/testing_utils/videotest_example.py\n</span><span class=\"gi\">+++ b/testing_utils/videotest_example.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import os\n+# GPU不使用を設定\n+os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n+\n</span> import keras\n import pickle\n from videotest import VideoTest\n<span class=\"p\">@@ -9,16 +13,38 @@</span> from ssd import SSD300 as SSD\n input_shape = (300,300,3)\n \n # Change this if you run with other classes than VOC\n<span class=\"gd\">-class_names = [\"background\", \"aeroplane\", \"bicycle\", \"bird\", \"boat\", \"bottle\", \"bus\", \"car\", \"cat\", \"chair\", \"cow\", \"diningtable\", \"dog\", \"horse\", \"motorbike\", \"person\", \"pottedplant\", \"sheep\", \"sofa\", \"train\", \"tvmonitor\"];\n</span><span class=\"gi\">+class_names = [ \n+                \"background\", \n+                \"aeroplane\", \n+                \"bicycle\", \n+                \"bird\", \n+                \"boat\", \n+                \"bottle\", \n+                \"bus\", \n+                \"car\", \n+                \"cat\", \n+                \"chair\", \n+                \"cow\", \n+                \"diningtable\", \n+                \"dog\", \n+                \"horse\", \n+                \"motorbike\", \n+                \"person\", \n+                \"pottedplant\", \n+                \"sheep\", \n+                \"sofa\", \n+                \"train\", \n+                \"tvmonitor\"\n+            ];\n</span> NUM_CLASSES = len(class_names)\n \n model = SSD(input_shape, num_classes=NUM_CLASSES)\n \n # Change this path if you want to use your own trained weights\n<span class=\"gd\">-model.load_weights('../weights_SSD300.hdf5') \n</span><span class=\"gi\">+model.load_weights('../../weights_SSD300.hdf5') \n</span>         \n vid_test = VideoTest(class_names, model, input_shape)\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('path/to/your/video.mkv')\n</span><span class=\"gi\">+vid_test.run('../../testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h3 id=\"ssd_keras_2patch\">ssd_keras_2.patch</h3>\n\n<p>keras修正対応</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ssd_keras_2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd.py ssd_keras.tmp/ssd.py\n</span><span class=\"gd\">--- ssd_keras/ssd.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd.py\t2021-05-21 07:06:44.970000000 +0900\n</span><span class=\"p\">@@ -1,19 +1,17 @@</span>\n \"\"\"Keras implementation of SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.layers import Activation\n-#from keras.layers import AtrousConvolution2D\n-from keras.layers import Convolution2D\n-from keras.layers import Dense\n-from keras.layers import Flatten\n-from keras.layers import GlobalAveragePooling2D\n-from keras.layers import Input\n-from keras.layers import MaxPooling2D\n-#from keras.layers import merge\n-from keras.layers.merge import concatenate\n-from keras.layers import Reshape\n-from keras.layers import ZeroPadding2D\n-from keras.models import Model\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.keras.layers import Activation\n+from tensorflow.keras.layers import Convolution2D\n+from tensorflow.keras.layers import Dense\n+from tensorflow.keras.layers import Flatten\n+from tensorflow.keras.layers import GlobalAveragePooling2D\n+from tensorflow.keras.layers import Input\n+from tensorflow.keras.layers import MaxPooling2D\n+from tensorflow.keras.layers import concatenate\n+from tensorflow.keras.layers import Reshape\n+from tensorflow.keras.layers import ZeroPadding2D\n+from tensorflow.keras.models import Model\n</span> \n from ssd_layers import Normalize\n from ssd_layers import PriorBox\n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/ssd_layers.py ssd_keras.tmp/ssd_layers.py\n</span><span class=\"gd\">--- ssd_keras/ssd_layers.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/ssd_layers.py\t2021-05-21 06:31:11.780000000 +0900\n</span><span class=\"p\">@@ -1,8 +1,8 @@</span>\n \"\"\"Some special pupropse layers for SSD.\"\"\"\n \n<span class=\"gd\">-import keras.backend as K\n-from keras.engine.topology import InputSpec\n-from keras.engine.topology import Layer\n</span><span class=\"gi\">+import tensorflow.keras.backend as K\n+from tensorflow.python.keras.engine.input_spec import InputSpec\n+from tensorflow.python.keras.engine.base_layer import Layer\n</span> import numpy as np\n import tensorflow as tf\n \n<span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest.py ssd_keras.tmp/testing_utils/videotest.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest.py\t2021-05-21 07:08:24.680000000 +0900\n</span><span class=\"p\">@@ -1,15 +1,13 @@</span>\n \"\"\" A class for testing a SSD model on a video file or webcam \"\"\"\n \n import cv2\n<span class=\"gd\">-import keras\n-from keras.applications.imagenet_utils import preprocess_input\n-# from keras.backend.tensorflow_backend import set_session\n-from keras.models import Model\n-from keras.preprocessing import image \n</span><span class=\"gi\">+import tensorflow.keras as keras\n+from tensorflow.keras.applications.imagenet_utils import preprocess_input\n+from tensorflow.keras.models import Model\n+from tensorflow.keras.preprocessing import image \n</span> import pickle\n import numpy as np\n from random import shuffle\n<span class=\"gd\">-# from scipy.misc import imread, imresize\n</span> from imageio import imread\n from timeit import default_timer as timer\n \n<span class=\"p\">@@ -179,6 +177,7 @@</span>\n             cv2.putText(to_draw, fps, (3,10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0,0,0), 1)\n             \n             cv2.imshow(\"SSD result\", to_draw)\n<span class=\"gd\">-            cv2.waitKey(10)\n-            \n-        \n</span><span class=\"gi\">+            key = cv2.waitKey(1)\n+            if key == 27:\n+                # ESCキー\n+                break\n</span><span class=\"gh\">diff -ur '--exclude=.git' '--exclude=__pycache__' ssd_keras/testing_utils/videotest_example.py ssd_keras.tmp/testing_utils/videotest_example.py\n</span><span class=\"gd\">--- ssd_keras/testing_utils/videotest_example.py\t2021-05-21 07:13:41.880000000 +0900\n</span><span class=\"gi\">+++ ssd_keras.tmp/testing_utils/videotest_example.py\t2021-05-21 07:04:24.320000000 +0900\n</span><span class=\"p\">@@ -2,7 +2,7 @@</span>\n # GPU不使用を設定\n os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n \n<span class=\"gd\">-import keras\n</span><span class=\"gi\">+import tensorflow.keras as keras\n</span> import pickle\n from videotest import VideoTest\n \n<span class=\"p\">@@ -47,4 +47,4 @@</span>\n \n # To test on webcam 0, remove the parameter (or change it to another number\n # to test on that webcam)\n<span class=\"gd\">-vid_test.run('../../testvideo3.mp4')\n</span><span class=\"gi\">+vid_test.run('../../images/testvideo3.mp4')\n</span></code></pre></div></div>\n\n<h2 id=\"学習済み重みファイルのダウンロード\">学習済み重みファイルのダウンロード</h2>\n\n<p>参照先の記載にしたがって、重み学習済み重みファイルをダウンロードする。</p>\n\n<p>wgetでは取得できなかったので、ブラウザで↓ここ から weights_SSD300.hdf5 をダウンロード。<br />\n<a href=\"https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA\" target=\"_blank\">https://mega.nz/folder/7RowVLCL#q3cEVRK9jyOSB9el3SssIA</a><br />\nで、ZIPファイルをカレントディレクトリに解凍しておく。</p>\n\n<h2 id=\"ソースのダウンロードパッチをあてる\">ソースのダウンロード&パッチをあてる</h2>\n\n<p>githubからソースをダウンロードする。<br />\nこのままではエラーになるので、先ほど作成したパッチファイル<code class=\"language-plaintext highlighter-rouge\">ssd_keras.patch</code>でパッチをあてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/rykov8/ssd_keras.git\n<span class=\"nb\">cd </span>ssd_keras\npatch <span class=\"nt\">-p1</span> < ../ssd_keras.patch \n<span class=\"c\"># Keras修正対応パッチ</span>\npatch <span class=\"nt\">-p1</span> < ../ssd_keras_2.patch \n</code></pre></div></div>\n\n<h2 id=\"実行\">実行</h2>\n\n<p>実行する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>testing_utils/\npython videotest_example.py\n</code></pre></div></div>\n\n<p>おー。<br />\nしかし遅い…. <br />\nKerasは遅いみたい。。。orz…</p>\n\n<h1 id=\"こんなんもある\">こんなんもある</h1>\n\n<p><a href=\"https://qiita.com/karaage0703/items/8567cc192e151bac3e50\" target=\"_blank\">「Object Detection API」で物体検出の自前データを学習する方法(TensorFlow 2.x版)</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Docker": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO 2022.1(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINO 2022.1のbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>openVINO 2022.1はRaspberry Pi OS(64bit)向けのバイナリがリリースされていないので、自力でbuildしてみます。</p>\n\n<p>今回もUbuntu上のDockerコンテナを使用しましたが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思います。</p>\n\n<p>前回はPythonを諦めてクロスコンパイルする方法とbuild時間を諦めてセルフコンパイル(エミュレーション)する方法を使いましたが、<br />\n今回はPython以外をクロスコンパイル、Python関連部をセルフコンパイル(エミュレーション)して生成物をマージする方法をとってみます。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_2022.1_pi64 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_2022.1_pi64\n</code></pre></div></div>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>workディレクトリを作成し、openvino と openvino_contrib のリポジトリをcloneします。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 2022.1.1 <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git\ngit <span class=\"nt\">-C</span> ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib checkout 1a28b530ab40d2ad79ab29021dfddfbbc7d2db0b\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の2022.1だと一部のノードが未対応とエラーになるため、対応済みのcommitを使用します。<br />\ntagが振られていないので、commit IDを指定してcheckoutします。<br />\nこれ以降のcommitではopenvinoのバージョン2022.2が必要になります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ntagやbranchが設定されていない場合はcloneでcheckoutするバージョンを指定できないため、\n一旦cloneしてからcommit IDを指定してcheckoutします。<br />\nsubmoluleのcheckoutは対象のバージョンをcheckoutしてから行います。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nopenvino_contrib の最新commit(試した時点ではcommit ID <code class=\"language-plaintext highlighter-rouge\">fd2ac364435757d23a9b3e91d67235b5e6555bf9</code>)を使用する場合は\nopenvinoのバージョン2022.2を使用する必要がありますが、試した時点で <code class=\"language-plaintext highlighter-rouge\">2022.2.0.dev20220829</code> がリリースされているので\nこれを使用します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0.dev20220829  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  https://github.com/openvinotoolkit/openvino_contrib.git\ngit -C ./work/openvino_contrib checkout fd2ac364435757d23a9b3e91d67235b5e6555bf9\ngit -C ./work/openvino_contrib submodule update --init --recursive --depth 1\n</code></pre></div>  </div>\n  <blockquote>\n    <p>2022.2.0正式リリース後はこんな感じになるのかな?</p>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir work\ngit -C ./work clone  -b 2022.2.0  --recursive --depth 1 https://github.com/openvinotoolkit/openvino.git\ngit -C ./work clone  -b 2022.2    --recursive --depth 1 https://github.com/openvinotoolkit/openvino_contrib.git\n</code></pre></div>    </div>\n  </blockquote>\n\n  <p>この場合、NVIDIA GPUのpluginのbuildでエラーになるため、以下のcmakeのオプションに以下のオプションを追加します。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      -D BUILD_nvidia_plugin=OFF\n</code></pre></div>  </div>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h1 id=\"openvinoのbuildクロスコンパイル\">openVINOのBuild(クロスコンパイル)</h1>\n\n<p>クロスコンパイルでpython関連以外の部分をbuildします。</p>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir cross</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">cross/Dockerfile</code>を作成します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  cross/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates:arm64 <span class=\"se\">\\\n</span>    libboost-regex-dev:arm64 <span class=\"se\">\\\n</span>    libgtk2.0-dev:arm64 <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev:arm64 <span class=\"se\">\\\n</span>    libcairo2-dev:arm64 <span class=\"se\">\\\n</span>    libpango1.0-dev:arm64 <span class=\"se\">\\\n</span>    libglib2.0-dev:arm64 <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev:arm64 <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗します</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeは新しめのをインストールしておきたいので、3.23.2をbuildして使用しています。<br />\nもしかすると、<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールしたものをそのまま使っても大丈夫かもしれませんが。</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_cross cross\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\ncacheを使わずimage buildしたい場合は<code class=\"language-plaintext highlighter-rouge\">--no-cache</code>オプションを追加します。<br />\n以前に作ったイメージのキャッシュを使って<code class=\"language-plaintext highlighter-rouge\">apt install</code>がエラーになったことがあったので。<br />\n(デフォルトのリポジトリに変更があったらしい)</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_cross_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_cross_2 ov_2022.1_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_cross_2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_2022.1_pi64_cross_2 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/cmake/arm64.toolchain.cmake <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_BEH_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLDNN</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_FUNCTIONAL_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">THREADING</span><span class=\"o\">=</span>SEQ <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">CONTRIB_TOP</span><span class=\"k\">}</span>/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span> 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=${WORK_DIR}/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"クロスコンパイル終了\">クロスコンパイル終了</h3>\n<p>クロスコンパイルはここまでなので、コンテナから抜ける。</p>\n\n<h1 id=\"openvinoのbuildセルフコンパイル\">openVINOのBuild(セルフコンパイル)</h1>\n\n<p>セルフコンパイルでpython関連部分をbuildします。<br />\ncythonを使うときにクロスコンパイルする方法が分からないので、セルフコンパイルで。</p>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">mkdir emu</code>してから、以下の内容で<code class=\"language-plaintext highlighter-rouge\">emu/Dockerfile</code>を作成します。</p>\n\n<p>python部だけなので、こんなにライブラリとか要らない気もしますが、全部セルフコンパイルするときのことも考えて\n全部入りのイメージを作っておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  emu/Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    automake <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    git-lfs <span class=\"se\">\\\n</span>    libtool <span class=\"se\">\\\n</span>    autoconf <span class=\"se\">\\\n</span>    shellcheck <span class=\"se\">\\\n</span>    patchelf <span class=\"se\">\\\n</span>    curl <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    ccache <span class=\"se\">\\\n</span>    unzip <span class=\"se\">\\\n</span>    libssl-dev <span class=\"se\">\\\n</span>    ca-certificates <span class=\"se\">\\\n</span>    libboost-regex-dev <span class=\"se\">\\\n</span>    libgtk2.0-dev <span class=\"se\">\\\n</span>    pkg-config <span class=\"se\">\\\n</span>    libenchant-2-dev <span class=\"se\">\\\n</span>    libcairo2-dev <span class=\"se\">\\\n</span>    libpango1.0-dev <span class=\"se\">\\\n</span>    libglib2.0-dev <span class=\"se\">\\\n</span>    gstreamer1.0-plugins-base <span class=\"se\">\\\n</span>    libopenblas-dev <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-enchant <span class=\"se\">\\\n</span>    python3-setuptools <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">RUN </span><span class=\"nv\">installed_cmake_ver</span><span class=\"o\">=</span>3.23.2 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    wget <span class=\"s2\">\"https://github.com/Kitware/CMake/releases/download/v</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">/cmake-</span><span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span><span class=\"s2\">.tar.gz\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">tar </span>xf cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"o\">(</span><span class=\"nb\">cd </span>cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> <span class=\"o\">&&</span> ./bootstrap <span class=\"nt\">--parallel</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"s2\">\"</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span><span class=\"s2\">\"</span> <span class=\"o\">&&</span> make <span class=\"nb\">install</span><span class=\"o\">)</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span> cmake-<span class=\"k\">${</span><span class=\"nv\">installed_cmake_ver</span><span class=\"k\">}</span>.tar.gz\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成します。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_2022.1_pi64_emu emu\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成します。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_2022.1_pi64_emu_2</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_2022.1_pi64_emu_2 ov_2022.1_pi64_emu /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker container start <span class=\"nt\">-ia</span> ov_2022.1_pi64_emu_2\n</code></pre></div></div>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"shell変数の設定とbuildディレクトリの作成-1\">shell変数の設定とbuildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">WORK_DIR</span><span class=\"o\">=</span>/work\n<span class=\"nv\">OV_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino/\n<span class=\"nv\">CONTRIB_TOP</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/openvino_contrib\n\n<span class=\"nb\">cd</span> <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>\n<span class=\"nb\">mkdir </span>build_python <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build_python\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">WORK_DIR</span><span class=\"k\">}</span>/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">InferenceEngineDeveloperPackage_DIR</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/build <span class=\"se\">\\</span>\n      <span class=\"k\">${</span><span class=\"nv\">OV_TOP</span><span class=\"k\">}</span>/src/bindings/python 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n<code class=\"language-plaintext highlighter-rouge\">CMAKE_INSTALL_PREFIX</code>の設定はクロスコンパイルのときと同じ設定にしてください。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\npyenvでインストールしたpythonなど、デフォルトでないpythonを使用する場合に指定します。<br />\n(以下の設定値はubuntu 22.04の標準インストールの場合のパスなのであまり参考にならないかも)</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  -D PYTHON_EXECUTABLE=/usr/bin/python3.8 \\\n  -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.8.so \\\n  -D PYTHON_INCLUDE_DIR=/usr/include/python3.8 \\\n  -D PYTHON_MODULE_EXTENSION=\".so\" \\\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"make-1\">make</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/intel/openvino</code> にインストールされます。</p>\n\n<h3 id=\"セルフコンパイル終了\">セルフコンパイル終了</h3>\n<p>セルフコンパイルはここまでなので、コンテナから抜けます。</p>\n\n<h1 id=\"インストール媒体の作成\">インストール媒体の作成</h1>\n\n<p>ホスト側の<code class=\"language-plaintext highlighter-rouge\">work</code>ディレクトリ内を見ると、<code class=\"language-plaintext highlighter-rouge\">intel</code>ディレクトリが出来ているので、ここをtarなどで固めておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>work\n<span class=\"nb\">tar </span>czvf ov1.tar.gz intel/\n</code></pre></div></div>\n\n<p>この<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiにコピーして展開します。</p>\n\n<h1 id=\"raspberrypiへのインストール\">RaspberryPiへのインストール</h1>\n\n<h2 id=\"インストール\">インストール</h2>\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">ov1.tar.gz</code>をRaspberryPiの適当なディレクトリに展開します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/proj</code>ディレクトリに展開しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">pushd</span> /proj/\n<span class=\"nb\">tar </span>xzvf ov1.tar.gz \n<span class=\"nb\">popd</span>\n</code></pre></div></div>\n<p>これで<code class=\"language-plaintext highlighter-rouge\">/proj/intel/openvino</code>ディレクトリにインストールされました。</p>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n<p>環境変数の設定のため、以下を実行します。<br />\nshell起動の度に実行が必要なので<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>などに書いておくと良いです。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">source</span> /proj/intel/openvino/setupvars.sh \n</code></pre></div></div>\n\n<h2 id=\"udevルールの設定\">udevルールの設定</h2>\n<p>以下のスクリプトを実行すればNCS2を挿せば認識されるようになります。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/proj/intel/openvino/install_dependencies/install_NCS_udev_rules.sh \n</code></pre></div></div>\n\n<h2 id=\"opencvのインストール\">openCVのインストール</h2>\n<p>openCVの必要になるので、インストールしておきます。<br />\n今回はお手軽にpipでインストール。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>opencv-python\n</code></pre></div></div>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認用のプログラムは<a href=\"https://github.com/ippei8jp/ov_trial_2022.1\" target=\"_blank\">https://github.com/ippei8jp/ov_trial_2022.1</a> とかにあります。<br />\nでもモデルのダウンロード/コンバートはRaspberryPiではできないので、UbuntuやWondowsで実行したものをコピーして使用してください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINOのクロスコンパイル</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINOのクロスコンパイル</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild(クロスコンパイル環境)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi OS(64bit)向けにopenVINOをクロスコンパイルする方法についてまとめた。<br />\nセルフコンパイル(Docker使用)については『<a href=\"/memoBlog/2022/03/07/openVINO_build_2.html\" target=\"_blank\">openVINO(Raspberry Pi OS(64bit)向け)のbuild</a>』を参照。<br />\nただ、クロスコンパイルだとセルフコンパイルの10倍くらい速い(環境によるけど)ので、クロスコンパイルがおススメ。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_cross <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_cross\n</code></pre></div></div>\n\n<h2 id=\"ソースの取得\">ソースの取得</h2>\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h3>\n<p>以下の1つのpatchファイルを作成する。<br />\nサンプル(テスト?)プログラムのBuildを抑制してコンパイル時間の短縮を計っている。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"opencv-の-gitリポジトリを-clone\">openCV の gitリポジトリを clone</h3>\n<p>opencv のリポジトリをcloneする(opencvのBuildを行わない場合は不要)。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> amd64/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> arm64 <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-arm64 <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:arm64 <span class=\"se\">\\\n</span>    libgtk-3-dev:arm64 <span class=\"se\">\\\n</span>    libavcodec-dev:arm64 <span class=\"se\">\\\n</span>    libavformat-dev:arm64 <span class=\"se\">\\\n</span>    libswscale-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:arm64 <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:arm64 <span class=\"se\">\\\n</span>    libpython3-dev:arm64 <span class=\"se\">\\\n</span>    libprotobuf-dev:arm64 <span class=\"se\">\\\n</span>    libprotoc-dev:arm64 <span class=\"se\">\\\n</span>    protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-numpy <span class=\"se\">\\\n</span>    cython3 <span class=\"se\">\\\n</span>    scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_cross <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_cross_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_cross_1 ov_pi64_cross /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_cross_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_cross_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n<p>ここからコンテナ内</p>\n\n<h2 id=\"buildディレクトリの作成\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/openvino/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/openvino/build\n</code></pre></div></div>\n\n<h2 id=\"cmake実行\">cmake実行</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm64.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">IE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_SAMPLES</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_CLANG_FORMAT</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_OPENCV</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n    .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>サンプルはBuildしないので、ENABLE_SAMPLES=OFF を設定</li>\n    <li>ソースをいじるわけではないので、ENABLE_CLANG_FORMAT=OFF を設定</li>\n    <li>openCVインストールされていないので、ENABLE_OPENCV=OFF を設定<br />\n(サンプルのBuildしないのでopenCVなくても大丈夫)</li>\n  </ul>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nログには いくつかWarningがあるが、とくに問題はなさそう</p>\n</blockquote>\n\n<h2 id=\"make\">make</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h2 id=\"その他細々したところ\">その他細々したところ</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"c\"># クロスコンパイルを反映したファイル名になっていないので修正</span>\n<span class=\"nb\">mv</span> /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-x86_64-linux-gnu.so /work/opt/intel/openvino/python/python3.9/_pyngraph.cpython-39-aarch64-linux-gnu.so\n\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n  <ul>\n    <li>CPU Extentionは<code class=\"language-plaintext highlighter-rouge\">make install</code>でコピーされないので手動でインストールする。</li>\n    <li>バイナリリリースに<code class=\"language-plaintext highlighter-rouge\">inference_engine</code>のシンボリックリンクがあるので同様に作成しておく。</li>\n    <li>ngraphのライブラリファイルのファイル名がx86_64(ホスト環境の名前)になっているので、aarch64に修正。<br />\nバイナリ自体はaarch64になっているので、ファイル名のリネームだけでOK。<br />\n本来はファイル名決めてるところで対処するのが良いのだろうけど、とりあえず力技で。</li>\n  </ul>\n</blockquote>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<p>openCVのBuild方法についてもメモっておく。<br />\npythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。<br />\nその場合は、ここはスキップしても大丈夫。<br />\nopenVINOをBuildしたDockerコンテナで引き続き作業を行う</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk-3-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libjpeg-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libpng-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev:arm64\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev:arm64\n</code></pre></div></div>\n<h2 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n</code></pre></div></div>\n<h2 id=\"cmakeの実行\">cmakeの実行</h2>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PKG_CONFIG_LIBDIR</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_ENABLE_PKG_CONFIG</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_FIND_ROOT_PATH</span><span class=\"o\">=</span>/ <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span>/work/opencv/platforms/linux/aarch64-gnu.toolchain.cmake <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_NUMPY_INCLUDE_DIRS</span><span class=\"o\">=</span>/usr/lib/python3/dist-packages/numpy/core/include <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n       .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nあらかじめ環境変数<code class=\"language-plaintext highlighter-rouge\">PKG_CONFIG_LIBDIR</code>を設定して<code class=\"language-plaintext highlighter-rouge\">pkg-config</code>でaarch64のライブラリとNativeのツール類を参照するように設定しておく。<br />\nこれをやらないと、libjpegとかをインストールしてあることを検出できない</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\ncmakeのオプションに <code class=\"language-plaintext highlighter-rouge\">-D CMAKE_FIND_DEBUG_MODE=1</code>を追加すると\ncmake中の<code class=\"language-plaintext highlighter-rouge\">find_xxx</code>の動作のログが出力されるので、パッケージのサーチなどの検索パスの確認などが容易になる。</p>\n</blockquote>\n\n<h2 id=\"make-1\">make</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h2 id=\"install-1\">install</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino/opencv</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/opencv</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-D CMAKE_INSTALL_PREFIX=/work/opt/intel/openvino/opencv</code>の部分を変更すれば良いけど、ここはopenVINOのインストール先と合わせておかないとうまく動かない。</p>\n\n<h1 id=\"実機へのインストール\">実機へのインストール</h1>\n\n<p><code class=\"language-plaintext highlighter-rouge\">opt</code>ディレクトリ以下を丸ごとアーカイブする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<p>作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>をRaspberryPiの適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"コンテナから出る\">コンテナから出る</h1>\n<p>Dockerコンテナは作業終了したら終了しておく。<br />\nCTRL-D でshell終了</p>\n\n<h1 id=\"補足\">補足</h1>\n<p>コンテナにインストールされているパッケージは以下の通り。<br />\nバージョン違いで動かなくなることもあるかもしれんので、念のため。</p>\n\n<p>こんな感じで確認できる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt list <span class=\"nt\">--installed</span> | <span class=\"nb\">grep</span> <span class=\"nt\">-v</span> automatic\n</code></pre></div></div>\n\n<p>で、こんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>build-essential/stable,now 12.9 amd64 [installed]\ncmake/stable,now 3.18.4-2+deb11u1 amd64 [installed]\ncrossbuild-essential-arm64/stable,stable,now 12.9 all [installed]\ncython3/stable,now 0.29.21-3+b1 amd64 [installed]\ngit/stable,now 1:2.30.2-1 amd64 [installed]\nlibavcodec-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibavformat-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibgstreamer-plugins-base1.0-dev/stable,now 1.18.4-2 arm64 [installed]\nlibgstreamer1.0-dev/stable,now 1.18.4-2.1 arm64 [installed]\nlibgtk-3-dev/stable,now 3.24.24-4 arm64 [installed]\nlibjpeg-dev/stable,now 1:2.0.6-4 arm64 [installed]\nlibpng-dev/stable,now 1.6.37-3 arm64 [installed]\nlibprotobuf-dev/stable,now 3.12.4-1 arm64 [installed]\nlibprotoc-dev/stable,now 3.12.4-1 arm64 [installed]\nlibpython3-dev/stable,now 3.9.2-3 arm64 [installed]\nlibswscale-dev/stable,stable-security,now 7:4.3.3-0+deb11u1 arm64 [installed]\nlibtiff-dev/stable,now 4.2.0-1 arm64 [installed]\nlibusb-1.0-0-dev/stable,now 2:1.0.24-3 arm64 [installed]\nlibwebp-dev/stable,now 0.6.1-2.1 arm64 [installed]\nprotobuf-compiler/stable,now 3.12.4-1 amd64 [installed]\npython3-minimal/stable,now 3.9.2-3 amd64 [installed]\npython3-numpy/stable,now 1:1.19.5-1 amd64 [installed]\npython3-pip/stable,stable,now 20.3.4-4 all [installed]\nscons/stable,stable,now 4.0.1+dfsg-2 all [installed]\nwget/stable,now 1.21-1+deb11u1 amd64 [installed]\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi OS(64bit)向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi OS(64bit)向け)のbuild</h1>\n      <p>Raspberry Pi OS(64bit)向けopenVINOのbuild</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>aspberry Pi OS(64bit)がリリースされたが、openVINOのBuild済みモジュールはまだこれに対応していない。<br />\nそのうち対応されると思うけど、とりあえず自前でBuildする方法を調べてみた。<br />\nついでにCPU Extensionも作成しておく。<br />\nなお、Raspberry Pi OS(32bit Buster)向けのBuild手順については、\n『<a href=\"/memoBlog/2021/10/28/openVINO_build.html\" target=\"_blank\">openVINO(Raspberry Pi向け)のbuild</a>』を参照。</p>\n\n<p>今回はUbuntu上のDockerコンテナを使用したが、おそらくWindowsのDocker Desktop for Windowsでも出来ると思う。</p>\n\n<p>今回もARM版Dockerコンテナを使用してセルフコンパイルする方法で行う。<br />\n手順そのものは特殊なことはないので、Raspberry Pi上のNative環境でもBuildできそうだけど、\nディスク容量とかスワップ領域とか気にしないといけないかもしれないので試してない。<br />\n(今回はクロスコンパイル環境はなし。cythonの出力モジュールも使いたかったので)</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h2 id=\"qemuのインストール\">qemuのインストール</h2>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h2 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h2>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi64_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi64_emu\n</code></pre></div></div>\n\n<h1 id=\"openvinoのbuild\">openVINOのBuild</h1>\n\n<h2 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h2>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work  clone  <span class=\"nt\">-b</span> 2021.4   <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h2 id=\"patchファイルを作成適用\">patchファイルを作成&適用</h2>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<p>上記のpatchをあてる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerコンテナの作成起動\">Dockerコンテナの作成&起動</h2>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm64v8/debian:bullseye</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python3-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«ユーザ名»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n32bit版との差分はこんな感じ。<br />\nあれ?32bit版の<code class=\"language-plaintext highlighter-rouge\">python-minimal</code>って間違ってる?<br />\n<code class=\"language-plaintext highlighter-rouge\">python3-numpy</code>で依存モジュールとしてインストールされて事なきを得たのか?<br />\n実質、ベースイメージを変更してるだけだな。</p>\n\n  <div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- Dockerfile.old\t2022-03-01 07:26:28.774187231 +0900\n</span><span class=\"gi\">+++ Dockerfile\t2022-03-01 07:19:45.668393598 +0900\n</span><span class=\"p\">@@ -1,4 +1,4 @@</span>\n<span class=\"gd\">-FROM arm32v7/debian:buster\n</span><span class=\"gi\">+FROM arm64v8/debian:bullseye\n</span> \n USER root\n \n<span class=\"p\">@@ -18,7 +18,7 @@</span>\n     libprotobuf-dev libprotoc-dev protobuf-compiler \\\n     cmake \\\n     python3-pip \\\n<span class=\"gd\">-    python-minimal \\\n</span><span class=\"gi\">+    python3-minimal \\\n</span>     python3-numpy cython3 scons\n \n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"dockerイメージ作成\">Dockerイメージ作成</h3>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi64_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h3>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi64_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi64_emu_1 ov_pi64_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h3 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/aarch64-linux-gnu/libpython3.9.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.9 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make\">make</h3>\n<p>数時間レベルでかかるので、のんびり待ちましょう。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。<br />\nインストール先を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">cmake</code>の\nオプションの<code class=\"language-plaintext highlighter-rouge\">-DCMAKE_INSTALL_PREFIX=/work/opt/intel/openvino</code>の部分を変更すれば良いけど、\nどうせアーカイブしてコピーして使うからあんまり関係ないとおもう。</p>\n\n<h3 id=\"その他細々したところ\">その他細々したところ</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CPU extension のコピー</span>\n<span class=\"nb\">cp</span> /work/openvino/bin/aarch64/Release/lib/libarmPlugin.so /work/opt/intel/openvino/deployment_tools/inference_engine/lib/aarch64/\n\n<span class=\"c\"># シンボリックリンクの作成</span>\n<span class=\"nb\">ln</span> <span class=\"nt\">-s</span> <span class=\"nt\">-r</span> /work/opt/intel/openvino/deployment_tools/inference_engine /work/opt/intel/openvino/\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf openvino.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コメント\">コメント</h3>\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>下のopenCVのBuild方法を参照。</li>\n      <li>pythonで使うだけなら、<code class=\"language-plaintext highlighter-rouge\">pip install opencv-python</code>すればopenCV使えるのでそれでも大丈夫。</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール\">実機へのインストール</h2>\n\n<p>最終的に作成した<code class=\"language-plaintext highlighter-rouge\">openvino.tar.gz</code>を適当なディレクトリに展開する。<br />\n<code class=\"language-plaintext highlighter-rouge\">/</code>に展開すれば<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino/~</code>となって一般的なインストールと同様となる。<br />\nどこに展開しても環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば、<br />\nその位置を基準にベースディレクトリを設定してくれる。</p>\n\n<h1 id=\"opencvのbuild\">openCVのBuild</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>ついでにopenCVのBuild方法についてもメモっておく。</p>\n\n<h2 id=\"準備-1\">準備</h2>\n<p>openCVのリポジトリをcloneしておく。<br />\n指定するタグは適宜変更してください。<br />\n今回はcontribはBuildしないのでcloneしない。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work clone  <span class=\"nt\">-b</span> 4.5.3-openvino-2021.4.2 <span class=\"nt\">--depth</span> 1 https://github.com/opencv/opencv\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナの作成起動-1\">Dockerコンテナの作成&起動</h2>\n<p>新しいDockerコンテナ作っても良いけど、別にその必要もないので上記のコンテナをそのまま使用する。</p>\n\n<h3 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h3>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi64_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi64_emu_1 /bin/bash\n</code></pre></div>  </div>\n  <h2 id=\"本番-1\">本番</h2>\n</blockquote>\n\n<h3 id=\"準備-2\">準備</h3>\n<p>足りないライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>apt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libgtk2.0-dev  libjpeg-dev libpng-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libwebp-dev\napt <span class=\"nb\">install</span> <span class=\"nt\">-y</span> libtiff-dev\n</code></pre></div></div>\n\n<h3 id=\"build\">Build</h3>\n\n<p>とりあえず、以下のコマンドで動くものができる。<br />\nどっか足りないとことかあるかもしれんけど、とりあえず動作確認した範囲では動いてる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/opencv/build <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/opencv/build\n\ncmake   <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_BUILD_TYPE</span><span class=\"o\">=</span>RELEASE <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino/opencv <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">CPU_BASELINE</span><span class=\"o\">=</span>NEON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">ENABLE_NEON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">WITH_OPENCL</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_TESTS</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python2</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">BUILD_opencv_python3</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">OPENCV_PYTHON_INSTALL_PATH</span><span class=\"o\">=</span>../python/python3 <span class=\"se\">\\</span>\n        <span class=\"nt\">-D</span> <span class=\"nv\">PYTHON3_LIMITED_API</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n\nmake <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n\n<span class=\"c\"># インストール</span>\nmake <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n\n<span class=\"nb\">cd</span> /work\n<span class=\"nb\">tar </span>czvf opencv.tar.gz opt\n</code></pre></div></div>\n\n<h3 id=\"コンテナから出る-1\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h2 id=\"実機へのインストール-1\">実機へのインストール</h2>\n<p>openVINOをBuildしたコンテナで続けてBuildした場合は<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>にopenVINO、openCVがインストールされている。<br />\nこれを適当なディレクトリに展開して環境変数設定スクリプト<code class=\"language-plaintext highlighter-rouge\">opt/intel/openvino/bin/setupvars.sh</code>を実行すれば良い。</p>\n\n<p>別のコンテナを使用したり、openVINOのBuild結果を削除していた場合は、<br />\n最終的に作成した<code class=\"language-plaintext highlighter-rouge\">opencv.tar.gz</code>をopenVINOをインストールしたディレクトリに展開する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openVINO(Raspberry Pi向け)のbuild</title>\n  </head>\n  <body>\n    <header>\n      <h1>openVINO(Raspberry Pi向け)のbuild</h1>\n      <p>Raspberry Pi向けopenVINOのbuild(特にCPU extension)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi用 openVINO は デフォルト状態ではCPUで実行できない(NCS2必須)。<br />\nそこで、オープンソース版openVINOを使用してCPU extensionを作成してみる。<br />\nとはいえ、CPU extension だけサクっと作成できなくて、openVINO全体を作成するハメに…</p>\n\n<p>Raspberry Pi 実機でbuildすると、ディスク容量がバカにならないし、<br />\nあまり実環境を弄りたくなかったので、<br />\nUbuntuマシン上のDockerコンテナで実行する方法を試してみる(Docker Desktop for Windowsでもできると思う)</p>\n\n<h1 id=\"arm版dockerコンテナを使用したセルフコンパイル\">ARM版Dockerコンテナを使用したセルフコンパイル</h1>\n\n<p>Dockerコンテナ全体をQEMU上でARMエミュレーションしてくれるので、特に難しいことを考えずに<br />\nネイティブ環境と変わりなくあつかえる。<br />\nでも、かなり遅い(実機よりちょっと速い?同じくらい?)。<br />\n試した環境では、x86_64な環境でクロスコンパイルした場合の15倍くらいかかった。  <br />\n(M1 Mac上でACVMを使うとかなり早いという噂も…M1 Mac持ってない😢  <a href=\"https://qiita.com/kose3/items/af9edc9c40c9ae8fc5c3\" target=\"_blank\">参考</a>  )</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>Dockerのインストールは<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>を参照。</p>\n\n<h3 id=\"qemuのインストール\">qemuのインストール</h3>\n<p>ARMのバイナリを実行するため、QEMUをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>qemu-user-static \n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nQEMUの情報: <a href=\"https://github.com/multiarch/qemu-user-static\" target=\"_blank\">https://github.com/multiarch/qemu-user-static</a></p>\n</blockquote>\n\n<h3 id=\"作業用ディレクトリの準備\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_emu <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_emu\n</code></pre></div></div>\n\n<h3 id=\"openvino-の-gitリポジトリを-clone\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成\">Dockerfileを作成</h3>\n<p>以下の内容でDockerfileを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> arm32v7/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev <span class=\"se\">\\\n</span>    libgtk-3-dev <span class=\"se\">\\\n</span>    libavcodec-dev <span class=\"se\">\\\n</span>    libavformat-dev <span class=\"se\">\\\n</span>    libswscale-dev <span class=\"se\">\\\n</span>    libgstreamer1.0-dev <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev <span class=\"se\">\\\n</span>    libpython3-dev <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nnumpyをpip3でインストールするとハンパない時間がかかるので、aptで入れる。<br />\nその他もパッケージが存在して、特に問題がなければaptで入れるのが良いと思う。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\ngit config ~ を設定してないと、cmake中にgit cloneが失敗する</p>\n</blockquote>\n\n<h3 id=\"patchファイルを作成\">patchファイルを作成</h3>\n\n<p>以下の1つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_emu <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_emu_1</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_emu_1 ov_pi_emu /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_emu_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_emu_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n以下のオプションを追加すると少しは速くなるかと思ったが、あまり変わらない。</p>\n  <ul>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_OPENCV=OFF</code></li>\n    <li><code class=\"language-plaintext highlighter-rouge\">-DENABLE_SAMPLES=OFF</code></li>\n  </ul>\n</blockquote>\n\n<h3 id=\"make\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n<p>これを実行すると。\n<code class=\"language-plaintext highlighter-rouge\">/work/opt/intel/openvino</code> にインストールされる。\nこれが実際の環境の<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino</code> に相当する。</p>\n\n<p>インテルリリース物との差は以下の通り。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">./documentation</code> がない\n    <ul>\n      <li>ドキュメントだけなので問題なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./inference_engine</code> がない\n    <ul>\n      <li>実体は <code class=\"language-plaintext highlighter-rouge\">deployment_tools/inference_engine</code> なので、シンボリックリンクを作れば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./opencv</code> がない\n    <ul>\n      <li><code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/opencv/</code>からコピーすれば良い</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./licensing</code> がない\n    <ul>\n      <li>ライセンス情報なので影響なし</li>\n    </ul>\n  </li>\n  <li><code class=\"language-plaintext highlighter-rouge\">./python/python3</code> がない\n    <ul>\n      <li>opencvのpythonモジュールがない\n        <ul>\n          <li>どこから持ってくれば良いんだろう?</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"コンテナから出る\">コンテナから出る</h3>\n<p>CTRL-D でshell終了</p>\n\n<h3 id=\"実機へのインストール\">実機へのインストール</h3>\n<p>CPU extensionだけなら<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l/</code><br />\nへコピーするだけで良い。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれはmake install してもこれはコピーされないらしい。</p>\n</blockquote>\n\n<p>openVINO全体のインストールなら<code class=\"language-plaintext highlighter-rouge\">work/opt/intel/openvino</code><br />\nを Raspberry Pi の <br />\n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/</code>にコピーすれば良いのだけど、opencvのpythonインタフェースがないので注意。<br />\nということで、実際に試していない…</p>\n\n<blockquote>\n  <p>[!NOTE]\n※※※※ メモ ※※※※ <br />\nopenCVはここでbuildするのではなく、<br />\n<a href=\"https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/\" target=\"_blank\">https://download.01.org/opencv/master/openvinotoolkit/thirdparty/linux/opencv/</a> \nからbuild済みモジュールをダウンロードして<br />\n<code class=\"language-plaintext highlighter-rouge\">/work/openvino/inference-engine/temp/opencv_4.5.2_debian9arm/</code><br />\nに展開している。</p>\n</blockquote>\n\n<h1 id=\"i386版32bit-x86dockerコンテナを使用したクロスコンパイル\">i386版(32bit x86)Dockerコンテナを使用したクロスコンパイル</h1>\n<h2 id=\"概要-1\">概要</h2>\n<p>セルフコンパイルは時間がかかりすぎるので、クロスコンパイルで試してみた。<br />\nかなり早くなったが、一部使えないモジュールが…<br />\n当初の目的のCPU extensionは使えるので、掲載しとく。</p>\n\n<blockquote>\n  <p>[!NOTE]\n当初、64bit版debianをベースに作業しようとしたが、\npybind11のbuildで以下のように怒られる。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Make Error at build/_deps/pybind11-src/tools/FindPythonLibsNew.cmake:127 (message):\n  Python config failure: Python is 64-bit, chosen compiler is 32-bit\nCall Stack (most recent call first):\n  build/_deps/pybind11-src/tools/pybind11Tools.cmake:16 (find_package)\n  build/_deps/pybind11-src/CMakeLists.txt:33 (include)\n</code></pre></div>  </div>\n  <p>以下のような対策が考えられる。</p>\n  <ul>\n    <li>FindPythonLibsNew.cmakeにbit数チェックをしないようにパッチを当てる\n      <ul>\n        <li>やり方がよう分からん…</li>\n      </ul>\n    </li>\n    <li>amd64なdebianに32bitのpythonをインストールする\n      <ul>\n        <li>イマイチうまくインストールできなかった</li>\n      </ul>\n    </li>\n  </ul>\n\n  <p>しかたないので、32bit版debianで作ることにした</p>\n</blockquote>\n\n<h2 id=\"準備-1\">準備</h2>\n\n<h3 id=\"作業用ディレクトリの準備-1\">作業用ディレクトリの準備</h3>\n\n<p>適当なディレクトリを作成して移動。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/docker_work/ov_pi_buster_32 <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/docker_work/ov_pi_buster_32\n</code></pre></div></div>\n<h3 id=\"openvino-の-gitリポジトリを-clone-1\">openVINO の gitリポジトリを clone</h3>\n<p>openvino と openvino_contrib のリポジトリをcloneする。<br />\n必ず同じディレクトリに(後の指定がめんどくさくなるので)。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>work\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4.1 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino.git \ngit <span class=\"nt\">-C</span> ./work/openvino         submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\ngit <span class=\"nt\">-C</span> ./work                  clone  <span class=\"nt\">-b</span> 2021.4 <span class=\"nt\">--depth</span> 1 https://github.com/openvinotoolkit/openvino_contrib.git\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib submodule update <span class=\"nt\">--init</span> <span class=\"nt\">--recursive</span> <span class=\"nt\">--depth</span> 1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nDockerコンテナ内から実行してもいいけど、ホストで実行した方が早いので。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">git submodule</code> にも <code class=\"language-plaintext highlighter-rouge\">--depth 1</code>をつけると早いし、ディスクの節約にもなる。</p>\n</blockquote>\n\n<h3 id=\"dockerfileを作成-1\">Dockerfileを作成</h3>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-dockerfile highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">FROM</span><span class=\"s\"> i386/debian:buster</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">RUN </span>dpkg <span class=\"nt\">--add-architecture</span> armhf <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get update <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    apt-get <span class=\"nb\">install</span> <span class=\"nt\">-y</span> <span class=\"nt\">--no-install-recommends</span> <span class=\"se\">\\\n</span>    build-essential <span class=\"se\">\\\n</span>    crossbuild-essential-armhf <span class=\"se\">\\\n</span>    git <span class=\"se\">\\\n</span>    wget <span class=\"se\">\\\n</span>    libusb-1.0-0-dev:armhf <span class=\"se\">\\\n</span>    libgtk-3-dev:armhf <span class=\"se\">\\\n</span>    libavcodec-dev:armhf <span class=\"se\">\\\n</span>    libavformat-dev:armhf <span class=\"se\">\\\n</span>    libswscale-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer1.0-dev:armhf <span class=\"se\">\\\n</span>    libgstreamer-plugins-base1.0-dev:armhf <span class=\"se\">\\\n</span>    libpython3-dev:armhf <span class=\"se\">\\\n</span>    libprotobuf-dev libprotoc-dev protobuf-compiler <span class=\"se\">\\\n</span>    cmake <span class=\"se\">\\\n</span>    python3-pip <span class=\"se\">\\\n</span>    python-minimal <span class=\"se\">\\\n</span>    python-argparse <span class=\"se\">\\\n</span>    python3-numpy cython3 scons\n\n<span class=\"c\"># aptでインストールするので削除</span>\n<span class=\"c\"># RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.3/cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     tar xzvf cmake-3.21.3.tar.gz && \\</span>\n<span class=\"c\">#     (cd cmake-3.21.3 && ./bootstrap --parallel=$(nproc --all) -- -DCMAKE_USE_OPENSSL=OFF && make --jobs=$(nproc --all) && make install) && \\</span>\n<span class=\"c\">#     rm -rf cmake-3.21.3 cmake-3.21.3.tar.gz</span>\n\n<span class=\"k\">RUN </span>git config <span class=\"nt\">--global</span> user.name <span class=\"s2\">\"«名前»\"</span> <span class=\"o\">&&</span> <span class=\"se\">\\\n</span>    git config <span class=\"nt\">--global</span> user.email <span class=\"s2\">\"«メールアドレス»\"</span>\n\n<span class=\"k\">WORKDIR</span><span class=\"s\"> /work</span>\n</code></pre></div></div>\n\n<h3 id=\"patchファイルを作成-1\">patchファイルを作成</h3>\n\n<p>以下の2つのpatchファイルを作成する。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch1.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake\nindex 6cb15a0..66a1ef6 100644\n</span><span class=\"gd\">--- a/cmake/dependencies.cmake\n</span><span class=\"gi\">+++ b/cmake/dependencies.cmake\n</span><span class=\"p\">@@ -19,8 +19,9 @@</span> if(CMAKE_CROSSCOMPILING AND CMAKE_HOST_SYSTEM_NAME MATCHES Linux AND CMAKE_HOST_\n     find_program(\n         SYSTEM_PROTOC\n         NAMES protoc\n<span class=\"gd\">-        PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n-        NO_DEFAULT_PATH)\n</span><span class=\"gi\">+        # PATHS \"${SYSTEM_PROTOC_ROOT}/bin\"\n+        # NO_DEFAULT_PATH)\n+        )\n</span>     if(NOT SYSTEM_PROTOC)\n         message(FATAL_ERROR \"[ONNX IMPORTER] Missing host protoc binary\")\n     endif()\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  patch2.patch\n</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/tests/SConscript b/tests/SConscript\nindex 041ed8f54..d90ffd844 100644\n</span><span class=\"gd\">--- a/tests/SConscript\n</span><span class=\"gi\">+++ b/tests/SConscript\n</span><span class=\"p\">@@ -28,12 +28,12 @@</span> Import('install_bin')\n \n # vars is imported from arm_compute:\n variables = [\n<span class=\"gd\">-    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", True),\n-    BoolVariable(\"validate_examples\", \"Build validate examples programs\", True),\n-    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", True),\n</span><span class=\"gi\">+    BoolVariable(\"benchmark_examples\", \"Build benchmark examples programs\", False),\n+    BoolVariable(\"validate_examples\", \"Build validate examples programs\", False),\n+    BoolVariable(\"reference_openmp\", \"Build reference validation with openmp\", False),\n</span>     #FIXME Switch the following two options to False before releasing\n<span class=\"gd\">-    BoolVariable(\"validation_tests\", \"Build validation test programs\", True),\n-    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", True),\n</span><span class=\"gi\">+    BoolVariable(\"validation_tests\", \"Build validation test programs\", False),\n+    BoolVariable(\"benchmark_tests\", \"Build benchmark test programs\", False),\n</span>     (\"test_filter\", \"Pattern to specify the tests' filenames to be compiled\", \"*.cpp\")\n ]\n</code></pre></div></div>\n\n<h3 id=\"上記のpatchをあてる-1\">上記のpatchをあてる</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../patch1.patch<span class=\"o\">)</span>\n<span class=\"o\">(</span><span class=\"nb\">cd</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary<span class=\"p\">;</span> patch <span class=\"nt\">-p1</span> < ../../../../../../patch2.patch<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\ngitコマンドでもpatchをあてられる。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git <span class=\"nt\">-C</span> ./work/openvino apply ../../patch1.patch\ngit <span class=\"nt\">-C</span> ./work/openvino_contrib/modules/arm_plugin/thirdparty/ComputeLibrary apply  ../../../../../../patch2.patch\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"dockerイメージ作成-1\">Dockerイメージ作成</h2>\n<p>DockerfileからDockerイメージを作成する。<br />\n以下ではイメージ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32</code> を使用。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker image build <span class=\"nt\">-t</span> ov_pi_buster_32 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h2 id=\"dockerコンテナ作成-1\">Dockerコンテナ作成</h2>\n<p>DockerイメージからDockerコンテナを作成する。<br />\n以下ではコンテナ名に <code class=\"language-plaintext highlighter-rouge\">ov_pi_buster_32_1</code> を使用。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"nt\">--name</span> ov_pi_buster_32_1 ov_pi_buster_32 /bin/bash\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">WARNING: The requested image's platform (linux/386) does not match the detected host platform (linux/amd64) and no specific platform was requested</code><br />\nと言われるけど大丈夫</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nWindowsでは<code class=\"language-plaintext highlighter-rouge\">$PWD</code>の代わりに<code class=\"language-plaintext highlighter-rouge\">%CD%</code>を使用</p>\n</blockquote>\n\n<h2 id=\"dockerコンテナ起動-1\">Dockerコンテナ起動</h2>\n<p>Dockerコンテナを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> ov_pi_buster_32_1\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nDockerコンテナに別コンソールから入るにはこれ</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> ov_pi_buster_32_1 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"本番-1\">本番</h2>\n<p>ここからコンテナ内</p>\n\n<h3 id=\"buildディレクトリの作成-1\">buildディレクトリの作成</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/openvino/\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\n</code></pre></div></div>\n\n<h3 id=\"cmake実行-1\">cmake実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cmake <span class=\"nt\">-DCMAKE_BUILD_TYPE</span><span class=\"o\">=</span>Release <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_INSTALL_PREFIX</span><span class=\"o\">=</span>/work/opt/intel/openvino <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_TOOLCHAIN_FILE</span><span class=\"o\">=</span><span class=\"s2\">\"../cmake/arm.toolchain.cmake\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_C_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DCMAKE_CXX_FLAGS</span><span class=\"o\">=</span><span class=\"s2\">\"-pthread\"</span> <span class=\"se\">\\</span>\n      <span class=\"nt\">-DENABLE_PYTHON</span><span class=\"o\">=</span>ON <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_EXECUTABLE</span><span class=\"o\">=</span>/usr/bin/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_LIBRARY</span><span class=\"o\">=</span>/usr/lib/arm-linux-gnueabihf/libpython3.7m.so <span class=\"se\">\\</span>\n      <span class=\"nt\">-DPYTHON_INCLUDE_DIR</span><span class=\"o\">=</span>/usr/include/python3.7 <span class=\"se\">\\</span>\n      <span class=\"nt\">-DIE_EXTRA_MODULES</span><span class=\"o\">=</span>../../openvino_contrib/modules <span class=\"se\">\\</span>\n      <span class=\"nt\">-DBUILD_java_api</span><span class=\"o\">=</span>OFF <span class=\"se\">\\</span>\n      .. 2>&1 | <span class=\"nb\">tee </span>cmake.log\n</code></pre></div></div>\n\n<h3 id=\"make-1\">make</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nt\">--jobs</span><span class=\"o\">=</span><span class=\"si\">$(</span><span class=\"nb\">nproc</span> <span class=\"nt\">--all</span><span class=\"si\">)</span> 2>&1 | <span class=\"nb\">tee </span>build.log\n</code></pre></div></div>\n\n<h3 id=\"install-1\">install</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>make <span class=\"nb\">install </span>2>&1 | <span class=\"nb\">tee </span>install.log\n</code></pre></div></div>\n\n<p>コンテナから出て、<br />\n<code class=\"language-plaintext highlighter-rouge\">work/openvino/bin/armv7l/Release/lib/libarmPlugin.so</code><br />\nを Raspberry Pi の \n<code class=\"language-plaintext highlighter-rouge\">/opt/intel/openvino_2021/inference_engine/lib/armv7l</code>/<br />\nへコピーする</p>\n\n<blockquote>\n  <p>[!WARNING]\ncythonの出力がx86のコードを吐くので、pythonモジュールの一部に正常に動作しないものがある。<br />\npythonモジュールを使いたいときはセルフコンパイルするしかないかな?</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerでopenVINO</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerでopenVINO</h1>\n      <p>DockerでopenVINOプログラムの開発</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>DockerコンテナでopenVINOのプログラム開発を行う手順。<br />\n↓ここを参考にUbuntu 20.04/openVINO 2021.3に変更してみる。ついでによく使う機能の準備もやっておく。<br />\n<a href=\"https://kuttsun.blogspot.com/2021/06/openvino-docker.html\">https://kuttsun.blogspot.com/2021/06/openvino-docker.html</a></p>\n\n<h1 id=\"dockerイメージの作成\">Dockerイメージの作成</h1>\n\n<p>上の参照先を参考に公式イメージに必要な処理を加えておく。<br />\nDockerfile は以下。<br />\n参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>ベースをopenVINO/ubuntu20に変更</li>\n  <li>sudoとvimとless入れとく。sudoはパスワードなしで動作するようにしとく。</li>\n  <li>開発マシンなのでbaskhの補完機能を有効にしておく</li>\n  <li>キーバインド変更 ( <code class=\"language-plaintext highlighter-rouge\">^p</code> / <code class=\"language-plaintext highlighter-rouge\">^n</code> )</li>\n  <li>日本語文字化け対策</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">install_openvino_dependencies.sh</code> がキー入力待ちになってbuildエラーになるので<code class=\"language-plaintext highlighter-rouge\">-y</code>オプションを追加</li>\n</ul>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Dockerfile\n</p>\n\n<div class=\"language-docker highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ベースイメージ</span>\n<span class=\"k\">FROM</span><span class=\"s\"> openvino/ubuntu20_dev:2021.3</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> root</span>\n\n<span class=\"k\">ENV</span><span class=\"s\"> DEBIAN_FRONTEND=noninteractive</span>\n\n<span class=\"c\"># sudo と vim と less のインストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install sudo </span>vim less <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo </span>openvino <span class=\"nv\">ALL</span><span class=\"o\">=</span><span class=\"se\">\\(</span>root<span class=\"se\">\\)</span> NOPASSWD:ALL <span class=\"o\">></span> /etc/sudoers.d/openvino <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">chmod </span>0440 /etc/sudoers.d/openvino\n\n<span class=\"c\"># bashの補完機能 & キーバインドの設定 & 日本語文字化け対策</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nb\">install </span>bash-completion <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"s2\">\". /usr/share/bash-completion/bash_completion\"</span> <span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-n</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-forward' </span><span class=\"se\">\\n\\\n</span><span class=\"s2\">bind '</span><span class=\"se\">\\\"\\C</span><span class=\"s2\">-p</span><span class=\"se\">\\\"</span><span class=\"s2\">: history-search-backward'</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc <span class=\"se\">\\\n</span>    <span class=\"o\">&&</span> <span class=\"nb\">echo</span> <span class=\"nt\">-e</span> <span class=\"s2\">\"</span><span class=\"se\">\\\n</span><span class=\"s2\">export LANG=C.UTF-8</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">export LANGUAGE=en_US:</span><span class=\"se\">\\n\\\n</span><span class=\"s2\">\"</span><span class=\"o\">>></span> /etc/bash.bashrc\n\n<span class=\"c\"># 依存パッケージのインストール(-yオプションで Yes自動選択)</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/install_dependencies <span class=\"o\">&&</span> ./install_openvino_dependencies.sh <span class=\"nt\">-y</span>\n\n<span class=\"c\"># サンプル、デモアプリのビルド</span>\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/samples/cpp <span class=\"o\">&&</span> ./build_samples.sh\n<span class=\"k\">RUN </span><span class=\"nb\">cd</span> /opt/intel/openvino/inference_engine/demos <span class=\"o\">&&</span> ./build_demos.sh\n<span class=\"c\"># /opt/intel/openvino_2021/deployment_tools/demo にデモアプリがある</span>\n\n<span class=\"c\"># 他に必要なものを適宜インストール</span>\n<span class=\"k\">RUN </span>apt update <span class=\"o\">&&</span> apt <span class=\"nt\">-y</span> <span class=\"nb\">install </span>wget git python3-pip\n<span class=\"k\">RUN </span>pip3 <span class=\"nb\">install </span>onnxruntime flask\n\n<span class=\"c\"># aptのクリア</span>\n<span class=\"k\">RUN </span>apt clean <span class=\"o\">&&</span> <span class=\"nb\">rm</span> <span class=\"nt\">-rf</span> /var/lib/apt/lists/<span class=\"k\">*</span>\n\n<span class=\"k\">USER</span><span class=\"s\"> openvino</span>\n\n<span class=\"c\"># bash起動</span>\n<span class=\"k\">CMD</span><span class=\"s\"> [ \"/bin/bash\" ]</span>\n</code></pre></div></div>\n\n<h1 id=\"ビルド\">ビルド</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker build <span class=\"nt\">-t</span> myopenvino/ubuntu20_dev:2021.3 <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h1 id=\"コンテナの生成\">コンテナの生成</h1>\n<p>参照先からの変更内容は以下の通り。</p>\n<ul>\n  <li>カレントディレクトリ下のworkを/workに割り当てるように追加</li>\n  <li>GPU関連の設定を削除</li>\n</ul>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ./work\ndocker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"se\">\\</span>\n       <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"k\">${</span><span class=\"nv\">DISPLAY</span><span class=\"k\">}</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n       <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>/work:/work <span class=\"se\">\\</span>\n       myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nX-Windowの表示先(<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code> 変数) は ここで固定されるので、<br />\n実行時に<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を変更したい場合は<br />\nコンテナをスタートした後、コンテナ内で手打ちで設定するか、<br />\n変更後の<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数を設定したターミナルから以下を実行。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> openvino_2021.3 /bin/bash\n</code></pre></div>  </div>\n</blockquote>\n\n<p>Windows の場合は以下な感じ。<br />\nDISPLAY変数は環境に合わせて変更してちょ。<br />\nNCS周りの設定は削除してある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> openvino_2021.3 <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.78.204:0.0 <span class=\"nt\">-v</span> %CD%<span class=\"se\">\\w</span>ork:/work myopenvino/ubuntu20_dev:2021.3\n</code></pre></div></div>\n<blockquote>\n  <p>[!TIP]\ndocker をWSL上のコマンドラインから起動しているときは<code class=\"language-plaintext highlighter-rouge\">%CD%</code>でなく<code class=\"language-plaintext highlighter-rouge\">$PWD</code><br />\nPowerShellでコマンドを複数行に分割する場合は、行末記号は<code class=\"language-plaintext highlighter-rouge\">\\</code> ではなく <code class=\"language-plaintext highlighter-rouge\">`</code><br />\nコマンドプロンプトでは<code class=\"language-plaintext highlighter-rouge\">^</code> NYAGOSは分からん😢<br />\nそれぞれ違ってびみょーにストレス…</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> openvino_2021.3\n</code></pre></div></div>\n\n<p>コンテナ内でデモを動かしてみる<br />\n(デモの実行で必要なライブラリ類がインストールされたりするので、実行しましょう)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ~/tmp\n<span class=\"nb\">cd</span> /opt/intel/openvino/deployment_tools/demo\n\n./demo_squeezenet_download_convert_run.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/demo1.log\n\n./demo_security_barrier_camera.sh 2>&1 | <span class=\"nb\">tee</span> ~/tmp/dem2.log\n</code></pre></div></div>\n\n<p>前に作ったプログラムを試してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/\ngit clone https://github.com/ippei8jp/ov_trial.git\n<span class=\"c\"># 入力画像の準備</span>\n<span class=\"nb\">cd </span>ov_trial/images/\nbash download.sh\n<span class=\"c\"># モデルファイルの準備(mobilenet-ssdのダウンロードがエラーになるけど大勢に影響ない) </span>\n<span class=\"nb\">cd</span> ../convert_model_ssd/\nbash convert_model_ssd.sh \n\n<span class=\"c\"># 認識してみる</span>\n<span class=\"nb\">cd</span> ../ssd/\nbash test.sh list\nbash test.sh 6\n</code></pre></div></div>\n\n<h1 id=\"ncs2の使用ubuntuのみ\">NCS2の使用(ubuntuのみ)</h1>\n<p>ubuntuではホストに接続したNCS2を使用することもできる。<br />\nただし、DockerコンテナからNCS2を使用するにはDokerホスト側にドライバをインストールしておく必要がある。<br />\n(udevルールだけ?イマイチ自信ないのでフルパッケージでインストールしておいた)<br />\n以下の部分がNCS2を使用するために必要な設定。(上記コマンド例では設定済み)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>       <span class=\"nt\">-v</span> /dev/bus/usb:/dev/bus/usb <span class=\"se\">\\</span>\n       <span class=\"nt\">--device-cgroup-rule</span><span class=\"o\">=</span><span class=\"s1\">'c 189:* rmw'</span> <span class=\"se\">\\</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ローカルのVSCodeからリモートホスト上のDockerコンテナ内のプログラムをデバッグする</h1>\n      <p>ローカル(Windows)のVSCodeからリモートホスト(ubuntu)上のDockerコンテナ内のプログラムをデバッグする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからUbuntu上のDockerコンテナに接続してデバッグする方法。</p>\n\n<p>UbuntuへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\" target=\"_blank\">こちら</a>\nsudo なしで Docker動かせるようにしとく必要あり</p>\n\n<h1 id=\"リモートホストへの接続\">リモートホストへの接続</h1>\n<p>UbuntuへのSSH接続の準備については<a href=\"/memoBlog/2021/10/11/SSH_setup.html\" target=\"_blank\">こちら</a></p>\n\n<h2 id=\"手順\">手順</h2>\n<ul>\n  <li>WindowsマシンでVScode 起動する</li>\n  <li>拡張機能「Remote Development」をインストールしておく。</li>\n  <li>左下にある「><」ボタンをクリック</li>\n  <li>上にメニューが出るので、「Connect to host…」 または「Connect Current Window to Host…」を選択</li>\n  <li>続いて「Select configured SSH host~」で接続するホストを選択。\n    <ul>\n      <li>新規接続の場合は「Add New SSH Host…」を選択</li>\n      <li>「ssh «user»@«IPアドレス or マシン名»」</li>\n      <li>設定を保存するファイルを選択。特に理由がなければ c:\\Users\\«ユーザ».config でいいかな。</li>\n      <li>右下に「Host added!」ウィンドウが出るので「Connect」をクリック</li>\n      <li>初めて接続するホストの場合、上にSelect the platform of remote host “~” と聞かれるのでOS種別を選択</li>\n      <li>「あんた«OS»を選らんだでー。~に保存したから変えたかったら ここ変更しぃや~」みたいなことを言ってるウィンドウが出るので「Don’t Show Again」をクリック</li>\n    </ul>\n  </li>\n  <li>接続された。右下の「><」ボタンが「>< SSH:«マシン名»」に変わっている。</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n一度接続すればリモートエクスプローラ(SSH TARGETS)に表示されるのでそこから接続しても良い。</p>\n</blockquote>\n\n<p>リモートホスト上のプログラムをデバッグしたい場合はここでフォルダを開いてごちょごちょやればよい。</p>\n\n<h1 id=\"dockerコンテナへの接続\">Dockerコンテナへの接続</h1>\n<h2 id=\"準備\">準備</h2>\n<p>WindowsマシンにDocker desktop for windows が必要になるので、インストールしておく。<br />\nWindowsへのDockerインストール方法は<a href=\"/memoBlog/2021/10/08/Docker_install.html\">こちら</a><br />\nCLIだけでよさそうなんだけど、CLIだけってのがどこかにあるのか分からんかったのでとりあえず全部入れた。<br />\nDocker Desktopは動いてなくて良いので、Exitして可。<br />\n普段から使わないならDocker Dashboardの設定のGeneralから「Start Docker Desktop when you log in」のチェックを はずしておけばOK。</p>\n\n<h2 id=\"dockerexeで疎通確認\">docker.exeで疎通確認</h2>\n<p>コマンドプロンプト等で以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">set </span><span class=\"nv\">DOCKER_HOST</span><span class=\"o\">=</span>ssh://«ユーザ名»@«ホスト»\ndocker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<p>リモートホスト上のコンテナの状態が返ってくるか確認。</p>\n\n<h2 id=\"docker-hostの設定\">DOCKER HOSTの設定</h2>\n<p>VScodeの<code class=\"language-plaintext highlighter-rouge\">settings.json</code> に以下の一文を追加する。もちろん上で確認した内容で。</p>\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"w\">    </span><span class=\"nl\">\"docker.host\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"ssh://«ユーザ名»@«ホスト»\"</span><span class=\"err\">,</span><span class=\"w\">\n</span></code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nローカルにつなぎたいときはこの行をコメントアウト(<code class=\"language-plaintext highlighter-rouge\">//</code>をつける)すればOK。<br />\n<code class=\"language-plaintext highlighter-rouge\">setting.json</code>はJSONファイルだけど、 <code class=\"language-plaintext highlighter-rouge\">//</code>でコメントアウトできる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nVScode settings.json の開き方</p>\n  <ul>\n    <li>メニュー ファイル→ユーザ設定→ 設定</li>\n    <li>設定画面の右上のボタン「設定(JSON)を開く」をクリック</li>\n  </ul>\n\n  <p>または</p>\n  <ul>\n    <li>メニュー表示→コマンドパレット</li>\n    <li>Preference:  Open Settings(JSON) を選択</li>\n  </ul>\n</blockquote>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その1\">VScodeでリモート エクスプローラからリモートホストに接続(その1)</h2>\n<p>リモートホストに拡張機能 Docker と Docker Explorer をインストールしておき、\nDockerペインを開くとリモートホスト上のコンテナとかが見える</p>\n\n<p>ここでは既にリモートホスト上でコンテナ作成済みとする。<br />\n(イメージからコンテナ作ったりDockerfileからBuildしたりできると思うけど、今はおいとく)</p>\n\n<ul>\n  <li>接続するコンテナが起動していない場合はDockerペインで使用するコンテナを右クリック→Start でコンテナを起動</li>\n  <li>起動したら対象コンテナのアイコンが三角マークになる</li>\n  <li>同じくDockerペインで使用するコンテナを右クリック→Attach Visual Studio Code を選択</li>\n  <li>select the container to attach VS Code と聞かれるのでアタッチするコンテナを選択(コンテナ選択してAttachしたはずだけど、なぜかここで再度選択が必要)</li>\n  <li>初めて接続した場合は「Attaching to a container may execute arbitrary code」<br />\nと言われるので、変なコードが実行されないことが分かっていれば Got it をクリック</li>\n  <li>接続された。右下の「><」ボタンが「>< Conteiner «コンテナ名»」に変わっている。</li>\n</ul>\n\n<p>あとはリモート SSH や ローカルのDockerでのデバッグと同じ。</p>\n\n<h2 id=\"接続の終了\">接続の終了</h2>\n<p>接続を終了する場合は</p>\n<ul>\n  <li>メニュー表示→コマンドパレット</li>\n  <li>Remote:  Close Remote Connection を選択</li>\n</ul>\n\n<p>このとき、コンテナからだけでなく、リモートホストからも切断される。</p>\n\n<h2 id=\"vscodeでリモート-エクスプローラからリモートホストに接続その2\">VScodeでリモート エクスプローラからリモートホストに接続(その2)</h2>\n<p>リモートエクスプローラ(Containers)で接続するコンテナを右クリックし、「Attach to Container」または「Attach in New Window」を選択<br />\n(コンテナが起動されていなければ起動して)コンテナに接続される。</p>\n\n<p>あんまりごちょごちょしなくて済むのでこっちの方がおススメかな。</p>\n\n<h1 id=\"ネットワークポート\">ネットワークポート</h1>\n<p>通常Cockerコンテナ内のネットワークポートをホストや外部コンピュータからアクセスするには、<br />\nコンテナ作成時に-p (–publish) オプションで接続を受け入れるポート番号を指定する必要があるが、<br />\nVScodeから接続している場合は、Docker内のネットワークポートにVScodeが実行されているマシンからlocalhost:«ポート番号»で接続できる。<br />\n(アクセス遅いけど、ちょっと別のポート開けて試したい なんて時には便利)</p>\n\n<p>ただし、これはDockerが動作しているホストコンピュータや他のコンピュータからはアクセスできない。<br />\nこれらからアクセスするには-pオプションを指定する必要がある。</p>\n\n<h1 id=\"その他\">その他</h1>\n<p><a href=\"https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0\">https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0</a><br />\n↑ここにある、「Remote-Containers: Open Folder in Container…」での手順はリモートホストに接続した状態では実行できないらしい。<br />\nどうしてもこのコンテナでデバッグしたい場合は、<br />\n一旦リモートホスト上でVSCodeを起動してコンテナを作成しておき、<br />\nその後ローカルPCからこのコンテナにアタッチするような手順をふめばデバッグできる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ubuntuにSSHサーバをセットアップする</title>\n  </head>\n  <body>\n    <header>\n      <h1>ubuntuにSSHサーバをセットアップする</h1>\n      <p>ubuntuにSSHサーバをセットアップするし、公開鍵認証を設定する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuにsshサーバをセットアップする\">UbuntuにSSHサーバをセットアップする</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ssh\nsystemctl start sshd\n</code></pre></div></div>\n\n<p>この状態でWindowsなどから以下のコマンドで接続するとパスワード認証でlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«ユーザ名»@«IPアドレス»<span class=\"s1\">'s password: «パスワードを入力»  \n</span></code></pre></div></div>\n\n<p>リモート接続でshellを使うだけならこれでも良いが、\nVScodeでリモートデバッグをしたりするときなどはパスワード入力を何回も行う必要があったりして面倒。<br />\nそこで、公開鍵認証を設定してパスワード入力を不要にする。</p>\n\n<h1 id=\"秘密鍵と公開鍵の生成と公開鍵ファイルの設置\">秘密鍵と公開鍵の生成と公開鍵ファイルの設置</h1>\n<p>Windowsマシンで以下のコマンドを実行して秘密鍵ファイルと公開鍵ファイルを生成する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh-keygen.exe <span class=\"nt\">-t</span> rsa\n<span class=\"o\">(</span>リターン3回<span class=\"o\">)</span>\n※ 本当はpassphase入れないといけないけど、ローカルお試し環境なので省略\n</code></pre></div></div>\n<p>実行すると以下のファイルが出来る</p>\n<ul>\n  <li>%USERPROFILE%/.ssh/id_rsa</li>\n  <li>%USERPROFILE%/.ssh/id_rsa.pub</li>\n</ul>\n\n<p>このうち、<code class=\"language-plaintext highlighter-rouge\">id_rsa.pub</code>をUbuntuマシンの <code class=\"language-plaintext highlighter-rouge\">~/.ssh</code>へ<code class=\"language-plaintext highlighter-rouge\">authorized_keys</code>というファイル名でコピー(既に存在する場合は追記)する。</p>\n<blockquote>\n  <p>[!NOTE]\nやり方検索すると<code class=\"language-plaintext highlighter-rouge\">scp</code>コマンドでコピーする方法が紹介されているが、\n家の中だけなのでネットワークドライブ経由でのコピーや\nファイル自体はテキストファイルなので、SSH接続したshellからエディタを起動して\nコピペするのでも良い。</p>\n</blockquote>\n\n<p>コピーが完了したらファイルのパーミッションを変更する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod </span>600 ~/.ssh/authorized_keys\n</code></pre></div></div>\n\n<h1 id=\"接続テスト\">接続テスト</h1>\n<p>この状態でWindowsマシンから以下のコマンドで接続するとパスワード認証なしでlog inできる。<br />\n(TeraTermなどでも可)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh «ユーザ名»@«IPアドレス»\n«パスワード入力なしで接続»\n</code></pre></div></div>\n\n<p>Windows側のユーザディレクトリ/.ssh/config の設定もやっておくと便利<br />\n参考: <a href=\"https://qiita.com/passol78/items/2ad123e39efeb1a5286b\">https://qiita.com/passol78/items/2ad123e39efeb1a5286b</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DockerコンテナからGUIを起動する</title>\n  </head>\n  <body>\n    <header>\n      <h1>DockerコンテナからGUIを起動する</h1>\n      <p>Windos/Ubuntu の DockerコンテナからGUIを起動する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"ubuntuでローカルのデスクトップに表示する場合\">Ubuntuでローカルのデスクトップに表示する場合</h1>\n<p>Docker(ubuntu)のみ。<br />\nコンテナ生成時に以下のように<code class=\"language-plaintext highlighter-rouge\">DISPLAY</code>変数の設定と<code class=\"language-plaintext highlighter-rouge\">/tmp/.X11-unix/</code>のマウントを行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test3 <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span><span class=\"nv\">$DISPLAY</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /tmp/.X11-unix/:/tmp/.X11-unix/ <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n<p>この場合、表示する前にホスト側で以下を実行しておく必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>xhost +local:\n</code></pre></div></div>\n<p>実行していない場合、GUI起動コマンド実行で以下のエラーが出る。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>No protocol specified\nError: Can't open display: XXX\n</code></pre></div></div>\n\n<p>Ubuntuを再起動したときに設定は忘れられてしまうので、起動の度に実行必要。</p>\n\n<blockquote>\n  <p>[!NOTE]\nxhostはセキュリティ上問題があるとのことだが、家の中だけだし、localだけなら許可してもいいかな…\nrc.localあたりに書いとこうかと思ったけど、使用するときだけ実行するのが無難かな。</p>\n</blockquote>\n\n<h1 id=\"windows上のvcxsrvに表示する場合\">Windows上のVcXsrvに表示する場合</h1>\n<p>Docker(windows)だとコレ一択。<br />\nDocker(ubuntu)でも大丈夫。<br />\nなので、Docker(ubuntu)にリモート接続で使用することがある場合はこっちを使っておくのが良いと思う。<br />\nWindowsマシンのIPアドレスが192.168.XXX.XXX(マシン名指定不可)だとして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test4 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    <span class=\"nt\">-e</span> <span class=\"nv\">DISPLAY</span><span class=\"o\">=</span>192.168.XXX.XXX:0.0 <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>VSCodeでDocker内のpythonプログラムをデバッグする</title>\n  </head>\n  <body>\n    <header>\n      <h1>VSCodeでDocker内のpythonプログラムをデバッグする</h1>\n      <p>VSCodeでDocker内のpythonプログラムをデバッグする(Windos/Ubuntu)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows上のVSCodeからWindows上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nubuntu上のVSCodeからubuntu上のDockerで動作しているコンテナ内のpythonプログラムをデバッグする方法。<br />\nどちらもほぼ同じ手順でデバッグできる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>VScodeに拡張機能Python、Docker、Remote Containers をインストールしておく</p>\n\n<h1 id=\"コンテナ起動\">コンテナ起動</h1>\n<p>ターミナルからコンテナ起動する<br />\nソースの編集をしやすいように、ホストのフォルダを<code class=\"language-plaintext highlighter-rouge\">/work</code>に割り当てている。<br />\nいや、VSCodeで編集すれば問題ないんだけどさ…<br />\nいつも編集は別のエディタ使ってたりするとコンテナ内のファイルいじるのが面倒なので…</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  Windows\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> /m/work/zzz:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ubuntu\n</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"nt\">-it</span> <span class=\"nt\">--name</span> py_test2 <span class=\"nt\">-v</span> <span class=\"sb\">`</span><span class=\"nb\">realpath</span> .<span class=\"sb\">`</span>:/work python:3.8-buster /bin/bash\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンテナを一度作成してあれば起動していなくても大丈夫らしい。</p>\n</blockquote>\n\n<h1 id=\"コンテナに接続\">コンテナに接続</h1>\n<p>VScodeのリモートエクスプローラにコンテナが見える</p>\n<blockquote>\n  <p>[!NOTE]\nRemote SSHやRemote WSLがインストールされている場合はリモートエクスプローラ上部のドロップダウンリストからContainersを選択</p>\n</blockquote>\n\n<p>対象のコンテナを右クリックして<code class=\"language-plaintext highlighter-rouge\">Attach to Container</code> または<code class=\"language-plaintext highlighter-rouge\">Attach in New Window</code>をクリック<br />\n<code class=\"language-plaintext highlighter-rouge\">Attaching to a container may execute arbitrary code</code><br />\nと言われるたら、変なコードが実行されないことが分かっていれば <code class=\"language-plaintext highlighter-rouge\">Got it</code> をクリック</p>\n<blockquote>\n  <p>[!NOTE]\n一度開いたフォルダはその下にショートカットが表示されているので、そこから開けば手っ取り早い。</p>\n</blockquote>\n\n<p>コンテナが開く</p>\n\n<p>コンテナ内には拡張機能が入ってないので、必要な拡張機能をインストールする</p>\n\n<h1 id=\"デバッグ\">デバッグ</h1>\n<p>エクスプローラでデバッグしたいフォルダを開いてソースを開く(VSCodeの設定によっては前回開いていたフォルダが開かれる)<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Python: Select Interpreter</code> で 使用するpythonを選択する。<br />\nこのとき、必ずしも使用するpythonのpathが表示されているとは限らないので、<br />\n(逆にコンテナ内にないホスト側のものが表示されたりする😢)<br />\n表示されていない場合は<code class=\"language-plaintext highlighter-rouge\">+ Enter Interpreter path...</code>から使用するpythonを選択する。<br />\n上記イメージの場合、<code class=\"language-plaintext highlighter-rouge\">/usr/local/bin/python3</code> なので、これを設定。</p>\n<blockquote>\n  <p>[!NOTE]\nあらかじめコンソールで which python3 して調べておく</p>\n</blockquote>\n\n<p>あとはローカルと同じようにデバッグできる。</p>\n\n<h1 id=\"コンテナとの接続終了\">コンテナとの接続終了</h1>\n\n<p>コンテナとの接続を終了するときは<br />\n表示→コマンドパレットで<code class=\"language-plaintext highlighter-rouge\">Remote: Close Remote Connection</code> で終了する。</p>\n\n<p>接続終了してもコンテナを停止しないので、別途停止処理を行う。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker stop py_test2\n</code></pre></div></div>\n\n<h1 id=\"おまけ\">おまけ</h1>\n<p>こういうのもある。<br />\n(参照しているのはmicrosoft純正のサンプルらしい)<br />\n普通にDocker使うのと異なるファイル<code class=\"language-plaintext highlighter-rouge\">devcontainer.json</code>を使うので、\n便利なんだか不便なんだか…<br />\nDocker拡張機能なくても動かせた気がする。<br />\n<a href=\"https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html\">https://python.kirikutitarou.com/2019/07/vs-code-docker-remote-container.html</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Dockerをインストールする</title>\n  </head>\n  <body>\n    <header>\n      <h1>Dockerをインストールする</h1>\n      <p>Windos/Ubuntu に Dockerをインストールする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"windows10-home-に-dockerをインストールする\">Windows10 Home に Dockerをインストールする</h1>\n<p>HomeだとWSL2必須なので、WSL2はあらかじめインストールして使用できるようにしておく。<br />\n<a href=\"/memoBlog/2021/03/03/WSL_memo.html\" target=\"_blank\">WSL2 メモ</a></p>\n\n<p><a href=\"https://docs.docker.jp/docker-for-windows/install-windows-home.html\" target=\"_blank\">https://docs.docker.jp/docker-for-windows/install-windows-home.html</a> を参考にインストールする。 <br />\nとはいっても、<a href=\"https://hub.docker.com/editions/community/docker-ce-desktop-windows/\" target=\"_blank\">https://hub.docker.com/editions/community/docker-ce-desktop-windows/</a>からダウンロードして実行するだけ。</p>\n\n<p>コンテナを一杯作るとデータ領域がどんどん肥大していくので、Cドライブから変更しておいた方が良いかも。<br />\n<a href=\"https://nosubject.io/windowsdocker-desktop-move-disk-image/\" target=\"_blank\">Docker Desktop の ディスク領域 を Cドライブから別のドライブへ移動する方法</a><br />\nを参考に作業すればOK。<br />\nVHDをエクスポート、元の仮想マシンのレジストリを削除、他の場所へ同名でインポート、とやってる。</p>\n\n<h1 id=\"ubuntu-に-dockerをインストールする\">Ubuntu に Dockerをインストールする</h1>\n<p><a href=\"https://docs.docker.jp/linux/step_one.html\" target=\"_blank\">https://docs.docker.jp/linux/step_one.html</a> を参考にインストールする。 <br />\n実際は以下を実行するだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>curl <span class=\"nt\">-fsSL</span> https://get.docker.com/ | sh\n</code></pre></div></div>\n\n<p>docker実行に逐一<code class=\"language-plaintext highlighter-rouge\">sudo</code>をつけるのは面倒なので、以下の設定をしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> docker\n</code></pre></div></div>\n<p>設定後は念のためリブートしておく(logoutだけで可らしいけど)。</p>\n\n<h1 id=\"インストール後のお試し実行\">インストール後のお試し実行</h1>\n<p>正常に動いていることを確認するためになんか動かしてみる。<br />\n以下はWindows版で書かれているが、基本的にUbuntuでも同じ。<br />\n<a href=\"https://qiita.com/nanaki11/items/97e5685ed84547526be2\" target=\"_blank\">https://qiita.com/nanaki11/items/97e5685ed84547526be2</a></p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">docker pull</code>はしなくても<code class=\"language-plaintext highlighter-rouge\">docker run</code>したときにローカルにimegeがなければ自動でダウンロードしてくれるらしい。</p>\n\n<h1 id=\"コマンド例\">コマンド例</h1>\n<p>ちょろっと試したコマンド群</p>\n<h2 id=\"コンテナの生成\">コンテナの生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの起動\">コンテナの起動</h2>\n<p>終了したコンテナの再開も同じ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker start <span class=\"nt\">-ia</span> py_test\n</code></pre></div></div>\n\n<h2 id=\"コンテナに新たなコンソール接続\">コンテナに新たなコンソール接続</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker <span class=\"nb\">exec</span> <span class=\"nt\">-it</span> py_test /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナの生成と起動を同時に行う\">コンテナの生成と起動を同時に行う</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">create</code>を<code class=\"language-plaintext highlighter-rouge\">run</code>に変えるだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"nwork-を-work-にマウントする場合windows\">n:\\work を /work にマウントする場合(Windows)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker create <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> /n/work:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"カレントディレクトリを-work-にマウントする場合ubuntu\">カレントディレクトリを /work にマウントする場合(ubuntu)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker run <span class=\"se\">\\</span>\n    <span class=\"nt\">-it</span> <span class=\"se\">\\</span>\n    <span class=\"nt\">--name</span> py_test2 <span class=\"se\">\\</span>\n    <span class=\"nt\">-v</span> <span class=\"nv\">$PWD</span>:/work <span class=\"se\">\\</span>\n    python:3.8-buster <span class=\"se\">\\</span>\n    /bin/bash\n</code></pre></div></div>\n\n<h2 id=\"コンテナ一覧起動中のもののみ\">コンテナ一覧(起動中のもののみ)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n<h2 id=\"コンテナ一覧終了したものを含む\">コンテナ一覧(終了したものを含む)</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker ps <span class=\"nt\">-a</span>\n</code></pre></div></div>\n\n<h2 id=\"pull済みイメージ一覧\">pull済みイメージ一覧</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker images\n</code></pre></div></div>\n\n<h2 id=\"コンテナの情報を確認する\">コンテナの情報を確認する</h2>\n<p>下記コマンドでJSONデータが出力される。<br />\n直近で興味ありそうなのは<code class=\"language-plaintext highlighter-rouge\">HostConfig</code>、<code class=\"language-plaintext highlighter-rouge\">Mounts</code>、<code class=\"language-plaintext highlighter-rouge\">NetworkSettings</code>あたりかな?</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>docker inspect py_test2\n</code></pre></div></div>\n\n<h1 id=\"どんなイメージがあるのか\">どんなイメージがあるのか?</h1>\n<p><a href=\"https://hub.docker.com/search?type=image\" target=\"_blank\">dockerhub</a>でサーチしてちょ。</p>\n\n<h1 id=\"dockerはwsl2でどんな感じで動いているのか\">DockerはWSL2でどんな感じで動いているのか?</h1>\n<p>あんまり意味ないけど。<br />\n<a href=\"https://www.docker.com/blog/new-docker-desktop-wsl2-backend/\" target=\"_blank\">https://www.docker.com/blog/new-docker-desktop-wsl2-backend/</a></p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "pytorch": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>DonkeyCar simulatorで強化学習(その3)</title>\n  </head>\n  <body>\n    <header>\n      <h1>DonkeyCar simulatorで強化学習(その3)</h1>\n      <p>DonkeyCar simulatorで強化学習のサンプルを実行してみる(VAE+SAC編)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_1.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a>、\n<a href=\"/memoBlog/2021/12/09/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その2)</a>\nではDonkeyCar simulatorに添付のサンプルプログラムを実行してみたが、結果がイマイチだったので別のプログラムを試してみる。<br />\n<del>パクった</del> 参考にしたのは、<a href=\"https://masato-ka.hatenablog.com/entry/2020/04/29/153505?fbclid=IwAR1sjfiN1dAGRn6vIKU9vOSnfoCCsmgvVXRV_MWaLdUr3FeIUvUAr1Ef_yo\" target=\"_blank\">Jetson Nanoで動く深層強化学習を使ったラジコン向け自動運転ソフトウェアの紹介</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work2/donkey_sim3\n<span class=\"nb\">cd</span> /work2/donkey_sim3/\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 donkey_sim3\npyenv <span class=\"nb\">local </span>donkey_sim3 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>opencv-python\npip <span class=\"nb\">install </span>torch\npip <span class=\"nb\">install </span>torchvision\npip <span class=\"nb\">install </span>pyyaml\npip <span class=\"nb\">install </span>stable_baselines3\npip <span class=\"nb\">install </span>gym\npip <span class=\"nb\">install </span>git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24\n\n<span class=\"c\"># tensorboard も必要</span>\npip <span class=\"nb\">install </span>tensorboard\n<span class=\"c\"># たぶん要らないけど、念のため入れとく(tensorboard 実行時になんか言われるので)</span>\npip <span class=\"nb\">install </span>tensorflow\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n今回は stable-baselines3 を使用するので、 tensorflow ではなく、pytorch。<br />\nしかし、tensorboardは必要(学習ログ記録のため)。<br />\ntensorboardで可視化機能を使用する際はtensorflowが入ってないと実行時になんか言われるので\n念のためtensorflowも入れとく(たぶん入れなくても大丈夫)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n試したときのモジュール類のバージョンは以下の通り</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>opencv-python                4.5.4.60\ntorch                        1.10.0\ntorchvision                  0.11.1\nPyYAML                       6.0\nstable-baselines3            1.3.0\ngym                          0.19.0\ngym-donkeycar                1.1.1      ← Githubのtagはv21.07.24\ntensorboard                  2.7.0\ntensorflow                   2.7.0\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"シミュレータのダウンロードインストール\">シミュレータのダウンロード&インストール</h2>\n\n<p><a href=\"/memoBlog/2021/12/06/donkeycar_2.html\" target=\"_blank\">DonkeyCar simulatorで強化学習(その1)</a> と同じ</p>\n\n<h2 id=\"プログラム\">プログラム</h2>\n<h3 id=\"プログラム拾ってくる\">プログラム拾ってくる。</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/masato-ka/airc-rl-agent.git\n<span class=\"nb\">cd </span>airc-rl-agent/\ngit checkout <span class=\"nt\">-b</span> release-v1.5.2 refs/tags/release-v1.5.2\n</code></pre></div></div>\n\n<h3 id=\"パッチをあてる\">パッチをあてる。</h3>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/config.yml b/config.yml\nindex bda2308..3bf2ad4 100644\n</span><span class=\"gd\">--- a/config.yml\n</span><span class=\"gi\">+++ b/config.yml\n</span><span class=\"p\">@@ -48,8 +48,8 @@</span> AGENT_SETTING:\n   N_COMMAND_HISTORY: 20\n   MIN_STEERING: -1.0\n   MAX_STEERING: 1.0\n<span class=\"gd\">-  MIN_THROTTLE: 0.7 # 0.4\n-  MAX_THROTTLE: 0.95 # 0.9\n</span><span class=\"gi\">+  MIN_THROTTLE: 0.3  # 0.7  # 0.4\n+  MAX_THROTTLE: 0.95 # 0.95 # 0.9\n</span>   MAX_STEERING_DIFF: 0.9 #0.35\n \n JETRACER_SETTING:\n<span class=\"gh\">diff --git a/learning_racer/commands/subcommand.py b/learning_racer/commands/subcommand.py\nindex 0cf6eac..e4474e7 100644\n</span><span class=\"gd\">--- a/learning_racer/commands/subcommand.py\n</span><span class=\"gi\">+++ b/learning_racer/commands/subcommand.py\n</span><span class=\"p\">@@ -56,6 +56,7 @@</span> def command_train(args, config):\n     model = CustomSAC(agent, args, config)\n     model.lean(callback=callback)\n     model.save(args.save)\n<span class=\"gi\">+    agent.close()\n</span> \n \n def command_demo(args, config):\n<span class=\"p\">@@ -65,4 +66,14 @@</span> def command_demo(args, config):\n     for step in range(args.time_steps):\n         if step % 100 == 0: print(\"step: \", step)\n         action, _states = model.predict(obs)\n<span class=\"gi\">+        steer = action[0]\n+        throttle = action[1]\n</span>         obs, rewards, dones, info = agent.step(action)\n<span class=\"gi\">+        steer2 = agent.action_history[-2]\n+        throttle2 = agent.action_history[-1]\n+        speed = info[\"speed\"]\n+        cte = info[\"cte\"]\n+        print(f'steer:{steer:9.5f}    steer2:{steer2:9.5f}    throttle:{throttle:9.5f}    throttle2:{throttle2:9.5f}    speed:{speed:9.5f}    cte:{cte:9.5f}')\n+        if dones :\n+            obs = agent.reset()\n+    agent.close()\n</span><span class=\"gh\">diff --git a/learning_racer/racer.py b/learning_racer/racer.py\nindex 3e67ca2..dee0905 100644\n</span><span class=\"gd\">--- a/learning_racer/racer.py\n</span><span class=\"gi\">+++ b/learning_racer/racer.py\n</span><span class=\"p\">@@ -1,3 +1,7 @@</span>\n<span class=\"gi\">+import sys\n+import os\n+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))\n+\n</span> import argparse\n from learning_racer.commands.subcommand import command_demo, command_train\n from learning_racer.config import ConfigReader\n<span class=\"p\">@@ -8,6 +12,20 @@</span> logger = getLogger(__name__)\n \n __version__ = '1.5.1'\n \n<span class=\"gi\">+track_list = [\n+    \"donkey-generated-roads-v0\",\n+    \"donkey-warehouse-v0\",\n+    \"donkey-avc-sparkfun-v0\",\n+    \"donkey-generated-track-v0\",\n+    \"donkey-mountain-track-v0\",\n+    \"donkey-roboracingleague-track-v0\",\n+    \"donkey-waveshare-v0\",\n+    \"donkey-minimonaco-track-v0\",\n+    \"donkey-warren-track-v0\",\n+    \"donkey-thunderhill-track-v0\",\n+    \"donkey-circuit-launch-track-v0\",\n+]\n+\n</span> parser = argparse.ArgumentParser(description='Learning Racer command.')\n parser.add_argument('--version', action='version', version='learning_racer version {} .'.format(__version__))\n subparser = parser.add_subparsers()\n<span class=\"p\">@@ -39,7 +57,7 @@</span> parser_train.add_argument('-host', '--sim-host', help='Define host IP of DonkeyS\n parser_train.add_argument('-port', '--sim-port', help='Define port number of DonkeySim host.',\n                           default='9091', type=int)\n parser_train.add_argument('-track', '--sim-track', help='Define track name for DonkeySim',\n<span class=\"gd\">-                          default='donkey-generated-track-v0', type=str)\n</span><span class=\"gi\">+                          default='donkey-generated-track-v0', type=str, choices=track_list)\n</span> parser_train.set_defaults(handler=command_train)\n \n # demo subcommand.\n<span class=\"p\">@@ -63,7 +81,7 @@</span> parser_demo.add_argument('-host', '--sim-host', help='Define host IP of DonkeySi\n parser_demo.add_argument('-port', '--sim-port', help='Define port number of DonkeySim host.',\n                          default='9091', type=int)\n parser_demo.add_argument('-track', '--sim-track', help='Define track name for DonkeySim',\n<span class=\"gd\">-                         default='donkey-generated-track-v0', type=str)\n</span><span class=\"gi\">+                         default='donkey-generated-track-v0', type=str, choices=track_list)\n</span> parser_demo.add_argument('-user', '--sim-user', help='Define user name for own car that showed DonkeySim',\n                          default='anonymous', type=str)\n parser_demo.add_argument('-car', '--sim-car', help='Define car model type for own car that showed DonkeySim',\n<span class=\"gh\">diff --git a/learning_racer/sac/custom_sac.py b/learning_racer/sac/custom_sac.py\nindex 734fd95..3642ca8 100644\n</span><span class=\"gd\">--- a/learning_racer/sac/custom_sac.py\n</span><span class=\"gi\">+++ b/learning_racer/sac/custom_sac.py\n</span><span class=\"p\">@@ -21,6 +21,7 @@</span> def _load_sac(agent, args, config, policy):\n                     sde_sample_freq=config.sac_sde_sample_freq()\n                     )\n     else:\n<span class=\"gi\">+        print(f\"**** load model{args.load_model} ****\")\n</span>         model = SAC.load(args.load_model, env=agent,\n                          policy_kwargs=policy,\n                          verbose=config.sac_verbose(),\n<span class=\"p\">@@ -31,7 +32,7 @@</span> def _load_sac(agent, args, config, policy):\n                          ent_coef=config.sac_ent_coef(), learning_rate=config.sac_learning_rate(),\n                          tensorboard_log=\"tblog\", gamma=config.sac_gamma(), tau=config.sac_tau(),\n                          use_sde_at_warmup=config.sac_use_sde_at_warmup(), use_sde=config.sac_use_sde(),\n<span class=\"gd\">-                         sde_sample_freq=config.sac_sample_freq(), n_episodes_rollout=1)\n</span><span class=\"gi\">+                         sde_sample_freq=config.sac_sde_sample_freq(), n_episodes_rollout=1)\n</span>     return model\n \n \n<span class=\"gh\">diff --git a/learning_racer/sac/hyperparam.py b/learning_racer/sac/hyperparam.py\nindex e58b3fa..5b4b3f0 100644\n</span><span class=\"gd\">--- a/learning_racer/sac/hyperparam.py\n</span><span class=\"gi\">+++ b/learning_racer/sac/hyperparam.py\n</span><span class=\"p\">@@ -2,7 +2,6 @@</span> import math\n \n from learning_racer.config.config import ConfigReader\n \n<span class=\"gd\">-hit_counter = 0\n</span> speed_counter = 0\n config = ConfigReader()\n \n<span class=\"p\">@@ -27,29 +26,32 @@</span> def reward_sim(self, done):\n \n \n # For gym_donkey\n<span class=\"gd\">-hit_counter = 0\n</span> speed_counter = 0\n initial = False\n \n \n def episode_over_sim(self):\n<span class=\"gd\">-    global hit_counter, speed_counter, initial\n</span><span class=\"gi\">+    global speed_counter, initial\n</span>     #    print(self.speed)\n \n     if not initial and self.speed > 3.0:\n         initial = True\n \n     if self.hit != \"none\":\n<span class=\"gd\">-        hit_counter += 1\n-        if hit_counter > 5:\n-            self.over = True\n-            hit_counter = 0\n</span><span class=\"gi\">+        self.over = True\n+        initial = False\n+    elif math.fabs(self.cte) > self.max_cte * 1.5:\n+        self.over = True\n+        initial = False\n</span>     elif self.speed < 0.03 and initial:\n         speed_counter += 1\n         if speed_counter > 10:\n             self.over = True\n             speed_counter = 0\n<span class=\"gi\">+            initial = False\n</span>     elif self.missed_checkpoint:\n         self.over = True\n<span class=\"gi\">+        initial = False\n</span>     elif self.dq:\n         self.over = True\n<span class=\"gi\">+        initial = False\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n主な変更内容は、</p>\n  <ul>\n    <li>config.yml\n      <ul>\n        <li>MIN_THROTTLE の値修正(ちょっと速すぎな感じだったので)</li>\n      </ul>\n    </li>\n    <li>learning_racer/commands/subcommand.py\n      <ul>\n        <li>simulatorのクローズ処理を追加</li>\n        <li>demo時の状態表示を追加</li>\n        <li>demo時のdonesステータスでsimulator初期化を追加</li>\n      </ul>\n    </li>\n    <li>learning_racer/racer.py\n      <ul>\n        <li>pip installせずに実行できるよう、sys.pathを修正する部分の追加</li>\n      </ul>\n    </li>\n    <li>learning_racer/sac/custom_sac.py\n      <ul>\n        <li>typo修正</li>\n      </ul>\n    </li>\n    <li>learning_racer/sac/hyperparam.py\n      <ul>\n        <li>エピソード終了判定<code class=\"language-plaintext highlighter-rouge\">episode_over_sim()</code>の変更</li>\n      </ul>\n    </li>\n  </ul>\n\n</blockquote>\n\n<h3 id=\"vaeの学習済みモデルを拾ってくる\">VAEの学習済みモデルを拾ってくる</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>learning_racer/\nwget <span class=\"s2\">\"https://drive.google.com/uc?export=download&id=19r1yuwiRGGV-BjzjoCzwX8zmA8ZKFNcC\"</span> <span class=\"nt\">-O</span> vae.torch\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nこのVAEの学習済みモデルは<code class=\"language-plaintext highlighter-rouge\">donkey-generated-track-v0</code>用なので、\n以下の実行ではこのコースを使用する(<code class=\"language-plaintext highlighter-rouge\">-track</code>オプションのデフォルト)。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">donkey-waveshare-v0</code>は簡単なコースなので流用できるっぽい。</p>\n</blockquote>\n\n<h1 id=\"とりあえず学習\">とりあえず学習</h1>\n<p>とりあえず学習。<br />\nリモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。\nシミュレータ実行マシンのIPアドレスを<code class=\"language-plaintext highlighter-rouge\">--host</code>オプションに指定します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python racer.py train <span class=\"nt\">-robot</span><span class=\"o\">=</span>sim <span class=\"nt\">-vae</span><span class=\"o\">=</span>./vae.torch <span class=\"nt\">-config</span><span class=\"o\">=</span>../config.yml <span class=\"nt\">-device</span><span class=\"o\">=</span>cpu <span class=\"nt\">-host</span><span class=\"o\">=</span>192.168.78.200 \n</code></pre></div></div>\n\n<p>追加学習する場合は元のモデルファイルを<code class=\"language-plaintext highlighter-rouge\">-l</code>オプションで指定します。<br />\n学習に使用するステップ数を変更する場合は<code class=\"language-plaintext highlighter-rouge\">-steps</code>オプションで指定します(デフォルトは5000)。<br />\nその他詳細はソースを見てちょ。</p>\n\n<h1 id=\"学習結果でテストしてみる\">学習結果でテストしてみる。</h1>\n<p>学習のときのコマンド<code class=\"language-plaintext highlighter-rouge\">train</code>を<code class=\"language-plaintext highlighter-rouge\">demo</code>に変更するだけです。<br />\nテストを実行するステップ数を変更したい場合は<code class=\"language-plaintext highlighter-rouge\">--steps</code>オプションで指定します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python racer.py demo <span class=\"nt\">-robot</span><span class=\"o\">=</span>sim <span class=\"nt\">-vae</span><span class=\"o\">=</span>./vae.torch <span class=\"nt\">-config</span><span class=\"o\">=</span>../config.yml <span class=\"nt\">-device</span><span class=\"o\">=</span>cpu <span class=\"nt\">-host</span><span class=\"o\">=</span>192.168.78.200\n</code></pre></div></div>\n<p>途中で止めたい場合はCTRL-Cで止めてください。</p>\n\n<h1 id=\"ソースを読んでみる\">ソースを読んでみる</h1>\n\n<p>のはやめとく。</p>\n\n<p>おおざっぱに言うと、コースの画像を入力してその特徴を抽出するVAE(Variational Auto Encoder)と\nVAEの出力と過去の操作(steering/throttle)の履歴を入力に次の操作を決定するSAC(Soft-Actor-Critic)で構成されている。</p>\n\n<p>VAEはあらかじめ大量のコース画像を撮影したデータで学習しておく(<code class=\"language-plaintext highlighter-rouge\">airc-rl-agent/notebooks/colabo/VAE_CNN.ipyn</code>)。<br />\nこの学習はカメラ画像さえ用意できていれば実機(or シミュレータ)は不要なので、Google Colaboratoryなど高性能のマシンで一気に学習できる。<br />\n上記では参照元ページで用意されていた学習済みモデルを使用している。</p>\n\n<p>VAEは車載カメラ画像(RGBのカラー画像)で160x120pixelにリサイズしたものの下部160x80pixelを入力としている。<br />\n出力は32個のデータ。</p>\n\n<p>VAEは160x80x3(38400)の画素データを32の出力に圧縮するので、そのまま画素データを入力するより学習効率が上がるのかな??<br />\nちゃんと検証してないけど、「右カーブ」とか「左カーブ」とか「直進」みたいな情報に集約されるのかな?</p>\n\n<p>SACの入力はVAEの出力(32個)と過去の操作履歴(過去何回分かは<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.N_COMMAND_HISTOR</code>で指定。\n上記手順で使用した設定値は20なので、steeringとthrottleの2個 × 20 で40個)を使用。<br />\n出力はsteeringとthrottleの2個のデータ。</p>\n\n<p>SACの出力はそのまま車の操作に使用するのではなく、<br />\nthrottleは<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.MIN_THROTTLE</code>と<code class=\"language-plaintext highlighter-rouge\">AGENT_SETTING.MAX_THROTTLE</code>で指定した範囲に変換。<br />\nsteeringは前回の設定値との差が<code class=\"language-plaintext highlighter-rouge\">config.yml</code> の <code class=\"language-plaintext highlighter-rouge\">MAX_STEERING_DIFF</code>で指定した値を超えないように制限処理、<br />\nを行って使用する。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "ESP32": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Bluetooth classic でシリアル通信(SPP)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Bluetooth classic でシリアル通信(SPP)</h1>\n      <p>ESP32 Bluetooth classic(SPP)を使用してシリアル通信するデモプログラム</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>シリアル通信でデータを送受信したいけど、有線接続はできない場合にBluetooth classicのSPP(Serial Port Profile )を使用して\nCOMポートとして接続する方法のデモ。<br />\nesp-idfのサンプルプログラムが私にとっては複雑怪奇だったので、ちょっとシンプルにしてみた。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは</p>\n<ul>\n  <li>VFS版: <a href=\"https://github.com/ippei8jp/BT_SPP_VFS\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_VFS</a></li>\n  <li>Callback版: <a href=\"https://github.com/ippei8jp/BT_SPP_CB\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_CB</a></li>\n</ul>\n\n<p>にあるのでcloneしてください。</p>\n\n<p>このプログラムではPC等のCOMポートへ/から接続して送信したデータをエコーバックするだけのデモプログラムです。<br />\nそれぞれのイベント発生時に発生イベントとパラメータを表示するようにしてあるので、動作の理解の一助になります…\nなったらいいな…でも期待はするな….</p>\n\n<p>上記2つのリポジトリはファイル構成を合わせてあるので、diffをとるとVFSとCallbackでどのような違いがあるのか分かりやすい<br />\n… かもね…</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<ul>\n  <li>VFS版: <a href=\"https://github.com/ippei8jp/BT_SPP_VFS#readme\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_VFS#readme</a></li>\n  <li>Callback版: <a href=\"https://github.com/ippei8jp/BT_SPP_CB#readme\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_CB#readme</a></li>\n</ul>\n\n<p>を参照してください。</p>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ <br />\n最近こればっかりや…</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>エコーバックタスクをコマンドシェルタスクなどに入れ替えるとすぐ使える…とも思えんけど…<br />\n踏み台くらいにはなるでしょう。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>BLEでアプリケーションパラメータ設定</title>\n  </head>\n  <body>\n    <header>\n      <h1>BLEでアプリケーションパラメータ設定</h1>\n      <p>ESP32 BLEを使用してアプリケーションパラメータの設定を変更する処理の雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>アプリケーションを作成したとき、マシン名のように端末毎に変更を変更したり、\nサーバ名のように設置条件によって変更したいパラメータってありますよね。<br />\nいつもは起動時に設定モードに入ったり、動作中に簡易シェルを動かしてコンソール(UART)から設定していましたが、<br />\n実装面積などの関係でUARTが接続できなかったりした場合、それ以外の方法としてBLEで設定する方法を考えました。<br />\n(ESP32の場合、Flash書き換えでUART使うので繋がない訳にはいかないのですが…)</p>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nを参考にカスタムプロファイルでアプリケーションパラメータをread/writeできるようにしてみました。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは<a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a><br />\nにあるのでcloneしてください。</p>\n\n<p>このプログラムではアプリケーションはWi-Fiに接続するだけの処理です。<br />\nうまくパラメータが設定できて、nvsに保存しておけば、2回目以降はBLEによる設定なしにWi-Fiに接続することができます。<br />\n接続できれば、外部マシンからpingを打って応答があることが確認できます。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a> のREADME.mdを参照してください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nパラメータの設定はRaspberryPiのpythonから行っていますが、その気になればAndroidのBLE接続確認ツールなどからでも設定できます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n設定パラメータにループインターバルがありますが、プログラム中では参照していません。<br />\n数値を設定する例として入れてあります。</p>\n</blockquote>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>設定したいパラメータが増えてたら、Characteristicを増やしていけばいくらでも対応できるハズ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>pythonでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に pythonスクリプトでアクセスしてみる方法についてのメモ。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<p>pythonスクリプトはRaspberryPiで動作している(実際に試したのはPi4だが、Pi3/Pi0wでも同様)。<br />\nubuntu-PCでも同様にできるはずだが、うちのマシンは内蔵Bluetoothのバージョンが古くてBLE非対応だったので試してない。<br />\nwindows-PCはよくわからん…</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/test1\n<span class=\"nb\">cd</span> /work/ble/test1\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.9.10 bluepy\npyenv <span class=\"nb\">local </span>bluepy\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>bluepy\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/9bbdfa53526411967975097cfbcc66e6.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>ESP32側はAdvertising 開始状態にしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>python ble_hr.py\n</code></pre></div></div>\n<p>デバイスのスキャンを行うので<code class=\"language-plaintext highlighter-rouge\">sudo</code>が必要。</p>\n<blockquote>\n  <p>[!NOTE]\nもし、scanせずにアドレスを指定して実行するだけの処理に書き換えれば<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要になる。</p>\n</blockquote>\n\n<h1 id=\"説明\">説明</h1>\n\n<h2 id=\"ble_hr_delegateクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR_Delegate</code>クラス</h2>\n<p>Notifyを受け取っての処理は<code class=\"language-plaintext highlighter-rouge\">bluepy.btle.DefaultDelegate</code>クラスを継承したクラスを作成して登録する必要がある。<br />\n処理自体は<code class=\"language-plaintext highlighter-rouge\">handleNotification</code>メソッドをオーバーライドして定義する。<br />\n受け取るデータ<code class=\"language-plaintext highlighter-rouge\">data</code>はbytes型なので、数値として使用する場合は<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換してやる必要があるが、<br />\nこの時のエンディアンは接続しているデバイスのFW仕様によるので、どちらを使うかはあらかじめ確認しておく必要がある。<br />\n(大抵はFWを動かしているCPUのエンディアンなのかな?)</p>\n\n<h2 id=\"ble_hrクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR</code>クラス</h2>\n<p>peripheralを操作するための処理をクラス化してある。<br />\nクラス化は必須ではないけど、処理をまとめておいた方が分かりやすいかな?と思ったので。</p>\n\n<p>コンストラクタ、接続、Characteristicのリード/ライト、Notifyの有効化/無効化/ポーリング、切断などの処理がある。</p>\n\n<h2 id=\"main関数\"><code class=\"language-plaintext highlighter-rouge\">main</code>関数</h2>\n<p>メイン処理。<br />\n処理の流れはこんな感じ。</p>\n<ul>\n  <li>デバイスのスキャン</li>\n  <li>スキャン結果から指定されたUUIDを持つデバイスを探す\n    <ul>\n      <li>UUIDやデバイス名が必ずしも同じところにあるとは限らないので色々読んでみる必要がある</li>\n    </ul>\n  </li>\n  <li>複数のデバイスを同時に操作することも可能だが、今回は最初の1個だけを決め打ちで使う</li>\n  <li>接続</li>\n  <li>Characteristicのリード\n    <ul>\n      <li>ここもリード結果はbytes型なので、<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換する</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト\n    <ul>\n      <li>ライトデータはbytes型に変換する必要があるが、この処理は、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.write()</code>で変換しているのでここではそのまま。</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト結果の確認\n    <ul>\n      <li>ライトできたか確認するために、再度リードしている</li>\n    </ul>\n  </li>\n  <li>Notifyの有効化</li>\n  <li>Notifyが通知されることを確認するために少し待つ\n    <ul>\n      <li>Notifyを待つ間、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.waitForNotifications()</code>(<code class=\"language-plaintext highlighter-rouge\">Peripheral.waitForNotifications()</code>のラッパ)をコールし続ける必要がある。<br />\nこれをコールしないとNotifyを受信できない(キューイングされるがコールバックは実行されない)。</li>\n    </ul>\n  </li>\n  <li>Notifyの無効化\n    <ul>\n      <li>Notifyが入らないことを確認するためにちょっと待つ</li>\n    </ul>\n  </li>\n  <li>切断</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry PiでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry PiでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に Raspberry Pi からアクセスしてみる方法についてのメモ。</p>\n\n<p>Androidでアクセスすると、色々とブラックボックスで処理されてどうなってるのか分かり難いので理解を深める意味で試してみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"メモ\">メモ</h1>\n\n<p>ここにあるように、BLEでは「ボンディング(参照先ではペアリングと表記)なし」で実行するのが無難と思われる<br />\n<a href=\"https://www.musen-connect.co.jp/blog/course/trial-production/ble-beginner-8/\" target=\"_blank\">【サルでもわかるBLE入門】(8) ペアリング</a></p>\n\n<p>Wiresharkによるパケットキャプチャの解説(たぶん、そんなレイヤでデバッグすることはないと思うけど)<br />\n<a href=\"https://re-engines.com/2021/08/16/ble-secure/\" target=\"_blank\">BLEのペアリングをWiresharkでキャプチャしながら学ぶ</a></p>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<h1 id=\"ペリフェラル機器をスキャン\">ペリフェラル機器をスキャン</h1>\n\n<p>まずは接続可能デバイスをスキャンしないと始まらないので、スキャンする。<br />\nもちろん、ESP32側はAdvertising 開始状態である必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo timeout </span>5s hcitool lescan        ← 5秒間スキャンしてみる\nLE Scan ...\n48:BA:7E:24:D0:AA <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n50:17:FC:8C:D1:87 ESP_BLE_HR            ←見つかった\nE4:9A:9F:40:AD:09 <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\nC4:49:BB:8A:7F:6C EX-ZR1800-8A7F6B\nC4:49:BB:8A:7F:6C <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hcitool lescan</code>の実行には<code class=\"language-plaintext highlighter-rouge\">sudo</code>必須。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout 5s</code> を付けずにCTRL+Cで停止しても良い。</p>\n\n<h1 id=\"対象デバイスにアクセスしてみる\">対象デバイスにアクセスしてみる</h1>\n\n<blockquote>\n  <p>[!NOTE]\n<strong>UUIDについて</strong></p>\n\n  <p>16bit UUIDは以下のXXXXの部分(それ以外の部分が一致しないものは128bit UUID)<br />\n<code class=\"language-plaintext highlighter-rouge\">0000XXXX-0000-1000-8000-00805f9b34fb</code></p>\n\n  <p>16bit UUIDは 以下のページを参照<br />\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a></p>\n</blockquote>\n\n<h2 id=\"コマンド起動と接続\">コマンド起動と接続</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">gatttool</code>の実行に<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要。<br />\n<code class=\"language-plaintext highlighter-rouge\">«アドレス»</code> には上でみつけたアドレスを指定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>gatttool <span class=\"nt\">-t</span> random <span class=\"nt\">-I</span> <span class=\"nt\">-b</span> «アドレス»             ← ツールの実行   以下、インタラクティブモードに入る\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> connect                  ← 接続 \nAttempting to connect to 50:17:FC:8C:D1:87\nConnection successful                             ← 接続成功  \n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"サービス一覧を取得\">サービス一覧を取得</h2>\n\n<p>サービスの一覧を取得してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> primary\nattr handle: 0x0001, end grp handle: 0x0005 uuid: 00001801-0000-1000-8000-00805f9b34fb\nattr handle: 0x0014, end grp handle: 0x001c uuid: 00001800-0000-1000-8000-00805f9b34fb\nattr handle: 0x0028, end grp handle: 0xffff uuid: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<p>それぞれこんな意味</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>UUID</th>\n      <th>種別</th>\n      <th>ハンドル範囲</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>1801</td>\n      <td>Generic Attribute</td>\n      <td>0x0001 ~ 0x0005</td>\n    </tr>\n    <tr>\n      <td>1800</td>\n      <td>Generic Acces</td>\n      <td>0x0014 ~ 0x001c</td>\n    </tr>\n    <tr>\n      <td>180d</td>\n      <td>Heart Rate</td>\n      <td>0x0028 ~ 0xffff</td>\n    </tr>\n  </tbody>\n</table>\n\n<h2 id=\"generic-accesを調べてみる\">Generic Accesを調べてみる</h2>\n\n<p>上で調べたGeneric Acces のハンドル範囲を指定して実行。<br />\n表示されるUUIDを\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a>\nで探して右側にメモっておいた。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x14 0x1c\nhandle: 0x0014, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0015, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb        ← device name\nhandle: 0x0017, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb        ← Appearance\nhandle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb        ← Central Address Resolution\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"device-name-を読んでみる\">device name を読んでみる</h2>\n\n<p>とりあえず devece nameを読んでみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x016                       ← handle 0x16<span class=\"o\">(</span>device name<span class=\"o\">)</span> のリード\nCharacteristic value/descriptor: 45 53 50 5f 42 4c 45 5f 48 52     ← 結果\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<p>このままだとなんだかわからん…<br />\n別ウィンドゥで以下を実行。<br />\nただし、<code class=\"language-plaintext highlighter-rouge\">nkf</code>はデフォルトでインストールされていないので<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールする。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">echo</code>の中身には上でリードした結果をコピペする。<br />\nこれを<code class=\"language-plaintext highlighter-rouge\">xxd</code>コマンドでバイナリに変換、<br />\n<code class=\"language-plaintext highlighter-rouge\">nkf</code>で文字コード変換を行う(これだとUTF-8→UTF-8なのであんまり意味ない気が…)。<br />\n結果は改行されずに、プロンプトが続けて表示されるので注意。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">echo</span> <span class=\"s2\">\"45 53 50 5f 42 4c 45 5f 48 52\"</span>  | xxd <span class=\"nt\">-p</span> <span class=\"nt\">-r</span>  | nkf <span class=\"nt\">-WwmQ</span>\nESP_BLE_HR        ← おぉ、読めてる\n<span class=\"nv\">$ </span>\n</code></pre></div></div>\n\n<h2 id=\"heart-rateサービスを調べてみる\">Heart Rateサービスを調べてみる</h2>\n<p>同様にHeart Rateサービスについて調べてみる。<br />\nUUIDについてのメモも同様。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x0028 0xffff\nhandle: 0x0028, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0029, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002a, uuid: 00002a37-0000-1000-8000-00805f9b34fb        ← Heart Rate Measurement\nhandle: 0x002b, uuid: 00002902-0000-1000-8000-00805f9b34fb        ← Client Characteristic Configuration\nhandle: 0x002c, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002d, uuid: 00002a38-0000-1000-8000-00805f9b34fb        ← Body Sensor Location\nhandle: 0x002e, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002f, uuid: 00002a39-0000-1000-8000-00805f9b34fb        ← Heart Rate Control Point\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"heart-rate-control-point-を読み書きしてみる\">Heart Rate Control Point を読み書きしてみる</h2>\n\n<p>Characteristicの読み書きを試すため、Heart Rate Control Point(ハンドル0x2f;c<code class=\"language-plaintext highlighter-rouge\">har-desc</code>の結果から取得)にアクセスしてみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 読んでみる\nCharacteristic value/descriptor: 00                   ← 読めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 01       ← 書いてみる\nCharacteristic value was written successfully         ← 書けた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 確認してみる\nCharacteristic value/descriptor: 01                   ← 書けてる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 0x02     ← 書き込み値に0xを付けたらエラーになる\nError: Characteristic Write Request failed: Attribute value length is invalid\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<h2 id=\"notificationを有効にしてみる\">Notificationを有効にしてみる</h2>\n\n<p>NotificationをONにするにはCCCを操作する。<br />\nNotificationで受信したデータは自動で表示される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 00 00                ← Notification OFFになってる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0100     ← Notification ON にしてみる<span class=\"o\">(</span>0100を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\nNotification handle <span class=\"o\">=</span> 0x002a value: 50 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 51 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 52 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 01 00                ← Notification ONになってる\nNotification handle <span class=\"o\">=</span> 0x002a value: 53 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 54 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 55 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 56 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 57 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0000     ← Notification OFF にしてみる<span class=\"o\">(</span>0000を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>                              ← 以降、Notificationは停止\n</code></pre></div></div>\n\n<h2 id=\"書き込み禁止のcharacteristicに書き込んでみる\">書き込み禁止のCharacteristicに書き込んでみる</h2>\n\n<p>書き込み禁止のCharacteristicに書き込んでみるとどうなるか試してみる。<br />\n当然エラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>50:17:FC:8C:D1:87][LE]> char-write-req 0x2d 01         ← Body Sensor Locationに書き込んでみる\nError: Characteristic Write Request failed: Attribute can<span class=\"s1\">'t be written   ← エラーになった\n</span></code></pre></div></div>\n\n<h2 id=\"切断する\">切断する</h2>\n\n<p>操作が終わったら切断する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> disconnect                        ← 切断\n<span class=\"o\">(</span>gatttool:1840<span class=\"o\">)</span>: GLib-WARNING <span class=\"k\">**</span>: 12:55:27.500: Invalid file descriptor.   ← なんか言われるけど無視して良い\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> <span class=\"nb\">exit</span>                              ← インタラクティブモードの終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る\n</code></pre></div></div>\n\n<h1 id=\"bluetoothctlでアクセス参考\">bluetoothctlでアクセス(参考)</h1>\n\n<p>「ボンディングする」設定の場合、bluetoothctlでアクセスする必要がある。<br />\nボンディングしない設定で使う分には関係ないが、せっかく調べたのでメモっておく。</p>\n\n<p>ボンディング前後でアドレス違ったりしてイマイチ使いにくい。<br />\nどうしても「ボンディングする」にしなければならない場合は、自身のアドレスをパブリックアドレスにしておけばちょっとマシかも。</p>\n\n<h2 id=\"メモ-1\">メモ</h2>\n\n<p>bluetoothctlのコマンド <br />\n<a href=\"https://qiita.com/noraworld/items/55c0cb1eb52cf8dccc12\" target=\"_blank\">bluetoothctl のコマンド一覧と使い方をまとめてみた</a></p>\n\n<p>bluetoothctlだとGATTへのアクセスができないっぽいので、ボンディングの登録/解除以外は使えないっぽいな…</p>\n\n<h2 id=\"前提-1\">前提</h2>\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス           (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングする                           (ESP_LE_AUTH_REQ_SC_MITM_BOND)</li>\n  <li>IO capabilityはcapabilityはDisplayYesNo    (ESP_IO_CAP_IO)</li>\n</ul>\n\n<h2 id=\"起動\">起動</h2>\n\n<p>ツールの起動。<br />\n<code class=\"language-plaintext highlighter-rouge\">sudo</code>必要<br />\n以下インタラクティブモードで操作。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo </span>bluetoothctl                                        ← 起動\n</code></pre></div></div>\n\n<h2 id=\"スキャン\">スキャン</h2>\n\n<p>接続可能デバイスを見つけるためにスキャンする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# scan on                                       ← スキャン開始\nDiscovery started\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>NEW] Device 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\n<span class=\"o\">[</span>NEW] Device 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\n<span class=\"o\">[</span>NEW] Device 62:D1:88:DD:4F:7C リビングルーム\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E RSSI: <span class=\"nt\">-38</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower: 3\n・・・\n<span class=\"o\">[</span>bluetooth]# scan off                                      ← スキャン停止\nDiscovery stopped\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: no\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower is nil\n・・・\n<span class=\"o\">[</span>bluetooth]# devices                                       ← 接続可能デバイスの表示\nDevice 5A:E1:9A:05:96:E0 ESP_BLE_HR                        ← これがESP32<span class=\"o\">(</span>ランダムアドレスなので起動の度に変化する<span class=\"o\">)</span>\nDevice 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\nDevice 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\nDevice 62:D1:88:DD:4F:7C リビングルーム\n\n</code></pre></div></div>\n\n<h2 id=\"agentの登録\">agentの登録</h2>\n\n<p>ボンディングのために、agentを登録する(数字を入力したり、Yes/Noを選択したりするやつ)。<br />\nこちらの設定と相手側の設定の組み合わせで最終的にどの方法が使われるか決定される。<br />\nたとえば、こちら側を NoInputNoOutput に設定しておけば、相手側が DisplayYesNo であってもYes/Noの入力は求められない。<br />\n逆の設定でも同様。</p>\n\n<p>登録された状態で他のCapabilityで登録しようとしても「既に登録済み」と言われるので、念のため一旦登録解除してから登録しておく。<br />\nこのあたり、情報少なくてイマイチよく分からない…</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# agent off                                    ← 一旦agentの登録解除\nAgent unregistered                                         ← 解除された\n<span class=\"o\">[</span>ESP_BLE_HR]# agent DisplayYesNo                           ← DisplayYesNoで登録\nAgent registered                                           ← 登録された\n</code></pre></div></div>\n\n<h2 id=\"接続\">接続</h2>\n\n<p>接続する。<code class=\"language-plaintext highlighter-rouge\">connect</code>でなく、<code class=\"language-plaintext highlighter-rouge\">pair</code>で実行。<br />\n<code class=\"language-plaintext highlighter-rouge\">connect</code>による接続は後述。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# pair 5A:E1:9A:05:96:E0                       ← 接続\nAttempting to pair with 5A:E1:9A:05:96:E0\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 Connected: <span class=\"nb\">yes\n</span>Request confirmation\n<span class=\"o\">[</span>agent] Confirm passkey 680456 <span class=\"o\">(</span><span class=\"nb\">yes</span>/no<span class=\"o\">)</span>:                   ← agentがYes/Noを聞いてくる\n<span class=\"o\">[</span>NEW] Primary Service                                      ← これが自動的に表示されて上の質問を見失うので注意!!\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001\n        00001801-0000-1000-8000-00805f9b34fb\n        Generic Attribute Profile\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001/char0002\n        00002a05-0000-1000-8000-00805f9b34fb\n        Service Changed\n・・・\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0028/char002e\n        00002a39-0000-1000-8000-00805f9b34fb\n        Heart Rate Control Point\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001800-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001801-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 ServicesResolved: <span class=\"nb\">yes\nyes</span>                                                         ← yesを入力<span class=\"o\">(</span>同時に相手側でもyes入力<span class=\"o\">)</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Address: 94:B9:7E:65:AF:5E\nPairing successful                                         ← 接続された\n<span class=\"o\">[</span>ESP_BLE_HR]# paired-devices                               ← ボンディング結果を確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR                        ← advertisingがランダムアドレスでもパブリックアドレスで登録されるので注意!!\n<span class=\"o\">[</span>ESP_BLE_HR]#                                                以降、接続はこのアドレスを使用する!!\n</code></pre></div></div>\n\n<h2 id=\"切断\">切断</h2>\n\n<p>切断する。<br />\nCharacteristicアクセスできないので、実質ボンディングするのみ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断する\nAttempting to disconnect from 94:B9:7E:65:AF:5E            ← パブリックアドレスが表示されている\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<h2 id=\"再接続\">再接続</h2>\n\n<p>ボンディング済みのデバイスに再接続する場合の手順。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスの表示\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# connect 94:B9:7E:65:AF:5E                     ← 表示されたアドレスで接続\nAttempting to connect to 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: <span class=\"nb\">yes\n</span>Connection successful                                      ← 接続された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断\nAttempting to disconnect from 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<p>ボンディングしてない機器に対して<code class=\"language-plaintext highlighter-rouge\">connect</code>すると、<code class=\"language-plaintext highlighter-rouge\">agent off</code> で <code class=\"language-plaintext highlighter-rouge\">pair</code> したような動作になる模様。</p>\n\n<h2 id=\"ボンディング解除\">ボンディング解除</h2>\n\n<p>ボンディング済みデバイスを登録削除する。<br />\nESP32側も忘れず登録削除しておくこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスを確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# remove 94:B9:7E:65:AF:5E                      ← ボンディング解除\n<span class=\"o\">[</span>DEL] Descriptor                                           ← なんか ずらずらっと削除されたと出る\n        /org/bluez/hci0/dev_5F_76_EF_D2_45_E7/service0001/char0002/desc0004\n        00002902-0000-1000-8000-00805f9b34fb\n        Client Characteristic Configuration\n・・・\nDevice has been removed                                    ← 削除された\n<span class=\"o\">[</span>bluetooth]# paired-devices                                ← 確認\n<span class=\"o\">[</span>bluetooth]#                                               ← 削除されてる\n</code></pre></div></div>\n\n<h2 id=\"ツールの終了\">ツールの終了</h2>\n\n<p>ツールを終了してShellに戻る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# <span class=\"nb\">exit</span>                                          ← またはquitまたはCTRL+Dで終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る \n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でBLEのデモを動かす 補足</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でBLEのデモを動かす 補足</h1>\n      <p>ESP32にBLEのデモの認証方法についての補足</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a>\nでは認証方法(IO capability なので入出能力と言うべきか? あまり直感的でないのでここでは認証方法と呼んでおこう)<br />\nを<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_NONE</code>(NoInputNoOutput; 入出力なし)に設定していたが、これを別の認証方法に変更する場合についてのメモ。</p>\n<blockquote>\n  <p>[!NOTE]\n自作の範囲だと<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_NONE</code>しか使わないと思うけど、使いたくなった時に備えて。</p>\n</blockquote>\n\n<h1 id=\"esp_io_cap_none-noinputnooutput\">ESP_IO_CAP_NONE (NoInputNoOutput)</h1>\n<p>入出力両方なし。<br />\npasskey(PINcode)入力などはなし。<br />\n接続すると自動的に鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (92315) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (92315) BLE_HEART_RATE:     connection start\nV (92975) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (92975) BLE_HEART_RATE:     event nor handled\nV (93245) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (93245) BLE_HEART_RATE:     event nor handled\nE (97855) BT_BTM: btm_ble_remove_resolving_list_entry_complete remove resolving list error 0x2\nV (98285) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (98285) BLE_HEART_RATE:     event nor handled\nW (98335) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (98375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98375) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (98375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98375) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (98385) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98385) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (98405) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98405) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (98405) nvs: nvs_open_from_partition bt_config.conf 1\nD (98415) nvs: nvs_set_blob bt_cfg_key0 475\nD (98425) nvs: nvs_close 4\nD (98425) nvs: nvs_open_from_partition bt_config.conf 1\nD (98425) nvs: nvs_set_blob bt_cfg_key0 475\nD (98485) nvs: nvs_close 5\nD (98485) nvs: nvs_open_from_partition bt_config.conf 1\nD (98485) nvs: nvs_set_blob bt_cfg_key0 475\nD (98495) nvs: nvs_close 6\nD (98495) nvs: nvs_open_from_partition bt_config.conf 1\nD (98495) nvs: nvs_set_blob bt_cfg_key0 475\nD (98515) nvs: nvs_close 7\nD (98515) nvs: nvs_open_from_partition bt_config.conf 1\nD (98515) nvs: nvs_set_blob bt_cfg_key0 475\nD (98515) nvs: nvs_close 8\nV (98515) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (98525) BLE_HEART_RATE:     remote BD_ADDR: 5d5308bb0efd\nI (98525) BLE_HEART_RATE:     address type = 1\nI (98535) BLE_HEART_RATE:     pair status = success\nI (98535) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_BOND\nI (98545) BLE_HEART_RATE:     Bonded devices number : 1\nI (98545) BLE_HEART_RATE:     Bonded devices list :\nI (98555) BLE_HEART_RATE:        0 :   5d:53:08:bb:0e:fd\nV (99025) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99025) BLE_HEART_RATE:     event nor handled\nV (99545) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99545) BLE_HEART_RATE:     event nor handled\nV (99755) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99755) BLE_HEART_RATE:     event nor handled```\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_out-displayonly\">ESP_IO_CAP_OUT (DisplayOnly)</h1>\n<p>表示機器のみ必要。<br />\n自分が指定するpasskeyをコンソール等に表示し、相手側(ホスト)にpasskey(PINcode)入力させる。</p>\n\n<p>passkeyは<code class=\"language-plaintext highlighter-rouge\">esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, ~);</code>で設定するので、<br />\n必ず表示しなくてはいけない、ということはない(BTヘッドフォンなどでマニュアルに「0000を入力」などと書かれているのと同じ)。</p>\n\n<p>相手側には入力手段が必須。</p>\n\n<p>GAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:               // passkey通知要求イベント\n        // 自身がDisplayOnly(ESP_IO_CAP_OUT)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_PASSKEY_NOTIF_EVT ====\");\n        // passkeyの表示\n        printf(\"**** The passkey Notify number:%06d\\n\", param->ble_security.key_notif.passkey);\n        break;\n</code></pre></div></div>\n\n<p>相手側で入力されたpasskeyが正しければ鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (17105) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (17105) BLE_HEART_RATE:     connection start\nV (17775) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17775) BLE_HEART_RATE:     event nor handled\nV (18025) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (18025) BLE_HEART_RATE:     event nor handled\nV (21935) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_PASSKEY_NOTIF_EVT(11)\nI (21935) BLE_HEART_RATE:     ==== ESP_GAP_BLE_PASSKEY_NOTIF_EVT ====\n**** The passkey Notify number:123456                     ← 相手側にこのpasskeyを入力\nV (22185) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (22185) BLE_HEART_RATE:     event nor handled\nW (33505) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (33535) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33535) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (33535) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33535) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (33545) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33545) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (33575) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33575) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (33575) nvs: nvs_open_from_partition bt_config.conf 1\nD (33575) nvs: nvs_set_blob bt_cfg_key0 250\nD (33595) nvs: nvs_close 4\nD (33595) nvs: nvs_open_from_partition bt_config.conf 1\nD (33595) nvs: nvs_set_blob bt_cfg_key0 264\nD (33605) nvs: nvs_close 5\nD (33605) nvs: nvs_open_from_partition bt_config.conf 1\nD (33605) nvs: nvs_set_blob bt_cfg_key0 347\nD (33625) nvs: nvs_close 6\nD (33625) nvs: nvs_open_from_partition bt_config.conf 1\nD (33625) nvs: nvs_set_blob bt_cfg_key0 407\nD (33625) nvs: nvs_close 7\nD (33625) nvs: nvs_open_from_partition bt_config.conf 1\nD (33635) nvs: nvs_set_blob bt_cfg_key0 462\nD (33635) nvs: nvs_close 8\nD (33645) nvs: nvs_open_from_partition bt_config.conf 1\nD (33645) nvs: nvs_set_blob bt_cfg_key0 476\nD (33655) nvs: nvs_close 9\nV (33655) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (33655) BLE_HEART_RATE:     remote BD_ADDR: 786562f732fc\nI (33655) BLE_HEART_RATE:     address type = 1\nI (33665) BLE_HEART_RATE:     pair status = success\nI (33665) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (33675) BLE_HEART_RATE:     Bonded devices number : 1\nI (33675) BLE_HEART_RATE:     Bonded devices list :\nI (33685) BLE_HEART_RATE:        0 :   78:65:62:f7:32:fc\nV (34185) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34185) BLE_HEART_RATE:     event nor handled\nV (34695) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34695) BLE_HEART_RATE:     event nor handled\nV (34885) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34885) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<p>passkeyを間違えると当然接続されない。<br />\n接続が成功したかどうかは、ログの以下の部分で判別できる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (27095) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (27095) BLE_HEART_RATE:     remote BD_ADDR: 67c015dc4505\nI (27105) BLE_HEART_RATE:     address type = 1\nI (27105) BLE_HEART_RATE:     pair status = fail            ← failしている\nI (27115) BLE_HEART_RATE:     reason = 0x51                 ← 失敗した原因だけど、ドキュメントがない...\nI (27115) BLE_HEART_RATE:     Bonded devices number : 0\nI (27125) BLE_HEART_RATE:     Bonded devices list :\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_in--keyboardonly\">ESP_IO_CAP_IN  (KeyboardOnly)</h1>\n<p>入力機器のみ必要。<br />\n相手側に表示されたpasskeyをコンソール等から入力する。</p>\n\n<p>passkeyは相手側から指定される値なので、どのような値かは相手の仕様による。<br />\n相手側には表示手段が必須。</p>\n\n<p>GAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_PASSKEY_REQ_EVT:                 // passkey 要求\n        // KeyboardOnly(ESP_IO_CAP_IN)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_PASSKEY_REQ_EVT ====\");\n        // 以下の関数で相手側に表示されたパスキーを返す\n        uint32_t    passkey;\n        char        passkey_buff[16];\n        int         passkey_len;\n        do {\n            printf(\"**** input paskey : \");\n            fflush(stdout);\n            passkey_len = uart_gets(passkey_buff, sizeof(passkey_buff));\n        } while (passkey_len == 0);\n        passkey = (uint32_t)strtol(passkey_buff, NULL, 10);\n        esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, passkey);\n        break;\n</code></pre></div></div>\n\n<p>passkeyに使用している<code class=\"language-plaintext highlighter-rouge\">uart_gets()</code>関数については後述。</p>\n\n<p>入力したpasskeyが正しければ鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (16805) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (16805) BLE_HEART_RATE:     connection start\nV (17425) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17425) BLE_HEART_RATE:     event nor handled\nV (17675) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17685) BLE_HEART_RATE:     event nor handled\nE (20765) BT_BTM: btm_ble_remove_resolving_list_entry_complete remove resolving list error 0x2\nV (20955) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_PASSKEY_REQ_EVT(12)\nI (20955) BLE_HEART_RATE:     ==== ESP_GAP_BLE_PASSKEY_REQ_EVT ====\n**** input paskey : 047528                                  ← 相手側で表示されているpasskeyを入力\nV (36455) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (36455) BLE_HEART_RATE:     event nor handled\nW (37335) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (37375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37375) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (37375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37375) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (37385) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37385) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (37405) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37405) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (37415) nvs: nvs_open_from_partition bt_config.conf 1\nD (37415) nvs: nvs_set_blob bt_cfg_key0 476\nD (37425) nvs: nvs_close 4\nD (37425) nvs: nvs_open_from_partition bt_config.conf 1\nD (37425) nvs: nvs_set_blob bt_cfg_key0 476\nD (37495) nvs: nvs_close 5\nD (37495) nvs: nvs_open_from_partition bt_config.conf 1\nD (37495) nvs: nvs_set_blob bt_cfg_key0 476\nD (37505) nvs: nvs_close 6\nD (37505) nvs: nvs_open_from_partition bt_config.conf 1\nD (37505) nvs: nvs_set_blob bt_cfg_key0 476\nD (37525) nvs: nvs_close 7\nD (37525) nvs: nvs_open_from_partition bt_config.conf 1\nD (37525) nvs: nvs_set_blob bt_cfg_key0 476\nD (37525) nvs: nvs_close 8\nV (37525) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (37535) BLE_HEART_RATE:     remote BD_ADDR: 786562f732fc\nI (37535) BLE_HEART_RATE:     address type = 1\nI (37545) BLE_HEART_RATE:     pair status = success\nI (37545) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (37555) BLE_HEART_RATE:     Bonded devices number : 1\nI (37555) BLE_HEART_RATE:     Bonded devices list :\nI (37565) BLE_HEART_RATE:        0 :   78:65:62:f7:32:fc\nV (38255) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (38255) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<p>passkeyを間違えたときの動作は <code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_OUT</code>(DisplayOnly)の場合と同様。</p>\n\n<h1 id=\"esp_io_cap_io-displayyesno\">ESP_IO_CAP_IO (DisplayYesNo)</h1>\n<p>入力機器/表示機器 両方必要。</p>\n\n<p>相手側に表示されたpasskeyとコンソールに表示されたpasskeyを目視確認して等しければyを入力し、相手側でも接続許可をタップする。\n確認せずにYesを選択しても良いけど、それならこのモードを指定する必要はないでしょう。</p>\n\n<p>相手側にも入力/表示手段が必須。<br />\nGAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_NC_REQ_EVT:                      // 数値比較リクエスト イベント\n        // DisplayYesNo(ESP_IO_CAP_IO)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_NC_REQ_EVT ====\");\n        printf(\"**** the passkey Notify number:%d\\n\", param->ble_security.key_notif.passkey);\n        printf(\"**** Accept? (y/n) : \");\n        fflush(stdout);\n        int kb_key = uart_getchar();\n        printf(\"%c\\n\", kb_key);\n        if (kb_key == 'y' || kb_key == 'Y') {\n            // 接続受け入れ\n            esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true);\n        }\n        else {\n            // 接続拒否\n            esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, false);\n        }\n        break;\n</code></pre></div></div>\n\n<p>両方でyesを選択すれば鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (14185) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (14185) BLE_HEART_RATE:     connection start\nV (14855) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (14855) BLE_HEART_RATE:     event nor handled\nV (15145) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (15145) BLE_HEART_RATE:     event nor handled\nE (18775) BT_SMP: Value for numeric comparison = 260195\nV (18775) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_NC_REQ_EVT(16)\nI (18775) BLE_HEART_RATE:     ==== ESP_GAP_BLE_NC_REQ_EVT ====\n**** the passkey Notify number:260195                                               ← 相手側で表示されている数値と目視比較\n**** Accept? (y/n) : y                                                              ← y 入力、相手側でもyesクリック\nV (26785) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (26785) BLE_HEART_RATE:     event nor handled\nW (28245) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (28275) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28275) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (28275) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28285) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (28285) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28295) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (28305) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28305) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (28315) nvs: nvs_open_from_partition bt_config.conf 1\nD (28315) nvs: nvs_set_blob bt_cfg_key0 250\nD (28325) nvs: nvs_close 4\nD (28325) nvs: nvs_open_from_partition bt_config.conf 1\nD (28325) nvs: nvs_set_blob bt_cfg_key0 264\nD (28335) nvs: nvs_close 5\nD (28335) nvs: nvs_open_from_partition bt_config.conf 1\nD (28335) nvs: nvs_set_blob bt_cfg_key0 347\nD (28355) nvs: nvs_close 6\nD (28355) nvs: nvs_open_from_partition bt_config.conf 1\nD (28355) nvs: nvs_set_blob bt_cfg_key0 407\nD (28365) nvs: nvs_close 7\nD (28365) nvs: nvs_open_from_partition bt_config.conf 1\nD (28365) nvs: nvs_set_blob bt_cfg_key0 462\nD (28385) nvs: nvs_close 8\nD (28385) nvs: nvs_open_from_partition bt_config.conf 1\nD (28385) nvs: nvs_set_blob bt_cfg_key0 476\nD (28395) nvs: nvs_close 9\nV (28395) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (28395) BLE_HEART_RATE:     remote BD_ADDR: 612610f26701\nI (28395) BLE_HEART_RATE:     address type = 1\nI (28405) BLE_HEART_RATE:     pair status = success\nI (28405) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (28415) BLE_HEART_RATE:     Bonded devices number : 1\nI (28415) BLE_HEART_RATE:     Bonded devices list :\nI (28425) BLE_HEART_RATE:        0 :   61:26:10:f2:67:01\nV (28905) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (28905) BLE_HEART_RATE:     event nor handled\nV (29435) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (29435) BLE_HEART_RATE:     event nor handled\nV (29655) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (29655) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_kbdisp-keyboard-display\">ESP_IO_CAP_KBDISP (Keyboard display)</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_OUT</code>(DisplayOnly) と <code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_IN</code>(KeyboardOnly) の合わせ技かと思いきや、<br />\n<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_IO</code>(DisplayYesNo)と同じ動作。<br />\nたしかにキーボードと表示両方必要だわな。。。</p>\n\n<h1 id=\"コンソール入力ルーチン\">コンソール入力ルーチン</h1>\n<p>passkeyの入力など、コンソールからの入力が必要な場合、<code class=\"language-plaintext highlighter-rouge\">gets()</code>などを使用するとキー入力待ちの間タスク切り替えが行われずに他のタスクが動作できない。<br />\n(esp-idfはFreeRTOSを使用したマルチタスク構成)。\nそこで、<code class=\"language-plaintext highlighter-rouge\">gets()</code>/<code class=\"language-plaintext highlighter-rouge\">getchar()</code>の代わりとなる関数を用意した。<br />\n動作としては、キー入力待ちの少しの間、<code class=\"language-plaintext highlighter-rouge\">vTaskDelay()</code>でCPUを解放して他のタスクの動作を阻害しないようにしている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">uart_checkkey()</code>は今回使ってないけど、〇秒以内に入力がなければデフォルトで動作、のような動作を実現するのに使用する関数。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">printf()</code>もあちこちのタスクから出力する場合はセマフォで排他処理した方が良いけど、今回は特に問題になりそうにないのでそのまま使用。</p>\n\n<p>Buildは これらのファイルをsrcディレクトリにぶち込むだけでOK。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  uart_console.h\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#include    <stdio.h>\n#include    <stdint.h>\n#include    <stdbool.h>\n\nextern bool uart_checkkey(int loop_num);\nextern int uart_getchar(void);\nextern int uart_gets(char* buf, int max);\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  uart_console.c\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#include    <stdio.h>\n#include    <stdint.h>\n#include    <stdbool.h>\n#include    <string.h>\n#include    <stdarg.h>\n\n#include    \"freertos/FreeRTOS.h\"\n#include    \"freertos/task.h\"\n#include    \"esp_system.h\"\n#include    \"rom/uart.h\"\n\n#include    \"uart_console.h\"\n\n// ========= UARTからの入力待ち ===============================================\n// param    loop_num: 待ち時間(単位100msec)\n// return   true: キー入力があった     false: キー入力はなかった\nbool uart_checkkey(int loop_num)\n{\n    bool    ret = false;\n    uint8_t ch;\n     for (int loop_cnt = 0; loop_cnt < loop_num; loop_cnt++) {\n        // UARTから1文字取得\n        if (uart_rx_one_char(&ch) == OK) {\n            // 入力あり\n            ret = true;\n            break;\n        }\n        if ((loop_cnt % 5)== 0) {\n            // たくさん出ると鬱陶しいので5回毎に\n            putchar('.');\n            fflush(stdout);\n        }\n        // 100ms待つ\n        vTaskDelay(100 / portTICK_RATE_MS);\n    }\n    putchar('\\n');\n\n    // バッファにたまっているデータを読み捨てる\n    while (uart_rx_one_char(&ch) == OK);\n    return ret;\n}\n\n\n// ========= UARTから1文字取得 ================================================\n// param    なし\n// return   文字コード\n// note     CRは無視するので注意\nint uart_getchar(void)\n{\n    uint8_t ch;\n    while (1) {\n        // UARTから1文字取得\n        if (uart_rx_one_char(&ch) == OK) {\n            // 入力あり\n            if (ch == '\\r') {\n                // CRなら次の値を取得\n                continue;\n            }\n            // 入力された値を返す\n            return ch;\n        }\n        // 100ms待つ(CPUを握りっぱなしにしないように)\n        vTaskDelay(100 / portTICK_RATE_MS);\n    }\n}\n\n// ========= UARTから1行取得 ===================================================\n// param    buf: 文字列格納領域へのポインタ\n//          max: 最大文字列長\n// return   入力された文字列長\nint uart_gets(char* buf, int max)\n{\n    int     i = 0;\n    while (i < (max - 1)) {     // null terminate の分を空けておくので max - 1\n        char ch = uart_getchar();\n        if (ch == '\\n') {\n            // LFで終了\n            putchar(ch);\n            fflush(stdout);\n            break;\n        }\n        if (ch == '\\b' || ch == 0x7f) {     // BackSpace or DEL\n            if (i > 0) {        // 先頭でない\n                i--;            // ポインタを一つ前に\n                putchar('\\b');  // 前の文字の表示を削除\n                putchar(' ');\n                putchar('\\b');\n                fflush(stdout);\n            }\n        }\n        else {\n            // それ以外の文字はバッファに格納\n            buf[i] = ch;\n            i++;\n            putchar(ch);        // 表示\n            fflush(stdout);\n        }\n    }\n    buf[i] = '\\0';          // null terminate\n    return i;\n}\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でBLEのデモを動かす</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でBLEのデモを動かす</h1>\n      <p>ESP32にBLEのデモを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>gistにupしたので、gistの埋め込みリンク貼っとく(コードをコピペするのめんどくさかったから)。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/3719faf64374d438fd879ce567becb4b\" target=\"_blank\">こちら</a> \nからどうぞ。</p>\n\n<script src=\"https://gist.github.com/ippei8jp/3719faf64374d438fd879ce567becb4b.js\"></script>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でJTAGデバッグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でJTAGデバッグ</h1>\n      <p>ESP32にFT232Hを接続してJTAGデバッグしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>ESP32のデフォルトの開発環境だと、シリアル通信でFlash書き込んで、<br />\nせいぜいprintfデバッグするしかないが、<br />\nJTAG接続でオンチップデバッグ機能を使えば、もっと使いやすくなるはず。</p>\n\n<p>ESP32のボードは<a href=\"https://www.espressif.com/en/products/devkits/esp32-devkitc\" target=\"_blank\">ESP32-DevKitC-VE</a>\n(<a href=\"https://www.espressif.com/sites/default/files/documentation/esp32-wrover-e_esp32-wrover-ie_datasheet_en.pdf\" target=\"_blank\">ESP32-WROVER-E</a>搭載)\nを使用。</p>\n\n<p>JTAGコントローラは<a href=\"https://ftdichip.com/products/ft232hl/\" target=\"_blank\">FTDIのFT232HL</a>を使用した\n<a href=\"https://akizukidenshi.com/catalog/g/gK-06503/\" target=\"_blank\">秋月電子のAE-FT232HL</a>を使用する(安価なので)。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://www.sunhayato.co.jp/material2/ett09/item_759\" target=\"_blank\">サンハヤトのMM-FT232H</a>\nが拡張コネクタが付いてて使いやすそうなんだけど、お値段かなりお高め…orz…</p>\n</blockquote>\n\n<p>IDEは以前はEclipse一択だったけど、最近はVisual Studio Code に拡張機能<a href=\"https://platformio.org/\" target=\"_blank\">PlatformIO</a>を使うのが\n流行ってるみたいなので、こっちを選択。<br />\nもう Visual Studio Code 最強だな…</p>\n\n<h1 id=\"まずはチュートリアルに沿って試してみる\">まずはチュートリアルに沿って試してみる</h1>\n\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html\" target=\"_blank\">PlatformIOの公式チュートリアル</a>に沿ってツールのインストール~JTAGを使用しないプログラムの書き込み、実行を試す。</p>\n\n<p>まずはツールとボードの動作確認ということで、まだJTAGモジュールは接続しない。</p>\n\n<h2 id=\"ツールのインストール\">ツールのインストール</h2>\n<p>これは上記ページには書いてないので、こっちを参照(Visual Studio Codeインストール済みなら参照するまでもないけど。)<br />\n<a href=\"https://kunsen.net/2018/07/28/post-618/\" target=\"_blank\">薫染庵 途上日誌 PlatformIO IDE for VSCode でESP32のプログラム開発</a><br />\n「3 ESP32プロジェクト作成」の手前まで(以降の説明はarduinoプロジェクトなので)。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPlatformIOのインストールには結構時間がかかる(数分くらい)。 \n右下に出るinstalling~のウィンドウが見難いので「ハングアップした~」と焦って強制終了しないように注意。</p>\n</blockquote>\n\n<h2 id=\"プロジェクトの作成\">プロジェクトの作成</h2>\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#setting-up-the-project\" target=\"_blank\">公式チュートリアルのSetting Up the Project</a>\nに従ってプロジェクトを作成。</p>\n<ul>\n  <li>Nameにプロジェクト名を設定</li>\n  <li>Boardで<code class=\"language-plaintext highlighter-rouge\">Espressif ESP32 Dev Module</code>を選択</li>\n  <li>Frameworkで<code class=\"language-plaintext highlighter-rouge\">Espressif IoT Development Framework</code>を選択(ESP-IDF)</li>\n  <li>Project Wizardの一番下、Locationのチェックをはずすとフォルダを選択できる<br />\nここで指定したフォルダの下にNameで設定した名前のフォルダが作られる<br />\nチェックしたままだと<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%\\Documents\\PlatformIO\\Projects\\</code>に作成されるらしい</li>\n  <li>「このフォルダーないのファイルの作成者を信頼しますか?」と聞かれたら、「はい」を選択</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\n初回のみ、プロジェクトを作成すると、自動でESP-IDFがインストールされる。<br />\n環境にもよるけど、15分とかのオーダで覚悟してちょ。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nESP-IDFのインストールにはpythonが必要だが、platformioが自前で持っているのでインストールしなくても大丈夫っぽい。<br />\ngitはインストールしとかないとダメなのかな?なくても大丈夫な気もするけどわからん。</p>\n</blockquote>\n\n<h2 id=\"iniファイルの修正\">iniファイルの修正</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">platformio.ini</code>に<code class=\"language-plaintext highlighter-rouge\">monitor_speed = 115200</code>の1行を追加<br />\n最終的なの内容は以下の通り。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = espidf\nmonitor_speed = 115200\n</code></pre></div></div>\n\n<h2 id=\"ソースコードの追加\">ソースコードの追加</h2>\n<p><a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#adding-code-to-the-generated-project\" target=\"_blank\">公式チュートリアルのAdding Code to the Generated Project</a>\nにあるソースを<code class=\"language-plaintext highlighter-rouge\">src\\main.c</code>にコピペする</p>\n\n<blockquote>\n  <p>[!NOTE]\nCMakeLists.txtがどーたらこーたらとwarningが書いてあるけど、無視して良い。<br />\nバージョン変わってちょっと書き方変わったらしい。</p>\n</blockquote>\n\n<p>そのままでも無問題だけど、以下のパッチをあてておくと LEDがチカチカして かつ コンソールにカウント値が表示されるので、\nプログラムが動いてることが一目瞭然。<br />\n(もちろん、IO26端子にLEDを接続しておかないと見えないよ。端子変えるなら<code class=\"language-plaintext highlighter-rouge\">GPIO_NUM_26</code>の部分(2か所)を適当に変更してちょ。)</p>\n\n<p>あと、<code class=\"language-plaintext highlighter-rouge\">tcpip_adapter_init()</code>が非推奨だとワーニングがでるので、<code class=\"language-plaintext highlighter-rouge\">esp_netif_init()</code>に変更してある。<br />\n参考:<a href=\"https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/tcpip_adapter_migration.html\">https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/tcpip_adapter_migration.html</a></p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- main.c.org  2021-12-26 11:13:05.474815000 +0900\n</span><span class=\"gi\">+++ main.c      2021-12-26 11:12:42.842345600 +0900\n</span><span class=\"p\">@@ -18,6 +18,9 @@</span>\n #include \"lwip/err.h\"\n #include \"lwip/sys.h\"\n\n+#include       <stdio.h>\n<span class=\"gi\">+#include \"driver/gpio.h\"\n+\n</span> #define EXAMPLE_ESP_WIFI_SSID      \"mywifissid\"\n #define EXAMPLE_ESP_WIFI_PASS      \"mywifipass\"\n #define EXAMPLE_MAX_STA_CONN       (3)\n<span class=\"p\">@@ -40,7 +43,7 @@</span>\n\n void wifi_init_softap()\n {\n<span class=\"gd\">-    tcpip_adapter_init();\n</span><span class=\"gi\">+    esp_netif_init();\n</span>     ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();\n<span class=\"p\">@@ -81,4 +84,14 @@</span>\n\n     ESP_LOGI(TAG, \"ESP_WIFI_MODE_AP\");\n     wifi_init_softap();\n<span class=\"gi\">+\n+    gpio_set_direction(GPIO_NUM_26, GPIO_MODE_OUTPUT);\n+    int level = 0;\n+    int count = 0;\n+    while (true) {\n+        gpio_set_level(GPIO_NUM_26, level);\n+        level = !level;\n+        printf(\"count=%d\\n\", count++);\n+        vTaskDelay(300 / portTICK_PERIOD_MS);\n+    }\n</span> }\n</code></pre></div></div>\n\n<h2 id=\"ビルド\">ビルド</h2>\n<p>ビルド実行方法色々書いてあるけど、お好きな方法でどうぞ。<br />\n初回はライブラリもビルドするので時間がかかる。<br />\n(<code class=\"language-plaintext highlighter-rouge\">platform.ini</code>修正時も?)</p>\n\n<p>ターミナルに<code class=\"language-plaintext highlighter-rouge\">SUCCESS</code>と出てるのを確認して次へ。</p>\n\n<p>ターミナルの内容確認して不要になったら何かキーを押すと閉じられる。</p>\n\n<h2 id=\"ターゲットプログラムのダウンロード\">ターゲットプログラムのダウンロード</h2>\n<p>チュートリアルページにはuploadって書いてあるけど、普通はdownloadだと思うんだけど…<br />\nこれもお好きな方法でどうぞ。</p>\n\n<h2 id=\"実行状況の確認\">実行状況の確認</h2>\n<p>シリアルモニタでコンソール入出力を確認できる。<br />\nこれも起動方法はお好きな方法でどうぞ。</p>\n\n<p>うまく動いてたら、スマホやタブレットでWi-Fiスキャンすると「mywifissid」というSSIDが見つかるはず。<br />\n接続してもつながらないけど、なんか接続要求を受けたのがコンソールに表示されるみたい。</p>\n\n<h1 id=\"jtagデバッガを使用したデバッグ\">JTAGデバッガを使用したデバッグ</h1>\n<p>PlatformIOとESP32の動作が確認できたので、次はJTAGデバッガ。<br />\n念のため、cleanしてbuildファイルを一度消しておくのが良いかもしれない。</p>\n\n<p>でも、公式チュートリアルの<a href=\"https://docs.platformio.org/en/latest/tutorials/espressif32/espidf_debugging_unit_testing_analysis.html#debugging-the-firmware\" target=\"_blank\">Debugging the Firmware</a> \n以降は <a href=\"https://www.olimex.com/Products/ARM/JTAG/ARM-USB-OCD-H/\" target=\"_blank\">OLIMEXのARM-USB-OCD-H</a>\nを使用することが前提なので、今回は参照しない。</p>\n\n<p>代わりに<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h\" target=\"_blank\">Long-ship ESP32をPlatformIO上でJTAG(FT232H)デバッグする</a>を参照。<br />\n(でも、微妙に異なるのでちょっと補足書いとく)<br />\n<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc7\" target=\"_blank\">事前準備(自動書き込み)</a>までは上記で済んでいるのでスキップ。</p>\n\n<h2 id=\"ドライバの更新\">ドライバの更新</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc8\" target=\"_blank\">ドライバ更新</a>\nにあるように、ドライバの更新をする。</p>\n\n<p>ドライバ更新の詳しい手順は<a href=\"https://www.m-kobayashi.org/working_log/2018/06/10_01.html\" target=\"_blank\">ESP32で遊ぶ 開発環境を作る (4)</a>の「FT232HL のドライバをインストール」あたりを参照すると分かりやすい。</p>\n\n<p>最初に PCにFT232Hを接続しておくことを忘れないように。<br />\nツールは、<a href=\"https://zadig.akeo.ie/\" target=\"_blank\">Zadigのページ </a>のダウンロードからダウンロード。2021/12/23現在の最新は2.7。<br />\nメニューのoptions→ListAllDevices をやるのを忘れずに(忘れると表示されなくて「あれ?」となります(^^ゞ ) <br />\n対象のデバイスを見つけやすいように、不要なUSBデバイス(特に他のFTDIデバイス)は取り外しておいた方がいいかも。</p>\n\n<p>これは最初に1回やればOK</p>\n\n<h2 id=\"esp32とft232hの結線\">ESP32とFT232Hの結線</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc9\" target=\"_blank\">結線</a>の記載とは\nボードが異なるので、ボードのコネクタ名を含めて結線情報を掲載しておく。<br />\n以下の端子を結線する。</p>\n\n<table style=\"width:400px;\" border=\"3\">\n  <tbody>\n    <tr bgcolor=\"#ff7f7f\">\n      <th colspan=\"2\" width=\"50%\"><strong>FT232H</strong></th>\n      <th colspan=\"2\"><strong>ESP32</strong></th>\n    </tr>\n    <tr>\n      <td width=\"25%\">AD0(TxD)</td><td>J2-7</td>\n      <td width=\"25%\">IO13</td><td>J1-15</td>\n    </tr>\n    <tr>\n      <td>AD1(RxD)</td><td>J2-8</td>\n      <td>IO12</td><td>J1-13</td>\n    </tr>\n    <tr>\n      <td>AD2(RTS#)</td><td>J2-9</td>\n      <td>IO15</td><td>J2-17</td>\n    </tr>\n    <tr>\n      <td>AD3(CTS#)</td><td>J2-10</td>\n      <td>GPIO14</td><td>J3-12</td>\n    </tr>\n    <tr>\n      <td>AD5</td><td>J2-12</td>\n      <td>EN</td><td>J1-2</td>\n    </tr>\n    <tr>\n      <td>GND</td><td>J1-1</td>\n      <td>GND</td><td>J3-1</td>\n    </tr>\n  </tbody>\n</table>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc9\" target=\"_blank\">結線</a>には<br />\nAC1-EN結線と書いてあるけど、<br />\n設定値から判断してAD5-EN結線と思われる。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://www.m-kobayashi.org/working_log/2018/06/10_01.html\" target=\"_blank\">ESP32で遊ぶ 開発環境を作る (4)</a>には<br />\nENの結線書いてないけど、結線なくても動くらしい。<br />\nRESET信号がJTAG側から入るのかな?</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nespressifのページによると、sRSTはオプションで繋いでも対応してるコンフィギュレーションが少ないと書いてある。<br />\nでも、CH_PDってどこやねん?<br />\n<a href=\"https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html#jtag-debugging-selecting-jtag-adapter\">https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html#jtag-debugging-selecting-jtag-adapter</a></p>\n</blockquote>\n\n<h2 id=\"iniファイルの修正-1\">iniファイルの修正</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">platformio.ini</code>に<code class=\"language-plaintext highlighter-rouge\">debug_tool = minimodule</code>の1行を追加<br />\n最終的なの内容は以下の通り。<br />\nこれはプロジェクト毎に必要。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = espidf\nmonitor_speed = 115200\ndebug_tool = minimodule\n</code></pre></div></div>\n<h2 id=\"minimoduleの設定変更\">minimoduleの設定変更</h2>\n<p><a href=\"https://lang-ship.com/blog/program/esp32-platformio-jtag-ft232h/#toc11\" target=\"_blank\">minimoduleの設定変更</a> のように以下のパッチでファイル修正<br />\n(コメントは変えなくても良いけど、あとで参照して分からなくなるので変更しておく)</p>\n\n<blockquote>\n  <p>[!WARNING]\nこの段階では<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%.platformio\\packages\\tool-openocd-esp32\\</code>ディレクトリがまだない(ダウウンロードされていない)ので、<br />\n一度、Visual Studio Codeのデバッグサイドバーを開き、デバッグターゲットに「PIO Debug」を選択し、実行ボタン(三角アイコン)をクリック<br />\nコンパイルが行われたあと、デバッガプログラムをダウンロードし、起動される。<br />\nデバッガの起動でエラー(<code class=\"language-plaintext highlighter-rouge\">no device found</code>)になるので、一旦キャンセルし、以下の修正を行う。</p>\n</blockquote>\n\n<p>修正するファイル:<br />\n<code class=\"language-plaintext highlighter-rouge\">%HOMEPATH%.platformio\\packages\\tool-openocd-esp32\\share\\openocd\\scripts\\interface\\ftdi\\minimodule.cfg</code></p>\n\n<p>変更内容は、ディスクリプタとPID(FT2232H→FT232H)。<br />\n変更後、Visual Studio Codeの再起動必要。<br />\nこれは最初に1回やればOK</p>\n\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- minimodule.cfg.org  2021-07-21 22:38:02.000000000 +0900\n</span><span class=\"gi\">+++ minimodule.cfg      2021-12-26 13:09:51.740579600 +0900\n</span><span class=\"p\">@@ -1,16 +1,16 @@</span>\n #\n<span class=\"gd\">-# FTDI MiniModule\n</span><span class=\"gi\">+# Akizuki AE-FT232HL(FTDI FT232HL)\n</span> #\n<span class=\"gd\">-# http://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT2232H_Mini_Module.pdf\n</span><span class=\"gi\">+# https://akizukidenshi.com/catalog/g/gK-06503/\n</span> #\n\n interface ftdi\n<span class=\"gd\">-ftdi_device_desc \"FT2232H MiniModule\"\n-ftdi_vid_pid 0x0403 0x6010\n</span><span class=\"gi\">+ftdi_device_desc \"Single RS232-HS\"\n+ftdi_vid_pid 0x0403 0x6014\n</span>\n # Every pin set as high impedance except TCK, TDI, TDO and TMS\n ftdi_layout_init 0x0008 0x000b\n\n-# nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip)\n<span class=\"gi\">+# nSRST defined on pin J2-12 of AE-FT232HL(pin ADBUS5 [AD5] on the FT232HL chip)\n</span> # This choice is arbitrary. Use other GPIO pin if desired.\n ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n好きなツール名を付けれれば良いんだけど、できないみたいなので一番近いものを修正して使用するということらしい。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">ftdi_layout_signal</code>の設定値を変えればESP32のEN端子に接続するFT232Hの端子を変更できるはずだけど試してない。<br />\nたぶん、値の意味はbit15から順に、 <code class=\"language-plaintext highlighter-rouge\">GPIOH7</code>、<code class=\"language-plaintext highlighter-rouge\">GPIOH6</code>、・・・、<code class=\"language-plaintext highlighter-rouge\">GPIOH0</code>、<code class=\"language-plaintext highlighter-rouge\">GPIOL3</code>、・・・、<code class=\"language-plaintext highlighter-rouge\">GPIOL0</code>、\n<code class=\"language-plaintext highlighter-rouge\">TMS/CS</code>、<code class=\"language-plaintext highlighter-rouge\">TDO/DI</code>、<code class=\"language-plaintext highlighter-rouge\">TDI/DO</code>、<code class=\"language-plaintext highlighter-rouge\">TCK/SK</code>に割り当てられていて、それらの端子は<code class=\"language-plaintext highlighter-rouge\">AC7</code>~<code class=\"language-plaintext highlighter-rouge\">AC0</code>、<code class=\"language-plaintext highlighter-rouge\">AD7</code>~<code class=\"language-plaintext highlighter-rouge\">AD0</code>にあたるものと思われる。<br />\n<a href=\"https://ftdichip.com/wp-content/uploads/2020/08/DS_FT232H.pdf\" target=\"_blank\">https://ftdichip.com/wp-content/uploads/2020/08/DS_FT232H.pdf</a> の「3.2 FT232H Pin Description」の表の\nMPSSEの桁を参照。<br />\nよって、<code class=\"language-plaintext highlighter-rouge\">ftdi_layout_signal</code>の設定値<code class=\"language-plaintext highlighter-rouge\">0x80</code>はAD5端子にあたると推測できる。<br />\nでも、つながなくても動いてるなぁ… 🤔</p>\n</blockquote>\n\n<h2 id=\"デバッグ\">デバッグ</h2>\n<p>Visual Studio Codeのデバッグサイドバーを開き、デバッグターゲットに「PIO Debug」を選択し、実行ボタン(三角アイコン)をクリックすると\nターゲットの依存関係にしたがってbuildを行い、ダウンロード、実行(<code class=\"language-plaintext highlighter-rouge\">app_main()</code>の先頭で一旦停止)を行う。<br />\nなお、デバッグターゲットに「PIO Debug (skip Pre-Debug)」だと、buildは行わず ダウンロード~のみ行う。\n「PIO Debug (without uploading)」ダウンロードも行わず、実行のみ。<br />\n通常は「PIO Debug」を選んでおけば問題ない。</p>\n\n<p>変数の確認やブレークポイントの設定、実行制御(go, step over, step in,…)などは他の環境と大差ない。 <br />\nレジスタダンプも動いてるっぽい。<br />\nコールスタックも動いてるっぽい。<br />\nメモリと逆アセンブルは動かし方分からんかった…</p>\n\n<blockquote>\n  <p>[!NOTE]\nコンソール入出力もVSCodeで上記のシリアルモニタ起動で送受信を行うことができるが、<br />\n外部ツール(TeraTermなど)でモニタすることが可能。<br />\nFlashの書き換えがJTAG経由なので、シリアルポートを他のツールがつかんだままでも大丈夫みたい。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!WARNING]\nプログラムを実行すると、コンソールに<code class=\"language-plaintext highlighter-rouge\">Brownout detector was triggered</code>と表示されてリセットを繰り返すことがある。<br />\nこれは、電圧低下を検出したことによるfail safeのリセット動作らしい。<br />\nWi-Fiを有効化したとき、モジュールに流れる電流が10mA程度→100~200mA程度(実測値)に上がる。<br />\nモジュールを接続しているUSB Hubにたくさんのデバイスを接続していると、電流を確保できなくなって 電圧が低下することがある模様。<br />\nこの場合、USB Hubに接続されている他のデバイスを取り外すか、セルフパワードHubに交換すると正常に動作するようになる。 <br />\nあと、使用するUSBケーブルのインピーダンスが大きいと電流増加で電圧が低下するので、大電流対応のUSBケーブルを使用しましょう。</p>\n\n</blockquote>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "BLE": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>AndroidでpythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>AndroidでpythonでBLE</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerでBLE通信アプリを作ってみたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2025/04/04/Buildozer_2.html\">Buildozerでブロック崩しを作る</a>ではゲームを作ってみたが、次はペリフェラルを使ってみたくなるのが人情というもの。<br />\n<a href=\"https://bleak.readthedocs.io/en/latest/\" target=\"_blank\">Bleak</a>というモジュールがクロスプラットフォームでAndroidでも使えるらしい。<br />\nということで、Bleakを使ってBLEを使用するアプリを作って、それをBuildozerでAndroidアプリ化してみる。</p>\n\n<p>以下、<a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>での環境構築が終わっているものとして進める。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>これまで使用してきたWSL環境だとBluetoothが使用できないので、開発にはRaspberryPi5を使用することにした(Pi3以降なら大丈夫だと思う)。<br />\npyenvで仮想環境作ってkivyとbleakをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<h1 id=\"通信相手の準備\">通信相手の準備</h1>\n<p>通信相手は前に作ったランダム値を送るペリフェラルを使った。<br />\n<a href=\"https://github.com/ippei8jp/MultiBLE/tree/main/micropython\" target=\"_blank\">ここ</a>のble_RandomSensor3.py を\nRascberryPi PICO や ESP32 の micropython で動かしておく。</p>\n\n<p>micropythoの使い方は以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは下の「開く」をクリックすると表示されます。<br />\nダウンロードする場合は<a href=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1\" target=\"_blank\">こちら</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nimportしている<code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>は\n<a href=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7\" target=\"_blank\">ここ</a>\nにあります。</p>\n</blockquote>\n\n<p>用意するファイルはこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── kivy_ble.py\n└── scrolllabel.py\n</code></pre></div></div>\n\n<p>↓をクリックするとソースが開きます。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1.js\"></script>\n</dev>\n\n<h1 id=\"raspberrypiで実行\">RaspberryPiで実行</h1>\n<p>まずはPythonスクリプトが動くことを確認するために、RaspBerryPiで動かしてみる。<br />\n通信相手がいないと動かないので、事前に上の通信相手を実行しておく。</p>\n\n<p>RaspberyPi上でkivy_ble.pyを実行するとウィンドウが開くので、connectボタンをクリックする。<br />\nペリフェラルをスキャンが開始され、最初に見つかったデバイスに接続される。<br />\nさらにDATA1とDATA2のNotifyハンドラが登録され、受信データがウィンドウ右上の表示領域に表示される。<br />\ndisconnectボタンをクリックすると切断される。<br />\nQUITボタンをクリックするとプログラム終了。<br />\nウィンドウ下半分のログ表示領域には情報が表示される。この領域はスクロール可能。</p>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>と同様の手順でAndroidアプリ化していく。</p>\n\n<h2 id=\"ファイルの準備\">ファイルの準備</h2>\n\n<ul>\n  <li>BuidozerがインストールされたWSLの仮想マシンに作業ディレクトリを作成</li>\n  <li>作業ディレクトリに 上で作成した<code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code> <code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>をコピー</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code>を <code class=\"language-plaintext highlighter-rouge\">main.py</code> にリネーム</li>\n  <li>RaspberryPiの≪Bleakインストール先≫>/bleak/backends/p4android/recipes を 作業ディレクトリにコピー(ディレクトリまるごと)\n    <blockquote>\n      <p>[!NOTE]\nBleakのインストール先ディレクトリは以下のコマンドで確認できます</p>\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"bleak \"</span>\n</code></pre></div>      </div>\n    </blockquote>\n  </li>\n</ul>\n\n<p>-または以下でもOK</p>\n<blockquote>\n  <p>[!NOTE]</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> recipes/bleak\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/__init__.py\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/fix_setup.py\n</code></pre></div>  </div>\n</blockquote>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer init</code> を実行して<code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>を生成する</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>に以下の修正を加える</li>\n</ul>\n\n<dev class=\"accordion_head\"></dev>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- buildozer.spec.org  2025-04-09 07:58:44.836709400 +0900\n</span><span class=\"gi\">+++ buildozer.spec      2025-04-17 08:12:06.676451390 +0900\n</span><span class=\"p\">@@ -1,10 +1,10 @@</span>\n [app]\n\n # (str) Title of your application\n<span class=\"gd\">-title = My Application\n</span><span class=\"gi\">+title = BLE Demo\n</span>\n # (str) Package name\n<span class=\"gd\">-package.name = myapp\n</span><span class=\"gi\">+package.name = bledemo\n</span>\n # (str) Package domain (needed for android/ios packaging)\n package.domain = org.test\n<span class=\"p\">@@ -22,7 +22,7 @@</span>\n #source.exclude_exts = spec\n\n # (list) List of directory to exclude (let empty to not exclude anything)\n<span class=\"gd\">-#source.exclude_dirs = tests, bin, venv\n</span><span class=\"gi\">+source.exclude_dirs = tests, bin, venv, recipes\n</span>\n # (list) List of exclusions using pattern matching\n # Do not prefix with './'\n<span class=\"p\">@@ -37,7 +37,13 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements =\n+    python3,\n+    kivy,\n+    bleak,\n+    typing_extensions,\n+    async_to_sync,\n+    async-timeout\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n<span class=\"p\">@@ -95,7 +101,14 @@</span>\n\n # (list) Permissions\n # (See https://python-for-android.readthedocs.io/en/latest/buildoptions/#build-options-1 for all the supported syntaxes and properties)\n<span class=\"gd\">-#android.permissions = android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)\n</span><span class=\"gi\">+android.permissions =\n+    BLUETOOTH,\n+    BLUETOOTH_SCAN,\n+    BLUETOOTH_CONNECT,\n+    BLUETOOTH_ADMIN,\n+    ACCESS_FINE_LOCATION,\n+    ACCESS_COARSE_LOCATION,\n+    ACCESS_BACKGROUND_LOCATION\n</span>\n # (list) features (adds uses-feature -tags to manifest)\n #android.features = android.hardware.usb.host\n<span class=\"p\">@@ -330,7 +343,7 @@</span>\n #p4a.source_dir =\n\n # (str) The directory in which python-for-android should look for your own build recipes (if any)\n<span class=\"gd\">-#p4a.local_recipes =\n</span><span class=\"gi\">+p4a.local_recipes = ./recipes\n</span>\n # (str) Filename to the hook for p4a\n #p4a.hook =\n</code></pre></div></div>\n\n<ul>\n  <li>最終的に作業ディレクトリは以下のようになる\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>≪作業ディレクトリ≫\n├── buildozer.spec\n├── main.py\n├── scrolllabel.py\n└── recipes\n     └── bleak\n         ├── __init__.py\n         └── fix_setup.py\n</code></pre></div>    </div>\n    <h2 id=\"build\">build</h2>\n    <p>以下のコマンドでbuidする</p>\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"インストール実行\">インストール&実行</h2>\n<p>Windows側でadbサーバを起動しておき、以下を実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>connectボタンを最初にクリックした時、「この端末の位置情報へのアクセスをBLE Demoに許可しますか?」と聞かれたら「許可」をクリック\n(Androidのバージョンによって違うかもしれん。ターゲットAPIレベルで決まるんだっけ?)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Web Bluetooth APIを試す</title>\n  </head>\n  <body>\n    <header>\n      <h1>Web Bluetooth APIを試す</h1>\n      <p>Web bluetooth APIを試した時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>ブラウザからBluetoothにアクセスできる<a href=\"https://developer.mozilla.org/ja/docs/Web/API/Web_Bluetooth_API\" target=\"_blank\">Web Bluetooth API</a>\nを試してみた時に作ったプログラムを貼っておきます。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"ペリフェラル機器\">ペリフェラル機器</h2>\n\n<p>BLEは通信なので、通信相手が必要です。<br />\n市販機器を使うと仕様を調べるのが大変なので、エイヤッと自分で作っりました。<br />\nといっても Raspberry Pi Pico W にmicropythonのF/Wを書き込んでプログラム実行するだけ。<br />\n(使用したmicropython F/Wは「MicroPython v1.23.0 on 2024-06-02」です)</p>\n\n<p>以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。 と言ってもWi-Fiとか要らないからパクり先のリンク貼ってあるだけだけど。</p>\n\n<p>ということで、以下のソースを Raspberry Pi Pico で実行しておきます。<br />\n(特にH/W依存なことはしてないので、ESP32でも動くかも)</p>\n\n<p>BLEの処理については「micropython aioble」とかでググってください。<br />\nでも、公式のサンプル動かした例ばっかりであんまりないんだよなぁ…</p>\n\n<p>==懺悔==<br />\nUUIDはどっかのサンプルの値をちょこっといじったものです。<br />\n(調べたら温度計用のUUIDでした)<br />\n本来ならUUIDをちゃんと生成しないといけません。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=ble_peripheral.py\"></script>\n</dev>\n\n<h2 id=\"webサーバ\">Webサーバ</h2>\n<p>Web Bluetooth APIを使用するのは、HTMLファイルをHTTPSサーバからロードしなければならない仕様のようです。\n(httpやfileでは不可)<br />\nファイル1個だけなので、どこかのサーバの片隅に置くとかでも良いと思います。<br />\nローカルでサーバを立てるならApacheとかnginxとかで立ててください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsでApacheを使うなら<a href=\"https://nanbu.marune205.net/2022/01/windows10-apache-ssl.html?m=1\" target=\"_blank\">WindowsのApacheサーバーでSSL</a>\nあたりが参考になりました。<br />\nただし、仮の証明書を作るバッチファイルで、Apacheのインストール先がc:¥Apache24 以外の場合は\n以下の設定を追加しておく必要があります。</p>\n  <div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SET</span><span class=\"w\"> </span><span class=\"nx\">OPENSSL_CONF</span><span class=\"o\">=</span><span class=\"err\">≪</span><span class=\"n\">Apache</span><span class=\"err\">のインストール先≫</span><span class=\"nx\">\\conf\\openssl.cnf</span><span class=\"w\">\n</span></code></pre></div>  </div>\n  <p>インストール先を<code class=\"language-plaintext highlighter-rouge\">m:\\Apache24</code>にした場合の変更例はこんな感じ。</p>\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- aaa.txt     2024-07-29 06:58:34.154735900 +0900\n</span><span class=\"gi\">+++ make-snakeoil-cert.bat      2024-07-26 05:09:37.394502700 +0900\n</span><span class=\"p\">@@ -1,8 +1,11 @@</span>\n REM openssl.exe\n<span class=\"gd\">-SET OPENSSL=c:\\Apache24\\bin\\openssl.exe\n</span><span class=\"gi\">+SET OPENSSL=m:\\Apache24\\bin\\openssl.exe\n+\n+REM openssl.cnf\n+SET OPENSSL_CONF=m:\\Apache24\\conf\\openssl.cnf\n</span>\n REM 証明書用データの出力場所\n<span class=\"gd\">-SET ROOTDIR=c:\\Apache24\\certs\n</span><span class=\"gi\">+SET ROOTDIR=m:\\Apache24\\certs\n</span>\n REM サーバーのドメインまたはIPアドレス\n SET IPADDRESS=localhost\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h1 id=\"htmlファイル\">HTMLファイル</h1>\n\n<p>Web Bluetooth API のサンプルプログラムを以下に示します。<br />\nこれをHTTPSサーバに置いておきます</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=BLE_sample.html\"></script>\n</dev>\n\n<h1 id=\"実験\">実験</h1>\n\n<p>ペリフェラルプログラムを動作させておき、\nブラウザで上記HTMLファイルを開きます。</p>\n\n<p>アクセスするPCやスマホはBLE対応のBluetoothが搭載されている必要があります。<br />\nブラウザはChromeかEdge(は試してないけど)で。(firefox不可)</p>\n\n<p>WindowsPCとAndroidスマホのChromeは動作確認しました。<br />\nmacとiPhoneは持ってないので試してません。</p>\n\n<p>次に「接続」ボタンをクリック、「XXXXXがペア接続を要求しています」ダイアログが出るので\n「mpy-sensor」を選択し、「ペア設定」をクリックします。</p>\n\n<p>接続されると DATA1 に受信したデータを表示します。<br />\nDATA1はNotificationありのデータ読み取りです。<br />\nNotificationイベントを受けてデータを読み取ります。<br />\n上は1行を常に書き換えるタイプ。<br />\n下は過去分を含め10行程度表示(それ以前は削除)するタイプです。<br />\n受診自体は1回でページの書き換え処理を2通り行っています。</p>\n\n<p>DATA2はNotificationなしのデータ読み取りです。<br />\nREADボタンをクリックすると読み取った値を表示します。</p>\n\n<p>測定間隔のテキストボックスに数値を入力し、「WRITE」をクリックすると\nDATA1の取得間隔を変更できます。<br />\n値は100~5000が有効で、範囲外の値が設定されると範囲内の値に補正されます(補正はペリフェラル川で行っています)。</p>\n\n<p>接続を終了するには「切断」をクリックします。</p>\n\n<h1 id=\"操作例\">操作例</h1>\n\n<p><a href=\"/memoBlog/misc/WEB_BT_API_2024-07-29_075522.mp4\" target=\"_blank\">操作例の動画</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>BLEでアプリケーションパラメータ設定</title>\n  </head>\n  <body>\n    <header>\n      <h1>BLEでアプリケーションパラメータ設定</h1>\n      <p>ESP32 BLEを使用してアプリケーションパラメータの設定を変更する処理の雛形</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>アプリケーションを作成したとき、マシン名のように端末毎に変更を変更したり、\nサーバ名のように設置条件によって変更したいパラメータってありますよね。<br />\nいつもは起動時に設定モードに入ったり、動作中に簡易シェルを動かしてコンソール(UART)から設定していましたが、<br />\n実装面積などの関係でUARTが接続できなかったりした場合、それ以外の方法としてBLEで設定する方法を考えました。<br />\n(ESP32の場合、Flash書き換えでUART使うので繋がない訳にはいかないのですが…)</p>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nを参考にカスタムプロファイルでアプリケーションパラメータをread/writeできるようにしてみました。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは<a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a><br />\nにあるのでcloneしてください。</p>\n\n<p>このプログラムではアプリケーションはWi-Fiに接続するだけの処理です。<br />\nうまくパラメータが設定できて、nvsに保存しておけば、2回目以降はBLEによる設定なしにWi-Fiに接続することができます。<br />\n接続できれば、外部マシンからpingを打って応答があることが確認できます。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><a href=\"https://github.com/ippei8jp/BLE_PARAM_CONFIG\" target=\"_blank\">https://github.com/ippei8jp/BLE_PARAM_CONFIG</a> のREADME.mdを参照してください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nパラメータの設定はRaspberryPiのpythonから行っていますが、その気になればAndroidのBLE接続確認ツールなどからでも設定できます。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n設定パラメータにループインターバルがありますが、プログラム中では参照していません。<br />\n数値を設定する例として入れてあります。</p>\n</blockquote>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>設定したいパラメータが増えてたら、Characteristicを増やしていけばいくらでも対応できるハズ…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>pythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>pythonでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に pythonスクリプトでアクセスしてみる方法についてのメモ。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<p>pythonスクリプトはRaspberryPiで動作している(実際に試したのはPi4だが、Pi3/Pi0wでも同様)。<br />\nubuntu-PCでも同様にできるはずだが、うちのマシンは内蔵Bluetoothのバージョンが古くてBLE非対応だったので試してない。<br />\nwindows-PCはよくわからん…</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/test1\n<span class=\"nb\">cd</span> /work/ble/test1\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.9.10 bluepy\npyenv <span class=\"nb\">local </span>bluepy\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>bluepy\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/9bbdfa53526411967975097cfbcc66e6.js\"></script>\n</dev>\n\n<h1 id=\"実行\">実行</h1>\n\n<p>ESP32側はAdvertising 開始状態にしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>python ble_hr.py\n</code></pre></div></div>\n<p>デバイスのスキャンを行うので<code class=\"language-plaintext highlighter-rouge\">sudo</code>が必要。</p>\n<blockquote>\n  <p>[!NOTE]\nもし、scanせずにアドレスを指定して実行するだけの処理に書き換えれば<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要になる。</p>\n</blockquote>\n\n<h1 id=\"説明\">説明</h1>\n\n<h2 id=\"ble_hr_delegateクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR_Delegate</code>クラス</h2>\n<p>Notifyを受け取っての処理は<code class=\"language-plaintext highlighter-rouge\">bluepy.btle.DefaultDelegate</code>クラスを継承したクラスを作成して登録する必要がある。<br />\n処理自体は<code class=\"language-plaintext highlighter-rouge\">handleNotification</code>メソッドをオーバーライドして定義する。<br />\n受け取るデータ<code class=\"language-plaintext highlighter-rouge\">data</code>はbytes型なので、数値として使用する場合は<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換してやる必要があるが、<br />\nこの時のエンディアンは接続しているデバイスのFW仕様によるので、どちらを使うかはあらかじめ確認しておく必要がある。<br />\n(大抵はFWを動かしているCPUのエンディアンなのかな?)</p>\n\n<h2 id=\"ble_hrクラス\"><code class=\"language-plaintext highlighter-rouge\">BLE_HR</code>クラス</h2>\n<p>peripheralを操作するための処理をクラス化してある。<br />\nクラス化は必須ではないけど、処理をまとめておいた方が分かりやすいかな?と思ったので。</p>\n\n<p>コンストラクタ、接続、Characteristicのリード/ライト、Notifyの有効化/無効化/ポーリング、切断などの処理がある。</p>\n\n<h2 id=\"main関数\"><code class=\"language-plaintext highlighter-rouge\">main</code>関数</h2>\n<p>メイン処理。<br />\n処理の流れはこんな感じ。</p>\n<ul>\n  <li>デバイスのスキャン</li>\n  <li>スキャン結果から指定されたUUIDを持つデバイスを探す\n    <ul>\n      <li>UUIDやデバイス名が必ずしも同じところにあるとは限らないので色々読んでみる必要がある</li>\n    </ul>\n  </li>\n  <li>複数のデバイスを同時に操作することも可能だが、今回は最初の1個だけを決め打ちで使う</li>\n  <li>接続</li>\n  <li>Characteristicのリード\n    <ul>\n      <li>ここもリード結果はbytes型なので、<code class=\"language-plaintext highlighter-rouge\">int.from_bytes()</code>で数値に変換する</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト\n    <ul>\n      <li>ライトデータはbytes型に変換する必要があるが、この処理は、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.write()</code>で変換しているのでここではそのまま。</li>\n    </ul>\n  </li>\n  <li>Characteristicのライト結果の確認\n    <ul>\n      <li>ライトできたか確認するために、再度リードしている</li>\n    </ul>\n  </li>\n  <li>Notifyの有効化</li>\n  <li>Notifyが通知されることを確認するために少し待つ\n    <ul>\n      <li>Notifyを待つ間、<code class=\"language-plaintext highlighter-rouge\">BLE_HR.waitForNotifications()</code>(<code class=\"language-plaintext highlighter-rouge\">Peripheral.waitForNotifications()</code>のラッパ)をコールし続ける必要がある。<br />\nこれをコールしないとNotifyを受信できない(キューイングされるがコールバックは実行されない)。</li>\n    </ul>\n  </li>\n  <li>Notifyの無効化\n    <ul>\n      <li>Notifyが入らないことを確認するためにちょっと待つ</li>\n    </ul>\n  </li>\n  <li>切断</li>\n</ul>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry PiでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry PiでBLE</h1>\n      <p>ESP32 BLEのデモにRaspberry Piからアクセスしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a> \n<a href=\"/memoBlog/2022/01/21/ESP32_BLE_2.html\" target=\"_blank\">ESP32でBLEのデモを動かす 補足</a> \nで作ったESP32のBLE peripheral に Raspberry Pi からアクセスしてみる方法についてのメモ。</p>\n\n<p>Androidでアクセスすると、色々とブラックボックスで処理されてどうなってるのか分かり難いので理解を深める意味で試してみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\n使用したESP32側のソースは<a href=\"https://gist.github.com/ippei8jp/2b3abdd3f9c733be8039fe46a050adca\" target=\"_blank\">こちら</a></p>\n</blockquote>\n\n<h1 id=\"メモ\">メモ</h1>\n\n<p>ここにあるように、BLEでは「ボンディング(参照先ではペアリングと表記)なし」で実行するのが無難と思われる<br />\n<a href=\"https://www.musen-connect.co.jp/blog/course/trial-production/ble-beginner-8/\" target=\"_blank\">【サルでもわかるBLE入門】(8) ペアリング</a></p>\n\n<p>Wiresharkによるパケットキャプチャの解説(たぶん、そんなレイヤでデバッグすることはないと思うけど)<br />\n<a href=\"https://re-engines.com/2021/08/16/ble-secure/\" target=\"_blank\">BLEのペアリングをWiresharkでキャプチャしながら学ぶ</a></p>\n\n<h1 id=\"前提\">前提</h1>\n\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス  (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングしない                (ESP_LE_AUTH_REQ_SC_MITM)</li>\n  <li>IO capabilityはNoInputNoOutput    (ESP_IO_CAP_NONE)</li>\n</ul>\n\n<h1 id=\"ペリフェラル機器をスキャン\">ペリフェラル機器をスキャン</h1>\n\n<p>まずは接続可能デバイスをスキャンしないと始まらないので、スキャンする。<br />\nもちろん、ESP32側はAdvertising 開始状態である必要がある。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo timeout </span>5s hcitool lescan        ← 5秒間スキャンしてみる\nLE Scan ...\n48:BA:7E:24:D0:AA <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n50:17:FC:8C:D1:87 ESP_BLE_HR            ←見つかった\nE4:9A:9F:40:AD:09 <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\nC4:49:BB:8A:7F:6C EX-ZR1800-8A7F6B\nC4:49:BB:8A:7F:6C <span class=\"o\">(</span>unknown<span class=\"o\">)</span>\n</code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hcitool lescan</code>の実行には<code class=\"language-plaintext highlighter-rouge\">sudo</code>必須。<br />\n<code class=\"language-plaintext highlighter-rouge\">timeout 5s</code> を付けずにCTRL+Cで停止しても良い。</p>\n\n<h1 id=\"対象デバイスにアクセスしてみる\">対象デバイスにアクセスしてみる</h1>\n\n<blockquote>\n  <p>[!NOTE]\n<strong>UUIDについて</strong></p>\n\n  <p>16bit UUIDは以下のXXXXの部分(それ以外の部分が一致しないものは128bit UUID)<br />\n<code class=\"language-plaintext highlighter-rouge\">0000XXXX-0000-1000-8000-00805f9b34fb</code></p>\n\n  <p>16bit UUIDは 以下のページを参照<br />\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a></p>\n</blockquote>\n\n<h2 id=\"コマンド起動と接続\">コマンド起動と接続</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">gatttool</code>の実行に<code class=\"language-plaintext highlighter-rouge\">sudo</code>は不要。<br />\n<code class=\"language-plaintext highlighter-rouge\">«アドレス»</code> には上でみつけたアドレスを指定する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span>gatttool <span class=\"nt\">-t</span> random <span class=\"nt\">-I</span> <span class=\"nt\">-b</span> «アドレス»             ← ツールの実行   以下、インタラクティブモードに入る\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> connect                  ← 接続 \nAttempting to connect to 50:17:FC:8C:D1:87\nConnection successful                             ← 接続成功  \n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"サービス一覧を取得\">サービス一覧を取得</h2>\n\n<p>サービスの一覧を取得してみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> primary\nattr handle: 0x0001, end grp handle: 0x0005 uuid: 00001801-0000-1000-8000-00805f9b34fb\nattr handle: 0x0014, end grp handle: 0x001c uuid: 00001800-0000-1000-8000-00805f9b34fb\nattr handle: 0x0028, end grp handle: 0xffff uuid: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<p>それぞれこんな意味</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>UUID</th>\n      <th>種別</th>\n      <th>ハンドル範囲</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>1801</td>\n      <td>Generic Attribute</td>\n      <td>0x0001 ~ 0x0005</td>\n    </tr>\n    <tr>\n      <td>1800</td>\n      <td>Generic Acces</td>\n      <td>0x0014 ~ 0x001c</td>\n    </tr>\n    <tr>\n      <td>180d</td>\n      <td>Heart Rate</td>\n      <td>0x0028 ~ 0xffff</td>\n    </tr>\n  </tbody>\n</table>\n\n<h2 id=\"generic-accesを調べてみる\">Generic Accesを調べてみる</h2>\n\n<p>上で調べたGeneric Acces のハンドル範囲を指定して実行。<br />\n表示されるUUIDを\n<a href=\"https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf\" target=\"_blank\">16-bit UUID Numbers Document</a>\nで探して右側にメモっておいた。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x14 0x1c\nhandle: 0x0014, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0015, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb        ← device name\nhandle: 0x0017, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb        ← Appearance\nhandle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb        ← Central Address Resolution\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"device-name-を読んでみる\">device name を読んでみる</h2>\n\n<p>とりあえず devece nameを読んでみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x016                       ← handle 0x16<span class=\"o\">(</span>device name<span class=\"o\">)</span> のリード\nCharacteristic value/descriptor: 45 53 50 5f 42 4c 45 5f 48 52     ← 結果\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<p>このままだとなんだかわからん…<br />\n別ウィンドゥで以下を実行。<br />\nただし、<code class=\"language-plaintext highlighter-rouge\">nkf</code>はデフォルトでインストールされていないので<code class=\"language-plaintext highlighter-rouge\">apt</code>でインストールする。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">echo</code>の中身には上でリードした結果をコピペする。<br />\nこれを<code class=\"language-plaintext highlighter-rouge\">xxd</code>コマンドでバイナリに変換、<br />\n<code class=\"language-plaintext highlighter-rouge\">nkf</code>で文字コード変換を行う(これだとUTF-8→UTF-8なのであんまり意味ない気が…)。<br />\n結果は改行されずに、プロンプトが続けて表示されるので注意。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">echo</span> <span class=\"s2\">\"45 53 50 5f 42 4c 45 5f 48 52\"</span>  | xxd <span class=\"nt\">-p</span> <span class=\"nt\">-r</span>  | nkf <span class=\"nt\">-WwmQ</span>\nESP_BLE_HR        ← おぉ、読めてる\n<span class=\"nv\">$ </span>\n</code></pre></div></div>\n\n<h2 id=\"heart-rateサービスを調べてみる\">Heart Rateサービスを調べてみる</h2>\n<p>同様にHeart Rateサービスについて調べてみる。<br />\nUUIDについてのメモも同様。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-desc 0x0028 0xffff\nhandle: 0x0028, uuid: 00002800-0000-1000-8000-00805f9b34fb        ← Primary Service\nhandle: 0x0029, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002a, uuid: 00002a37-0000-1000-8000-00805f9b34fb        ← Heart Rate Measurement\nhandle: 0x002b, uuid: 00002902-0000-1000-8000-00805f9b34fb        ← Client Characteristic Configuration\nhandle: 0x002c, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002d, uuid: 00002a38-0000-1000-8000-00805f9b34fb        ← Body Sensor Location\nhandle: 0x002e, uuid: 00002803-0000-1000-8000-00805f9b34fb        ← Characteristic\nhandle: 0x002f, uuid: 00002a39-0000-1000-8000-00805f9b34fb        ← Heart Rate Control Point\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>\n</code></pre></div></div>\n\n<h2 id=\"heart-rate-control-point-を読み書きしてみる\">Heart Rate Control Point を読み書きしてみる</h2>\n\n<p>Characteristicの読み書きを試すため、Heart Rate Control Point(ハンドル0x2f;c<code class=\"language-plaintext highlighter-rouge\">har-desc</code>の結果から取得)にアクセスしてみる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 読んでみる\nCharacteristic value/descriptor: 00                   ← 読めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 01       ← 書いてみる\nCharacteristic value was written successfully         ← 書けた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2f           ← 確認してみる\nCharacteristic value/descriptor: 01                   ← 書けてる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2f 0x02     ← 書き込み値に0xを付けたらエラーになる\nError: Characteristic Write Request failed: Attribute value length is invalid\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> \n</code></pre></div></div>\n\n<h2 id=\"notificationを有効にしてみる\">Notificationを有効にしてみる</h2>\n\n<p>NotificationをONにするにはCCCを操作する。<br />\nNotificationで受信したデータは自動で表示される。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 00 00                ← Notification OFFになってる\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0100     ← Notification ON にしてみる<span class=\"o\">(</span>0100を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\nNotification handle <span class=\"o\">=</span> 0x002a value: 50 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 51 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 52 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-read-hnd 0x2b           ← CCCを読んでみる\nCharacteristic value/descriptor: 01 00                ← Notification ONになってる\nNotification handle <span class=\"o\">=</span> 0x002a value: 53 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 54 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 55 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 56 10             ← Notificationを受信\nNotification handle <span class=\"o\">=</span> 0x002a value: 57 10             ← Notificationを受信\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> char-write-req 0x2b 0000     ← Notification OFF にしてみる<span class=\"o\">(</span>0000を書き込む<span class=\"o\">)</span>\nCharacteristic value was written successfully         ← 書き込めた\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]>                              ← 以降、Notificationは停止\n</code></pre></div></div>\n\n<h2 id=\"書き込み禁止のcharacteristicに書き込んでみる\">書き込み禁止のCharacteristicに書き込んでみる</h2>\n\n<p>書き込み禁止のCharacteristicに書き込んでみるとどうなるか試してみる。<br />\n当然エラーになる。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>50:17:FC:8C:D1:87][LE]> char-write-req 0x2d 01         ← Body Sensor Locationに書き込んでみる\nError: Characteristic Write Request failed: Attribute can<span class=\"s1\">'t be written   ← エラーになった\n</span></code></pre></div></div>\n\n<h2 id=\"切断する\">切断する</h2>\n\n<p>操作が終わったら切断する。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> disconnect                        ← 切断\n<span class=\"o\">(</span>gatttool:1840<span class=\"o\">)</span>: GLib-WARNING <span class=\"k\">**</span>: 12:55:27.500: Invalid file descriptor.   ← なんか言われるけど無視して良い\n<span class=\"o\">[</span>50:17:FC:8C:D1:87][LE]> <span class=\"nb\">exit</span>                              ← インタラクティブモードの終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る\n</code></pre></div></div>\n\n<h1 id=\"bluetoothctlでアクセス参考\">bluetoothctlでアクセス(参考)</h1>\n\n<p>「ボンディングする」設定の場合、bluetoothctlでアクセスする必要がある。<br />\nボンディングしない設定で使う分には関係ないが、せっかく調べたのでメモっておく。</p>\n\n<p>ボンディング前後でアドレス違ったりしてイマイチ使いにくい。<br />\nどうしても「ボンディングする」にしなければならない場合は、自身のアドレスをパブリックアドレスにしておけばちょっとマシかも。</p>\n\n<h2 id=\"メモ-1\">メモ</h2>\n\n<p>bluetoothctlのコマンド <br />\n<a href=\"https://qiita.com/noraworld/items/55c0cb1eb52cf8dccc12\" target=\"_blank\">bluetoothctl のコマンド一覧と使い方をまとめてみた</a></p>\n\n<p>bluetoothctlだとGATTへのアクセスができないっぽいので、ボンディングの登録/解除以外は使えないっぽいな…</p>\n\n<h2 id=\"前提-1\">前提</h2>\n<p>ESP側の設定は以下の通り。</p>\n\n<ul>\n  <li>自身のアドレスはランダムアドレス           (BLE_ADDR_TYPE_RANDOM)</li>\n  <li>ボンディングする                           (ESP_LE_AUTH_REQ_SC_MITM_BOND)</li>\n  <li>IO capabilityはcapabilityはDisplayYesNo    (ESP_IO_CAP_IO)</li>\n</ul>\n\n<h2 id=\"起動\">起動</h2>\n\n<p>ツールの起動。<br />\n<code class=\"language-plaintext highlighter-rouge\">sudo</code>必要<br />\n以下インタラクティブモードで操作。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">$ </span><span class=\"nb\">sudo </span>bluetoothctl                                        ← 起動\n</code></pre></div></div>\n\n<h2 id=\"スキャン\">スキャン</h2>\n\n<p>接続可能デバイスを見つけるためにスキャンする。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# scan on                                       ← スキャン開始\nDiscovery started\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>NEW] Device 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\n<span class=\"o\">[</span>NEW] Device 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\n<span class=\"o\">[</span>NEW] Device 62:D1:88:DD:4F:7C リビングルーム\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E RSSI: <span class=\"nt\">-38</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower: 3\n・・・\n<span class=\"o\">[</span>bluetooth]# scan off                                      ← スキャン停止\nDiscovery stopped\n<span class=\"o\">[</span>CHG] Controller DC:A6:32:70:E7:B2 Discovering: no\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E TxPower is nil\n・・・\n<span class=\"o\">[</span>bluetooth]# devices                                       ← 接続可能デバイスの表示\nDevice 5A:E1:9A:05:96:E0 ESP_BLE_HR                        ← これがESP32<span class=\"o\">(</span>ランダムアドレスなので起動の度に変化する<span class=\"o\">)</span>\nDevice 70:51:DB:1C:EF:BC 70-51-DB-1C-EF-BC\nDevice 7D:85:86:11:F3:D9 7D-85-86-11-F3-D9\nDevice 62:D1:88:DD:4F:7C リビングルーム\n\n</code></pre></div></div>\n\n<h2 id=\"agentの登録\">agentの登録</h2>\n\n<p>ボンディングのために、agentを登録する(数字を入力したり、Yes/Noを選択したりするやつ)。<br />\nこちらの設定と相手側の設定の組み合わせで最終的にどの方法が使われるか決定される。<br />\nたとえば、こちら側を NoInputNoOutput に設定しておけば、相手側が DisplayYesNo であってもYes/Noの入力は求められない。<br />\n逆の設定でも同様。</p>\n\n<p>登録された状態で他のCapabilityで登録しようとしても「既に登録済み」と言われるので、念のため一旦登録解除してから登録しておく。<br />\nこのあたり、情報少なくてイマイチよく分からない…</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# agent off                                    ← 一旦agentの登録解除\nAgent unregistered                                         ← 解除された\n<span class=\"o\">[</span>ESP_BLE_HR]# agent DisplayYesNo                           ← DisplayYesNoで登録\nAgent registered                                           ← 登録された\n</code></pre></div></div>\n\n<h2 id=\"接続\">接続</h2>\n\n<p>接続する。<code class=\"language-plaintext highlighter-rouge\">connect</code>でなく、<code class=\"language-plaintext highlighter-rouge\">pair</code>で実行。<br />\n<code class=\"language-plaintext highlighter-rouge\">connect</code>による接続は後述。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# pair 5A:E1:9A:05:96:E0                       ← 接続\nAttempting to pair with 5A:E1:9A:05:96:E0\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 Connected: <span class=\"nb\">yes\n</span>Request confirmation\n<span class=\"o\">[</span>agent] Confirm passkey 680456 <span class=\"o\">(</span><span class=\"nb\">yes</span>/no<span class=\"o\">)</span>:                   ← agentがYes/Noを聞いてくる\n<span class=\"o\">[</span>NEW] Primary Service                                      ← これが自動的に表示されて上の質問を見失うので注意!!\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001\n        00001801-0000-1000-8000-00805f9b34fb\n        Generic Attribute Profile\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0001/char0002\n        00002a05-0000-1000-8000-00805f9b34fb\n        Service Changed\n・・・\n<span class=\"o\">[</span>NEW] Characteristic\n        /org/bluez/hci0/dev_5A_E1_9A_05_96_E0/service0028/char002e\n        00002a39-0000-1000-8000-00805f9b34fb\n        Heart Rate Control Point\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001800-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 00001801-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 UUIDs: 0000180d-0000-1000-8000-00805f9b34fb\n<span class=\"o\">[</span>CHG] Device 5A:E1:9A:05:96:E0 ServicesResolved: <span class=\"nb\">yes\nyes</span>                                                         ← yesを入力<span class=\"o\">(</span>同時に相手側でもyes入力<span class=\"o\">)</span>\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Address: 94:B9:7E:65:AF:5E\nPairing successful                                         ← 接続された\n<span class=\"o\">[</span>ESP_BLE_HR]# paired-devices                               ← ボンディング結果を確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR                        ← advertisingがランダムアドレスでもパブリックアドレスで登録されるので注意!!\n<span class=\"o\">[</span>ESP_BLE_HR]#                                                以降、接続はこのアドレスを使用する!!\n</code></pre></div></div>\n\n<h2 id=\"切断\">切断</h2>\n\n<p>切断する。<br />\nCharacteristicアクセスできないので、実質ボンディングするのみ。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断する\nAttempting to disconnect from 94:B9:7E:65:AF:5E            ← パブリックアドレスが表示されている\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<h2 id=\"再接続\">再接続</h2>\n\n<p>ボンディング済みのデバイスに再接続する場合の手順。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスの表示\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# connect 94:B9:7E:65:AF:5E                     ← 表示されたアドレスで接続\nAttempting to connect to 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: <span class=\"nb\">yes\n</span>Connection successful                                      ← 接続された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: <span class=\"nb\">yes</span>\n<span class=\"o\">[</span>ESP_BLE_HR]# disconnect                                   ← 切断\nAttempting to disconnect from 94:B9:7E:65:AF:5E\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E ServicesResolved: no\nSuccessful disconnected                                    ← 切断された\n<span class=\"o\">[</span>CHG] Device 94:B9:7E:65:AF:5E Connected: no\n<span class=\"o\">[</span>bluetooth]#\n</code></pre></div></div>\n\n<p>ボンディングしてない機器に対して<code class=\"language-plaintext highlighter-rouge\">connect</code>すると、<code class=\"language-plaintext highlighter-rouge\">agent off</code> で <code class=\"language-plaintext highlighter-rouge\">pair</code> したような動作になる模様。</p>\n\n<h2 id=\"ボンディング解除\">ボンディング解除</h2>\n\n<p>ボンディング済みデバイスを登録削除する。<br />\nESP32側も忘れず登録削除しておくこと。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# paired-devices                                ← ボンディング済みデバイスを確認\nDevice 94:B9:7E:65:AF:5E ESP_BLE_HR\n<span class=\"o\">[</span>bluetooth]# remove 94:B9:7E:65:AF:5E                      ← ボンディング解除\n<span class=\"o\">[</span>DEL] Descriptor                                           ← なんか ずらずらっと削除されたと出る\n        /org/bluez/hci0/dev_5F_76_EF_D2_45_E7/service0001/char0002/desc0004\n        00002902-0000-1000-8000-00805f9b34fb\n        Client Characteristic Configuration\n・・・\nDevice has been removed                                    ← 削除された\n<span class=\"o\">[</span>bluetooth]# paired-devices                                ← 確認\n<span class=\"o\">[</span>bluetooth]#                                               ← 削除されてる\n</code></pre></div></div>\n\n<h2 id=\"ツールの終了\">ツールの終了</h2>\n\n<p>ツールを終了してShellに戻る。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">[</span>bluetooth]# <span class=\"nb\">exit</span>                                          ← またはquitまたはCTRL+Dで終了\n<span class=\"nv\">$ </span>                                                         ← Shellに戻る \n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でBLEのデモを動かす 補足</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でBLEのデモを動かす 補足</h1>\n      <p>ESP32にBLEのデモの認証方法についての補足</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p><a href=\"/memoBlog/2022/01/19/ESP32_BLE_1.html\" target=\"_blank\">ESP32でBLEのデモを動かす</a>\nでは認証方法(IO capability なので入出能力と言うべきか? あまり直感的でないのでここでは認証方法と呼んでおこう)<br />\nを<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_NONE</code>(NoInputNoOutput; 入出力なし)に設定していたが、これを別の認証方法に変更する場合についてのメモ。</p>\n<blockquote>\n  <p>[!NOTE]\n自作の範囲だと<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_NONE</code>しか使わないと思うけど、使いたくなった時に備えて。</p>\n</blockquote>\n\n<h1 id=\"esp_io_cap_none-noinputnooutput\">ESP_IO_CAP_NONE (NoInputNoOutput)</h1>\n<p>入出力両方なし。<br />\npasskey(PINcode)入力などはなし。<br />\n接続すると自動的に鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (92315) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (92315) BLE_HEART_RATE:     connection start\nV (92975) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (92975) BLE_HEART_RATE:     event nor handled\nV (93245) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (93245) BLE_HEART_RATE:     event nor handled\nE (97855) BT_BTM: btm_ble_remove_resolving_list_entry_complete remove resolving list error 0x2\nV (98285) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (98285) BLE_HEART_RATE:     event nor handled\nW (98335) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (98375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98375) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (98375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98375) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (98385) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98385) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (98405) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (98405) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (98405) nvs: nvs_open_from_partition bt_config.conf 1\nD (98415) nvs: nvs_set_blob bt_cfg_key0 475\nD (98425) nvs: nvs_close 4\nD (98425) nvs: nvs_open_from_partition bt_config.conf 1\nD (98425) nvs: nvs_set_blob bt_cfg_key0 475\nD (98485) nvs: nvs_close 5\nD (98485) nvs: nvs_open_from_partition bt_config.conf 1\nD (98485) nvs: nvs_set_blob bt_cfg_key0 475\nD (98495) nvs: nvs_close 6\nD (98495) nvs: nvs_open_from_partition bt_config.conf 1\nD (98495) nvs: nvs_set_blob bt_cfg_key0 475\nD (98515) nvs: nvs_close 7\nD (98515) nvs: nvs_open_from_partition bt_config.conf 1\nD (98515) nvs: nvs_set_blob bt_cfg_key0 475\nD (98515) nvs: nvs_close 8\nV (98515) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (98525) BLE_HEART_RATE:     remote BD_ADDR: 5d5308bb0efd\nI (98525) BLE_HEART_RATE:     address type = 1\nI (98535) BLE_HEART_RATE:     pair status = success\nI (98535) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_BOND\nI (98545) BLE_HEART_RATE:     Bonded devices number : 1\nI (98545) BLE_HEART_RATE:     Bonded devices list :\nI (98555) BLE_HEART_RATE:        0 :   5d:53:08:bb:0e:fd\nV (99025) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99025) BLE_HEART_RATE:     event nor handled\nV (99545) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99545) BLE_HEART_RATE:     event nor handled\nV (99755) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (99755) BLE_HEART_RATE:     event nor handled```\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_out-displayonly\">ESP_IO_CAP_OUT (DisplayOnly)</h1>\n<p>表示機器のみ必要。<br />\n自分が指定するpasskeyをコンソール等に表示し、相手側(ホスト)にpasskey(PINcode)入力させる。</p>\n\n<p>passkeyは<code class=\"language-plaintext highlighter-rouge\">esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, ~);</code>で設定するので、<br />\n必ず表示しなくてはいけない、ということはない(BTヘッドフォンなどでマニュアルに「0000を入力」などと書かれているのと同じ)。</p>\n\n<p>相手側には入力手段が必須。</p>\n\n<p>GAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:               // passkey通知要求イベント\n        // 自身がDisplayOnly(ESP_IO_CAP_OUT)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_PASSKEY_NOTIF_EVT ====\");\n        // passkeyの表示\n        printf(\"**** The passkey Notify number:%06d\\n\", param->ble_security.key_notif.passkey);\n        break;\n</code></pre></div></div>\n\n<p>相手側で入力されたpasskeyが正しければ鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (17105) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (17105) BLE_HEART_RATE:     connection start\nV (17775) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17775) BLE_HEART_RATE:     event nor handled\nV (18025) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (18025) BLE_HEART_RATE:     event nor handled\nV (21935) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_PASSKEY_NOTIF_EVT(11)\nI (21935) BLE_HEART_RATE:     ==== ESP_GAP_BLE_PASSKEY_NOTIF_EVT ====\n**** The passkey Notify number:123456                     ← 相手側にこのpasskeyを入力\nV (22185) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (22185) BLE_HEART_RATE:     event nor handled\nW (33505) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (33535) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33535) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (33535) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33535) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (33545) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33545) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (33575) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (33575) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (33575) nvs: nvs_open_from_partition bt_config.conf 1\nD (33575) nvs: nvs_set_blob bt_cfg_key0 250\nD (33595) nvs: nvs_close 4\nD (33595) nvs: nvs_open_from_partition bt_config.conf 1\nD (33595) nvs: nvs_set_blob bt_cfg_key0 264\nD (33605) nvs: nvs_close 5\nD (33605) nvs: nvs_open_from_partition bt_config.conf 1\nD (33605) nvs: nvs_set_blob bt_cfg_key0 347\nD (33625) nvs: nvs_close 6\nD (33625) nvs: nvs_open_from_partition bt_config.conf 1\nD (33625) nvs: nvs_set_blob bt_cfg_key0 407\nD (33625) nvs: nvs_close 7\nD (33625) nvs: nvs_open_from_partition bt_config.conf 1\nD (33635) nvs: nvs_set_blob bt_cfg_key0 462\nD (33635) nvs: nvs_close 8\nD (33645) nvs: nvs_open_from_partition bt_config.conf 1\nD (33645) nvs: nvs_set_blob bt_cfg_key0 476\nD (33655) nvs: nvs_close 9\nV (33655) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (33655) BLE_HEART_RATE:     remote BD_ADDR: 786562f732fc\nI (33655) BLE_HEART_RATE:     address type = 1\nI (33665) BLE_HEART_RATE:     pair status = success\nI (33665) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (33675) BLE_HEART_RATE:     Bonded devices number : 1\nI (33675) BLE_HEART_RATE:     Bonded devices list :\nI (33685) BLE_HEART_RATE:        0 :   78:65:62:f7:32:fc\nV (34185) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34185) BLE_HEART_RATE:     event nor handled\nV (34695) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34695) BLE_HEART_RATE:     event nor handled\nV (34885) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (34885) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<p>passkeyを間違えると当然接続されない。<br />\n接続が成功したかどうかは、ログの以下の部分で判別できる。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (27095) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (27095) BLE_HEART_RATE:     remote BD_ADDR: 67c015dc4505\nI (27105) BLE_HEART_RATE:     address type = 1\nI (27105) BLE_HEART_RATE:     pair status = fail            ← failしている\nI (27115) BLE_HEART_RATE:     reason = 0x51                 ← 失敗した原因だけど、ドキュメントがない...\nI (27115) BLE_HEART_RATE:     Bonded devices number : 0\nI (27125) BLE_HEART_RATE:     Bonded devices list :\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_in--keyboardonly\">ESP_IO_CAP_IN  (KeyboardOnly)</h1>\n<p>入力機器のみ必要。<br />\n相手側に表示されたpasskeyをコンソール等から入力する。</p>\n\n<p>passkeyは相手側から指定される値なので、どのような値かは相手の仕様による。<br />\n相手側には表示手段が必須。</p>\n\n<p>GAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_PASSKEY_REQ_EVT:                 // passkey 要求\n        // KeyboardOnly(ESP_IO_CAP_IN)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_PASSKEY_REQ_EVT ====\");\n        // 以下の関数で相手側に表示されたパスキーを返す\n        uint32_t    passkey;\n        char        passkey_buff[16];\n        int         passkey_len;\n        do {\n            printf(\"**** input paskey : \");\n            fflush(stdout);\n            passkey_len = uart_gets(passkey_buff, sizeof(passkey_buff));\n        } while (passkey_len == 0);\n        passkey = (uint32_t)strtol(passkey_buff, NULL, 10);\n        esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, passkey);\n        break;\n</code></pre></div></div>\n\n<p>passkeyに使用している<code class=\"language-plaintext highlighter-rouge\">uart_gets()</code>関数については後述。</p>\n\n<p>入力したpasskeyが正しければ鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (16805) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (16805) BLE_HEART_RATE:     connection start\nV (17425) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17425) BLE_HEART_RATE:     event nor handled\nV (17675) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (17685) BLE_HEART_RATE:     event nor handled\nE (20765) BT_BTM: btm_ble_remove_resolving_list_entry_complete remove resolving list error 0x2\nV (20955) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_PASSKEY_REQ_EVT(12)\nI (20955) BLE_HEART_RATE:     ==== ESP_GAP_BLE_PASSKEY_REQ_EVT ====\n**** input paskey : 047528                                  ← 相手側で表示されているpasskeyを入力\nV (36455) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (36455) BLE_HEART_RATE:     event nor handled\nW (37335) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (37375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37375) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (37375) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37375) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (37385) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37385) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (37405) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (37405) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (37415) nvs: nvs_open_from_partition bt_config.conf 1\nD (37415) nvs: nvs_set_blob bt_cfg_key0 476\nD (37425) nvs: nvs_close 4\nD (37425) nvs: nvs_open_from_partition bt_config.conf 1\nD (37425) nvs: nvs_set_blob bt_cfg_key0 476\nD (37495) nvs: nvs_close 5\nD (37495) nvs: nvs_open_from_partition bt_config.conf 1\nD (37495) nvs: nvs_set_blob bt_cfg_key0 476\nD (37505) nvs: nvs_close 6\nD (37505) nvs: nvs_open_from_partition bt_config.conf 1\nD (37505) nvs: nvs_set_blob bt_cfg_key0 476\nD (37525) nvs: nvs_close 7\nD (37525) nvs: nvs_open_from_partition bt_config.conf 1\nD (37525) nvs: nvs_set_blob bt_cfg_key0 476\nD (37525) nvs: nvs_close 8\nV (37525) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (37535) BLE_HEART_RATE:     remote BD_ADDR: 786562f732fc\nI (37535) BLE_HEART_RATE:     address type = 1\nI (37545) BLE_HEART_RATE:     pair status = success\nI (37545) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (37555) BLE_HEART_RATE:     Bonded devices number : 1\nI (37555) BLE_HEART_RATE:     Bonded devices list :\nI (37565) BLE_HEART_RATE:        0 :   78:65:62:f7:32:fc\nV (38255) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (38255) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<p>passkeyを間違えたときの動作は <code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_OUT</code>(DisplayOnly)の場合と同様。</p>\n\n<h1 id=\"esp_io_cap_io-displayyesno\">ESP_IO_CAP_IO (DisplayYesNo)</h1>\n<p>入力機器/表示機器 両方必要。</p>\n\n<p>相手側に表示されたpasskeyとコンソールに表示されたpasskeyを目視確認して等しければyを入力し、相手側でも接続許可をタップする。\n確認せずにYesを選択しても良いけど、それならこのモードを指定する必要はないでしょう。</p>\n\n<p>相手側にも入力/表示手段が必須。<br />\nGAP(Generic Access Profile)のコールバック(<code class=\"language-plaintext highlighter-rouge\">gap_event_handler()</code>)の以下の部分で行う。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>      case ESP_GAP_BLE_NC_REQ_EVT:                      // 数値比較リクエスト イベント\n        // DisplayYesNo(ESP_IO_CAP_IO)のときに発生する\n        ESP_LOGI(APP_TAG, \"    ==== ESP_GAP_BLE_NC_REQ_EVT ====\");\n        printf(\"**** the passkey Notify number:%d\\n\", param->ble_security.key_notif.passkey);\n        printf(\"**** Accept? (y/n) : \");\n        fflush(stdout);\n        int kb_key = uart_getchar();\n        printf(\"%c\\n\", kb_key);\n        if (kb_key == 'y' || kb_key == 'Y') {\n            // 接続受け入れ\n            esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true);\n        }\n        else {\n            // 接続拒否\n            esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, false);\n        }\n        break;\n</code></pre></div></div>\n\n<p>両方でyesを選択すれば鍵交換して接続される。<br />\n接続動作以降のログ例は以下。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>V (14185) BLE_HEART_RATE: - GATT_EVT: ESP_GATTS_CONNECT_EVT(14)\nI (14185) BLE_HEART_RATE:     connection start\nV (14855) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (14855) BLE_HEART_RATE:     event nor handled\nV (15145) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (15145) BLE_HEART_RATE:     event nor handled\nE (18775) BT_SMP: Value for numeric comparison = 260195\nV (18775) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_NC_REQ_EVT(16)\nI (18775) BLE_HEART_RATE:     ==== ESP_GAP_BLE_NC_REQ_EVT ====\n**** the passkey Notify number:260195                                               ← 相手側で表示されている数値と目視比較\n**** Accept? (y/n) : y                                                              ← y 入力、相手側でもyesクリック\nV (26785) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (26785) BLE_HEART_RATE:     event nor handled\nW (28245) BT_SMP: FOR LE SC LTK IS USED INSTEAD OF STK\nV (28275) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28275) BLE_HEART_RATE:     key type = ESP_LE_KEY_LENC\nV (28275) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28285) BLE_HEART_RATE:     key type = ESP_LE_KEY_PENC\nV (28285) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28295) BLE_HEART_RATE:     key type = ESP_LE_KEY_LID\nV (28305) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_KEY_EVT(9)\nI (28305) BLE_HEART_RATE:     key type = ESP_LE_KEY_PID\nD (28315) nvs: nvs_open_from_partition bt_config.conf 1\nD (28315) nvs: nvs_set_blob bt_cfg_key0 250\nD (28325) nvs: nvs_close 4\nD (28325) nvs: nvs_open_from_partition bt_config.conf 1\nD (28325) nvs: nvs_set_blob bt_cfg_key0 264\nD (28335) nvs: nvs_close 5\nD (28335) nvs: nvs_open_from_partition bt_config.conf 1\nD (28335) nvs: nvs_set_blob bt_cfg_key0 347\nD (28355) nvs: nvs_close 6\nD (28355) nvs: nvs_open_from_partition bt_config.conf 1\nD (28355) nvs: nvs_set_blob bt_cfg_key0 407\nD (28365) nvs: nvs_close 7\nD (28365) nvs: nvs_open_from_partition bt_config.conf 1\nD (28365) nvs: nvs_set_blob bt_cfg_key0 462\nD (28385) nvs: nvs_close 8\nD (28385) nvs: nvs_open_from_partition bt_config.conf 1\nD (28385) nvs: nvs_set_blob bt_cfg_key0 476\nD (28395) nvs: nvs_close 9\nV (28395) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_AUTH_CMPL_EVT(8)\nI (28395) BLE_HEART_RATE:     remote BD_ADDR: 612610f26701\nI (28395) BLE_HEART_RATE:     address type = 1\nI (28405) BLE_HEART_RATE:     pair status = success\nI (28405) BLE_HEART_RATE:     auth mode = ESP_LE_AUTH_REQ_SC_MITM_BOND\nI (28415) BLE_HEART_RATE:     Bonded devices number : 1\nI (28415) BLE_HEART_RATE:     Bonded devices list :\nI (28425) BLE_HEART_RATE:        0 :   61:26:10:f2:67:01\nV (28905) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (28905) BLE_HEART_RATE:     event nor handled\nV (29435) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (29435) BLE_HEART_RATE:     event nor handled\nV (29655) BLE_HEART_RATE: * GAP_EVT: ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT(20)\nI (29655) BLE_HEART_RATE:     event nor handled\n</code></pre></div></div>\n\n<h1 id=\"esp_io_cap_kbdisp-keyboard-display\">ESP_IO_CAP_KBDISP (Keyboard display)</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_OUT</code>(DisplayOnly) と <code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_IN</code>(KeyboardOnly) の合わせ技かと思いきや、<br />\n<code class=\"language-plaintext highlighter-rouge\">ESP_IO_CAP_IO</code>(DisplayYesNo)と同じ動作。<br />\nたしかにキーボードと表示両方必要だわな。。。</p>\n\n<h1 id=\"コンソール入力ルーチン\">コンソール入力ルーチン</h1>\n<p>passkeyの入力など、コンソールからの入力が必要な場合、<code class=\"language-plaintext highlighter-rouge\">gets()</code>などを使用するとキー入力待ちの間タスク切り替えが行われずに他のタスクが動作できない。<br />\n(esp-idfはFreeRTOSを使用したマルチタスク構成)。\nそこで、<code class=\"language-plaintext highlighter-rouge\">gets()</code>/<code class=\"language-plaintext highlighter-rouge\">getchar()</code>の代わりとなる関数を用意した。<br />\n動作としては、キー入力待ちの少しの間、<code class=\"language-plaintext highlighter-rouge\">vTaskDelay()</code>でCPUを解放して他のタスクの動作を阻害しないようにしている。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">uart_checkkey()</code>は今回使ってないけど、〇秒以内に入力がなければデフォルトで動作、のような動作を実現するのに使用する関数。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">printf()</code>もあちこちのタスクから出力する場合はセマフォで排他処理した方が良いけど、今回は特に問題になりそうにないのでそのまま使用。</p>\n\n<p>Buildは これらのファイルをsrcディレクトリにぶち込むだけでOK。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  uart_console.h\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#include    <stdio.h>\n#include    <stdint.h>\n#include    <stdbool.h>\n\nextern bool uart_checkkey(int loop_num);\nextern int uart_getchar(void);\nextern int uart_gets(char* buf, int max);\n</code></pre></div></div>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  uart_console.c\n</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#include    <stdio.h>\n#include    <stdint.h>\n#include    <stdbool.h>\n#include    <string.h>\n#include    <stdarg.h>\n\n#include    \"freertos/FreeRTOS.h\"\n#include    \"freertos/task.h\"\n#include    \"esp_system.h\"\n#include    \"rom/uart.h\"\n\n#include    \"uart_console.h\"\n\n// ========= UARTからの入力待ち ===============================================\n// param    loop_num: 待ち時間(単位100msec)\n// return   true: キー入力があった     false: キー入力はなかった\nbool uart_checkkey(int loop_num)\n{\n    bool    ret = false;\n    uint8_t ch;\n     for (int loop_cnt = 0; loop_cnt < loop_num; loop_cnt++) {\n        // UARTから1文字取得\n        if (uart_rx_one_char(&ch) == OK) {\n            // 入力あり\n            ret = true;\n            break;\n        }\n        if ((loop_cnt % 5)== 0) {\n            // たくさん出ると鬱陶しいので5回毎に\n            putchar('.');\n            fflush(stdout);\n        }\n        // 100ms待つ\n        vTaskDelay(100 / portTICK_RATE_MS);\n    }\n    putchar('\\n');\n\n    // バッファにたまっているデータを読み捨てる\n    while (uart_rx_one_char(&ch) == OK);\n    return ret;\n}\n\n\n// ========= UARTから1文字取得 ================================================\n// param    なし\n// return   文字コード\n// note     CRは無視するので注意\nint uart_getchar(void)\n{\n    uint8_t ch;\n    while (1) {\n        // UARTから1文字取得\n        if (uart_rx_one_char(&ch) == OK) {\n            // 入力あり\n            if (ch == '\\r') {\n                // CRなら次の値を取得\n                continue;\n            }\n            // 入力された値を返す\n            return ch;\n        }\n        // 100ms待つ(CPUを握りっぱなしにしないように)\n        vTaskDelay(100 / portTICK_RATE_MS);\n    }\n}\n\n// ========= UARTから1行取得 ===================================================\n// param    buf: 文字列格納領域へのポインタ\n//          max: 最大文字列長\n// return   入力された文字列長\nint uart_gets(char* buf, int max)\n{\n    int     i = 0;\n    while (i < (max - 1)) {     // null terminate の分を空けておくので max - 1\n        char ch = uart_getchar();\n        if (ch == '\\n') {\n            // LFで終了\n            putchar(ch);\n            fflush(stdout);\n            break;\n        }\n        if (ch == '\\b' || ch == 0x7f) {     // BackSpace or DEL\n            if (i > 0) {        // 先頭でない\n                i--;            // ポインタを一つ前に\n                putchar('\\b');  // 前の文字の表示を削除\n                putchar(' ');\n                putchar('\\b');\n                fflush(stdout);\n            }\n        }\n        else {\n            // それ以外の文字はバッファに格納\n            buf[i] = ch;\n            i++;\n            putchar(ch);        // 表示\n            fflush(stdout);\n        }\n    }\n    buf[i] = '\\0';          // null terminate\n    return i;\n}\n</code></pre></div></div>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>ESP32でBLEのデモを動かす</title>\n  </head>\n  <body>\n    <header>\n      <h1>ESP32でBLEのデモを動かす</h1>\n      <p>ESP32にBLEのデモを動かしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <p>gistにupしたので、gistの埋め込みリンク貼っとく(コードをコピペするのめんどくさかったから)。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/3719faf64374d438fd879ce567becb4b\" target=\"_blank\">こちら</a> \nからどうぞ。</p>\n\n<script src=\"https://gist.github.com/ippei8jp/3719faf64374d438fd879ce567becb4b.js\"></script>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Bluetooth classic": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Bluetooth classic でシリアル通信(SPP)</title>\n  </head>\n  <body>\n    <header>\n      <h1>Bluetooth classic でシリアル通信(SPP)</h1>\n      <p>ESP32 Bluetooth classic(SPP)を使用してシリアル通信するデモプログラム</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>シリアル通信でデータを送受信したいけど、有線接続はできない場合にBluetooth classicのSPP(Serial Port Profile )を使用して\nCOMポートとして接続する方法のデモ。<br />\nesp-idfのサンプルプログラムが私にとっては複雑怪奇だったので、ちょっとシンプルにしてみた。</p>\n\n<h1 id=\"プログラムソース\">プログラムソース</h1>\n<p>使用したESP32側のソースは</p>\n<ul>\n  <li>VFS版: <a href=\"https://github.com/ippei8jp/BT_SPP_VFS\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_VFS</a></li>\n  <li>Callback版: <a href=\"https://github.com/ippei8jp/BT_SPP_CB\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_CB</a></li>\n</ul>\n\n<p>にあるのでcloneしてください。</p>\n\n<p>このプログラムではPC等のCOMポートへ/から接続して送信したデータをエコーバックするだけのデモプログラムです。<br />\nそれぞれのイベント発生時に発生イベントとパラメータを表示するようにしてあるので、動作の理解の一助になります…\nなったらいいな…でも期待はするな….</p>\n\n<p>上記2つのリポジトリはファイル構成を合わせてあるので、diffをとるとVFSとCallbackでどのような違いがあるのか分かりやすい<br />\n… かもね…</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<ul>\n  <li>VFS版: <a href=\"https://github.com/ippei8jp/BT_SPP_VFS#readme\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_VFS#readme</a></li>\n  <li>Callback版: <a href=\"https://github.com/ippei8jp/BT_SPP_CB#readme\" target=\"_blank\">https://github.com/ippei8jp/BT_SPP_CB#readme</a></li>\n</ul>\n\n<p>を参照してください。</p>\n\n<h1 id=\"解説\">解説</h1>\n<p>は、、、、、面倒なのでソース読んでちょ。(^^ゞ <br />\n最近こればっかりや…</p>\n\n<h1 id=\"応用\">応用</h1>\n<p>エコーバックタスクをコマンドシェルタスクなどに入れ替えるとすぐ使える…とも思えんけど…<br />\n踏み台くらいにはなるでしょう。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "MediaPipe": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MediaPipeの手の認識でお絵かき</title>\n  </head>\n  <body>\n    <header>\n      <h1>MediaPipeの手の認識でお絵かき</h1>\n      <p>MediaPipe Handsでの手の認識結果と使ってお絵かきしてみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>MediaPipeで手の認識</p>\n\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』の手の認識子処理を使って空間にお絵かきしてみる。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』を参照。</p>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<h2 id=\"共通ルーチン\">共通ルーチン</h2>\n<p>『<a href=\"/memoBlog/2022/03/17/mediapipe_hands.html\" target=\"_blank\"> MediaPipeで手の認識 </a>』を参照。</p>\n\n<h2 id=\"お絵かきプログラム\">お絵かきプログラム</h2>\n\n<p>お絵かきプログラム本体。<br />\n人差し指先端に点を打っていくことでお絵かきしている。<br />\n人差し指だけ立てた状態(ジェスチャ ONE)だと赤、人差し指と中指を立てた状態(ジェスチャ PEACE)だと緑で描画するようにしてあるが、この組み合わせにあまり意味はない。なんとなく色を切り替えてみたかったので。<br />\nコマンドラインオプションと表示中操作についてはソース見てちょ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  oekaki.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n<span class=\"n\">HandLandmark</span> <span class=\"o\">=</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span>  <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span>         <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n<span class=\"c1\">#     parser.add_argument(\"-nh\", \"--num_hand\",         default=2,   type=int,     help=\"(optional) Max number of hands\")\n</span>    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n# max_num_hands            = args.num_hand            # 検出する手の個数\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"mi\">1</span>                        <span class=\"c1\"># 検出する手の個数 今回は1固定\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">verbose2</span>                 <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>\n\n<span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">True</span>                    <span class=\"c1\"># 鏡像使用\n</span><span class=\"n\">fg_only</span>                  <span class=\"o\">=</span> <span class=\"bp\">False</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"n\">COLOR_WHITE</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_BLUE</span>  <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_GREEN</span> <span class=\"o\">=</span> <span class=\"p\">(</span>  <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">COLOR_RED</span>   <span class=\"o\">=</span> <span class=\"p\">(</span>  <span class=\"mi\">0</span><span class=\"p\">,</span>   <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># カメラ\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像サイズ\n</span><span class=\"n\">image_width</span>  <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_WIDTH</span><span class=\"p\">))</span>\n<span class=\"n\">image_height</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FRAME_HEIGHT</span><span class=\"p\">))</span>\n<span class=\"n\">fps</span>          <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">CAP_PROP_FPS</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'image size : </span><span class=\"si\">{</span><span class=\"n\">image_width</span><span class=\"si\">}</span><span class=\"s\"> x </span><span class=\"si\">{</span><span class=\"n\">image_height</span><span class=\"si\">}</span><span class=\"s\"> @ </span><span class=\"si\">{</span><span class=\"n\">fps</span><span class=\"si\">}</span><span class=\"s\">Hz'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 前景イメージを作成\n</span><span class=\"n\">image_fg</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">full</span><span class=\"p\">((</span><span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span>   <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">,</span>            <span class=\"c1\"># 動画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>        <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 前のフレーム処理完了時刻を初期化\n</span>    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># キャプチャ\n</span>        <span class=\"n\">success</span><span class=\"p\">,</span> <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">success</span><span class=\"p\">:</span>\n            <span class=\"c1\"># エラーになったら再度キャプチャ\n</span>            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Ignoring empty camera frame.\"</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>        <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n            <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        \n        <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>        <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>        <span class=\"c1\"># 検出できたか?\n</span>            <span class=\"c1\"># ポーズの認識\n</span>            <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># 人差し指先の位置\n</span>            <span class=\"n\">finger_x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n            <span class=\"n\">finger_y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'(</span><span class=\"si\">{</span><span class=\"n\">finger_x</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">finger_y</span><span class=\"si\">:</span><span class=\"mi\">4</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">)  </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># ポーズによって色を変更\n</span>            <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"o\">==</span> <span class=\"s\">'ONE'</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"n\">COLOR_RED</span>           <span class=\"c1\"># 赤\n</span>            <span class=\"k\">elif</span> <span class=\"n\">gesture</span> <span class=\"o\">==</span> <span class=\"s\">'PEACE'</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"n\">COLOR_GREEN</span>         <span class=\"c1\"># 緑\n</span>            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"n\">color</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n            <span class=\"k\">if</span> <span class=\"n\">color</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># 前景イメージに点を打つ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">circle</span><span class=\"p\">(</span><span class=\"n\">image_fg</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">finger_x</span><span class=\"p\">,</span> <span class=\"n\">finger_y</span><span class=\"p\">)</span> <span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"n\">color</span><span class=\"p\">,</span> <span class=\"n\">thickness</span><span class=\"o\">=-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># フレーム処理時間\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 現在のフレーム処理完了時刻\n</span>        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>                   <span class=\"c1\"># このフレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        \n        <span class=\"c1\"># FPS表示\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                <span class=\"sa\">f</span><span class=\"s\">'FPS:</span><span class=\"si\">{</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>  <span class=\"c1\"># 文字列\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">50</span><span class=\"p\">),</span>                    <span class=\"c1\"># 座標\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                <span class=\"n\">COLOR_RED</span><span class=\"p\">,</span>                  <span class=\"c1\"># 色\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>            <span class=\"p\">)</span>\n        <span class=\"c1\"># 表示\n</span>        <span class=\"k\">if</span> <span class=\"n\">fg_only</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 前景イメージだけ表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image_fg</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># 画像を重ね合わせ(COLOR_WHITEを透過色として指定)て表示\n</span>            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">where</span><span class=\"p\">(</span><span class=\"n\">image_fg</span> <span class=\"o\">==</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">image_fg</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># 表示終了待ち\n</span>        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'c'</span><span class=\"p\">):</span>\n            <span class=\"c1\"># 前景イメージを初期化\n</span>            <span class=\"n\">image_fg</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">full</span><span class=\"p\">((</span><span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"n\">COLOR_WHITE</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">uint8</span><span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'d'</span><span class=\"p\">):</span>\n            <span class=\"n\">fg_only</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">fg_only</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'v'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'b'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose2</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose2</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'p'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imwrite</span><span class=\"p\">(</span>\n                    <span class=\"sa\">f</span><span class=\"s\">'z_oekaki_</span><span class=\"si\">{</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">datetime</span><span class=\"p\">.</span><span class=\"n\">now</span><span class=\"p\">().</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s\">\"%d_%H%M%S\"</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s\">.jpg'</span><span class=\"p\">,</span> \n                    <span class=\"n\">image_fg</span>\n                <span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"c1\"># ウィンドウをすべて閉じる\n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># カメラリリース\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: oekaki.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD]\n                 <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h1 id=\"感想\">感想</h1>\n\n<p>それなりにお絵かきできるけど…</p>\n<ul>\n  <li>認識処理が遅いと手をゆっくり動かさないと線にならない</li>\n  <li>ポーズの認識の精度がイマイチで描画結果が微妙な感じになる</li>\n</ul>\n\n<p>実際にユーザインタフェースとして使うには色々と工夫が必要かな。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MediaPipeで手の認識</title>\n  </head>\n  <body>\n    <header>\n      <h1>MediaPipeで手の認識</h1>\n      <p>MediaPipe Handsで手の認識処理をやってみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n\n<p>MediaPipe Handsを使って手の認識処理を行ってみる。<br />\nMediaPipeを使用するとかなり簡単に手の特徴点を取得できる。<br />\nまた、各特徴点の位置がわかるので、それらの位置関係からポーズを取得することもできる。</p>\n\n<p>参考: <a href=\"https://google.github.io/mediapipe/solutions/hands.html\" target=\"_blank\">https://google.github.io/mediapipe/solutions/hands.html</a></p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"python仮想環境の準備\">python仮想環境の準備</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># 作業ディレクトリ作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/ble/mediapipe\n<span class=\"nb\">cd</span> /work/ble/mediapipe\n\n<span class=\"c\"># 仮想環境構築</span>\npyenv virtualenv 3.8.11 mediapipe\npyenv <span class=\"nb\">local </span>mediapipe\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n\n<span class=\"c\"># 必要なライブラリのインストール</span>\npip <span class=\"nb\">install </span>mediapipe\n</code></pre></div></div>\n\n<h1 id=\"プログラム\">プログラム</h1>\n<h2 id=\"共通ルーチン\">共通ルーチン</h2>\n\n<p>各指の関節と指先の位置関係から指が伸びているのか、曲がっているのかを判別し(親指だけは各関節の角度から判別)、<br />\nその組み合わせからどのようなポーズなのかを判別している。<br />\nアルゴリズムは <a href=\"https://github.com/geaxgx/openvino_hand_tracker\">https://github.com/geaxgx/openvino_hand_tracker</a> から拝借した。<br />\n元のプログラムは各関節の位置を検出された手の画像を回転して角度調整した画像のY座標から取得しているが、<br />\n今回は手の角度が分からないので、手首から各関節位置までの距離を比較するように変更した。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  hand_gesture.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">HandLandmark</span> <span class=\"o\">=</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">distance</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">):</span>\n    <span class=\"c1\"># a, b: 2 points in 3D (x,y,z)\n</span>    <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">a</span> <span class=\"o\">-</span> <span class=\"n\">b</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">angle</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span><span class=\"p\">,</span> <span class=\"n\">c</span><span class=\"p\">):</span>\n    <span class=\"c1\"># a, b and c : points as np.array([x, y, z]) \n</span>    <span class=\"n\">ba</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">-</span> <span class=\"n\">b</span>\n    <span class=\"n\">bc</span> <span class=\"o\">=</span> <span class=\"n\">c</span> <span class=\"o\">-</span> <span class=\"n\">b</span>\n    <span class=\"n\">cosine_angle</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">dot</span><span class=\"p\">(</span><span class=\"n\">ba</span><span class=\"p\">,</span> <span class=\"n\">bc</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"p\">(</span><span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">ba</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">bc</span><span class=\"p\">))</span>\n    <span class=\"n\">angle</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">arccos</span><span class=\"p\">(</span><span class=\"n\">cosine_angle</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">degrees</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># ジェスチャの認識\n# 参考: https://github.com/geaxgx/openvino_hand_tracker\n</span><span class=\"k\">def</span> <span class=\"nf\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">debug</span> <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">):</span>\n    <span class=\"c1\"># 各landmarkの手首からの距離を求める\n</span>    <span class=\"n\">lm_pos</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">array</span><span class=\"p\">([[</span><span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">lm</span><span class=\"p\">.</span><span class=\"n\">z</span><span class=\"p\">]</span> <span class=\"k\">for</span> <span class=\"n\">lm</span> <span class=\"ow\">in</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">])</span>    <span class=\"c1\"># 計算のためndarray化\n</span>    <span class=\"c1\"># lm_pos = np.array([[lm.x, lm.y] for lm in landmarks.landmark])          # 計算のためndarray化(zは無視)\n</span>    <span class=\"n\">r_</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"p\">.</span><span class=\"n\">linalg</span><span class=\"p\">.</span><span class=\"n\">norm</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span> <span class=\"o\">-</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">WRIST</span><span class=\"p\">],</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>        <span class=\"c1\"># numpyなので一括計算\n</span>    \n    <span class=\"c1\"># 親指の角度で状態判別\n</span>    <span class=\"n\">distance0</span> <span class=\"o\">=</span> <span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">],</span>     <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指の第二関節と人差し指の付け根の距離\n</span>    <span class=\"n\">distance1</span> <span class=\"o\">=</span> <span class=\"n\">distance</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span>    <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">]</span>        <span class=\"p\">)</span>     <span class=\"c1\"># 親指の付け根と親指の第二関節の距離\n</span>    <span class=\"n\">angle0</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">WRIST</span><span class=\"p\">],</span>      <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_CMC</span><span class=\"p\">],</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指付け根の角度\n</span>    <span class=\"n\">angle1</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_CMC</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span> <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">]</span> <span class=\"p\">)</span>     <span class=\"c1\"># 親指第二関節の角度\n</span>    <span class=\"n\">angle2</span> <span class=\"o\">=</span> <span class=\"n\">angle</span><span class=\"p\">(</span><span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_MCP</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_IP</span><span class=\"p\">],</span>  <span class=\"n\">lm_pos</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">THUMB_TIP</span><span class=\"p\">])</span>     <span class=\"c1\"># 親指第一関節の角度\n</span>    <span class=\"n\">thumb_angle</span> <span class=\"o\">=</span> <span class=\"n\">angle0</span> <span class=\"o\">+</span> <span class=\"n\">angle1</span> <span class=\"o\">+</span> <span class=\"n\">angle2</span>\n    <span class=\"k\">if</span> <span class=\"n\">thumb_angle</span> <span class=\"o\">></span> <span class=\"mi\">460</span> <span class=\"ow\">and</span> <span class=\"n\">distance0</span> <span class=\"o\">/</span> <span class=\"n\">distance1</span> <span class=\"o\">></span> <span class=\"mf\">1.2</span><span class=\"p\">:</span> \n        <span class=\"n\">thumb_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">thumb_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    \n    <span class=\"c1\"># 人差し指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">index_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 中指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">MIDDLE_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">middle_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 薬指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">RING_FINGER_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">ring_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># 小指の状態\n</span>    <span class=\"k\">if</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_TIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_DIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_PIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_PIP</span><span class=\"p\">]</span> <span class=\"o\">></span> <span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">PINKY_TIP</span><span class=\"p\">]</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">pinky_state</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n    <span class=\"c1\"># Gesture\n</span>    <span class=\"k\">if</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FIST\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"OK\"</span> \n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"PEACE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"ONE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"TWO\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"THREE\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>      <span class=\"c1\"># 日本型の3\n</span>        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"THREE_J\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FOUR\"</span>\n    <span class=\"k\">elif</span> <span class=\"n\">thumb_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">index_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">middle_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">ring_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">pinky_state</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"s\">\"FIVE\"</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n    \n    <span class=\"c1\"># for debug\n</span>    <span class=\"c1\"># print(f'{r_[HandLandmark.INDEX_FINGER_MCP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_PIP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_DIP]:6.3f}  {r_[HandLandmark.INDEX_FINGER_TIP]:6.3f}    {index_state}')\n</span>\n    <span class=\"k\">if</span> <span class=\"n\">debug</span> <span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">21</span><span class=\"p\">):</span>\n            <span class=\"n\">lm_x</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"c1\"># * image_width\n</span>            <span class=\"n\">lm_y</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"c1\"># * image_height\n</span>            <span class=\"n\">lm_z</span> <span class=\"o\">=</span> <span class=\"n\">landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">].</span><span class=\"n\">z</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">HandLandmark</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">))</span><span class=\"si\">:</span><span class=\"mi\">32</span><span class=\"n\">s</span><span class=\"si\">}</span><span class=\"s\">(</span><span class=\"si\">{</span><span class=\"n\">i</span><span class=\"si\">:</span><span class=\"mi\">2</span><span class=\"n\">d</span><span class=\"si\">}</span><span class=\"s\">):   </span><span class=\"si\">{</span><span class=\"n\">lm_x</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">, </span><span class=\"si\">{</span><span class=\"n\">lm_y</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">,</span><span class=\"si\">{</span><span class=\"n\">lm_z</span><span class=\"si\">:</span><span class=\"mf\">9.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\"> </span><span class=\"si\">{</span><span class=\"n\">r_</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"si\">:</span><span class=\"mf\">6.3</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">gesture</span>\n</code></pre></div></div>\n\n<h2 id=\"カメラ画像から認識\">カメラ画像から認識</h2>\n<p>カメラ画像から認識してみる。<br />\nこっちの方が用途は多いかな。<br />\nコマンドラインオプションについてはソース見てちょ。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  test_camera.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span>  <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span>         <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-nh\"</span><span class=\"p\">,</span> <span class=\"s\">\"--num_hand\"</span><span class=\"p\">,</span>         <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span>   <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Max number of hands\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num_hand</span>            <span class=\"c1\"># 検出する手の個数\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">verbose2</span>                 <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>\n<span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">True</span>                    <span class=\"c1\"># 鏡像使用\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># カメラ\n</span><span class=\"n\">cap</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">VideoCapture</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span>   <span class=\"o\">=</span> <span class=\"bp\">False</span><span class=\"p\">,</span>            <span class=\"c1\"># 動画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>        <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 前のフレーム処理完了時刻を初期化\n</span>    \n    <span class=\"k\">while</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">isOpened</span><span class=\"p\">():</span>\n        <span class=\"c1\"># キャプチャ\n</span>        <span class=\"n\">success</span><span class=\"p\">,</span> <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">success</span><span class=\"p\">:</span>\n            <span class=\"c1\"># エラーになったら再度キャプチャ\n</span>            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Ignoring empty camera frame.\"</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n        \n        <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>        <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n            <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 画像サイズ\n</span>        <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n        \n        <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>        <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n        \n        <span class=\"c1\"># 検出結果の処理\n</span>        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">handedness</span> <span class=\"ow\">in</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_handedness</span><span class=\"p\">):</span>\n                <span class=\"k\">if</span> <span class=\"n\">verbose</span> <span class=\"ow\">or</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'--------------------------------------------------------------------------'</span><span class=\"p\">)</span>\n                \n                <span class=\"c1\"># データは鏡像として判別されているので、鏡像でなければラベルを入れ替え\n</span>                <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"k\">if</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span> <span class=\"o\">==</span> <span class=\"s\">\"Left\"</span> <span class=\"p\">:</span>\n                        <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Right\"</span>\n                    <span class=\"k\">else</span> <span class=\"p\">:</span>\n                        <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Left\"</span>\n                \n                <span class=\"c1\"># ジェスチャの認識\n</span>                <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n                \n                <span class=\"k\">if</span> <span class=\"n\">verbose2</span> <span class=\"p\">:</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'==== sore ======================='</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">index</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'score   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">score</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'label   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>            <span class=\"c1\"># あんまりあてにならないな...\n</span>                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'gesture : </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n                    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'================================='</span><span class=\"p\">)</span>\n                \n                <span class=\"c1\"># landmarkの描画\n</span>                <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">draw_landmarks</span><span class=\"p\">(</span>\n                    <span class=\"n\">image</span><span class=\"p\">,</span>                              <span class=\"c1\"># 画像\n</span>                    <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span>                     <span class=\"c1\"># ランドマーク\n</span>                    <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span>          <span class=\"c1\"># ランドマーク接続リスト\n</span>                    <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_landmarks_style</span><span class=\"p\">(),</span>       <span class=\"c1\"># ランドマーク描画スタイル\n</span>                    <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_connections_style</span><span class=\"p\">()</span>      <span class=\"c1\"># 接続描画スタイル\n</span>                <span class=\"p\">)</span>\n                <span class=\"c1\"># ジェスチャ表示\n</span>                <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"p\">:</span>\n                    <span class=\"c1\"># 人差し指の付け根あたりに表示\n</span>                    <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n                    <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                        <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                        <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>     <span class=\"c1\"># 文字列\n</span>                        <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">),</span>                     <span class=\"c1\"># 座標\n</span>                        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                        <span class=\"mi\">1</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                        <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                        <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>                    <span class=\"p\">)</span>\n        \n        <span class=\"c1\"># フレーム処理時間\n</span>        <span class=\"n\">cur_time</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>                              <span class=\"c1\"># 現在のフレーム処理完了時刻\n</span>        <span class=\"n\">frame_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span> <span class=\"o\">-</span> <span class=\"n\">prev_time</span>                   <span class=\"c1\"># このフレームの処理時間\n</span>        <span class=\"n\">prev_time</span> <span class=\"o\">=</span> <span class=\"n\">cur_time</span>\n        \n        <span class=\"c1\"># FPS表示\n</span>        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                <span class=\"sa\">f</span><span class=\"s\">'FPS:</span><span class=\"si\">{</span><span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"n\">frame_time</span><span class=\"si\">:</span><span class=\"p\">.</span><span class=\"mi\">2</span><span class=\"n\">f</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>  <span class=\"c1\"># 文字列\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">50</span><span class=\"p\">),</span>                    <span class=\"c1\"># 座標\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>            <span class=\"p\">)</span>\n        <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 表示終了待ち\n</span>        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'v'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'b'</span><span class=\"p\">):</span>\n            <span class=\"n\">verbose2</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"n\">verbose2</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'q'</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"mi\">27</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n<span class=\"c1\"># ウィンドウをすべて閉じる\n</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># カメラリリース\n</span><span class=\"n\">cap</span><span class=\"p\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"静止画像から認識\">静止画像から認識</h2>\n\n<p>デバッグ用途など、静止画から認識する場合はこちら。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  test_photo.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># 参考:\n# https://google.github.io/mediapipe/solutions/hands.html\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cv2</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">mediapipe</span> <span class=\"k\">as</span> <span class=\"n\">mp</span>\n<span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"n\">np</span>\n<span class=\"kn\">from</span> <span class=\"nn\">argparse</span> <span class=\"kn\">import</span> <span class=\"n\">ArgumentParser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">hand_gesture</span> <span class=\"kn\">import</span> <span class=\"n\">recognize_gesture</span>\n\n<span class=\"n\">mp_hands</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">hands</span>\n<span class=\"n\">mp_drawing</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_utils</span>\n<span class=\"n\">mp_drawing_styles</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"p\">.</span><span class=\"n\">solutions</span><span class=\"p\">.</span><span class=\"n\">drawing_styles</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">build_argparser</span><span class=\"p\">():</span>\n    <span class=\"n\">parser</span> <span class=\"o\">=</span> <span class=\"n\">ArgumentParser</span><span class=\"p\">()</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'input'</span><span class=\"p\">,</span> <span class=\"n\">metavar</span><span class=\"o\">=</span><span class=\"s\">\"INPUT_FILE\"</span><span class=\"p\">,</span>                          <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"Path to the input picture \"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'-v'</span><span class=\"p\">,</span> <span class=\"s\">'--verbose'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                 <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp verbose message\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--detail'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                        <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) use full model\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">'--world'</span><span class=\"p\">,</span> <span class=\"n\">action</span><span class=\"o\">=</span><span class=\"s\">'store_true'</span><span class=\"p\">,</span>                         <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) disp world landmark map\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-nh\"</span><span class=\"p\">,</span> <span class=\"s\">\"--num_hand\"</span><span class=\"p\">,</span>         <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span>   <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span>     <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Max number of hands\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-dt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--detect_threshold\"</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Detection threshold\"</span><span class=\"p\">)</span>\n    <span class=\"n\">parser</span><span class=\"p\">.</span><span class=\"n\">add_argument</span><span class=\"p\">(</span><span class=\"s\">\"-tt\"</span><span class=\"p\">,</span> <span class=\"s\">\"--track_threshold\"</span><span class=\"p\">,</span>  <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"nb\">type</span><span class=\"o\">=</span><span class=\"nb\">float</span><span class=\"p\">,</span>   <span class=\"n\">help</span><span class=\"o\">=</span><span class=\"s\">\"(optional) Tracking threshold\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">return</span> <span class=\"n\">parser</span>\n\n<span class=\"c1\"># コマンドラインパラメータの取得\n</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">build_argparser</span><span class=\"p\">().</span><span class=\"n\">parse_args</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># 入力ファイル名\n</span><span class=\"nb\">file</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"nb\">input</span>\n\n<span class=\"c1\"># mediapipe パラメータ\n</span><span class=\"n\">model_complexity</span>         <span class=\"o\">=</span> <span class=\"mi\">1</span> <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detail</span> <span class=\"k\">else</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span><span class=\"n\">max_num_hands</span>            <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">num_hand</span>            <span class=\"c1\"># 検出する手の個数\n</span><span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">detect_threshold</span>    <span class=\"c1\"># 閾値\n</span><span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">track_threshold</span>     <span class=\"c1\"># 閾値\n</span><span class=\"n\">verbose</span>                  <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">verbose</span>             <span class=\"c1\"># デバッグメッセージ\n</span><span class=\"n\">use_mirror_image</span>         <span class=\"o\">=</span> <span class=\"bp\">False</span>                    <span class=\"c1\"># 鏡像使用しない\n</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'max_num_hands:</span><span class=\"si\">{</span><span class=\"n\">max_num_hands</span><span class=\"si\">}</span><span class=\"s\">   model_complexity:</span><span class=\"si\">{</span><span class=\"n\">model_complexity</span><span class=\"si\">}</span><span class=\"s\">    min_detection_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_detection_confidence</span><span class=\"si\">}</span><span class=\"s\">    min_tracking_confidence:</span><span class=\"si\">{</span><span class=\"n\">min_tracking_confidence</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># mediapipeのオープン\n</span><span class=\"k\">with</span> <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">Hands</span><span class=\"p\">(</span>\n                        <span class=\"n\">static_image_mode</span> <span class=\"o\">=</span> <span class=\"bp\">True</span><span class=\"p\">,</span>               <span class=\"c1\"># 静止画モード\n</span>                        <span class=\"n\">max_num_hands</span>    <span class=\"o\">=</span> <span class=\"n\">max_num_hands</span><span class=\"p\">,</span>       <span class=\"c1\"># 検出する手の個数\n</span>                        <span class=\"n\">model_complexity</span> <span class=\"o\">=</span> <span class=\"n\">model_complexity</span><span class=\"p\">,</span>    <span class=\"c1\"># 0: liteモデル /1: fullモデル\n</span>                        <span class=\"n\">min_detection_confidence</span> <span class=\"o\">=</span> <span class=\"n\">min_detection_confidence</span><span class=\"p\">,</span>    <span class=\"c1\"># 閾値\n</span>                        <span class=\"n\">min_tracking_confidence</span>  <span class=\"o\">=</span> <span class=\"n\">min_tracking_confidence</span>      <span class=\"c1\"># 閾値\n</span>                    <span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">hands</span><span class=\"p\">:</span>\n    \n    <span class=\"c1\"># 画像読み込み\n</span>    <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imread</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">)</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'file name : </span><span class=\"si\">{</span><span class=\"nb\">file</span><span class=\"si\">}</span><span class=\"s\">   image size : </span><span class=\"si\">{</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 鏡像表示する場合は左右反転する\n</span>    <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n        <span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">flip</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 画像サイズ\n</span>    <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">_</span> <span class=\"o\">=</span> <span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">shape</span>\n    \n    <span class=\"c1\"># BGR画像をRGB画像に変換して認識処理\n</span>    <span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">hands</span><span class=\"p\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">cvtColor</span><span class=\"p\">(</span><span class=\"n\">image</span><span class=\"p\">,</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">COLOR_BGR2RGB</span><span class=\"p\">))</span>\n    \n    <span class=\"c1\"># 検出結果の処理\n</span>    <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">handedness</span> <span class=\"ow\">in</span> <span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_handedness</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">verbose</span> <span class=\"p\">:</span>\n                <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'--------------------------------------------------------------------------'</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># データは鏡像として判別されているので、鏡像でなければラベルを入れ替え\n</span>            <span class=\"k\">if</span> <span class=\"n\">use_mirror_image</span> <span class=\"p\">:</span>\n                <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span>\n            <span class=\"k\">else</span> <span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">label</span> <span class=\"o\">==</span> <span class=\"s\">\"Left\"</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Right\"</span>\n                <span class=\"k\">else</span> <span class=\"p\">:</span>\n                    <span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"s\">\"Left\"</span>\n            \n            <span class=\"c1\"># ジェスチャの認識\n</span>            <span class=\"n\">gesture</span> <span class=\"o\">=</span> <span class=\"n\">recognize_gesture</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">,</span> <span class=\"n\">image_height</span><span class=\"p\">,</span> <span class=\"n\">image_width</span><span class=\"p\">,</span> <span class=\"n\">verbose</span><span class=\"p\">)</span>\n            \n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'==== sore ======================='</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'index   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">index</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'score   : </span><span class=\"si\">{</span><span class=\"n\">handedness</span><span class=\"p\">.</span><span class=\"n\">classification</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">].</span><span class=\"n\">score</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'label   : </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">'gesture : </span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">)</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'================================='</span><span class=\"p\">)</span>\n            \n            <span class=\"c1\"># landmarkの描画\n</span>            <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">draw_landmarks</span><span class=\"p\">(</span>\n                <span class=\"n\">image</span><span class=\"p\">,</span>                              <span class=\"c1\"># 画像\n</span>                <span class=\"n\">hand_landmarks</span><span class=\"p\">,</span>                     <span class=\"c1\"># ランドマーク\n</span>                <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span>          <span class=\"c1\"># ランドマーク接続リスト\n</span>                <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_landmarks_style</span><span class=\"p\">(),</span>       <span class=\"c1\"># ランドマーク描画スタイル\n</span>                <span class=\"n\">mp_drawing_styles</span><span class=\"p\">.</span><span class=\"n\">get_default_hand_connections_style</span><span class=\"p\">()</span>      <span class=\"c1\"># 接続描画スタイル\n</span>            <span class=\"p\">)</span>\n            <span class=\"c1\"># ジェスチャ表示\n</span>            <span class=\"k\">if</span> <span class=\"n\">gesture</span> <span class=\"p\">:</span>\n                <span class=\"c1\"># 人差し指の付け根あたりに表示\n</span>                <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">image_width</span><span class=\"p\">)</span>\n                <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">hand_landmarks</span><span class=\"p\">.</span><span class=\"n\">landmark</span><span class=\"p\">[</span><span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HandLandmark</span><span class=\"p\">.</span><span class=\"n\">INDEX_FINGER_MCP</span> <span class=\"p\">].</span><span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">image_height</span><span class=\"p\">)</span>\n                <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">putText</span><span class=\"p\">(</span>\n                    <span class=\"n\">image</span><span class=\"p\">,</span>                      <span class=\"c1\"># 画像\n</span>                    <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">gesture</span><span class=\"si\">}</span><span class=\"s\">   </span><span class=\"si\">{</span><span class=\"n\">label</span><span class=\"si\">}</span><span class=\"s\">'</span><span class=\"p\">,</span>     <span class=\"c1\"># 文字列\n</span>                    <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">),</span>                     <span class=\"c1\"># 座標\n</span>                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">FONT_HERSHEY_SIMPLEX</span><span class=\"p\">,</span>   <span class=\"c1\"># フォント\n</span>                    <span class=\"mi\">1</span><span class=\"p\">,</span>                          <span class=\"c1\"># フォントスケール\n</span>                    <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">255</span><span class=\"p\">),</span>                <span class=\"c1\"># 色\n</span>                    <span class=\"mi\">2</span><span class=\"p\">,</span>                          <span class=\"c1\"># 文字の太さ\n</span>                    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">LINE_AA</span>                 <span class=\"c1\"># 描画アルゴリズム\n</span>                <span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"** NO HANDS **\"</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 表示\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imshow</span><span class=\"p\">(</span><span class=\"s\">'MediaPipe Hands'</span><span class=\"p\">,</span> <span class=\"n\">image</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 表示終了待ち\n</span>    <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n        <span class=\"n\">k</span> <span class=\"o\">=</span> <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">waitKey</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">k</span> <span class=\"o\">==</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"s\">'p'</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">imwrite</span><span class=\"p\">(</span>\n                    <span class=\"s\">'output_'</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"p\">),</span> \n                    <span class=\"n\">image</span>\n                <span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"ow\">not</span> <span class=\"n\">k</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n          <span class=\"k\">break</span>\n    \n    <span class=\"c1\"># ウィンドウをすべて閉じる\n</span>    <span class=\"n\">cv2</span><span class=\"p\">.</span><span class=\"n\">destroyAllWindows</span><span class=\"p\">()</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">args</span><span class=\"p\">.</span><span class=\"n\">world</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># hand world landmarks の 3D座標の表示\n</span>        <span class=\"k\">if</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_world_landmarks</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">hand_world_landmarks</span> <span class=\"ow\">in</span> <span class=\"n\">results</span><span class=\"p\">.</span><span class=\"n\">multi_hand_world_landmarks</span><span class=\"p\">:</span>\n                <span class=\"n\">mp_drawing</span><span class=\"p\">.</span><span class=\"n\">plot_landmarks</span><span class=\"p\">(</span>\n                                <span class=\"n\">hand_world_landmarks</span><span class=\"p\">,</span> \n                                <span class=\"n\">mp_hands</span><span class=\"p\">.</span><span class=\"n\">HAND_CONNECTIONS</span><span class=\"p\">,</span> \n                                <span class=\"n\">azimuth</span><span class=\"o\">=</span><span class=\"mi\">5</span>\n                            <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<h2 id=\"カメラ画像から認識-1\">カメラ画像から認識</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: test_camera.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-nh</span> NUM_HAND]\n                      <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">-nh</span> NUM_HAND, <span class=\"nt\">--num_hand</span> NUM_HAND\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Max number of hands\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h2 id=\"静止画像から認識-1\">静止画像から認識</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usage: test_photo.py <span class=\"o\">[</span><span class=\"nt\">-h</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-v</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--detail</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">--world</span><span class=\"o\">]</span> <span class=\"o\">[</span><span class=\"nt\">-nh</span> NUM_HAND]\n                     <span class=\"o\">[</span><span class=\"nt\">-dt</span> DETECT_THRESHOLD] <span class=\"o\">[</span><span class=\"nt\">-tt</span> TRACK_THRESHOLD]\n                     INPUT_FILE\n\npositional arguments:\n  INPUT_FILE            Path to the input picture\n\noptional arguments:\n  <span class=\"nt\">-h</span>, <span class=\"nt\">--help</span>            show this <span class=\"nb\">help </span>message and <span class=\"nb\">exit</span>\n  <span class=\"nt\">-v</span>, <span class=\"nt\">--verbose</span>         <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp verbose message\n  <span class=\"nt\">--detail</span>              <span class=\"o\">(</span>optional<span class=\"o\">)</span> use full model\n  <span class=\"nt\">--world</span>               <span class=\"o\">(</span>optional<span class=\"o\">)</span> disp world landmark map\n  <span class=\"nt\">-nh</span> NUM_HAND, <span class=\"nt\">--num_hand</span> NUM_HAND\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Max number of hands\n  <span class=\"nt\">-dt</span> DETECT_THRESHOLD, <span class=\"nt\">--detect_threshold</span> DETECT_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Detection threshold\n  <span class=\"nt\">-tt</span> TRACK_THRESHOLD, <span class=\"nt\">--track_threshold</span> TRACK_THRESHOLD\n                        <span class=\"o\">(</span>optional<span class=\"o\">)</span> Tracking threshold\n</code></pre></div></div>\n\n<h1 id=\"説明\">説明</h1>\n\n<p>説明….するほどのことはないな。<br />\nほとんど出来あいの処理。</p>\n\n<p>各指の状態からポーズを取得する処理を変更すれば、ほかの認識(ジャンケン認識など)にも変更可能。<br />\nまた、人差し指の指先をトラッキングしていけば、バーチャルお絵描きなんてのもできるかも。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "linux": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>キーボードコマンダーのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>キーボードコマンダーのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用キーボードコマンダーのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/18/key_commander_1.html\" target=\"_blank\">キーボードコマンダーのひな型(C言語版)</a>\nのpython版も作/memoBlog定して使うだけなんだけど、<br />\nstdinの設定を元に戻すのを忘れないように、クラス化してデストラクタで設定を戻すようにしてみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれまでatexitモジュール使って終了処理ルーチン登録して<br />\nそこで元に戻してたけど、処理追加忘れて悲しいことになったことが数知れず…</p>\n</blockquote>\n\n<h1 id=\"ちょっと解説\">ちょっと解説</h1>\n<p>このクラスは、複数の箇所からインスタンスを作成してしまうとstdinの設定変更が複数箇所で行われてしまい、<br />\nデストラクタの実行順序によっては正常に元に戻せなくなる可能性がある。<br />\nそれを回避するため、Singletonパターンを適用し、インスタンスが一つだけ保持するようにした。</p>\n\n<p>しかし、これだけでは不十分で、コンストラクタ(<code class=\"language-plaintext highlighter-rouge\">__init__()</code>)が<code class=\"language-plaintext highlighter-rouge\">KeyReader()</code>実行の度に実行されてしまう。(下のNOTE参照) <br />\nそこで、インスタンス変数にコンストラクタ実行済みフラグ(<code class=\"language-plaintext highlighter-rouge\">_inited</code>)を用意し、\nこれが存在しないときのみコンストラクタ処理を実行するようにしている。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">__new__</code>、<code class=\"language-plaintext highlighter-rouge\">__init__</code>、<code class=\"language-plaintext highlighter-rouge\">__del__</code>の実行タイミングは以下のプログラムで確認できる。</p>\n\n  <pre><code class=\"language-pythn\">class Hoge:\n    def __new__(cls, *args, **kargs):\n        print(\"__new__\")\n        if not hasattr(cls, \"_instance\"):\n            print(\"create\")\n            cls._instance = super().__new__(cls)\n        return cls._instance\n    \n    # コンストラクタ\n    def __init__(self):\n        print(\"__init__\")\n        if not hasattr(self, \"_inited\"):\n            print(\"init\")\n            self._inited = True\n    \n    # デストラクタ\n    def __del__(self):\n        print(\"__del__\")\n    \n    def __call__(self):\n        print(\"__call__\")\n\ndef func2() :\n    h2 = Hoge()\n    print(\"h2 before\")\n    h2()\n    print(\"h2 after\")\n\ndef func1() :\n    h1 = Hoge()\n    print(\"h1 before\")\n    h1()\n    print(\"h1 after\")\n\nprint(\"func1 before\")\nfunc1()\nprint(\"func1 after\")\n\nprint(\"func2 before\")\nfunc2()\nprint(\"func2 after\")\n\nprint(\"end\")\n\n</code></pre>\n  <p>実行結果は以下。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>func1 before\n__new__\ncreate                  ← 1回だけ表示されている\n__init__\ninit                    ← 1回だけ表示されている\nh1 before\n__call__\nh1 after\nfunc1 after\nfunc2 before\n__new__\n__init__\nh2 before\n__call__\nh2 after\nfunc2 after\nend\n__del__\n</code></pre></div>  </div>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">Hoge()</code>が実行されると、<code class=\"language-plaintext highlighter-rouge\">__new__()</code>が実行されるが、\n2回目以降は新たにインスタンスを作成せずクラス変数<code class=\"language-plaintext highlighter-rouge\">_instance</code>に格納されたインスタンスを返す。<br />\n(2回目は「create」が表示されていない)</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__init__()</code>が<code class=\"language-plaintext highlighter-rouge\">Hoge()</code>実行の度に実行されているのが分かる。<br />\n(つまりインスタンス生成時に実行されるわけではない)<br />\n<code class=\"language-plaintext highlighter-rouge\">__init__()</code>内でインスタンス変数<code class=\"language-plaintext highlighter-rouge\">_inited</code>の存在をチェックしているので<br />\n「init」は1回しか表示されていないのが分かる。</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__del__()</code> はインスタンス破棄時に実行されるので、1回しか実行されない。</p>\n\n</blockquote>\n\n<p>その他のプログラムの動作についてはソース読んでちょ。<br />\nって、ほとんど何もしてないけど。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>キーボードコマンダーのひな型(C言語版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>キーボードコマンダーのひな型(C言語版)</h1>\n      <p>linuxでのテストプログラム用キーボードコマンダー</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/15/test_shell_1.html\" target=\"_blank\">test shellのひな型</a>\nのようなテストシェルでコマンド処理するほどでもないが、いくつかのパターンを繰り返し実行してテストしてみたい\n場合に使えるキーボードコマンダー(という名前がふさわしいか分からないが)のひな型を作ってみた。</p>\n\n<p>キー入力1個(例えば<code class=\"language-plaintext highlighter-rouge\">a</code>キー)でリターンを押さずに何らかの処理が実行できると便利な時がある。<br />\nまた、ターゲットボードのスイッチ入力の代替処理としても便利かもしれない。</p>\n\n<p>Windowsの<code class=\"language-plaintext highlighter-rouge\">getch()</code>関数みたいなものと言えば分かるかな?<br />\nキー入力自体はブロッキング処理なので、<code class=\"language-plaintext highlighter-rouge\">kbhit()</code>みたいな使い方はできない。<br />\n(これを行うには<code class=\"language-plaintext highlighter-rouge\">select()</code>をタイムアウト付きで組み合わせて使う必要があるが、\n簡単なテスト用を想定しているので そこまでは対応しない)</p>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n大体コメントに書いたつもり。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6435ac7e3381ec2f8af0b1fdb166d469\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6435ac7e3381ec2f8af0b1fdb166d469.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>test shellのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>test shellのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用コマンド入力処理のサンプルのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/15/test_shell_1.html\" target=\"_blank\">test shellのひな型</a>\nでC言語版を作ったので、python版も作っておこうかと作ってみた。</p>\n\n<p>pythonには『行指向のコマンドインタープリタのサポート』というcmdモジュールが標準で用意されている。<br />\nこれを使用すれば、そんなに手間もかからず実装できる。<br />\n補完処理やヘルプ表示も簡単。<br />\nコマンドの大文字/小文字同一視はできなかったけど…</p>\n\n<p>コマンド補完だけでなく、パラメータ補完も可能。<br />\nもちろん、補完のための処理は書かないといけないけど。</p>\n\n<p>標準モジュールしか使ってないので、モジュールをインストールする必要なし。</p>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n大体コメントに書いたつもり。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>test shellのひな型</title>\n  </head>\n  <body>\n    <header>\n      <h1>test shellのひな型</h1>\n      <p>linuxでのテストプログラム用コマンド入力処理のサンプル</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>linuxでプログラムを作ったとき、ユニットテストを各処理(コマンド)単位で行いたいときに、テストシェルを作ると便利。<br />\nでも、その都度作っていると効率悪いので、ひな型を作ってみた。<br />\nどうせなら、コマンドヒストリとか、入力補完とかあると便利だなぁ~、ということで、<br />\n<code class=\"language-plaintext highlighter-rouge\">readline</code>使ってそれらを実現しておく。</p>\n\n<p>たぶん、bash使ってるシステムなら<code class=\"language-plaintext highlighter-rouge\">libreadline</code>も入ってるだろうから、特にインストールとかも不要。</p>\n\n<h1 id=\"コンパイル方法\">コンパイル方法</h1>\n<p>以下のコマンドでコンパイルできる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gcc test_shell.c <span class=\"nt\">-lreadline</span> <span class=\"nt\">-o</span> test_shell\n</code></pre></div></div>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n『コマンド定義』の部分を所望のコマンドと処理に書き換えて使ってちょ。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/fbccd09aefa28dd097a13c68d0111d0d\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/fbccd09aefa28dd097a13c68d0111d0d.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "sample program": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>キーボードコマンダーのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>キーボードコマンダーのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用キーボードコマンダーのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/18/key_commander_1.html\" target=\"_blank\">キーボードコマンダーのひな型(C言語版)</a>\nのpython版も作/memoBlog定して使うだけなんだけど、<br />\nstdinの設定を元に戻すのを忘れないように、クラス化してデストラクタで設定を戻すようにしてみた。</p>\n\n<blockquote>\n  <p>[!NOTE]\nこれまでatexitモジュール使って終了処理ルーチン登録して<br />\nそこで元に戻してたけど、処理追加忘れて悲しいことになったことが数知れず…</p>\n</blockquote>\n\n<h1 id=\"ちょっと解説\">ちょっと解説</h1>\n<p>このクラスは、複数の箇所からインスタンスを作成してしまうとstdinの設定変更が複数箇所で行われてしまい、<br />\nデストラクタの実行順序によっては正常に元に戻せなくなる可能性がある。<br />\nそれを回避するため、Singletonパターンを適用し、インスタンスが一つだけ保持するようにした。</p>\n\n<p>しかし、これだけでは不十分で、コンストラクタ(<code class=\"language-plaintext highlighter-rouge\">__init__()</code>)が<code class=\"language-plaintext highlighter-rouge\">KeyReader()</code>実行の度に実行されてしまう。(下のNOTE参照) <br />\nそこで、インスタンス変数にコンストラクタ実行済みフラグ(<code class=\"language-plaintext highlighter-rouge\">_inited</code>)を用意し、\nこれが存在しないときのみコンストラクタ処理を実行するようにしている。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">__new__</code>、<code class=\"language-plaintext highlighter-rouge\">__init__</code>、<code class=\"language-plaintext highlighter-rouge\">__del__</code>の実行タイミングは以下のプログラムで確認できる。</p>\n\n  <pre><code class=\"language-pythn\">class Hoge:\n    def __new__(cls, *args, **kargs):\n        print(\"__new__\")\n        if not hasattr(cls, \"_instance\"):\n            print(\"create\")\n            cls._instance = super().__new__(cls)\n        return cls._instance\n    \n    # コンストラクタ\n    def __init__(self):\n        print(\"__init__\")\n        if not hasattr(self, \"_inited\"):\n            print(\"init\")\n            self._inited = True\n    \n    # デストラクタ\n    def __del__(self):\n        print(\"__del__\")\n    \n    def __call__(self):\n        print(\"__call__\")\n\ndef func2() :\n    h2 = Hoge()\n    print(\"h2 before\")\n    h2()\n    print(\"h2 after\")\n\ndef func1() :\n    h1 = Hoge()\n    print(\"h1 before\")\n    h1()\n    print(\"h1 after\")\n\nprint(\"func1 before\")\nfunc1()\nprint(\"func1 after\")\n\nprint(\"func2 before\")\nfunc2()\nprint(\"func2 after\")\n\nprint(\"end\")\n\n</code></pre>\n  <p>実行結果は以下。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>func1 before\n__new__\ncreate                  ← 1回だけ表示されている\n__init__\ninit                    ← 1回だけ表示されている\nh1 before\n__call__\nh1 after\nfunc1 after\nfunc2 before\n__new__\n__init__\nh2 before\n__call__\nh2 after\nfunc2 after\nend\n__del__\n</code></pre></div>  </div>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">Hoge()</code>が実行されると、<code class=\"language-plaintext highlighter-rouge\">__new__()</code>が実行されるが、\n2回目以降は新たにインスタンスを作成せずクラス変数<code class=\"language-plaintext highlighter-rouge\">_instance</code>に格納されたインスタンスを返す。<br />\n(2回目は「create」が表示されていない)</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__init__()</code>が<code class=\"language-plaintext highlighter-rouge\">Hoge()</code>実行の度に実行されているのが分かる。<br />\n(つまりインスタンス生成時に実行されるわけではない)<br />\n<code class=\"language-plaintext highlighter-rouge\">__init__()</code>内でインスタンス変数<code class=\"language-plaintext highlighter-rouge\">_inited</code>の存在をチェックしているので<br />\n「init」は1回しか表示されていないのが分かる。</p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">__del__()</code> はインスタンス破棄時に実行されるので、1回しか実行されない。</p>\n\n</blockquote>\n\n<p>その他のプログラムの動作についてはソース読んでちょ。<br />\nって、ほとんど何もしてないけど。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/52abfcb0406019319befdbbbba83c5cc.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>キーボードコマンダーのひな型(C言語版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>キーボードコマンダーのひな型(C言語版)</h1>\n      <p>linuxでのテストプログラム用キーボードコマンダー</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/15/test_shell_1.html\" target=\"_blank\">test shellのひな型</a>\nのようなテストシェルでコマンド処理するほどでもないが、いくつかのパターンを繰り返し実行してテストしてみたい\n場合に使えるキーボードコマンダー(という名前がふさわしいか分からないが)のひな型を作ってみた。</p>\n\n<p>キー入力1個(例えば<code class=\"language-plaintext highlighter-rouge\">a</code>キー)でリターンを押さずに何らかの処理が実行できると便利な時がある。<br />\nまた、ターゲットボードのスイッチ入力の代替処理としても便利かもしれない。</p>\n\n<p>Windowsの<code class=\"language-plaintext highlighter-rouge\">getch()</code>関数みたいなものと言えば分かるかな?<br />\nキー入力自体はブロッキング処理なので、<code class=\"language-plaintext highlighter-rouge\">kbhit()</code>みたいな使い方はできない。<br />\n(これを行うには<code class=\"language-plaintext highlighter-rouge\">select()</code>をタイムアウト付きで組み合わせて使う必要があるが、\n簡単なテスト用を想定しているので そこまでは対応しない)</p>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n大体コメントに書いたつもり。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6435ac7e3381ec2f8af0b1fdb166d469\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6435ac7e3381ec2f8af0b1fdb166d469.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>test shellのひな型(python版)</title>\n  </head>\n  <body>\n    <header>\n      <h1>test shellのひな型(python版)</h1>\n      <p>linuxでのテストプログラム用コマンド入力処理のサンプルのpython版</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/05/15/test_shell_1.html\" target=\"_blank\">test shellのひな型</a>\nでC言語版を作ったので、python版も作っておこうかと作ってみた。</p>\n\n<p>pythonには『行指向のコマンドインタープリタのサポート』というcmdモジュールが標準で用意されている。<br />\nこれを使用すれば、そんなに手間もかからず実装できる。<br />\n補完処理やヘルプ表示も簡単。<br />\nコマンドの大文字/小文字同一視はできなかったけど…</p>\n\n<p>コマンド補完だけでなく、パラメータ補完も可能。<br />\nもちろん、補完のための処理は書かないといけないけど。</p>\n\n<p>標準モジュールしか使ってないので、モジュールをインストールする必要なし。</p>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n大体コメントに書いたつもり。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/34eecc51eec5e94ea121783fe5bdd368.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>test shellのひな型</title>\n  </head>\n  <body>\n    <header>\n      <h1>test shellのひな型</h1>\n      <p>linuxでのテストプログラム用コマンド入力処理のサンプル</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>linuxでプログラムを作ったとき、ユニットテストを各処理(コマンド)単位で行いたいときに、テストシェルを作ると便利。<br />\nでも、その都度作っていると効率悪いので、ひな型を作ってみた。<br />\nどうせなら、コマンドヒストリとか、入力補完とかあると便利だなぁ~、ということで、<br />\n<code class=\"language-plaintext highlighter-rouge\">readline</code>使ってそれらを実現しておく。</p>\n\n<p>たぶん、bash使ってるシステムなら<code class=\"language-plaintext highlighter-rouge\">libreadline</code>も入ってるだろうから、特にインストールとかも不要。</p>\n\n<h1 id=\"コンパイル方法\">コンパイル方法</h1>\n<p>以下のコマンドでコンパイルできる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gcc test_shell.c <span class=\"nt\">-lreadline</span> <span class=\"nt\">-o</span> test_shell\n</code></pre></div></div>\n\n<p>プログラムの動作についてはソース読んでちょ。<br />\n『コマンド定義』の部分を所望のコマンドと処理に書き換えて使ってちょ。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/fbccd09aefa28dd097a13c68d0111d0d\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/fbccd09aefa28dd097a13c68d0111d0d.js\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "RaspberryPiPICO": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) でI2C Slave その2</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) でI2C Slave その2</h1>\n      <p>Raspberry Pi Pico W の SDK を使用してI2C Slaveプログラムを作成する(その2)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2023/10/28/RasPiPico_i2c_slave.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) でI2C Slave</a>\nでI2Cスレーブのプログラムを載せましたが、ちょっと特殊な構成のデバイスをエミュレートしていたので\n一般的なレジスタアクセスをエミュレートするプログラムを作ってみました。</p>\n\n<blockquote>\n  <p>[!NOTE]\n公式サンプル<code class=\"language-plaintext highlighter-rouge\">pico-examples/i2c/slave_mem_i2c</code>をちょこっと修正しただけですが。</p>\n</blockquote>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"i2cの結線\">I2Cの結線</h2>\n\n<p>以下のように結線します。<br />\nPico側はソース中の割り当て端子を変更すれば別の端子でもOKです。<br />\n今回はI2C0とI2C1を使うので、両方結線します。<br />\npull-up抵抗はPi3についているのでここでは付けません。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>Pi3</th>\n      <th>Pico</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>SDA1(pin3)</td>\n      <td>I2C0_SDA/GP16(Pin21) I2C1_SDA/GP18(Pin24)</td>\n    </tr>\n    <tr>\n      <td>SCL1(pin5)</td>\n      <td>I2C0_SCL/GP17(Pin22) I2C1_SCL/GP19(Pin25)</td>\n    </tr>\n  </tbody>\n</table>\n\n<blockquote>\n  <p>[!NOTE]\n別に2ch使わなくても良いのですが、8bitアクセスと16bitアクセスを作りたかったので。<br />\nそれぞれ別のプログラムにすると動作確認が面倒だったのでまとめちゃいました。</p>\n</blockquote>\n\n<p>その他の準備は\n<a href=\"/memoBlog/2023/10/28/RasPiPico_i2c_slave.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) でI2C Slave</a>\nを参照してください。</p>\n\n<h1 id=\"picoのプログラム\">Picoのプログラム</h1>\n\n<h2 id=\"プロジェクト生成\">プロジェクト生成</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">pico_project</code>でプロジェクトを生成します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">pico_project</code>については、\n<a href=\"/memoBlog/2023/10/23/RasPiPico_3.html\" target=\"_blank\">Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</a>\nの「自作プロジェクトの作成」を参照してください)</p>\n</blockquote>\n\n<p>設定内容は以下の通りです</p>\n\n<ul>\n  <li>Project Name に プロジェクト名(例:i2c_slave_2ch)</li>\n  <li>Location に プロジェクトを作成するディレクトリ</li>\n  <li>Board Type で「pico_w」を選択</li>\n  <li>Library Options で「I2C interface」を選択</li>\n  <li>Pico wireless Options で「PicoW onboard LED」を選択</li>\n  <li>Console Options では必要な方式をチェック(両方でも可)</li>\n  <li>IDE Options で「Create VSCode Project」にチェック、「Debugger」は「SWD」を選択</li>\n</ul>\n\n<h2 id=\"プログラムの作成\">プログラムの作成</h2>\n<p>作成したプログラムを以下に示します。</p>\n\n<h3 id=\"メインルーチン\">メインルーチン</h3>\n\n<p>メインルーチンはI2Cを初期化したあと無限ループします。<br />\nループ内ではI2Cに関する処理はなく、生存確認用のLチカと\nキー入力監視して入力に応じて処理を行っています。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_2ch.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/stdlib.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"hardware/i2c.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/cyw43_arch.h\"</span><span class=\"cp\">\n</span>\n<span class=\"c1\">// プロトタイプ宣言</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n\n\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n\n\n<span class=\"kt\">int64_t</span> <span class=\"nf\">alarm_callback</span><span class=\"p\">(</span><span class=\"n\">alarm_id_t</span> <span class=\"n\">id</span><span class=\"p\">,</span> <span class=\"kt\">void</span> <span class=\"o\">*</span><span class=\"n\">user_data</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// Put your timeout handler code in here</span>\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"kt\">int</span> <span class=\"nf\">main</span><span class=\"p\">()</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">stdio_init_all</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// STDIOがUSBのとき、USB認識されないことがあるのでstdio初期化の後、ちょっと待つ</span>\n    <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">3000</span><span class=\"p\">);</span>\n\n    <span class=\"n\">puts</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">I2C slave 2ch\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// LEDを使うためにwifi初期化</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">cyw43_arch_init</span><span class=\"p\">())</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"Wi-Fi init failed\"</span><span class=\"p\">);</span>\n        <span class=\"k\">return</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\">// I2Cスレーブ 初期化</span>\n    <span class=\"n\">setup_i2c_slave0</span><span class=\"p\">();</span>\n    <span class=\"n\">setup_i2c_slave1</span><span class=\"p\">();</span>\n    \n\n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// ==== 生存確認用にLチカ ====</span>\n        <span class=\"c1\">// 現在の出力値取得</span>\n        <span class=\"n\">bool</span> <span class=\"n\">led_out</span> <span class=\"o\">=</span> <span class=\"n\">cyw43_arch_gpio_get</span> <span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">);</span>\n        <span class=\"c1\">// 出力反転</span>\n        <span class=\"n\">cyw43_arch_gpio_put</span><span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">,</span> <span class=\"o\">!</span><span class=\"n\">led_out</span><span class=\"p\">);</span>\n\n        <span class=\"c1\">// キー入力監視</span>\n        <span class=\"kt\">int</span> <span class=\"n\">key_in</span> <span class=\"o\">=</span>  <span class=\"n\">getchar_timeout_us</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'D'</span><span class=\"p\">)</span> <span class=\"o\">||</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'d'</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// 表示モード反転</span>\n            <span class=\"n\">DISP_flag</span> <span class=\"o\">=</span> <span class=\"o\">!</span><span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"**** DISP on ****</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"**** DISP off ****</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'0'</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// slave0データ表示</span>\n            <span class=\"n\">disp_data_slave0</span><span class=\"p\">();</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">key_in</span> <span class=\"o\">==</span> <span class=\"sc\">'1'</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// slave1データ表示</span>\n            <span class=\"n\">disp_data_slave1</span><span class=\"p\">();</span>\n        <span class=\"p\">}</span>\n\n\n        <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">1000</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"i2c0処理\">I2C0処理</h3>\n\n<h4 id=\"初期化\">初期化</h4>\n<p>I2C0の初期化は<code class=\"language-plaintext highlighter-rouge\">setup_i2c_slave0</code>です。<br />\n主に端子の初期化とI2C0の初期化、\nI2Cスレーブの初期化(I2C割り込みハンドラからのコールバックの登録)を行っています。</p>\n\n<p>読み書きするデータは1アドレスあたり8bitとしています。</p>\n\n<h4 id=\"処理本体\">処理本体</h4>\n<p>I2C0処理本体は<code class=\"language-plaintext highlighter-rouge\">i2c_slave0_handler()</code>です。</p>\n\n<p>これはI2C割り込みハンドラからのコールバック処理です。<br />\nなので、できるだけ速やかにリターンする必要があります。\nprintfなどの時間のかかる処理は行わないほうが良いのですが、\nデバッグ用途に送受信データを表示したいのでprintfで表示しています。<br />\nprintfをなくして高速に応答できるように、フラグを使用してprintfの有効/無効化を行っています。<br />\nフラグはメインルーチンでコンソールからのキー入力で切り替えています。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave0.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/rand.h></span><span class=\"c1\">      // 乱数</span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"k\">extern</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">16</span><span class=\"p\">;</span>  <span class=\"c1\">//GP16(Pin21)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">17</span><span class=\"p\">;</span>  <span class=\"c1\">//GP17(Pin22)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">256</span><span class=\"p\">];</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>\n    <span class=\"n\">bool</span> <span class=\"n\">mem_address_written</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"== ch0 ==  addr : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"mh\">0xff</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">+=</span><span class=\"mh\">0x10</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"%02x : %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">14</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">get_rand_32</span><span class=\"p\">();</span>        <span class=\"c1\">// 乱数で初期化</span>\n    <span class=\"p\">}</span>\n    <span class=\"c1\">// アドレス初期化</span>\n    <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではないけど使っちゃお...</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave0_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// STOP/RESTART後の最初の書き込みはアドレス更新</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 set memory address : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// メモリ内容書き換え</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 write memory : %02x : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// メモリから1バイト送信する</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">];</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 read memory : %02x : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// 次の書き込みはアドレス更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch0 STOP/RESTART condition</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave0</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch0</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave0_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch0 done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"i2c1処理\">I2C1処理</h3>\n\n<p>I2C1は読み書きするデータが1アドレスあたり16bitとしていることを除けばI2C0と同じです。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave1.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/rand.h></span><span class=\"c1\">      // 乱数</span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n<span class=\"c1\">// 表示フラグ</span>\n<span class=\"k\">extern</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_flag</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x32</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">18</span><span class=\"p\">;</span>  <span class=\"c1\">//GP18(Pin24)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE1_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">19</span><span class=\"p\">;</span>  <span class=\"c1\">//GP19(Pin25)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">512</span><span class=\"p\">];</span>\n    <span class=\"kt\">uint16_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>\n    <span class=\"n\">bool</span> <span class=\"n\">mem_address_written</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_data_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"== ch1 ==  addr : %02x  %s</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">);</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"mh\">0x200</span><span class=\"p\">;</span> <span class=\"n\">i</span><span class=\"o\">+=</span><span class=\"mh\">0x10</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"%03x : %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                   <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">14</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">get_rand_32</span><span class=\"p\">();</span>        <span class=\"c1\">// 乱数で初期化</span>\n    <span class=\"p\">}</span>\n    <span class=\"c1\">// アドレス初期化</span>\n    <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではないけど使っちゃお...</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave1_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// STOP/RESTART後の最初の書き込みはアドレス更新</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint16_t</span><span class=\"p\">)</span><span class=\"n\">addr</span> <span class=\"o\">*</span> <span class=\"mi\">2</span><span class=\"p\">;</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 set memory address : %02x(%03x)</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// メモリ内容書き換え</span>\n            <span class=\"kt\">uint16_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n            <span class=\"p\">}</span>\n            <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">data</span><span class=\"p\">;</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n                <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 write memory : %02x %s : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span>  <span class=\"n\">addr</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// メモリから1バイト送信する</span>\n        <span class=\"kt\">uint16_t</span> <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"p\">}</span>\n        <span class=\"kt\">uint8_t</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">addr</span><span class=\"p\">];</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 read memory : %02x %s : %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">addr</span><span class=\"o\">/</span><span class=\"mi\">2</span><span class=\"p\">,</span>  <span class=\"n\">addr</span> <span class=\"o\">%</span> <span class=\"mi\">2</span> <span class=\"o\">?</span> <span class=\"s\">\"MSB\"</span><span class=\"o\">:</span><span class=\"s\">\"LSB\"</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// 次の書き込みはアドレス更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address_written</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_flag</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n            <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"ch1 STOP/RESTART condition</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave1</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch1</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE1_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c1</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c1</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE1_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave1_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave ch1 done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n</code></pre></div></div>\n\n<h3 id=\"cmake設定ファイル\">cmake設定ファイル</h3>\n\n<p><code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>の\n<code class=\"language-plaintext highlighter-rouge\">add_executable</code> に <code class=\"language-plaintext highlighter-rouge\">i2c_slave0.c</code>と<code class=\"language-plaintext highlighter-rouge\">i2c_slave1.c</code>(追加したファイル名)を追加します。<br />\n<code class=\"language-plaintext highlighter-rouge\">target_link_libraries</code> に <code class=\"language-plaintext highlighter-rouge\">pico_i2c_slave</code>(I2Cスレーブを使用)と<code class=\"language-plaintext highlighter-rouge\">pico_rand</code>(乱数を使用)を追加します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  CMakeLists.txt\n</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># Generated Cmake Pico project file</span>\n\n<span class=\"nb\">cmake_minimum_required</span><span class=\"p\">(</span>VERSION 3.13<span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_C_STANDARD 11<span class=\"p\">)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_CXX_STANDARD 17<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise pico_sdk from installed location</span>\n<span class=\"c1\"># (note this can come from environment, CMake cache etc)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_SDK_PATH <span class=\"s2\">\"/work/pico/pico-sdk\"</span><span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_BOARD pico_w CACHE STRING <span class=\"s2\">\"Board type\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># Pull in Raspberry Pi Pico SDK (must be before project)</span>\n<span class=\"nb\">include</span><span class=\"p\">(</span>pico_sdk_import.cmake<span class=\"p\">)</span>\n\n<span class=\"nb\">if</span> <span class=\"p\">(</span>PICO_SDK_VERSION_STRING VERSION_LESS <span class=\"s2\">\"1.4.0\"</span><span class=\"p\">)</span>\n  <span class=\"nb\">message</span><span class=\"p\">(</span>FATAL_ERROR <span class=\"s2\">\"Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is </span><span class=\"si\">${</span><span class=\"nv\">PICO_SDK_VERSION_STRING</span><span class=\"si\">}</span><span class=\"s2\">\"</span><span class=\"p\">)</span>\n<span class=\"nb\">endif</span><span class=\"p\">()</span>\n\n<span class=\"nb\">project</span><span class=\"p\">(</span>i2c_slave_2ch C CXX ASM<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise the Raspberry Pi Pico SDK</span>\n<span class=\"nf\">pico_sdk_init</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># Add executable. Default name is the project name, version 0.1</span>\n\n<span class=\"nb\">add_executable</span><span class=\"p\">(</span>i2c_slave_2ch \n                i2c_slave_2ch.c\n                i2c_slave0.c\n                i2c_slave1.c\n                <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_set_program_name</span><span class=\"p\">(</span>i2c_slave_2ch <span class=\"s2\">\"i2c_slave_2ch\"</span><span class=\"p\">)</span>\n<span class=\"nf\">pico_set_program_version</span><span class=\"p\">(</span>i2c_slave_2ch <span class=\"s2\">\"0.1\"</span><span class=\"p\">)</span>\n\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>i2c_slave_2ch 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>i2c_slave_2ch 0<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard library to the build</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_2ch\n        pico_stdlib<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard include files to the build</span>\n<span class=\"nb\">target_include_directories</span><span class=\"p\">(</span>i2c_slave_2ch PRIVATE\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>/.. <span class=\"c1\"># for our common lwipopts or any other standard includes, if required</span>\n<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add any user requested libraries</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_2ch \n        hardware_i2c\n        pico_cyw43_arch_none\n        pico_i2c_slave\n        pico_rand\n        <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_add_extra_outputs</span><span class=\"p\">(</span>i2c_slave_2ch<span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>あとはビルドしてRaspberry Pi Picoに書き込みます。</p>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認です。<br />\nここからはRaspberry Pi3 での作業です。</p>\n\n<h2 id=\"i2cdetect\">i2cdetect</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdetect</code> で I2Cバス上でデバイスが検出されるか確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n\n<p>Picoのプログラムで設定したスレーブアドレス(<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>と<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE1_ADDRESS</code>の設定値。上のプログラムだと0x17と0x32)\nが表示されていればOKです。<br />\n表示されていない場合はPicoのプログラムやボードの結線を見直してください。</p>\n\n<h2 id=\"i2cdump\">i2cdump</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdump</code> で レジスタダンプしてみます。</p>\n\n<h3 id=\"i2c0\">I2C0</h3>\n<p>I2C0のレジスタをダンプしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdump <span class=\"nt\">-y</span> 1 0x17\n</code></pre></div></div>\n<p>RaspberryPiPICOのコンソールで<code class=\"language-plaintext highlighter-rouge\">0</code>を入力し、Slave0のレジスタをダンプした内容と比較して\n内容が同じであることを確認します。</p>\n\n<h3 id=\"i2c1\">I2C1</h3>\n<p>I2C1のレジスタをダンプしてみます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i2cdump <span class=\"nt\">-y</span> 1 0x32 w\n</code></pre></div></div>\n<p>RaspberryPiPICOのコンソールで<code class=\"language-plaintext highlighter-rouge\">1</code>を入力し、Slave1のレジスタをダンプした内容と比較して\n内容が同じであることを確認します。</p>\n\n<h2 id=\"その他\">その他</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cset</code>や<code class=\"language-plaintext highlighter-rouge\">i2cget</code>で色々読み書きしてみてください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Web Bluetooth APIを試す</title>\n  </head>\n  <body>\n    <header>\n      <h1>Web Bluetooth APIを試す</h1>\n      <p>Web bluetooth APIを試した時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>ブラウザからBluetoothにアクセスできる<a href=\"https://developer.mozilla.org/ja/docs/Web/API/Web_Bluetooth_API\" target=\"_blank\">Web Bluetooth API</a>\nを試してみた時に作ったプログラムを貼っておきます。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"ペリフェラル機器\">ペリフェラル機器</h2>\n\n<p>BLEは通信なので、通信相手が必要です。<br />\n市販機器を使うと仕様を調べるのが大変なので、エイヤッと自分で作っりました。<br />\nといっても Raspberry Pi Pico W にmicropythonのF/Wを書き込んでプログラム実行するだけ。<br />\n(使用したmicropython F/Wは「MicroPython v1.23.0 on 2024-06-02」です)</p>\n\n<p>以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。 と言ってもWi-Fiとか要らないからパクり先のリンク貼ってあるだけだけど。</p>\n\n<p>ということで、以下のソースを Raspberry Pi Pico で実行しておきます。<br />\n(特にH/W依存なことはしてないので、ESP32でも動くかも)</p>\n\n<p>BLEの処理については「micropython aioble」とかでググってください。<br />\nでも、公式のサンプル動かした例ばっかりであんまりないんだよなぁ…</p>\n\n<p>==懺悔==<br />\nUUIDはどっかのサンプルの値をちょこっといじったものです。<br />\n(調べたら温度計用のUUIDでした)<br />\n本来ならUUIDをちゃんと生成しないといけません。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=ble_peripheral.py\"></script>\n</dev>\n\n<h2 id=\"webサーバ\">Webサーバ</h2>\n<p>Web Bluetooth APIを使用するのは、HTMLファイルをHTTPSサーバからロードしなければならない仕様のようです。\n(httpやfileでは不可)<br />\nファイル1個だけなので、どこかのサーバの片隅に置くとかでも良いと思います。<br />\nローカルでサーバを立てるならApacheとかnginxとかで立ててください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsでApacheを使うなら<a href=\"https://nanbu.marune205.net/2022/01/windows10-apache-ssl.html?m=1\" target=\"_blank\">WindowsのApacheサーバーでSSL</a>\nあたりが参考になりました。<br />\nただし、仮の証明書を作るバッチファイルで、Apacheのインストール先がc:¥Apache24 以外の場合は\n以下の設定を追加しておく必要があります。</p>\n  <div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SET</span><span class=\"w\"> </span><span class=\"nx\">OPENSSL_CONF</span><span class=\"o\">=</span><span class=\"err\">≪</span><span class=\"n\">Apache</span><span class=\"err\">のインストール先≫</span><span class=\"nx\">\\conf\\openssl.cnf</span><span class=\"w\">\n</span></code></pre></div>  </div>\n  <p>インストール先を<code class=\"language-plaintext highlighter-rouge\">m:\\Apache24</code>にした場合の変更例はこんな感じ。</p>\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- aaa.txt     2024-07-29 06:58:34.154735900 +0900\n</span><span class=\"gi\">+++ make-snakeoil-cert.bat      2024-07-26 05:09:37.394502700 +0900\n</span><span class=\"p\">@@ -1,8 +1,11 @@</span>\n REM openssl.exe\n<span class=\"gd\">-SET OPENSSL=c:\\Apache24\\bin\\openssl.exe\n</span><span class=\"gi\">+SET OPENSSL=m:\\Apache24\\bin\\openssl.exe\n+\n+REM openssl.cnf\n+SET OPENSSL_CONF=m:\\Apache24\\conf\\openssl.cnf\n</span>\n REM 証明書用データの出力場所\n<span class=\"gd\">-SET ROOTDIR=c:\\Apache24\\certs\n</span><span class=\"gi\">+SET ROOTDIR=m:\\Apache24\\certs\n</span>\n REM サーバーのドメインまたはIPアドレス\n SET IPADDRESS=localhost\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h1 id=\"htmlファイル\">HTMLファイル</h1>\n\n<p>Web Bluetooth API のサンプルプログラムを以下に示します。<br />\nこれをHTTPSサーバに置いておきます</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=BLE_sample.html\"></script>\n</dev>\n\n<h1 id=\"実験\">実験</h1>\n\n<p>ペリフェラルプログラムを動作させておき、\nブラウザで上記HTMLファイルを開きます。</p>\n\n<p>アクセスするPCやスマホはBLE対応のBluetoothが搭載されている必要があります。<br />\nブラウザはChromeかEdge(は試してないけど)で。(firefox不可)</p>\n\n<p>WindowsPCとAndroidスマホのChromeは動作確認しました。<br />\nmacとiPhoneは持ってないので試してません。</p>\n\n<p>次に「接続」ボタンをクリック、「XXXXXがペア接続を要求しています」ダイアログが出るので\n「mpy-sensor」を選択し、「ペア設定」をクリックします。</p>\n\n<p>接続されると DATA1 に受信したデータを表示します。<br />\nDATA1はNotificationありのデータ読み取りです。<br />\nNotificationイベントを受けてデータを読み取ります。<br />\n上は1行を常に書き換えるタイプ。<br />\n下は過去分を含め10行程度表示(それ以前は削除)するタイプです。<br />\n受診自体は1回でページの書き換え処理を2通り行っています。</p>\n\n<p>DATA2はNotificationなしのデータ読み取りです。<br />\nREADボタンをクリックすると読み取った値を表示します。</p>\n\n<p>測定間隔のテキストボックスに数値を入力し、「WRITE」をクリックすると\nDATA1の取得間隔を変更できます。<br />\n値は100~5000が有効で、範囲外の値が設定されると範囲内の値に補正されます(補正はペリフェラル川で行っています)。</p>\n\n<p>接続を終了するには「切断」をクリックします。</p>\n\n<h1 id=\"操作例\">操作例</h1>\n\n<p><a href=\"/memoBlog/misc/WEB_BT_API_2024-07-29_075522.mp4\" target=\"_blank\">操作例の動画</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) でI2C Slave</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) でI2C Slave</h1>\n      <p>Raspberry Pi Pico W の SDK を使用してI2C Slaveプログラムを作成する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico のI2C マスタを使用してI2Cデバイスにアクセスするプログラムプログラムは\nネット上のあちこちに落ちているのですが、\nI2Cスレーブとしてホストデバイスからアクセスされるサンプルはあまりありません。<br />\nそこで、あちこち探してプログラム作ったのでメモを残しておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n【ホントのところ】<br />\n「I2Cデバイスをポチったけど、納期が長くてプログラム開発に取り掛かれない~」となって\nなんちゃってI2Cデバイスを作って先行デバッグしようとしました。</p>\n</blockquote>\n\n<p>通信プログラムなので通信相手が必要ですが、今回はRaspberry Pi3上でpython3で動く\n簡単な動作確認プログラムを載せておきます。</p>\n\n<blockquote>\n  <p>[!NOTE]\n公式サンプルは<code class=\"language-plaintext highlighter-rouge\">pico-examples/i2c/slave_mem_i2c</code>にあります。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nmicropython版の例は<a href=\"https://python-academia.com/raspberry-pi-pico-slave/\" target=\"_blank\">ここ</a>\nとかにあるけど、ちぃーっと無理くり感が…</p>\n</blockquote>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"i2cの結線\">I2Cの結線</h2>\n\n<p>以下のように結線します。<br />\nPico側はソース中の割り当て端子を変更すれば別の端子でもOKです。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>Pi3</th>\n      <th>Pico</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>SDA1(pin3)</td>\n      <td>I2C0_SDA/GP16(Pin21)</td>\n    </tr>\n    <tr>\n      <td>SCL1(pin5)</td>\n      <td>I2C0_SCL/GP17(Pin22)</td>\n    </tr>\n  </tbody>\n</table>\n\n<h2 id=\"pi3でのi2c有効化\">Pi3でのI2C有効化</h2>\n\n<p>Pi3で以下のコマンドを実行し、I2Cを有効化します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config nonint do_i2c 0\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nまたは以下のように手動で設定</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>raspi-config\n</code></pre></div>  </div>\n\n  <p>以下のように設定</p>\n  <ul>\n    <li>3 Interface Options\n      <ul>\n        <li>I4 I2C\n          <ul>\n            <li>「Would you like the ARM I2C interface to be enabled?」<br />\n に対して「はい」を選択</li>\n            <li>「The ARM I2C interface is enabled」\nと表示されるので「了解」</li>\n          </ul>\n        </li>\n        <li>「Finish」で終了</li>\n      </ul>\n    </li>\n  </ul>\n\n</blockquote>\n\n<p>実行後、<code class=\"language-plaintext highlighter-rouge\">/dev/i2c-1</code>ファイルが存在することを確認してください。<br />\nリブートは不要です。</p>\n\n<h2 id=\"i2cツールのインストール\">I2Cツールのインストール</h2>\n\n<p>Pi3に<code class=\"language-plaintext highlighter-rouge\">i2cdetect</code>などのツールをインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>i2c-tools\n</code></pre></div></div>\n\n<h1 id=\"picoのプログラム\">Picoのプログラム</h1>\n\n<p>作成したプログラムを以下に示します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n今回元にしたI2Cデバイスは先頭アドレスからのバーストリードのみサポートしていたので<br />\nちょっと一般的なアドレス/データ指定の方法と違うけど、なんとなく想像はつくでしょう…</p>\n</blockquote>\n\n<h2 id=\"メインルーチン\">メインルーチン</h2>\n\n<p>メインルーチンはI2Cを初期化したあと無限ループします。<br />\nループ内ではI2Cに関する処理はなく、生存確認用のLチカと\nデバッグ用に送信データが更新されたときにデータを表示しているだけです。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_test.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/stdlib.h\"</span><span class=\"cp\">\n#include</span> <span class=\"cpf\">\"pico/cyw43_arch.h\"</span><span class=\"cp\">\n</span>\n<span class=\"c1\">// プロトタイプ宣言</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n<span class=\"k\">extern</span> <span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">);</span>\n\n<span class=\"kt\">int</span> <span class=\"nf\">main</span><span class=\"p\">()</span>\n<span class=\"p\">{</span>\n    <span class=\"n\">stdio_init_all</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// STDIOがUSBのとき、USB認識されないことがあるのでstdio初期化の後、ちょっと待つ</span>\n    <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">3000</span><span class=\"p\">);</span>\n\n    <span class=\"n\">puts</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"se\">\\n</span><span class=\"s\">I2C slave test\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// LEDを使うためにwifi初期化</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">cyw43_arch_init</span><span class=\"p\">())</span> <span class=\"p\">{</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"Wi-Fi init failed\"</span><span class=\"p\">);</span>\n        <span class=\"k\">return</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\">// I2Cスレーブ 初期化</span>\n    <span class=\"n\">setup_i2c_slave</span><span class=\"p\">();</span>\n    \n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">disp_next_data</span><span class=\"p\">();</span>\n        <span class=\"n\">sleep_ms</span><span class=\"p\">(</span><span class=\"mi\">1000</span><span class=\"p\">);</span>\n\n        <span class=\"c1\">// ==== 生存確認用にLチカ ====</span>\n        <span class=\"c1\">// 現在の出力値取得</span>\n        <span class=\"n\">bool</span> <span class=\"n\">led_out</span> <span class=\"o\">=</span> <span class=\"n\">cyw43_arch_gpio_get</span> <span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">);</span>\n        <span class=\"c1\">// 出力反転</span>\n        <span class=\"n\">cyw43_arch_gpio_put</span><span class=\"p\">(</span><span class=\"n\">CYW43_WL_GPIO_LED_PIN</span><span class=\"p\">,</span> <span class=\"o\">!</span><span class=\"n\">led_out</span><span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"k\">return</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"i2c処理\">I2C処理</h2>\n\n<h3 id=\"初期化\">初期化</h3>\n<p>I2Cの初期化は<code class=\"language-plaintext highlighter-rouge\">setup_i2c_slave</code>です。<br />\n主に端子の初期化とI2Cの初期化、\nI2Cスレーブの初期化(I2C割り込みハンドラからのコールバックの登録)を行っています。</p>\n\n<h3 id=\"処理本体\">処理本体</h3>\n<p>I2C処理本体は<code class=\"language-plaintext highlighter-rouge\">i2c_slave_handler()</code>です。</p>\n\n<p>これはI2C割り込みハンドラからのコールバック処理です。<br />\nなので、できるだけ速やかにリターンする必要があります\n(printfなどの時間のかかる処理は行わないほうが良い)。</p>\n\n<p>なお、今回はマスタの通信プログラムをデバッグするためのダミーデバイスという位置づけで作ったので\n通信を行うたびに異なるデータを送信するようにしてあります。\nこのデータの更新処理をストップ/リスタートコンディション時に行うようにしてあります。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  i2c_slave_test.c\n</p>\n\n<div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">#include</span> <span class=\"cpf\"><hardware/i2c.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/i2c_slave.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><pico/stdlib.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><stdio.h></span><span class=\"cp\">\n#include</span> <span class=\"cpf\"><string.h></span><span class=\"cp\">\n</span>\n\n<span class=\"c1\">// スレーブアドレス</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span><span class=\"p\">;</span>\n\n<span class=\"c1\">// ボーレート</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_BAUDRATE</span> <span class=\"o\">=</span> <span class=\"mi\">400000</span><span class=\"p\">;</span> <span class=\"c1\">// 400 kHz</span>\n\n<span class=\"c1\">// 使用端子</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SDA_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">16</span><span class=\"p\">;</span>  <span class=\"c1\">//GP16(Pin21)</span>\n<span class=\"k\">static</span> <span class=\"k\">const</span> <span class=\"n\">uint</span> <span class=\"n\">I2C_SLAVE0_SCL_PIN</span> <span class=\"o\">=</span> <span class=\"mi\">17</span><span class=\"p\">;</span>  <span class=\"c1\">//GP17(Pin22)</span>\n\n<span class=\"c1\">// スレーブ読み出しパラメータ</span>\n<span class=\"k\">static</span> <span class=\"k\">struct</span>\n<span class=\"p\">{</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">16</span><span class=\"p\">];</span>            <span class=\"c1\">// 読み出しデータ</span>\n    <span class=\"kt\">uint8_t</span> <span class=\"n\">mem_address</span><span class=\"p\">;</span>        <span class=\"c1\">// 読み出しインデックス</span>\n<span class=\"p\">}</span> <span class=\"n\">context</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示要求フラグ</span>\n<span class=\"k\">static</span> <span class=\"k\">volatile</span> <span class=\"n\">bool</span> <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n\n\n<span class=\"c1\">// 次のデータセットの表示</span>\n<span class=\"kt\">void</span> <span class=\"nf\">disp_next_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">DISP_REQ</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// 表示要求あり</span>\n        <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">false</span><span class=\"p\">;</span>\n        <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"NEXT: %02x %02x %02x %02x : %02x %02x %02x %02x : %02x %02x %02x %02x : %02x %02x %02x %02x</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">,</span> \n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">1</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">3</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">4</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">5</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">6</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">7</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">8</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span> <span class=\"mi\">9</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">10</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">11</span><span class=\"p\">],</span>\n                <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">12</span><span class=\"p\">],</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">13</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">14</span><span class=\"p\">],</span>  <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"mi\">15</span><span class=\"p\">]</span>\n            <span class=\"p\">);</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span> \n\n<span class=\"c1\">// 読み出しデータの初期化</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">init_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"kt\">uint8_t</span><span class=\"p\">)</span><span class=\"n\">i</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\">// 次に送信するデータの表示を要求</span>\n    <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n\n<span class=\"c1\">// 読み出しデータの更新</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">update_data</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n    <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\"><</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">);</span> <span class=\"n\">i</span><span class=\"o\">++</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span><span class=\"o\">++</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"c1\">// 次に送信するデータの表示を要求</span>\n    <span class=\"n\">DISP_REQ</span> <span class=\"o\">=</span> <span class=\"nb\">true</span><span class=\"p\">;</span>\n    <span class=\"k\">return</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2C ISRからのコールバック</span>\n<span class=\"c1\">// printfなど時間のかかる処理は使うべきではない</span>\n<span class=\"c1\">// 例えば、表示要求フラグを立ててメインルーチン側で表示してもらうようにするなど</span>\n<span class=\"k\">static</span> <span class=\"kt\">void</span> <span class=\"nf\">i2c_slave_handler</span><span class=\"p\">(</span><span class=\"n\">i2c_inst_t</span> <span class=\"o\">*</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">i2c_slave_event_t</span> <span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">switch</span> <span class=\"p\">(</span><span class=\"n\">event</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_RECEIVE</span><span class=\"p\">:</span> <span class=\"c1\">// write event</span>\n        <span class=\"p\">{</span>\n            <span class=\"c1\">// ライト動作はサポートしないのでとりあえず読み捨てておく</span>\n            <span class=\"k\">volatile</span> <span class=\"kt\">uint8_t</span> <span class=\"n\">dummy</span> <span class=\"o\">=</span> <span class=\"n\">i2c_read_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">);</span>\n            <span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span><span class=\"n\">dummy</span><span class=\"p\">;</span>    <span class=\"c1\">// ワーニング対策</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_REQUEST</span><span class=\"p\">:</span> <span class=\"c1\">// read event</span>\n        <span class=\"c1\">// 1バイト送信する</span>\n        <span class=\"n\">i2c_write_byte_raw</span><span class=\"p\">(</span><span class=\"n\">i2c</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">[</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"p\">]);</span>\n        <span class=\"c1\">// 次の転送に備えてインデックスを更新</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span><span class=\"o\">++</span><span class=\"p\">;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">>=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem</span><span class=\"p\">))</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// オーバフローしたら0にもどしておく</span>\n            <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"k\">case</span> <span class=\"n\">I2C_SLAVE_FINISH</span><span class=\"p\">:</span> <span class=\"c1\">// ストップ/リスタートコンディション時</span>\n        <span class=\"c1\">// リードポインタを初期化しておく</span>\n        <span class=\"n\">context</span><span class=\"p\">.</span><span class=\"n\">mem_address</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\n        \n        <span class=\"c1\">// テスト用ダミーデータなので、次の読み出しに備えて値を更新しておく</span>\n        <span class=\"n\">update_data</span><span class=\"p\">();</span>\n        \n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"nl\">default:</span>\n        <span class=\"k\">break</span><span class=\"p\">;</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// I2Cスレーブ初期化</span>\n<span class=\"kt\">void</span> <span class=\"nf\">setup_i2c_slave</span><span class=\"p\">(</span><span class=\"kt\">void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 端子初期化</span>\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SDA_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"n\">gpio_init</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_set_function</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">,</span> <span class=\"n\">GPIO_FUNC_I2C</span><span class=\"p\">);</span>\n    <span class=\"n\">gpio_pull_up</span><span class=\"p\">(</span><span class=\"n\">I2C_SLAVE0_SCL_PIN</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// 送信データの初期値をセットしておく</span>\n    <span class=\"n\">init_data</span><span class=\"p\">();</span>\n\n    <span class=\"c1\">// I2C初期化</span>\n    <span class=\"n\">i2c_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_BAUDRATE</span><span class=\"p\">);</span>\n\n    <span class=\"c1\">// I2Cスレーブとしての初期化</span>\n    <span class=\"n\">i2c_slave_init</span><span class=\"p\">(</span><span class=\"n\">i2c0</span><span class=\"p\">,</span> <span class=\"n\">I2C_SLAVE0_ADDRESS</span><span class=\"p\">,</span> <span class=\"o\">&</span><span class=\"n\">i2c_slave_handler</span><span class=\"p\">);</span>\n    <span class=\"n\">printf</span><span class=\"p\">(</span><span class=\"s\">\"setup i2c slave  done</span><span class=\"se\">\\n</span><span class=\"s\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"cmake設定ファイル\">cmake設定ファイル</h3>\n\n<p>プロジェクト生成ツールで作成したプロジェクト(一般的な設定に「I2C interface」のチェックを追加)に\n<code class=\"language-plaintext highlighter-rouge\">target_link_libraries</code> に <code class=\"language-plaintext highlighter-rouge\">pico_i2c_slave</code>を追加します。<br />\nまた、今回はメインルーチンとI2C処理を別ファイルに分けたので、\n<code class=\"language-plaintext highlighter-rouge\">add_executable</code> に <code class=\"language-plaintext highlighter-rouge\">i2c_slave0.c</code>(追加したファイル名)を追加します。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  CMakeLists.txt\n</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># Generated Cmake Pico project file</span>\n\n<span class=\"nb\">cmake_minimum_required</span><span class=\"p\">(</span>VERSION 3.13<span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_C_STANDARD 11<span class=\"p\">)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>CMAKE_CXX_STANDARD 17<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise pico_sdk from installed location</span>\n<span class=\"c1\"># (note this can come from environment, CMake cache etc)</span>\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_SDK_PATH <span class=\"s2\">\"/work/pico/pico-sdk\"</span><span class=\"p\">)</span>\n\n<span class=\"nb\">set</span><span class=\"p\">(</span>PICO_BOARD pico_w CACHE STRING <span class=\"s2\">\"Board type\"</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># Pull in Raspberry Pi Pico SDK (must be before project)</span>\n<span class=\"nb\">include</span><span class=\"p\">(</span>pico_sdk_import.cmake<span class=\"p\">)</span>\n\n<span class=\"nb\">if</span> <span class=\"p\">(</span>PICO_SDK_VERSION_STRING VERSION_LESS <span class=\"s2\">\"1.4.0\"</span><span class=\"p\">)</span>\n  <span class=\"nb\">message</span><span class=\"p\">(</span>FATAL_ERROR <span class=\"s2\">\"Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is </span><span class=\"si\">${</span><span class=\"nv\">PICO_SDK_VERSION_STRING</span><span class=\"si\">}</span><span class=\"s2\">\"</span><span class=\"p\">)</span>\n<span class=\"nb\">endif</span><span class=\"p\">()</span>\n\n<span class=\"nb\">project</span><span class=\"p\">(</span>i2c_slave_test C CXX ASM<span class=\"p\">)</span>\n\n<span class=\"c1\"># Initialise the Raspberry Pi Pico SDK</span>\n<span class=\"nf\">pico_sdk_init</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># Add executable. Default name is the project name, version 0.1</span>\n\n<span class=\"nb\">add_executable</span><span class=\"p\">(</span>i2c_slave_test i2c_slave_test.c i2c_slave0.c<span class=\"p\">)</span>\n\n<span class=\"nf\">pico_set_program_name</span><span class=\"p\">(</span>i2c_slave_test <span class=\"s2\">\"i2c_slave_test\"</span><span class=\"p\">)</span>\n<span class=\"nf\">pico_set_program_version</span><span class=\"p\">(</span>i2c_slave_test <span class=\"s2\">\"0.1\"</span><span class=\"p\">)</span>\n\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>i2c_slave_test 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>i2c_slave_test 0<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard library to the build</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_test\n        pico_stdlib<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add the standard include files to the build</span>\n<span class=\"nb\">target_include_directories</span><span class=\"p\">(</span>i2c_slave_test PRIVATE\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>\n  <span class=\"si\">${</span><span class=\"nv\">CMAKE_CURRENT_LIST_DIR</span><span class=\"si\">}</span>/.. <span class=\"c1\"># for our common lwipopts or any other standard includes, if required</span>\n<span class=\"p\">)</span>\n\n<span class=\"c1\"># Add any user requested libraries</span>\n<span class=\"nb\">target_link_libraries</span><span class=\"p\">(</span>i2c_slave_test \n        pico_i2c_slave\n        hardware_i2c\n        pico_cyw43_arch_none\n        <span class=\"p\">)</span>\n\n<span class=\"nf\">pico_add_extra_outputs</span><span class=\"p\">(</span>i2c_slave_test<span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>あとはビルドしてRaspberry Pi Picoに書き込みます。</p>\n\n<h1 id=\"動作確認\">動作確認</h1>\n\n<p>動作確認です。<br />\nここからはRaspberry Pi3 での作業です。</p>\n\n<h2 id=\"i2cdetect\">i2cdetect</h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">i2cdetect</code> で I2Cバス上でデバイスが検出されるか確認します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>i2cdetect <span class=\"nt\">-y</span> 1\n</code></pre></div></div>\n\n<p>Picoのプログラムで設定したスレーブアドレス(<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>の設定値。上のプログラムだと0x17)\nが表示されていればOKです。<br />\n表示されていない場合はPicoのプログラムやボードの結線を見直してください。</p>\n\n<h2 id=\"レジスタリードプログラム\">レジスタリードプログラム</h2>\n<p>Raspberry Pi3で以下のプログラムを実行します。<br />\n<code class=\"language-plaintext highlighter-rouge\">i2c_address</code>の設定値は上のプログラムの<code class=\"language-plaintext highlighter-rouge\">I2C_SLAVE0_ADDRESS</code>の設定値に合わせます。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">smbus2</span> <span class=\"kn\">import</span> <span class=\"n\">SMBus</span><span class=\"p\">,</span> <span class=\"n\">i2c_msg</span>\n\n<span class=\"n\">i2c_bus</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>                 <span class=\"c1\"># バス番号\n</span><span class=\"n\">i2c_address</span> <span class=\"o\">=</span> <span class=\"mh\">0x17</span>          <span class=\"c1\"># スレーブアドレス\n</span><span class=\"n\">data_size</span> <span class=\"o\">=</span> <span class=\"mi\">16</span>              <span class=\"c1\"># リードデータサイズ\n</span>\n<span class=\"c1\"># バスオープン\n</span><span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">SMBus</span><span class=\"p\">(</span><span class=\"n\">i2c_bus</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ読み出し\n</span><span class=\"n\">read</span> <span class=\"o\">=</span> <span class=\"n\">i2c_msg</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">(</span><span class=\"n\">i2c_address</span><span class=\"p\">,</span> <span class=\"n\">data_size</span><span class=\"p\">)</span>\n<span class=\"n\">bus</span><span class=\"p\">.</span><span class=\"n\">i2c_rdwr</span><span class=\"p\">(</span><span class=\"n\">read</span><span class=\"p\">)</span>\n<span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">read</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># データ表示\n</span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>正常に読み出せれば、以下のように結果が表示されます(10進数)。<br />\n(以下は何回か実行したあとの結果です)</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n</code></pre></div></div>\n\n<p>同時にPicoのシリアルポートからは以下のように次に読み出せるデータが表示されます(16進数)。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>NEXT: 06 07 08 09 : 0a 0b 0c 0d : 0e 0f 10 11 : 12 13 14 15\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W(SDK) を RaspberryPi3 + Visual Studio CodeでSWDデバッグ</h1>\n      <p>Raspberry Pi Pico W の SDK を使用したプログラムをRaspberryPi3 + Visual Studio CodeでSWDデバッグする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico W の SDK を使用したプログラムをRaspberryPi3 + Visual Studio CodeでSWDデバッグするときのメモ。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPi4 や Pi ZERO 2 W でも同様だと思うが、実際に試したのが Pi3 だったので。<br />\nたぶん Pi ZERO や Pi2 ではやめておいた方が無難。<br />\nPi ZERO 2 W やRAM512KByteだからビミョーかも…</p>\n</blockquote>\n\n<p><a href=\"https://www.raspberrypi.com/documentation/microcontrollers/\" target=\"_blank\">公式ドキュメントサイト</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico-JP.pdf\" target=\"_blank\">公式スタートアップガイド(日本語版)</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a></p>\n\n<p>試したときはRaspberryPi OS Lite(64bit) 使用(通常版でも大丈夫と思う)。</p>\n\n<h1 id=\"raspberrypi3のセットアップ\">RaspberryPi3のセットアップ</h1>\n\n<p>RaspberryPi3をセットアップします。<br />\nVisual Studio Code で リモートSSH接続するので、SSHが公開鍵認証で接続できるようにしておくこと。<br />\nセットアップの手順は\n<a href=\"https://ippei8jp.github.io/memoBlog/2022/06/28/raspios_64_Imager.html\" target=\"_blank\">Raspberry Pi OS(64bit)のインストール(Raspberry Pi Imager)</a>\nなど参照。</p>\n\n<blockquote>\n  <p>[!NOTE]\nターゲットボードにPico W を使用する場合はボード種別を指定しておくこと</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"export PICO_BOARD=pico_w\"</span> <span class=\"o\">>></span> ~/.bashrc\n<span class=\"nb\">source</span> ~/.bashrc\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"セットアップスクリプトの実行\">セットアップスクリプトの実行</h2>\n<p>公式ドキュメントに記載されている通り、セットアップスクリプトを実行すればセットアップはほぼ自動です。<br />\nただし、今回はVisual Studio CodeをRaspberryPi上ではなく、WindowsPC上で動かし、\nリモートSSHでRaspberryPiに接続する方法をとるので、Visual Studio Codeのインストールは不要です。<br />\nまた、私はRaspberryPiのシリアルコンソールを残しておきたいので、UARTのセットアップも行いません。<br />\n(UARTは別途USB-Serialアダプタを使用して接続)</p>\n\n<p>以下のようにセットアップスクリプトを実行します。<br />\n今回は<code class=\"language-plaintext highlighter-rouge\">/work</code>ディレクトリにインストールすることにしています。<br />\n別のディレクトリにインストールする場合は読み替えてください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work\n\n<span class=\"c\"># スクリプトダウンロード</span>\nwget https://raw.githubusercontent.com/raspberrypi/pico-setup/master/pico_setup.sh \n\n<span class=\"c\"># VSCODEのインストールとUARTの設定をスキップしてセットアップ</span>\n<span class=\"nv\">SKIP_VSCODE</span><span class=\"o\">=</span>1 <span class=\"nv\">SKIP_UART</span><span class=\"o\">=</span>1 bash pico_setup.sh\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nopenOCDのコンパイルとかで時間がかかるので(私が試したときは30分くらい)、<br />\nお茶でも飲んでのんびりお待ちくらはい。</p>\n</blockquote>\n\n<h2 id=\"セットアップスクリプト後の変更\">セットアップスクリプト後の変更</h2>\n\n<p>セットアップスクリプトでサンプルプログラムを一部ビルドしてくれますが、\nVisual Studio Code上の開発環境で作り直すので<code class=\"language-plaintext highlighter-rouge\">pico-examples/build</code>ディレクトリは削除しておいてください。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> /work/pico/pico-examples/build\n</code></pre></div></div>\n\n<p>また、Visual Studio Codeの設定ファイルを<code class=\"language-plaintext highlighter-rouge\">pico-examples/.vscode</code>ディレクトリに作成しておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/pico/pico-examples\n<span class=\"nb\">mkdir</span> .vscode\n<span class=\"nb\">cp </span>ide/vscode/launch-raspberrypi-swd.json .vscode/launch.json\n<span class=\"nb\">cp </span>ide/vscode/settings.json .vscode/settings.json\n</code></pre></div></div>\n\n<p>このままだとビルドが全ビルドになってしまい、時間がかかってしまうのでビルドターゲットを指定できるように変更しておきます。<br />\n【2024.08.29修正】\nどこかのタイミングのバージョンアップで設定できる内容が大幅に変更されたようなので、setting.jsonを以下の内容で全書き換えしておきます。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  settings.json\n</p>\n\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"p\">{</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.configureOnOpen\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"kc\">false</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.advanced\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n    </span><span class=\"nl\">\"build\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"buildTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"ctest\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"debug\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"launchTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n     </span><span class=\"nl\">\"launch\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"workflow\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"cpack\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">}</span><span class=\"w\">    \n  </span><span class=\"p\">},</span><span class=\"w\">\n</span><span class=\"p\">}</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<h1 id=\"raspberry-pi3とraspberry-pi-pico-の接続\">Raspberry Pi3とRaspberry Pi Pico の接続</h1>\n<p>この辺で一旦Raspberry Pi3をシャットダウンし、Raspberry Pi Picoと接続します(最初に接続しておいても良いけど)。<br />\n接続方法は 公式スタートアップガイド の 「Chapter 5. Flash Programming with SWD」の下の「5.2. SWD Port Wiring」\nあたりを参照してください。<br />\n私はPicoのシリアルポートをRaspberryPiではなくUSB-Serialに接続するようにしたので、図の上3本の結線は行わず\nPi3のGPIO24とPicoのSWDIO、Pi3のGPIO25とPicoのSWDCLK、双方のGND同士 の3本を結線しました。<br />\n(PicoのPin1~3はUSB-Serialに接続し、WindowsPCかRaspberry Pi3に接続)</p>\n\n<h2 id=\"visual-studio-coce-起動フォルダのオープン\">Visual Studio COCE 起動&フォルダのオープン</h2>\n\n<p>ホストPCでVisual Studio COCE 起動。<br />\nリモートSSHでRaspberryPi3 に接続し、セットアップツールでインストールした\nサンプルプログラムのディレクトリを開きます(上の例では/work/pico/pico-example)</p>\n\n<h2 id=\"拡張機能のインストール\">拡張機能のインストール</h2>\n<p>これは最初の起動時のみ実行します。</p>\n\n<p>拡張機能で「Cmake Tools」「C/C++(C/C++ for Visual Studio Code)」「Cortex Debug」をRaspberry Pi3 にインストールします。<br />\n(ホストPCではないのでSSH接続した後でインストールすること)</p>\n\n<p>「Cmake Tools」のインストールが完了したら歯車アイコン(設定)をクリックして設定画面を開き、\n“CMake: Parallel Jobs” の設定値を0から1(または2)に変更\n(0だと設定できる上限値になるはずだけど、プロセッサ数4に対して6が設定されてしまい、システムがハングアップしてしまうことがあるので)</p>\n\n<p>右下に「プロジェクト”pico-examples”を構成しますか? ソース:CMake Tools(拡張機能)」と表示されるのでYesをクリック<br />\n続いて「プロジェクトを開いたときに常に構成しますか? ソース:CMake Tools(拡張機能)」 と表示されるので「はい」をクリック</p>\n\n<h2 id=\"ビルドデバッグ\">ビルド~デバッグ</h2>\n<p>ステータスバーの「キットが選択されていません」をクリックすると\nウィンドウ上部に「pico-examplesのキットを選択してください」と表示されるので\n「GCC 12.2.1  arm-none-eabi」を選択(バージョンは異なるかも)</p>\n\n<blockquote>\n  <p>[!NOTE]\n「この大規模なワークスペース フォルダーでのファイルの変更をウォッチできません。\nこの問題を解決するには、手順のリンクに従ってください。 」\nと表示された場合\n/etc/sysctl.conf に以下を追記</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>fs.inotify.max_user_watches = 524288\n</code></pre></div>  </div>\n  <p>設定を反映</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>sysctl <span class=\"nt\">-p</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>ステータスバーで「プロジェクトを構成しています: pico-examples」が消えるのを待つ)</p>\n\n<p>ステータスバーで「既定のビルドターゲットの設定(ステータスバーの表示にマウスカーソルをあてると表示されるメッセージ)」と\n「起動するターゲットを選択します(ステータスバーの表示にマウスカーソルをあてると表示されるメッセージ)」を\nクリックしてデバッグしたいターゲットに設定します(例えば、picow_blink)。\nこれらば同じターゲットを指定する必要があります。(ビルドターゲットはallでも良いが、ビルドに時間がかかる)</p>\n<blockquote>\n  <p>[!NOTE]\nサンプルにあるide/vscode/settings.json そのままだと「既定のビルドターゲットの設定」がallのまま変更できないのでビルドに時間がかかるため\n上記の変更を行っています。</p>\n</blockquote>\n\n<p>構成が完了したら「実行とデバッグ」ウィンドウを開いて、右向き三角マーク(デバッグの開始)をクリック<br />\n(右向き三角マーク(デバッグの開始)が無ければ「実行とデバッグ」をクリック)<br />\nbuildが始まって、終わったらデバッガが起動します。<br />\nあとは他のデバッグ同様、RUNやSTEPなどでデバッグしてください。</p>\n\n<h1 id=\"自作プロジェクトの作成\">自作プロジェクトの作成</h1>\n\n<p>サンプルプログラムを改造してうんぬんするのはダサいだけでなく、関係ない処理が色々動いて\nビルドに時間がかかるので、自作プロジェクトの作成をした方が良いです。</p>\n\n<p><a href=\"https://ippei8jp.github.io/memoBlog/2023/10/11/RasPiPico_2.html\" target=\"_blank\">Raspberry Pi Pico W で SDK</a>\nの「自作プロジェクトの作成」にまとめておきましたが、デバッガの指定など追加手順もあるので\n再掲します。</p>\n\n<h2 id=\"プロジェクト生成ツールのインストール\">プロジェクト生成ツールのインストール</h2>\n<p>プロジェクト生成ツールをインストールして起動スクリプトを作成します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># ダウンロード</span>\n<span class=\"nb\">cd</span> /work/pico/\ngit clone https://github.com/raspberrypi/pico-project-generator.git\n\n<span class=\"c\"># 起動用スクリプトの作成</span>\n<span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> ~/bin\n<span class=\"nb\">cat</span> <span class=\"o\">></span> ~/bin/pico_project <span class=\"o\"><<</span> <span class=\"sh\">\"</span><span class=\"no\">_EOF_</span><span class=\"sh\">\"\n/work/Pico/pico-project-generator/pico_project.py --nouart --usb  --gui &\n</span><span class=\"no\">_EOF_\n\n</span><span class=\"nb\">chmod</span> +x ~/bin/pico_project\n\n<span class=\"c\"># tkinter のインストール(RaspberryPi OS lite の場合は要インストール)</span>\n<span class=\"nb\">sudo </span>apt-get <span class=\"nb\">install </span>python3-tk\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nそれまで<code class=\"language-plaintext highlighter-rouge\">~/bin</code>が存在していない場合は一旦ログアウトして再ログインで\n<code class=\"language-plaintext highlighter-rouge\">~/bin</code>にpathを通す(変数ゴチョゴチョやっても良いけど、再ログインが手っ取り早い)。</p>\n</blockquote>\n\n<h2 id=\"プロジェクト生成ツールの起動プロジェクト出力\">プロジェクト生成ツールの起動~プロジェクト出力</h2>\n\n<p>リモート接続で使用している場合はDISPLAY変数が設定されていること(ホストマシン)と、\nホストマシンでX-serverが動作していることを確認し、\nプロジェクト生成ツール起動スクリプトを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pico_project\n</code></pre></div></div>\n<p>ホストマシン上にプロジェクト生成ツールのウィンドウが表示されます。</p>\n\n<p>各パラメータを設定し、OKボタンをクリックしてプロジェクトを生成します。<br />\nこのウィンドウで必要な設定を行います。</p>\n\n<ul>\n  <li>Project Name に プロジェクト名を設定</li>\n  <li>Board Type でpico_w を選択</li>\n  <li>Library Options   PiCO Wirless Options で必要なオプションをチェック</li>\n  <li>Console Options は必要なら変更してください。<br />\n(常にUART使うなら起動スクリプトのオプション変更した方が良いかも)</li>\n  <li>Code Options は 必要なら設定。 Advancedボタンをクリックすればさらに多くのパラメータが設定できます。</li>\n  <li>その下は必要なら設定してちょ。</li>\n  <li>一番下の IDE Options は、「Create VSCode Project」をチェックし、「Debugger」に「SWD」を選択します。</li>\n</ul>\n\n<p>OKボタンをクリックしたらプロジェクトが作成され、cmakeが実行されます。<br />\n実行結果を表示するウィンドウが表示されますので、確認してOKボタンでクローズしてください。</p>\n\n<p>プロジェクト生成ツールはもう不要なのでクローズしてください。</p>\n\n<p>生成されたプロジェクトディレクトリの<code class=\"language-plaintext highlighter-rouge\">.vscode/settings.json</code> を以下の内容で全書き換えします。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  settings.json\n</p>\n\n<div class=\"language-json highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"p\">{</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.configureOnOpen\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"kc\">false</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n  </span><span class=\"nl\">\"cmake.options.advanced\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n    </span><span class=\"nl\">\"build\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"buildTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"visible\"</span><span class=\"w\">\n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"ctest\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\"> \n    </span><span class=\"nl\">\"debug\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"launchTarget\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\"> \n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n     </span><span class=\"nl\">\"launch\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"workflow\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">},</span><span class=\"w\">\n    </span><span class=\"nl\">\"cpack\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"p\">{</span><span class=\"w\">\n        </span><span class=\"nl\">\"statusBarVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"p\">,</span><span class=\"w\">\n        </span><span class=\"nl\">\"projectStatusVisibility\"</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"s2\">\"hidden\"</span><span class=\"w\"> \n    </span><span class=\"p\">}</span><span class=\"w\">    \n  </span><span class=\"p\">},</span><span class=\"w\">\n</span><span class=\"p\">}</span><span class=\"w\">\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n毎回修正するのが面倒なら、<code class=\"language-plaintext highlighter-rouge\">pico_project.py</code>の\n関数<code class=\"language-plaintext highlighter-rouge\">generateProjectFiles</code>内の変数<code class=\"language-plaintext highlighter-rouge\">s1</code>の定義(1195行目あたり)\nを上記の内容で書き換えてしまえば生成時にこの内容にできる。<br />\n(そのうち公式さんが修正するだろうけど)</p>\n</blockquote>\n\n<h2 id=\"visual-studio-code-でプロジェクトを開くデバッグ\">Visual Studio Code でプロジェクトを開く~デバッグ</h2>\n\n<p>Visual Studio Code のリモートエクスプローラからRaspberry Pi に接続し、作成したディレクトリを開きます。</p>\n\n<p>ProjectNameで指定した名前.c が生成されているので必要な変更を行います。<br />\nファイルを追加する場合は <code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code> の修正も忘れずに。</p>\n\n<p>ステータスバーの「キットが選択されていません」をクリックすると 上に「XXXXのキットを選択してください」と表示されるので\n「GCC 12.2.1  arm-none-eabi」を選択(バージョンは異なるかも)<br />\n構成が完了したら「実行とデバッグ」ウィンドウを開いて、右向き三角マーク(デバッグの開始)をクリック<br />\n(右向き三角マーク(デバッグの開始)が無ければ「実行とデバッグ」をクリック)<br />\n上中央に「ターゲットの起動対象を選択します」と表示されるので、プロジェクト名で指定した名前を選択します。</p>\n\n<p>コンパイルが始まり、エラーがなければそのままデバッガが起動し、main関数の先頭でbreakします。</p>\n\n<p>あとは普通にデバッグしてくらはい。</p>\n\n<h2 id=\"ソースファイルの追加\">ソースファイルの追加</h2>\n\n<p>ソースファイルを追加する場合は<code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code> の <code class=\"language-plaintext highlighter-rouge\">add_executable</code>に追加するソースファイルを追加します。</p>\n\n<p>変更前</p>\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">add_executable</span><span class=\"p\">(</span>test1 test1.c<span class=\"p\">)</span>\n</code></pre></div></div>\n<p>変更後</p>\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">add_executable</span><span class=\"p\">(</span>test1 test1.c sub.c<span class=\"p\">)</span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico W で SDK</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico W で SDK</h1>\n      <p>Raspberry Pi Pico W で SDK を使用したプログラム開発</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico W で SDK を使用したプログラム開発方法のメモ</p>\n\n<p><a href=\"https://www.raspberrypi.com/documentation/microcontrollers/\" target=\"_blank\">公式ドキュメントサイト</a></p>\n\n<h1 id=\"セットアップ手順\">セットアップ手順</h1>\n<p>以下を参考すれば大体分かります。 <br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico-JP.pdf\" target=\"_blank\">公式スタートアップガイド(日本語版)</a><br />\n<a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a></p>\n\n<p>以下は作業メモ。<br />\n環境はWSL2上のubuntu20.04。</p>\n\n<blockquote>\n  <p>[!NOTE]\nRaspberryPi用のセットアップのスクリプトは<a href=\"https://github.com/raspberrypi/pico-setup\" target=\"_blank\">ここ</a> にある <code class=\"language-plaintext highlighter-rouge\">pico_setup.sh</code> <br />\nそれ以外のLinuxでもうごくっぽいですが、余計なものまで入ってしまいそうなので、ここでは手動でセットアップします。</p>\n</blockquote>\n\n<h2 id=\"必要なツールをインストールする\">必要なツールをインストールする</h2>\n\n<p>以下のコマンドでインストールできます。\ngitとかは既に入ってるものとして。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential\n</code></pre></div></div>\n\n<h2 id=\"sdkをダウンロードする\">SDKをダウンロードする</h2>\n\n<p>ますは作業ディレクトリを作成してSDKをダウンロードします。<br />\n以下では <code class=\"language-plaintext highlighter-rouge\">/work/Pico</code> を作業ディレクトリとしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Pico <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Pico\ngit clone https://github.com/raspberrypi/pico-sdk.git\n<span class=\"nb\">cd </span>pico-sdk/\ngit submodule update <span class=\"nt\">--init</span>\n<span class=\"nb\">cd</span> ..\n</code></pre></div></div>\n\n<h2 id=\"環境変数の設定\">環境変数の設定</h2>\n\n<p>以下のコマンドを実行し、環境変数を設定します。<br />\n上でSDKのダウンロード先を変更している場合はそれにあわせて変更してください。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">export </span><span class=\"nv\">PICO_SDK_PATH</span><span class=\"o\">=</span>/work/Pico/pico-sdk\n</code></pre></div></div>\n\n<p>次回起動時にそなえて、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code> に同様のコマンドを追加しておきます。</p>\n\n<h2 id=\"サンプルプログラムをダウンロードする\">サンプルプログラムをダウンロードする</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/raspberrypi/pico-examples.git\n</code></pre></div></div>\n\n<h2 id=\"lチカしてみる\">Lチカしてみる</h2>\n\n<p><a href=\"https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf\" target=\"_blank\">公式スタートアップガイド</a>の\n「Chapter 3. Blinking an LED in C」にあるのはPico用のサンプルなので、Pico Wでは使えません。<br />\n(正確にはGPIO端子にLEDを接続すれば使えるが、オンボードのLEDは点滅しない)<br />\nで、Pico W 用の手順をまとめてみました。</p>\n\n<h3 id=\"cmakeの実行\">cmakeの実行</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>pico-examples\n<span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake .. <span class=\"nt\">-DPICO_BOARD</span><span class=\"o\">=</span>pico_w\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\ncmake のオプションに <code class=\"language-plaintext highlighter-rouge\">-DPICO_BOARD=pico_w</code>を追加することでPico W用の設定が有効になります。</p>\n</blockquote>\n\n<h3 id=\"lチカプログラムのビルド\">Lチカプログラムのビルド</h3>\n\n<p>その場でmakeするとすべてのサンプルプログラムがビルドされますが、時間がかかるので\nLチカプログラムだけビルドします。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>pico_w/wifi/blink/\nmake\n\n</code></pre></div></div>\n\n<p>これで <code class=\"language-plaintext highlighter-rouge\">pico-examples/build/pico_w/wifi/blink</code> の <code class=\"language-plaintext highlighter-rouge\">picow_blink.uf2</code>をpicoに書き込めばボード上のLEDが点滅するはず。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPico W のLチカのソースは <code class=\"language-plaintext highlighter-rouge\">pico-examples/pico_w/wifi/blink</code></p>\n\n  <p><code class=\"language-plaintext highlighter-rouge\">pico-examples\\pico</code> はpico用(Wなし)なので、実行してもオンボードのLEDが点灯しません。 \nこれを実行するには外付けLEDが必要です。</p>\n</blockquote>\n\n<h1 id=\"コンソール出力をusbに出力する\">コンソール出力をUSBに出力する</h1>\n\n<p>デフォルトでコンソール入出力はUART0に割り当てられています(端子はGP0(TX)/GP1(RX))。<br />\nUARTに接続するのが面倒なときはUSBから仮想COMポートに入出力できます。<br />\n手順は、ソースディレクトリの <code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>に以下を追加してmakeします。<br />\n例ではターゲット名に<code class=\"language-plaintext highlighter-rouge\">picow_blink</code>を使用していますが、使用するターゲットに合わせて変更してください。</p>\n\n<div class=\"language-cmake highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># enable usb output, disable uart output</span>\n<span class=\"nf\">pico_enable_stdio_usb</span><span class=\"p\">(</span>picow_blink 1<span class=\"p\">)</span>\n<span class=\"nf\">pico_enable_stdio_uart</span><span class=\"p\">(</span>picow_blink 0<span class=\"p\">)</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">CMakeLists.txt</code>を変更した場合でも <code class=\"language-plaintext highlighter-rouge\">make</code>を実行すればこの変更も反映されます。</p>\n</blockquote>\n\n<p>出来上がったuf2ファイルをPicoに書き込んだら自動的にリブートされるので、<br />\nPCに仮想COMポートドライバがインストールされたらTeratermで対象のCOMポートに接続します。</p>\n\n<h1 id=\"自作プロジェクトの作成\">自作プロジェクトの作成</h1>\n<p>サンプルプログラムを改造してうんぬんするのはダサいので、自作のプロジェクトを作ってみます。<br />\n一から作るのは面倒なので、プロジェクト生成ツールを使います。</p>\n\n<h2 id=\"プロジェクト生成ツールのダウンロード\">プロジェクト生成ツールのダウンロード</h2>\n\n<p>githubにプロジェクト生成ツールのリポジトリがあるのでダウンロードします。<br />\n以下では 前に作成した作業ディレクトリ <code class=\"language-plaintext highlighter-rouge\">/work/Pico</code> をダウンロードディレクトリとしています。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /work/Pico\ngit clone https://github.com/raspberrypi/pico-project-generator.git\n</code></pre></div></div>\n\n<p>ダウロードしたプログラムを直接起動しても良いですが、<br />\nオプション指定など忘れっぽいので起動スクリプトを用意しておきます。</p>\n\n<p>pathの通ったディレクトリ(<code class=\"language-plaintext highlighter-rouge\">~/bin</code>など)に以下の内容でファイルを作成し、実行属性を付与します。<br />\nファイル名は<code class=\"language-plaintext highlighter-rouge\">pico_project</code>とでもしておいてください。<br />\n実行ファイルのパスはダウンロード先に合わせて変更してね。<br />\n追加したいオプションがあったらご自由にどうぞ。<br />\nGUIを起動するので、最後に & をつけてバックグラウンド実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/Pico/pico-project-generator/pico_project.py <span class=\"nt\">--nouart</span> <span class=\"nt\">--usb</span>  <span class=\"nt\">--gui</span> &\n</code></pre></div></div>\n\n<h2 id=\"プロジェクトの作成\">プロジェクトの作成</h2>\n\n<p>上で作成したスクリプトを実行するとProject Generator のウィンドウが表示されます。<br />\nこのウィンドウで必要な設定を行います。</p>\n\n<ul>\n  <li>Project Name に プロジェクト名を設定</li>\n  <li>Board Type でpico_w を選択</li>\n  <li>Library Options   PiCO Wirless Options で必要なオプションをチェック</li>\n  <li>Console Options は必要なら変更してください。<br />\n(常にUART使うなら起動スクリプトのオプション変更した方が良いかも)</li>\n  <li>Code Options は 必要なら設定。 Advancedボタンをクリックすればさらに多くのパラメータが設定できます。</li>\n  <li>その下は必要なら設定してちょ。</li>\n</ul>\n\n<p>OKボタンをクリックしたらプロジェクトが作成され、cmakeが実行されます。<br />\n実行結果を表示するウィンドウが表示されますので、確認してOKボタンでクローズしてください。<br />\nLocationで指定したディレクトリ下のProjectNameで指定した名前のディレクトリに\nProjectNameで指定した名前.c が生成されているので必要な変更を行います。</p>\n\n<p>あとはコンソールでLocationで指定したディレクトリ下のProjectNameで指定したディレクトリ下の\nbuildディレクトリに移動し、<code class=\"language-plaintext highlighter-rouge\">make</code>を実行します。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico Wでmicropython with Visual Studio Code</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico Wでmicropython with Visual Studio Code</h1>\n      <p>Raspberry Pi Pico W でmicropython の開発にVisual Studio Codeを使用する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico Wでmicropython を使用する際の開発環境(IDE)に 公式では Thonny が推奨されていますが、\nVisual Studio Codeを使用することもできます。<br />\nこのとき、拡張機能 「MicroPico」(旧称Pico-W-Go) を使用します。<br />\nここでは先人の成果を<del>パクり</del> 参照しつつ、なんとなく手順を書いてみることにします。</p>\n\n<h1 id=\"環境構築\">環境構築</h1>\n\n<h2 id=\"pc側の準備\">PC側の準備</h2>\n<p>セットアップ手順は以下が分かりやすい。<br />\n<a href=\"https://flatisle.com/raspberrypi/2289/\" target=\"_blank\">Pico W で遊ぼう(環境構築)</a><br />\nただし、モジュール名が「Pico-W-Go」から「MicroPico」に変更されているので、読み替え必要。</p>\n\n<p>PC側はVisual Studio Code がインストールされていれば 拡張機能で「MicroPico」を検索してインストールするだけ。</p>\n\n<h2 id=\"本体側の準備\">本体側の準備</h2>\n<p>本体側はファームウェアの書き換えを行う。<br />\nファームウェアの最新版は\n<a href=\"https://www.raspberrypi.com/documentation/microcontrollers/micropython.html\" target=\"_blank\">Raspberry Pi Documentation > MicroPython</a>\nからダウンロードできます。<br />\nまた、<a href=\"https://micropython.org/download/RPI_PICO_W/\" target=\"_blank\">MicroPython > DOWNLOAD > Pico W</a>\nには、Nightly buildsのバイナリもあったりします。</p>\n\n<h2 id=\"動作確認\">動作確認</h2>\n<p>Raspberry pi Pico をPCに接続しておいて、Visual Studio Code を起動。</p>\n\n<ul>\n  <li>メニューの「ターミナル」→「新しいターミナル」でターミナルウィンドウを開く(デフォルト状態だとPowershellが実行される)。</li>\n  <li>ターミナルウィンドウの右上の「+」ボタン(新しいターミナル)のドロップダウンリストを開いて\n「Pico(W) vREPL」を選択してvREPLに接続する。<br />\n(+をクリックするとPowershellが新しく開かれるので右のvっぽい記号をクリックする)</li>\n  <li>以下のような表示が出る。<br />\n(バージョン番号とかはファームウェアによって異なる)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>MicroPython v1.20.0-198-g0eacdeb1c on 2023-06-13; Raspberry Pi Pico W with RP2040\nType \"help()\" for more information or .cls/.clear to clear the terminal.\n\n>>> \n</code></pre></div></div>\n\n<p>ここで色々コマンドを入力すれば実行できる</p>\n\n<h1 id=\"いつでもwifiにつなげるように準備\">いつでもwifiにつなげるように準備</h1>\n\n<p>適当なところにフォルダを作成し(以下の例では「test」)、その下にlibフォルダを作り、\nその下にmy_wifi.py として以下のファイルを作成しておく。<br />\n1行目~2行目は自分の環境に合わせて変更しておくこと。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    test\n     +-- lib\n          +-- my_wifi.py\n          \n</code></pre></div></div>\n\n<!-- ファイル名を付けたいときはこれを指定-->\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  my_wifi.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SSID_NAME</span> <span class=\"o\">=</span> <span class=\"s\">\"SSID名\"</span>\n<span class=\"n\">SSID_PASS</span> <span class=\"o\">=</span> <span class=\"s\">\"SSIDパスワード\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">utime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">network</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n<span class=\"c1\"># ==== connecti to wifi access point ============================================\n</span><span class=\"k\">def</span> <span class=\"nf\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">,</span> <span class=\"n\">timeout</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">):</span>\n    <span class=\"n\">wifi</span><span class=\"o\">=</span> <span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">WLAN</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">STA_IF</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'already Connected.    connect skip'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">active</span><span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">)</span>\n        <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"ow\">and</span> <span class=\"n\">timeout</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'.'</span><span class=\"p\">,</span> <span class=\"n\">end</span><span class=\"o\">=</span><span class=\"s\">''</span><span class=\"p\">)</span>\n            <span class=\"n\">utime</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">timeout</span> <span class=\"o\">-=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">():</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">Connected'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Connection failed!'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">False</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">disconnect</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">disconnect</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"n\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">SSID_NAME</span><span class=\"p\">,</span> <span class=\"n\">SSID_PASS</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">ifconfig</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n<p>Visual Studio Code のエクスプローラウィンドウで「フォルダを開く」ボタンをクリック\n(またはメニューの「ファイル」→「フォルダを開く」を選択)し、\n上で作成したフォルダ(例ではtest)を開きます。</p>\n\n<p>コマンドパレットで「MicroPico: Upload project to Pico」を選択します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n現在書き込まれているファイルをすべて消去するには<br />\nコマンドパレットで「MicroPico: Delete all files from board」を選択します。</p>\n\n</blockquote>\n\n<p>実際に書き込まれたかはターミナルウィンドウで以下のように実行することで確認できます。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">>>></span> <span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'lib'</span><span class=\"p\">]</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/lib'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'my_wifi.py'</span><span class=\"p\">]</span>\n</code></pre></div></div>\n<p>または後述の仮想ファイルシステムを使用しても確認できます。</p>\n\n<p>でもって、使用するプログラムで<code class=\"language-plaintext highlighter-rouge\">import my_wifi</code> とやれば接続できます。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">my_wifi.isconnected()</code> で接続中かが分かります。\n<code class=\"language-plaintext highlighter-rouge\">my_wifi.disconnect()</code> でAPから切断できます。</p>\n\n<h1 id=\"仮想ファイルシステムを使用する\">仮想ファイルシステムを使用する</h1>\n<p>仮想ファイルシステムを使用すると、現在PaspberryPi Pico(W)のストレージに書き込まれているファイルを\n直接確認/操作することができます。</p>\n\n<ul>\n  <li>コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n  <li>エクスプローラウィンドウに「Pico (W) Remote Workspace」ができ、その下にディレクトリ/ファイルが表示される</li>\n</ul>\n\n<p>ここのファイルを開くとPaspberryPi Pico(W)のストレージにあるファイルを直接参照できます。<br />\nまた、内容を変更して保存すると PaspberryPi Pico(W)のストレージに直接格納されます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPC上のファイルとPaspberryPi Pico(W)のストレージ上のファイルをあちこち弄くると\nどちらをどう書き換えたか分からなくなるので、できるだけPC上のファイルを書き換えて「Upload project to Pico」で\nPaspberryPi Pico(W)のストレージを同期するのが良いと思います。</p>\n</blockquote>\n\n<p>mipコマンドでダウンロードしたモジュールや、プログラムでPaspberryPi Pico(W)のストレージ上に作成したファイルをPCのコピーするには、</p>\n<ul>\n  <li>エクスプローラウィンドウで仮想ファイルシステム上のコピーしたいフォルダまたはファイルを選択</li>\n  <li>CTRLキーを押しながらコピーしたいPC上のフォルダの位置にドラッグ&ドロップ\n    <ul>\n      <li>CTRLキーを押さないでドラッグ&ドロップした場合は移動になるので、「移動しますか?」と聞かれる。移動するなら「移動」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<p>仮想ファイルシステムを消すには、</p>\n<ul>\n  <li>再度コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n</ul>\n\n<p>で、エクスプローラウィンドウから「Pico (W) Remote Workspace」が消えます。<br />\n(エクスプローラウィンドウの表示が消えるだけで、PaspberryPi Pico(W)のストレージから消えるわけではありません)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "micropython": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Raspberry Pi Pico Wでmicropython with Visual Studio Code</title>\n  </head>\n  <body>\n    <header>\n      <h1>Raspberry Pi Pico Wでmicropython with Visual Studio Code</h1>\n      <p>Raspberry Pi Pico W でmicropython の開発にVisual Studio Codeを使用する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Raspberry Pi Pico Wでmicropython を使用する際の開発環境(IDE)に 公式では Thonny が推奨されていますが、\nVisual Studio Codeを使用することもできます。<br />\nこのとき、拡張機能 「MicroPico」(旧称Pico-W-Go) を使用します。<br />\nここでは先人の成果を<del>パクり</del> 参照しつつ、なんとなく手順を書いてみることにします。</p>\n\n<h1 id=\"環境構築\">環境構築</h1>\n\n<h2 id=\"pc側の準備\">PC側の準備</h2>\n<p>セットアップ手順は以下が分かりやすい。<br />\n<a href=\"https://flatisle.com/raspberrypi/2289/\" target=\"_blank\">Pico W で遊ぼう(環境構築)</a><br />\nただし、モジュール名が「Pico-W-Go」から「MicroPico」に変更されているので、読み替え必要。</p>\n\n<p>PC側はVisual Studio Code がインストールされていれば 拡張機能で「MicroPico」を検索してインストールするだけ。</p>\n\n<h2 id=\"本体側の準備\">本体側の準備</h2>\n<p>本体側はファームウェアの書き換えを行う。<br />\nファームウェアの最新版は\n<a href=\"https://www.raspberrypi.com/documentation/microcontrollers/micropython.html\" target=\"_blank\">Raspberry Pi Documentation > MicroPython</a>\nからダウンロードできます。<br />\nまた、<a href=\"https://micropython.org/download/RPI_PICO_W/\" target=\"_blank\">MicroPython > DOWNLOAD > Pico W</a>\nには、Nightly buildsのバイナリもあったりします。</p>\n\n<h2 id=\"動作確認\">動作確認</h2>\n<p>Raspberry pi Pico をPCに接続しておいて、Visual Studio Code を起動。</p>\n\n<ul>\n  <li>メニューの「ターミナル」→「新しいターミナル」でターミナルウィンドウを開く(デフォルト状態だとPowershellが実行される)。</li>\n  <li>ターミナルウィンドウの右上の「+」ボタン(新しいターミナル)のドロップダウンリストを開いて\n「Pico(W) vREPL」を選択してvREPLに接続する。<br />\n(+をクリックするとPowershellが新しく開かれるので右のvっぽい記号をクリックする)</li>\n  <li>以下のような表示が出る。<br />\n(バージョン番号とかはファームウェアによって異なる)</li>\n</ul>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>MicroPython v1.20.0-198-g0eacdeb1c on 2023-06-13; Raspberry Pi Pico W with RP2040\nType \"help()\" for more information or .cls/.clear to clear the terminal.\n\n>>> \n</code></pre></div></div>\n\n<p>ここで色々コマンドを入力すれば実行できる</p>\n\n<h1 id=\"いつでもwifiにつなげるように準備\">いつでもwifiにつなげるように準備</h1>\n\n<p>適当なところにフォルダを作成し(以下の例では「test」)、その下にlibフォルダを作り、\nその下にmy_wifi.py として以下のファイルを作成しておく。<br />\n1行目~2行目は自分の環境に合わせて変更しておくこと。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    test\n     +-- lib\n          +-- my_wifi.py\n          \n</code></pre></div></div>\n\n<!-- ファイル名を付けたいときはこれを指定-->\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  my_wifi.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SSID_NAME</span> <span class=\"o\">=</span> <span class=\"s\">\"SSID名\"</span>\n<span class=\"n\">SSID_PASS</span> <span class=\"o\">=</span> <span class=\"s\">\"SSIDパスワード\"</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">utime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">network</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"bp\">None</span>\n<span class=\"c1\"># ==== connecti to wifi access point ============================================\n</span><span class=\"k\">def</span> <span class=\"nf\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">,</span> <span class=\"n\">timeout</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">):</span>\n    <span class=\"n\">wifi</span><span class=\"o\">=</span> <span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">WLAN</span><span class=\"p\">(</span><span class=\"n\">network</span><span class=\"p\">.</span><span class=\"n\">STA_IF</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'already Connected.    connect skip'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">active</span><span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n        <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"n\">ssid</span><span class=\"p\">,</span> <span class=\"n\">passkey</span><span class=\"p\">)</span>\n        <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span> <span class=\"ow\">and</span> <span class=\"n\">timeout</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'.'</span><span class=\"p\">,</span> <span class=\"n\">end</span><span class=\"o\">=</span><span class=\"s\">''</span><span class=\"p\">)</span>\n            <span class=\"n\">utime</span><span class=\"p\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n            <span class=\"n\">timeout</span> <span class=\"o\">-=</span> <span class=\"mi\">1</span>\n    \n    <span class=\"k\">if</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">():</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'</span><span class=\"se\">\\n</span><span class=\"s\">Connected'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'Connection failed!'</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">isconnected</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">isconnected</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">False</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">disconnect</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">disconnect</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"bp\">None</span>\n\n<span class=\"n\">wifi</span> <span class=\"o\">=</span> <span class=\"n\">connect_wifi</span><span class=\"p\">(</span><span class=\"n\">SSID_NAME</span><span class=\"p\">,</span> <span class=\"n\">SSID_PASS</span><span class=\"p\">)</span>\n\n<span class=\"k\">if</span> <span class=\"n\">wifi</span> <span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">wifi</span><span class=\"p\">.</span><span class=\"n\">ifconfig</span><span class=\"p\">())</span>\n</code></pre></div></div>\n\n<p>Visual Studio Code のエクスプローラウィンドウで「フォルダを開く」ボタンをクリック\n(またはメニューの「ファイル」→「フォルダを開く」を選択)し、\n上で作成したフォルダ(例ではtest)を開きます。</p>\n\n<p>コマンドパレットで「MicroPico: Upload project to Pico」を選択します。</p>\n\n<blockquote>\n  <p>[!NOTE]\n現在書き込まれているファイルをすべて消去するには<br />\nコマンドパレットで「MicroPico: Delete all files from board」を選択します。</p>\n\n</blockquote>\n\n<p>実際に書き込まれたかはターミナルウィンドウで以下のように実行することで確認できます。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"o\">>>></span> <span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'lib'</span><span class=\"p\">]</span>\n<span class=\"o\">>>></span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"s\">'/lib'</span><span class=\"p\">)</span>\n<span class=\"p\">[</span><span class=\"s\">'my_wifi.py'</span><span class=\"p\">]</span>\n</code></pre></div></div>\n<p>または後述の仮想ファイルシステムを使用しても確認できます。</p>\n\n<p>でもって、使用するプログラムで<code class=\"language-plaintext highlighter-rouge\">import my_wifi</code> とやれば接続できます。<br />\nなお、<code class=\"language-plaintext highlighter-rouge\">my_wifi.isconnected()</code> で接続中かが分かります。\n<code class=\"language-plaintext highlighter-rouge\">my_wifi.disconnect()</code> でAPから切断できます。</p>\n\n<h1 id=\"仮想ファイルシステムを使用する\">仮想ファイルシステムを使用する</h1>\n<p>仮想ファイルシステムを使用すると、現在PaspberryPi Pico(W)のストレージに書き込まれているファイルを\n直接確認/操作することができます。</p>\n\n<ul>\n  <li>コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n  <li>エクスプローラウィンドウに「Pico (W) Remote Workspace」ができ、その下にディレクトリ/ファイルが表示される</li>\n</ul>\n\n<p>ここのファイルを開くとPaspberryPi Pico(W)のストレージにあるファイルを直接参照できます。<br />\nまた、内容を変更して保存すると PaspberryPi Pico(W)のストレージに直接格納されます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nPC上のファイルとPaspberryPi Pico(W)のストレージ上のファイルをあちこち弄くると\nどちらをどう書き換えたか分からなくなるので、できるだけPC上のファイルを書き換えて「Upload project to Pico」で\nPaspberryPi Pico(W)のストレージを同期するのが良いと思います。</p>\n</blockquote>\n\n<p>mipコマンドでダウンロードしたモジュールや、プログラムでPaspberryPi Pico(W)のストレージ上に作成したファイルをPCのコピーするには、</p>\n<ul>\n  <li>エクスプローラウィンドウで仮想ファイルシステム上のコピーしたいフォルダまたはファイルを選択</li>\n  <li>CTRLキーを押しながらコピーしたいPC上のフォルダの位置にドラッグ&ドロップ\n    <ul>\n      <li>CTRLキーを押さないでドラッグ&ドロップした場合は移動になるので、「移動しますか?」と聞かれる。移動するなら「移動」をクリック</li>\n    </ul>\n  </li>\n</ul>\n\n<p>仮想ファイルシステムを消すには、</p>\n<ul>\n  <li>再度コマンドパレットで「MicroPico: Toggle Virtual File System (reloads UI and closes existing vREPLs)」を選択<br />\n(またはステータスバーの「Toggle Pico-W-FS」をクリック)</li>\n</ul>\n\n<p>で、エクスプローラウィンドウから「Pico (W) Remote Workspace」が消えます。<br />\n(エクスプローラウィンドウの表示が消えるだけで、PaspberryPi Pico(W)のストレージから消えるわけではありません)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "HTML": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>HTMLで疑似トースト表示</title>\n  </head>\n  <body>\n    <header>\n      <h1>HTMLで疑似トースト表示</h1>\n      <p>HTMLで疑似(なんちゃって)トースト表示するサンプル</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Javascriptでスクリプト書いていて、alert表示するとOKボタン押すまで戻ってこなくて使い勝手が悪いので、\n一定時間表示して勝手に消えるトースト表示みたいな表示ができないかと作ってみた。<br />\nあくまで簡易的なものなので、ウィンドウ作ったりとかはしてない。</p>\n\n<p>妙なこだわりで、消えるときはふわと消える(フェードアウト)にしてみた。<br />\n<code class=\"language-plaintext highlighter-rouge\">fadetime</code>を0にしたらぱっと消える。<br />\nま、ぱっと出てぱっと消えるなら<code class=\"language-plaintext highlighter-rouge\">style.visibility =\"visible\"</code>と<code class=\"language-plaintext highlighter-rouge\">style.visibility =\"hidden\"</code>でいいけど。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>以下のソースを適当に保存して、ブラウザで開いてちょ。<br />\nローカルファイル(file://)で開いてもOK。</p>\n\n<p>説明するほどのことはないので省略。</p>\n\n<p>ページの先頭に固定なので、スクロールしたら消えちゃうけど、\n表示領域の固定(position: fixed など)を使えばなんとかなりそう。</p>\n\n<p>表示が消える前に次の表示を始めたらうまくいかないかも…</p>\n\n<div class=\"language-html highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\"><!DOCTYPE HTML></span>\n<span class=\"nt\"><html</span> <span class=\"na\">lang=</span><span class=\"s\">\"ja\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><head></span>\n<span class=\"nt\"><meta</span> <span class=\"na\">charset=</span><span class=\"s\">\"UTF-8\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><title></span>疑似トースト表示<span class=\"nt\"></title></span>\n<span class=\"nt\"><script></span>\n<span class=\"c1\">// msgをdisptime(msec)表示後、fadetime(msec)でフェードアウトする</span>\n<span class=\"kd\">function</span> <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"nx\">msg</span><span class=\"p\">,</span> <span class=\"nx\">disptime</span><span class=\"o\">=</span><span class=\"mi\">2000</span><span class=\"p\">,</span> <span class=\"nx\">fadetime</span><span class=\"o\">=</span><span class=\"mi\">2000</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"kd\">let</span> <span class=\"nx\">elm</span> <span class=\"o\">=</span> <span class=\"nb\">document</span><span class=\"p\">.</span><span class=\"nx\">getElementById</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">toast</span><span class=\"dl\">\"</span><span class=\"p\">)</span>\n  <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">innerText</span> <span class=\"o\">=</span> <span class=\"nx\">msg</span><span class=\"p\">;</span>            <span class=\"c1\">// 表示メッセージの変更</span>\n  <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">style</span><span class=\"p\">.</span><span class=\"nx\">animation</span> <span class=\"o\">=</span> <span class=\"dl\">\"</span><span class=\"s2\">none</span><span class=\"dl\">\"</span><span class=\"p\">;</span>   <span class=\"c1\">// アニメーションをキャンセルして表示する</span>\n  <span class=\"nx\">setTimeout</span><span class=\"p\">(()</span> <span class=\"o\">=></span> <span class=\"p\">{</span>              <span class=\"c1\">// disptime経過後、アニメーションを開始する。</span>\n    <span class=\"nx\">elm</span><span class=\"p\">.</span><span class=\"nx\">style</span><span class=\"p\">.</span><span class=\"nx\">animation</span> <span class=\"o\">=</span> <span class=\"s2\">`fadeOut </span><span class=\"p\">${</span><span class=\"nx\">fadetime</span><span class=\"p\">}</span><span class=\"s2\">ms forwards`</span><span class=\"p\">;</span>\n  <span class=\"p\">},</span> <span class=\"nx\">disptime</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// ボタンクリック時にコールされる関数</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message1</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ1</span><span class=\"dl\">\"</span><span class=\"p\">,</span><span class=\"mi\">1000</span><span class=\"p\">,</span> <span class=\"mi\">4000</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message2</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ2</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"mi\">3000</span><span class=\"p\">,</span> <span class=\"mi\">1000</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message3</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ3</span><span class=\"dl\">\"</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"kd\">function</span> <span class=\"nx\">message4</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"nx\">toast_message</span><span class=\"p\">(</span><span class=\"dl\">\"</span><span class=\"s2\">メッセージ4</span><span class=\"dl\">\"</span><span class=\"p\">,</span> <span class=\"mi\">3000</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">);</span>\n<span class=\"p\">}</span>\n<span class=\"nt\"></script></span>\n<span class=\"nt\"></head></span>\n\n<span class=\"nt\"><style></span>\n<span class=\"c\">/* フェードアウトのキーフレーム */</span>\n<span class=\"k\">@keyframes</span> <span class=\"n\">fadeOut</span> <span class=\"p\">{</span>\n  <span class=\"err\">0</span><span class=\"o\">%</span> <span class=\"p\">{</span>\n    <span class=\"nl\">opacity</span><span class=\"p\">:</span> <span class=\"m\">1</span><span class=\"p\">;</span>\n  <span class=\"p\">}</span>\n  <span class=\"err\">100</span><span class=\"o\">%</span> <span class=\"p\">{</span>\n    <span class=\"nl\">opacity</span><span class=\"p\">:</span> <span class=\"m\">0</span><span class=\"p\">;</span>\n  <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c\">/* トースト表示領域 */</span>\n<span class=\"nf\">#toast</span><span class=\"p\">{</span>\n  <span class=\"c\">/* 背景色 */</span>\n  <span class=\"nl\">background-color</span><span class=\"p\">:</span> <span class=\"nb\">rgb</span><span class=\"p\">(</span><span class=\"m\">128</span><span class=\"p\">,</span><span class=\"m\">256</span><span class=\"p\">,</span><span class=\"m\">128</span><span class=\"p\">);</span>\n  <span class=\"c\">/* 0secでアニメーションして表示を消しておく */</span>\n  <span class=\"nl\">animation</span><span class=\"p\">:</span> <span class=\"n\">fadeOut</span> <span class=\"m\">0s</span> <span class=\"n\">forwards</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n<span class=\"c\">/* ボタンを大きくしたいので */</span>\n<span class=\"nc\">.font-large</span><span class=\"p\">{</span>\n    <span class=\"nl\">font-size</span><span class=\"p\">:</span> <span class=\"m\">130%</span><span class=\"p\">;</span>\n<span class=\"p\">}</span>\n<span class=\"nt\"></style></span>\n\n<span class=\"nt\"><body></span>\n<span class=\"nt\"><font</span> <span class=\"na\">size=</span><span class=\"s\">\"5\"</span><span class=\"nt\">></span>\n<span class=\"nt\"><div></span>\n  <span class=\"nt\"><H3></span>疑似トースト表示<span class=\"nt\"></H3></span>\n  <span class=\"c\"><!-- トースト表示領域 --></span>\n  <span class=\"nt\"><div</span> <span class=\"na\">id=</span><span class=\"s\">\"toast\"</span><span class=\"nt\">></span>\n    メッセージ領域\n  <span class=\"nt\"></div></span>\n  \n  <span class=\"c\"><!-- テスト用ボタン --></span>\n  <span class=\"nt\"><div></span>\n    <span class=\"nt\"><p></span>\n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ1\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message1();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ2\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message2();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ3\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message3();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n      <span class=\"nt\"><input</span> <span class=\"na\">type=</span><span class=\"s\">\"button\"</span> <span class=\"na\">value=</span><span class=\"s\">\"メッセージ4\"</span> <span class=\"na\">onclick=</span><span class=\"s\">\"message4();\"</span> <span class=\"na\">class=</span><span class=\"s\">\"font-large\"</span><span class=\"nt\">/></span> \n    <span class=\"nt\"></p></span>\n  <span class=\"nt\"><div></span>\n<span class=\"nt\"></div></span>\n<span class=\"nt\"></font></span>\n<span class=\"nt\"></body></span>\n<span class=\"nt\"></html></span>\n</code></pre></div></div>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    " micropython": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Web Bluetooth APIを試す</title>\n  </head>\n  <body>\n    <header>\n      <h1>Web Bluetooth APIを試す</h1>\n      <p>Web bluetooth APIを試した時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>ブラウザからBluetoothにアクセスできる<a href=\"https://developer.mozilla.org/ja/docs/Web/API/Web_Bluetooth_API\" target=\"_blank\">Web Bluetooth API</a>\nを試してみた時に作ったプログラムを貼っておきます。</p>\n\n<h1 id=\"準備\">準備</h1>\n\n<h2 id=\"ペリフェラル機器\">ペリフェラル機器</h2>\n\n<p>BLEは通信なので、通信相手が必要です。<br />\n市販機器を使うと仕様を調べるのが大変なので、エイヤッと自分で作っりました。<br />\nといっても Raspberry Pi Pico W にmicropythonのF/Wを書き込んでプログラム実行するだけ。<br />\n(使用したmicropython F/Wは「MicroPython v1.23.0 on 2024-06-02」です)</p>\n\n<p>以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。 と言ってもWi-Fiとか要らないからパクり先のリンク貼ってあるだけだけど。</p>\n\n<p>ということで、以下のソースを Raspberry Pi Pico で実行しておきます。<br />\n(特にH/W依存なことはしてないので、ESP32でも動くかも)</p>\n\n<p>BLEの処理については「micropython aioble」とかでググってください。<br />\nでも、公式のサンプル動かした例ばっかりであんまりないんだよなぁ…</p>\n\n<p>==懺悔==<br />\nUUIDはどっかのサンプルの値をちょこっといじったものです。<br />\n(調べたら温度計用のUUIDでした)<br />\n本来ならUUIDをちゃんと生成しないといけません。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=ble_peripheral.py\"></script>\n</dev>\n\n<h2 id=\"webサーバ\">Webサーバ</h2>\n<p>Web Bluetooth APIを使用するのは、HTMLファイルをHTTPSサーバからロードしなければならない仕様のようです。\n(httpやfileでは不可)<br />\nファイル1個だけなので、どこかのサーバの片隅に置くとかでも良いと思います。<br />\nローカルでサーバを立てるならApacheとかnginxとかで立ててください。</p>\n\n<blockquote>\n  <p>[!NOTE]\nWindowsでApacheを使うなら<a href=\"https://nanbu.marune205.net/2022/01/windows10-apache-ssl.html?m=1\" target=\"_blank\">WindowsのApacheサーバーでSSL</a>\nあたりが参考になりました。<br />\nただし、仮の証明書を作るバッチファイルで、Apacheのインストール先がc:¥Apache24 以外の場合は\n以下の設定を追加しておく必要があります。</p>\n  <div class=\"language-powershell highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">SET</span><span class=\"w\"> </span><span class=\"nx\">OPENSSL_CONF</span><span class=\"o\">=</span><span class=\"err\">≪</span><span class=\"n\">Apache</span><span class=\"err\">のインストール先≫</span><span class=\"nx\">\\conf\\openssl.cnf</span><span class=\"w\">\n</span></code></pre></div>  </div>\n  <p>インストール先を<code class=\"language-plaintext highlighter-rouge\">m:\\Apache24</code>にした場合の変更例はこんな感じ。</p>\n  <div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- aaa.txt     2024-07-29 06:58:34.154735900 +0900\n</span><span class=\"gi\">+++ make-snakeoil-cert.bat      2024-07-26 05:09:37.394502700 +0900\n</span><span class=\"p\">@@ -1,8 +1,11 @@</span>\n REM openssl.exe\n<span class=\"gd\">-SET OPENSSL=c:\\Apache24\\bin\\openssl.exe\n</span><span class=\"gi\">+SET OPENSSL=m:\\Apache24\\bin\\openssl.exe\n+\n+REM openssl.cnf\n+SET OPENSSL_CONF=m:\\Apache24\\conf\\openssl.cnf\n</span>\n REM 証明書用データの出力場所\n<span class=\"gd\">-SET ROOTDIR=c:\\Apache24\\certs\n</span><span class=\"gi\">+SET ROOTDIR=m:\\Apache24\\certs\n</span>\n REM サーバーのドメインまたはIPアドレス\n SET IPADDRESS=localhost\n</code></pre></div>  </div>\n\n</blockquote>\n\n<h1 id=\"htmlファイル\">HTMLファイル</h1>\n\n<p>Web Bluetooth API のサンプルプログラムを以下に示します。<br />\nこれをHTTPSサーバに置いておきます</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/2c78471896fa4aebc4c8f9dc76237126.js?file=BLE_sample.html\"></script>\n</dev>\n\n<h1 id=\"実験\">実験</h1>\n\n<p>ペリフェラルプログラムを動作させておき、\nブラウザで上記HTMLファイルを開きます。</p>\n\n<p>アクセスするPCやスマホはBLE対応のBluetoothが搭載されている必要があります。<br />\nブラウザはChromeかEdge(は試してないけど)で。(firefox不可)</p>\n\n<p>WindowsPCとAndroidスマホのChromeは動作確認しました。<br />\nmacとiPhoneは持ってないので試してません。</p>\n\n<p>次に「接続」ボタンをクリック、「XXXXXがペア接続を要求しています」ダイアログが出るので\n「mpy-sensor」を選択し、「ペア設定」をクリックします。</p>\n\n<p>接続されると DATA1 に受信したデータを表示します。<br />\nDATA1はNotificationありのデータ読み取りです。<br />\nNotificationイベントを受けてデータを読み取ります。<br />\n上は1行を常に書き換えるタイプ。<br />\n下は過去分を含め10行程度表示(それ以前は削除)するタイプです。<br />\n受診自体は1回でページの書き換え処理を2通り行っています。</p>\n\n<p>DATA2はNotificationなしのデータ読み取りです。<br />\nREADボタンをクリックすると読み取った値を表示します。</p>\n\n<p>測定間隔のテキストボックスに数値を入力し、「WRITE」をクリックすると\nDATA1の取得間隔を変更できます。<br />\n値は100~5000が有効で、範囲外の値が設定されると範囲内の値に補正されます(補正はペリフェラル川で行っています)。</p>\n\n<p>接続を終了するには「切断」をクリックします。</p>\n\n<h1 id=\"操作例\">操作例</h1>\n\n<p><a href=\"/memoBlog/misc/WEB_BT_API_2024-07-29_075522.mp4\" target=\"_blank\">操作例の動画</a></p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "tkinter": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tkinter で スクロール可能なcanvasを作る</title>\n  </head>\n  <body>\n    <header>\n      <h1>tkinter で スクロール可能なcanvasを作る</h1>\n      <p>tkinter で スクロール可能なcanvasを作る</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>tkinterでスクロール可能なcanvasのクラス<code class=\"language-plaintext highlighter-rouge\">ScrollableCanvas</code>を作ってみました。<br />\nぶっちゃけ、あちこちにその手の記事はあるのですが、なんか自分のコーディングスタイルとあってないの気がしたので\n微妙に書き換えてみました。</p>\n\n<h1 id=\"サンプルプログラム\">サンプルプログラム</h1>\n\n<p>さっそくサンプルプログラムを貼りつけておきます。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/0ccd48b5cec72ad363d7eaa452972b1f.js\"></script>\n</dev>\n\n<h2 id=\"解説のようなもの\">解説のようなもの</h2>\n\n<h3 id=\"canvas-を継承した-scrollablecanvas-クラス\">canvas を継承した ScrollableCanvas クラス</h3>\n<p>ネット上にある例では、Frameクラスを継承してその下にcanvasを貼り付けているものが多いですが、\nなんとなく余分なウィジェットを作りたくない気分だったのでCanvasクラスを継承するようにしてみました。<br />\nまた、コンストラクタ中でpackしている例が多かったですが、配置の自由度を上げるため上位側に任せるようにしました。</p>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>今回は縦スクロールのみ対応なので、canvasの幅はあらかじめ指定しておくようにしてあります。<br />\nまた、表示するウィジェットを配置するためのフレーム(<code class=\"language-plaintext highlighter-rouge\">child_frame</code>)は幅を自由に設定できるようにすると\n親ウィジェットであるcanvasの幅まで大きくなりますが、これだとスクロールバーが見えなくなります。<br />\nそこで、<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の幅はcanvasの幅からスクロールバーの幅を差し引いたサイズを設定しています。</p>\n\n<blockquote>\n  <p>[!NOTE]\n縦横スクロール可能にした場合は このあたり見直さないといけないかもしれない。</p>\n</blockquote>\n\n<p>また、マウスドラッグによるスクロールをスムーズにするため、スクロール量(<code class=\"language-plaintext highlighter-rouge\">yscrollincrement</code>)のデフォルトを1に設定しています。\nこれはScrollableCanvasクラスのインスタンスを生成する際に変更することができます。</p>\n\n<h3 id=\"ウィンドウイベント\">ウィンドウイベント</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">\"<Configure>\"</code> イベントをbindすることで、ウィンドウが移動されたり、リサイズされたりしたときに実行する処理を割り当てています。<br />\n<code class=\"language-plaintext highlighter-rouge\">\"<Configure>\"</code> イベントはウィンドウのリサイズ等だけでなく、pack()等でFrameのサイズが変更されたときも通知されます。</p>\n\n<p>ここではスクロール範囲の再設定を行っています。</p>\n\n<h3 id=\"マウスイベント\">マウスイベント</h3>\n\n<p>マウスイベントのbindは\n<a href=\"/memoBlog/2024/09/14/tkinter_event_1.html\" target=\"_blank\">tkinter で 低層のウィジェットでイベントを検出する</a>\nの方法を使用しています。</p>\n\n<table>\n  <thead>\n    <tr>\n      <th>操作</th>\n      <th>処理</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>左クリック</td>\n      <td>ドラッグ開始位置の設定</td>\n    </tr>\n    <tr>\n      <td>左クリック→マウス移動</td>\n      <td>縦方向の移動量に応じたスクロール</td>\n    </tr>\n    <tr>\n      <td>左ダブルクリック</td>\n      <td>子ウィジェットの追加</td>\n    </tr>\n    <tr>\n      <td>ホイール</td>\n      <td>縦方向スクロール</td>\n    </tr>\n    <tr>\n      <td>右クリック</td>\n      <td>子ウィジェットの全削除</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"実は\">実は…</h3>\n\n<p>右クリックで子ウィジェットを全削除した際、<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の高さは削除前の高さのままになっています。<br />\nつまり、なにもないフレームをスクロールできる状態になっています。<br />\n次に左ダブルクリックでウィジェットを追加したときに1ジェット1個分の高さに変更されます。<br />\nこの仕様が気持ち悪くて色々試したのですが、うまくいきませんでした。<br />\nそこで、「cleard」と表示して<code class=\"language-plaintext highlighter-rouge\">child_frame</code>の高さを変更して誤魔化しています。<br />\n子ウィジェットの差し替えしかしないのであれば特に気にしなくても良い部分だと思います。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>tkinter で 低層のウィジェットでイベントを検出する</title>\n  </head>\n  <body>\n    <header>\n      <h1>tkinter で 低層のウィジェットでイベントを検出する</h1>\n      <p>tkinter で 低層のウィジェットでイベントを検出する</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>tkinterでイベントを検出する際、対象のウィジェットの手前に別のウィジェットがあるとイベントを検出できません。<br />\nそれを回避し、手前にウィジェットが存在してもイベントが検出できるサンプルプログラムを書いてみました。</p>\n\n<h1 id=\"サンプルプログラム\">サンプルプログラム</h1>\n\n<p>さっそくサンプルプログラムを貼りつけておきます。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/59faf9f974e22d34a8e988954a32518b.js\"></script>\n</dev>\n\n<h2 id=\"解説のようなもの\">解説のようなもの</h2>\n\n<h3 id=\"canvasにバインドしたイベントハンドラ\">canvasにバインドしたイベントハンドラ</h3>\n\n<p>以下の部分が普通にcanvasにマウスクリックイベントをバインドしている部分です。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">test_canvas</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"s\">'<ButtonPress-1>'</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_on_click_canvas</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>canvas上(水色の部分)でクリックすると<code class=\"language-plaintext highlighter-rouge\">_on_click_canvas</code>が実行され、\n<code class=\"language-plaintext highlighter-rouge\">_on_click_canvas : click on canvas</code>と表示されます。<br />\nしかし、その上に配置されたラベル(labex_1x)上でクリックしたときは表示されません。</p>\n\n<p>labelもcanvasの一部なので、ここでもクリック処理が動いてほしいことはよくあると思います。</p>\n\n<h3 id=\"rootにバインドしたイベントハンドラ\">rootにバインドしたイベントハンドラ</h3>\n\n<p>そこで、以下の部分でrootにマウスクリックイベントをバインドします。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">winfo_toplevel</span><span class=\"p\">().</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"s\">'<ButtonPress-1>'</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_on_click</span><span class=\"p\">,</span> <span class=\"s\">\"+\"</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>これはrootにバインドされたイベントですから、当然canvas以外の部分でも処理が動きます。<br />\nそこで、イベントハンドラでマウス座標を取得し、canvasの範囲内かを確認し、\nそうであればクリック処理(ここでは<code class=\"language-plaintext highlighter-rouge\">_on_click : click on canvas</code>を表示)を実行します。<br />\nパラメータの最後の<code class=\"language-plaintext highlighter-rouge\">\"+\"</code>は、既にバインドされているハンドラがあった時、上書きせずに追加することを指定しています。<br />\n(つまり、以前にバインドしたハンドラと今回のハンドラ両方が実行されます)</p>\n\n<p>こちらの処理はcanvas上(水色の部分)でクリックしたときも\nその上に配置されたラベル(labex_1x)上でクリックしたときもクリック処理が実行されます。</p>\n\n<p>なお、イベントハンドラに渡されるパラメータ<code class=\"language-plaintext highlighter-rouge\">event</code>の<code class=\"language-plaintext highlighter-rouge\">event.x</code>、<code class=\"language-plaintext highlighter-rouge\">event.y</code>はウィジェット内の相対座標なので\n比較には<code class=\"language-plaintext highlighter-rouge\">event.x_root</code>、<code class=\"language-plaintext highlighter-rouge\">event.y_root</code>を使用して画面上の座標を使用します。<br />\n当然比較するcanvasの座標も<code class=\"language-plaintext highlighter-rouge\">widget.winfo_rootx()</code>、<code class=\"language-plaintext highlighter-rouge\">widget.winfo_rooty()</code>で画面上の座標を使用しなければなりません。</p>\n\n<h3 id=\"おまけ\">おまけ</h3>\n\n<p>おまけとして、ダブルクリックした位置に存在するウィジェットの一覧を表示する処理を入れておきました(<code class=\"language-plaintext highlighter-rouge\">_on_doubleclick</code>) 。<br />\nダブルクリックに意味はなく、クリックは既に使っていたのでダブルクリックにしただけです。</p>\n\n<blockquote>\n  <p>おーちゃくせずに別のプログラム書けよ > 自分</p>\n</blockquote>\n\n<h3 id=\"ふと思ったこと\">ふと思ったこと</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">event.widget</code> から 順に <code class=\"language-plaintext highlighter-rouge\">master</code> をたどって行き、対象のウィジェットが見つかるかで判断する方法もあるなぁ…<br />\nrootの <code class=\"language-plaintext highlighter-rouge\">master</code> は <code class=\"language-plaintext highlighter-rouge\">None</code> なのでそこでサーチ終了。<br />\nどっちが簡単かな…</p>\n\n<h3 id=\"ふと思ったこと-その2\">ふと思ったこと その2</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">bind</code>するときに、.winfo_children() を再帰的にサーチしてすべての子ウィジェットにbindしていく、という手もあるなぁ。<br />\nいっぱいウィジェット配置してるとえらいことになるかもしれんけど…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "renode": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Renodeお試し</title>\n  </head>\n  <body>\n    <header>\n      <h1>Renodeお試し</h1>\n      <p>シミュレータ Renode を試してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>おいそれと評価ボードを買えないボンビーの味方、シミュレータ(エミュレータ)。<br />\n<a href=\"https://www.qemu.org/\" target=\"_blank\">QEMU</a>が有名だけど、\n最近は<a href=\"https://renode.io/\" target=\"_blank\">Renode</a>というのもあるらしい。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://wokwi.com/\" target=\"_blank\">wokwi</a>というのもある。<br />\n見た目がきれいで惹かれるけど、VScodeで実行する環境のライセンスが\nよく分からんかった(30日は無料らしいけど、その後無料で更新できるのか、有料になるのか読み取れなかった)<br />\n至れり尽くせりなのはイヤだという天邪鬼気質もあるけど…</p>\n</blockquote>\n\n<p>ということで、Renodeをちらっと試してみた時のメモ。</p>\n\n<p>Renodeのドキュメントは<a href=\"https://renode.readthedocs.io/en/latest/\" target=\"_blank\">https://renode.readthedocs.io/en/latest/</a>にあります<br />\nソースやリリースバイナリは<a href=\"https://github.com/renode/renode\" target=\"_blank\">Github</a>にあります。</p>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"環境\">環境</h2>\n<p>今回はWindows11上のWSLのUbuntu 22.04で試してみます。</p>\n\n<h2 id=\"renodeのインストール\">Renodeのインストール</h2>\n<p>インストール用バイナリは<a href=\"https://github.com/renode/renode/releases\" target=\"_blank\">github</a>\nや<a href=\"https://builds.renode.io\" target=\"_blank\">https://builds.renode.io</a>にあります。</p>\n\n<p>プラットフォームはmono版と.NET版がありますが、ここではmono版を使います。<br />\ndebファイルがあるので、aptでもインストールできますが、ここではポータブル版を使います。</p>\n\n<p>以下のように実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /proj\nwget https://builds.renode.io/renode-latest.linux-portable.tar.gz\n<span class=\"nb\">mkdir </span>renode_portable\n<span class=\"nb\">tar </span>xvf  renode-latest.linux-portable.tar.gz <span class=\"nt\">-C</span> renode_portable <span class=\"nt\">--strip-components</span><span class=\"o\">=</span>1\n</code></pre></div></div>\n\n<p>これで <code class=\"language-plaintext highlighter-rouge\">/proj/renode_portable</code> に必要なファイルが展開されます。<br />\nここにPATHを通すため、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># renodeのインストール先をpathに追加</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span>/proj/renode_portable:<span class=\"nv\">$PATH</span>\n</code></pre></div></div>\n\n<h2 id=\"renodeの依存パッケージのインストール\">renodeの依存パッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mono-devel policykit-1 libgtk2.0-0 screen uml-utilities gtk-sharp2 libc6-dev libicu-dev gcc python3 python3-pip\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nmonoのリポジトリを追加してインストールする情報が散見されるが、ubuntu22.04のaptリポジトリにはmono-develも入っているらしい。<br />\nなので、普通に<code class=\"language-plaintext highlighter-rouge\">apt install</code>だけでインストールできる。<br />\nただし、最新版が欲しい場合は以下でインストールする。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ca-certificates gnupg\n<span class=\"nb\">sudo </span>gpg <span class=\"nt\">--homedir</span> /tmp <span class=\"nt\">--no-default-keyring</span> <span class=\"nt\">--keyring</span> /usr/share/keyrings/mono-official-archive-keyring.gpg <span class=\"nt\">--keyserver</span> hkp://keyserver.ubuntu.com:80 <span class=\"nt\">--recv-keys</span> 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF\n<span class=\"nb\">echo</span> <span class=\"s2\">\"deb [signed-by=/usr/share/keyrings/mono-official-archive-keyring.gpg] https://download.mono-project.com/repo/ubuntu stable-focal main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/mono-official-stable.list\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mono-devel\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"gccのインストール\">gccのインストール</h2>\n<p>Renodeの実行自体にコンパイラは不要ですが、実行するバイナリを作成するのに必要なので、gccをインストールします。</p>\n\n<p>ダウンロードサイト:<a href=\"https://developer.arm.com/downloads/-/gnu-rm\" target=\"_blank\">ARM Developer GNU Arm Embedded Toolchain Downloads</a></p>\n\n<p>以下の手順でインストールします(ファイル名/ディレクトリ名はダウンロードしたバージョンに合わせて変更)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /proj\nwget https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz\n<span class=\"nb\">tar </span>xvf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz \n\n<span class=\"c\"># 依存パッケージのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libncursesw5\n</code></pre></div></div>\n\n<p>PATHを通すため、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># arm-gccのインストール先をpathに追加</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span>/proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin:<span class=\"nv\">$PATH</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンパイラだけなら<code class=\"language-plaintext highlighter-rouge\">apt install gcc-arm-none-eabi</code>でインストールできますが、\ngdbが入ってないので上のサイトからダウンロードして使用します。</p>\n</blockquote>\n\n<h2 id=\"その他インストール\">その他インストール</h2>\n<p>ターゲットプログラムのbuild時にcmakeも使用するのでインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n</code></pre></div></div>\n\n<h1 id=\"デモの実行\">デモの実行</h1>\n<p>ドキュメントの<a href=\"https://renode.readthedocs.io/en/latest/introduction/demo.html\" target=\"_blank\">Running your first demo</a>\nにしたがって実行してみます。</p>\n\n<p>renodeを起動します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode\n</code></pre></div></div>\n\n<p>renodeウィンドウが開くのでそこで以下を入力</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>s @scripts/single-node/stm32f4_discovery.resc\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i @scripts/single-node/stm32f4_discovery.resc\ns\n</code></pre></div>  </div>\n  <p>と実行しても可。<br />\n<code class=\"language-plaintext highlighter-rouge\">i</code>は<code class=\"language-plaintext highlighter-rouge\">include</code>のalias<br />\n<code class=\"language-plaintext highlighter-rouge\">s</code>は<code class=\"language-plaintext highlighter-rouge\">start</code>のalias</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nrenode起動時に以下のようにパラメータとしてrescファイルを指定することもできます。<br />\nこれはincludeコマンドを実行するのと同義(というか起動時にincludeコマンドが実行されている)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode /proj/renode_portable/scripts/single-node/stm32f4_discovery.resc\n</code></pre></div>  </div>\n  <p>rescファイルのパスは絶対パス/カレントディレクトリからの相対パスで指定可能。<br />\n<code class=\"language-plaintext highlighter-rouge\">@</code>を使ったrenodeインストールディレクトリからの相対パスは指定不可。</p>\n</blockquote>\n\n<p>プログラムが実行されると uart4ウィンドウが開いてなにやら色々表示されます。</p>\n\n<p>renodeウィンドウで<code class=\"language-plaintext highlighter-rouge\">quit</code>と入力する(CTRL+Dでも可)と終了します。</p>\n\n<h2 id=\"おまけ\">おまけ</h2>\n<h3 id=\"その1\">その1</h3>\n<p>renodeウィンドウが見難かったら以下のように<code class=\"language-plaintext highlighter-rouge\">-P</code>オプションでポート番号を指定して実行し、</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode <span class=\"nt\">-P</span> 1234\n</code></pre></div></div>\n\n<p>他のターミナルから以下のように実行すると普段使っているターミナルから制御できます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>telnet localhost 1234\n</code></pre></div></div>\n\n<h3 id=\"その2\">その2</h3>\n<p>renode起動時に<code class=\"language-plaintext highlighter-rouge\">--console</code> オプションを指定すると、起動したターミナルがコンソールになります。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode <span class=\"nt\">--cnsole</span>\n</code></pre></div></div>\n<p>ログが同じターミナルに表示されるので見難くなったりするかもしれんけど</p>\n\n<h1 id=\"vscodeでデバッグ\">VScodeでデバッグ</h1>\n\n<p><a href=\"https://renode.readthedocs.io/en/latest/debugging/vscode.html\" target=\"_blank\">ドキュメント</a>\nの説明は分かり難いので、解説記事\n<a href=\"https://medium.com/@pc0is0me/getting-started-with-stm32f4-emulation-using-renode-f6cb158d27d1\" target=\"_blank\">Getting Started with STM32F4 Emulation using Renode</a>\nの手順を試してみます。</p>\n\n<h2 id=\"サンプルのリポジトリをclone\">サンプルのリポジトリをclone</h2>\n\n<p>まずはリポジトリをcloneします。<br />\n適当なディレクトリで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/PhanCuong91/data.git\n</code></pre></div></div>\n\n<h2 id=\"とりあえず動作確認\">とりあえず動作確認</h2>\n\n<p>VScodeでデバッグする前にターゲットプログラムのbuildが行えるか、\nbuildしたバイナリが実行できるか確認しておきます。<br />\nプログラムのbuildは以下のコマンドで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>data/renode\nbash build.bat\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nbatファイルなので、Windowsのバッチファイルですが、\n中身はLinuxでもそのまま実行できる内容なので、\nそのままシェルスクリプトとして実行します。</p>\n</blockquote>\n\n<p>こんな感じでbuildが実行されます。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Release build.\n-- The C compiler identification is GNU 13.3.1\n-- The CXX compiler identification is GNU 13.3.1\n-- The ASM compiler identification is GNU\n-- Found assembler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc\n-- Detecting C compiler ABI info\n-- Detecting C compiler ABI info - done\n-- Check for working C compiler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc - skipped\n-- Detecting C compile features\n-- Detecting C compile features - done\n-- Detecting CXX compiler ABI info\n-- Detecting CXX compiler ABI info - done\n-- Check for working CXX compiler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-g++ - skipped\n-- Detecting CXX compile features\n-- Detecting CXX compile features - done\n-- Configuring done\n-- Generating done\n-- Build files have been written to: /work/data/renode/build\n</code></pre></div></div>\n\n<p>正常にbuildできていれば<code class=\"language-plaintext highlighter-rouge\">build/src/STM32F4Template.elf</code>が出来ています。</p>\n\n<p>renodeを実行し、renodeターミナルで以下のように入力し、プログラムを実行します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mach create\nmachine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl\nsysbus LoadELF @/work/data/renode/build/src/STM32F4Template.elf \nshowAnalyzer sysbus.usart2\nstart\n</code></pre></div></div>\n\n<p>UART2ウィンドウに以下のように表示されればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Hello World!\n</code></pre></div></div>\n\n<p>確認したらrenodeを終了します。</p>\n\n<p>次の作業に備えて、buildディレクトリを削除(またはrename)しておきます。</p>\n\n<h2 id=\"vscodeでのデバッグ\">VScodeでのデバッグ</h2>\n\n<h3 id=\"rescファイルの修正\">rescファイルの修正</h3>\n<p>フルパスで記述されている部分を修正します。</p>\n\n<p>修正内容は以下。<br />\n<code class=\"language-plaintext highlighter-rouge\">$ORIGIN</code>を使用してrescファイルからの相対パス指定に変更。<br />\nこれにより、ダブルクォーテーションで囲む必要はなくなる。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/renode/renode-config.resc b/renode/renode-config.resc\nindex 2729cd1..fcb4f34 100644\n</span><span class=\"gd\">--- a/renode/renode-config.resc\n</span><span class=\"gi\">+++ b/renode/renode-config.resc\n</span><span class=\"p\">@@ -2,8 +2,8 @@</span>\n :description: This script runs the usart_printf example on stm32f4 discovery\n\n $name?=\"STM32F4_Discovery\"\n<span class=\"gd\">-$cmm_repl?=\"C:\\working\\data\\renode\\add-ccm.repl\"\n-$bin_path?=\"C:\\working\\data\\renode\\build\\src\\STM32F4Template.elf\"\n</span><span class=\"gi\">+$cmm_repl?=$ORIGIN/add-ccm.repl\n+$bin_path?=$ORIGIN/build/src/STM32F4Template.elf\n</span>\n # create Socket Terminal for UART\n emulation CreateServerSocketTerminal 3456 \"term\" false\n</code></pre></div></div>\n\n<h3 id=\"buildスクリプトに実行属性を付与\">buildスクリプトに実行属性を付与</h3>\n<p>元がwindows用なので、linuxで実行できるように実行属性を付与します。<br />\n中身はそのまま。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod</span> +x build-debug.bat\n</code></pre></div></div>\n\n<h3 id=\"vscodeを起動\">VScodeを起動</h3>\n<p>ホストOS側のVScodeを起動します。<br />\nWSLなので、ターミナルから以下のコマンドで起動してカレントディレクトリを開きます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>code <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"vscodeの拡張機能のインストール\">VScodeの拡張機能のインストール</h3>\n<p>VScodeの拡張機能で</p>\n<ul>\n  <li>C/C++ Extension Pack をインストールします</li>\n  <li>念のため、CMakeを無効化しておきます</li>\n</ul>\n\n<h3 id=\"実行\">実行</h3>\n\n<p>エクスプローラサイドパネルから<code class=\"language-plaintext highlighter-rouge\">src/main.c</code>を開き、<code class=\"language-plaintext highlighter-rouge\">main()</code> のどこかにブレークポイントを設定。<br />\nデバッグサイドパネルで 「Debug application in Renode」 を選んで実行。<br />\nRenoteターミナルとUART2ウィンドウが開き、設定したブレークポイントで停止するはず。<br />\n実行を再開すると、UART2ウィンドウに<code class=\"language-plaintext highlighter-rouge\">Hello World!</code>と表示され、無限ループに入る。</p>\n\n<h1 id=\"renode-interactive-visualization-example\">Renode interactive visualization example</h1>\n<p>組み込みプログラムなので、ターゲットボードの動作を目で見たくなるのが人情…<br />\nということで、Renode interactive visualization exampleを実行してみます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nWSLのネットワークモードは mirrored にしておきます\n(ほかのモードでも動くかもしれんけど、試してないので)</p>\n</blockquote>\n\n<p><a href=\"https://github.com/antmicro/renode-board-visualization\" target=\"_blank\">github</a>\nからソースを取得します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/antmicro/renode-board-visualization.git\n<span class=\"nb\">cd </span>renode-board-visualization/\n</code></pre></div></div>\n\n<p>Renodeを実行します。<br />\n(バイナリファイルがあるのでbuildは不要。というよりソースファイルはない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode scripts/blinky.resc\n</code></pre></div></div>\n\n<p>rescファイルに<code class=\"language-plaintext highlighter-rouge\">start</code>コマンドが書いてあるので、\n起動と同時にターゲットプログラムが実行されます。</p>\n\n<p>renodeを起動したターミナルにはGPIOアクセスのログが以下のように表示されます。<br />\n(ログが表示されるか否かはPeripheralのエミュレーションプログラムによるので、\nどのCPUても表示されるわけではありません)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>11:28:31.6894 [NOISY] gpio0: Setting pin 24 output to False\n11:28:32.6891 [NOISY] gpio0: Setting pin 24 output to True\n11:28:33.6891 [NOISY] gpio0: Setting pin 24 output to False\n11:28:34.6892 [NOISY] gpio0: Setting pin 24 output to True\n11:28:35.6892 [NOISY] gpio0: Setting pin 24 output to False\n</code></pre></div></div>\n\n<p>renodeコンソールで以下のコマンドを実行します。<br />\nこれによりWebサーバが起動します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>serveVisualization 8000\n</code></pre></div></div>\n\n<p>ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページが表示され、ボード左上のLED(赤色)が点滅しているのが確認できます。</p>\n\n<p>Webサーバを停止するため、renodeコンソールで以下のコマンドを実行します。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>stopVisualization\n</code></pre></div></div>\n\n<p>Renodeを終了します。</p>\n<blockquote>\n  <p>[!NOTE]\nWebサーバを停止せずにRenodeを終了しても構いません。<br />\n停止せずに終了すると終了時に python で たくさんEXCEPTIONが起こるので\n気持ち悪い人はWebサーバを停止してから終了しましょう。</p>\n</blockquote>\n\n<h1 id=\"自分の環境を作ってみた\">自分の環境を作ってみた</h1>\n\n<p>以上を踏まえて、一通り作ってみました。<br />\n(公式サンプルにはターゲットプログラムのソースがないので、\nソースからビルドする部分も含めて試してみたかった)</p>\n\n<p>作った環境はgithubに登録しておきました。<br />\n<a href=\"https://github.com/ippei8jp/renode_my_sample\" target=\"_blank\">https://github.com/ippei8jp/renode_my_sample</a></p>\n\n<h2 id=\"リポジトリのクローン\">リポジトリのクローン</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/ippei8jp/renode_my_sample.git\n<span class=\"nb\">cd </span>renode_my_sample\n</code></pre></div></div>\n<h3 id=\"ソース構成\">ソース構成</h3>\n<p>srcディレクトリ下がプログラムソースです。</p>\n\n<h4 id=\"mainc\">main.c</h4>\n<p>メインルーチンと割り込みハンドラなど。</p>\n\n<h4 id=\"syscallsc\">syscalls.c</h4>\n<p>printf/scanfなどを使用するためのsyscallルーチンを定義。<br />\nコンソール入出力のための最低限の処理だけを定義しています。</p>\n\n<h4 id=\"startup_stm32f40_41xxxs\">startup_stm32f40_41xxx.s</h4>\n<p>bootルーチン、ベクタテーブル、デフォルト割り込みハンドラなど。</p>\n\n<h4 id=\"system_stm32f4xxc\">system_stm32f4xx.c</h4>\n<p>初期化処理(C言語部)</p>\n\n<h4 id=\"cmakeliststxt\">CMakeLists.txt</h4>\n<p>cmake処理定義ファイル。<br />\nソースファイルを追加したときなどはここに追加していく。</p>\n\n<h3 id=\"ビルド実行\">ビルド&実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake ..\nmake\n<span class=\"nb\">cd</span> ..\nrenode script/renode-config.resc\n</code></pre></div></div>\n\n<h3 id=\"ブラウザで接続\">ブラウザで接続</h3>\n<p>GUI部品を表示するため、ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページにLEDとスイッチが表示されます。</p>\n\n<h3 id=\"ターゲットプログラム実行\">ターゲットプログラム実行</h3>\n<p>renodeターミナルで<code class=\"language-plaintext highlighter-rouge\">start</code>コマンドを実行するとターゲットプログラムが実行されます。</p>\n\n<h3 id=\"ブラウザの表示\">ブラウザの表示</h3>\n<p>ターゲットプログラムの動作に応じてLEDが順次点灯/消灯していきます。\nスイッチをクリックするとON/OFFがトグルします。<br />\nこのスイッチの情報はターゲットプログラムのメインループで表示されます。<br />\nまたON時は割り込みハンドラが起動され、UARTコンソールに割り込みメッセージが表示されます。</p>\n\n<h3 id=\"renode終了\">Renode終了</h3>\n<p>renodeターミナルで<code class=\"language-plaintext highlighter-rouge\">quit</code>コマンドを実行して Renodeを終了します。</p>\n\n<h2 id=\"vscodeでデバッグ-1\">VScodeでデバッグ</h2>\n\n<p>VScodeでデバッグする前にbuildディレクトリを削除しておいてください。</p>\n\n<h3 id=\"vscodeでcloneしたディレクトリを開く\">VScodeでcloneしたディレクトリを開く</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>code <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"ビルド\">ビルド</h3>\n<p>VSCodeで</p>\n<ul>\n  <li>cmakeサイドパネルを開く\n    <ul>\n      <li>「構成」右側のアイコンをクリックし、「GCC XX.X.X arm-noen-eabi」選択\n        <ul>\n          <li>cmakeが実行される</li>\n        </ul>\n      </li>\n      <li>「ビルド」右側のアイコンをクリックしbuid実行\n        <ul>\n          <li>makeが実行される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>実行とデバッグサイドパネルを開く\n    <ul>\n      <li>Debug application in Renode を選んで実行</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ブラウザで接続-1\">ブラウザで接続</h3>\n<p>GUI部品を表示するため、ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページにLEDとスイッチが表示されます。</p>\n\n<h3 id=\"ブラウザの表示-1\">ブラウザの表示</h3>\n<p>ターゲットプログラムの動作に応じてLEDが順次点灯/消灯していきます。\nスイッチをクリックするとON/OFFがトグルします。<br />\nこのスイッチの情報はターゲットプログラムのメインループで表示されます。<br />\nまたON時は割り込みハンドラが起動され、UARTコンソールに割り込みメッセージが表示されます。</p>\n\n<h3 id=\"デバッグ\">デバッグ</h3>\n<p>デバッグは他の環境と同じなので、ここでは何も書きません。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "STM32": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Renodeお試し</title>\n  </head>\n  <body>\n    <header>\n      <h1>Renodeお試し</h1>\n      <p>シミュレータ Renode を試してみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>おいそれと評価ボードを買えないボンビーの味方、シミュレータ(エミュレータ)。<br />\n<a href=\"https://www.qemu.org/\" target=\"_blank\">QEMU</a>が有名だけど、\n最近は<a href=\"https://renode.io/\" target=\"_blank\">Renode</a>というのもあるらしい。</p>\n<blockquote>\n  <p>[!NOTE]\n<a href=\"https://wokwi.com/\" target=\"_blank\">wokwi</a>というのもある。<br />\n見た目がきれいで惹かれるけど、VScodeで実行する環境のライセンスが\nよく分からんかった(30日は無料らしいけど、その後無料で更新できるのか、有料になるのか読み取れなかった)<br />\n至れり尽くせりなのはイヤだという天邪鬼気質もあるけど…</p>\n</blockquote>\n\n<p>ということで、Renodeをちらっと試してみた時のメモ。</p>\n\n<p>Renodeのドキュメントは<a href=\"https://renode.readthedocs.io/en/latest/\" target=\"_blank\">https://renode.readthedocs.io/en/latest/</a>にあります<br />\nソースやリリースバイナリは<a href=\"https://github.com/renode/renode\" target=\"_blank\">Github</a>にあります。</p>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"環境\">環境</h2>\n<p>今回はWindows11上のWSLのUbuntu 22.04で試してみます。</p>\n\n<h2 id=\"renodeのインストール\">Renodeのインストール</h2>\n<p>インストール用バイナリは<a href=\"https://github.com/renode/renode/releases\" target=\"_blank\">github</a>\nや<a href=\"https://builds.renode.io\" target=\"_blank\">https://builds.renode.io</a>にあります。</p>\n\n<p>プラットフォームはmono版と.NET版がありますが、ここではmono版を使います。<br />\ndebファイルがあるので、aptでもインストールできますが、ここではポータブル版を使います。</p>\n\n<p>以下のように実行します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /proj\nwget https://builds.renode.io/renode-latest.linux-portable.tar.gz\n<span class=\"nb\">mkdir </span>renode_portable\n<span class=\"nb\">tar </span>xvf  renode-latest.linux-portable.tar.gz <span class=\"nt\">-C</span> renode_portable <span class=\"nt\">--strip-components</span><span class=\"o\">=</span>1\n</code></pre></div></div>\n\n<p>これで <code class=\"language-plaintext highlighter-rouge\">/proj/renode_portable</code> に必要なファイルが展開されます。<br />\nここにPATHを通すため、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># renodeのインストール先をpathに追加</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span>/proj/renode_portable:<span class=\"nv\">$PATH</span>\n</code></pre></div></div>\n\n<h2 id=\"renodeの依存パッケージのインストール\">renodeの依存パッケージのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mono-devel policykit-1 libgtk2.0-0 screen uml-utilities gtk-sharp2 libc6-dev libicu-dev gcc python3 python3-pip\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nmonoのリポジトリを追加してインストールする情報が散見されるが、ubuntu22.04のaptリポジトリにはmono-develも入っているらしい。<br />\nなので、普通に<code class=\"language-plaintext highlighter-rouge\">apt install</code>だけでインストールできる。<br />\nただし、最新版が欲しい場合は以下でインストールする。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>ca-certificates gnupg\n<span class=\"nb\">sudo </span>gpg <span class=\"nt\">--homedir</span> /tmp <span class=\"nt\">--no-default-keyring</span> <span class=\"nt\">--keyring</span> /usr/share/keyrings/mono-official-archive-keyring.gpg <span class=\"nt\">--keyserver</span> hkp://keyserver.ubuntu.com:80 <span class=\"nt\">--recv-keys</span> 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF\n<span class=\"nb\">echo</span> <span class=\"s2\">\"deb [signed-by=/usr/share/keyrings/mono-official-archive-keyring.gpg] https://download.mono-project.com/repo/ubuntu stable-focal main\"</span> | <span class=\"nb\">sudo tee</span> /etc/apt/sources.list.d/mono-official-stable.list\n<span class=\"nb\">sudo </span>apt update\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>mono-devel\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"gccのインストール\">gccのインストール</h2>\n<p>Renodeの実行自体にコンパイラは不要ですが、実行するバイナリを作成するのに必要なので、gccをインストールします。</p>\n\n<p>ダウンロードサイト:<a href=\"https://developer.arm.com/downloads/-/gnu-rm\" target=\"_blank\">ARM Developer GNU Arm Embedded Toolchain Downloads</a></p>\n\n<p>以下の手順でインストールします(ファイル名/ディレクトリ名はダウンロードしたバージョンに合わせて変更)。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /proj\nwget https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz\n<span class=\"nb\">tar </span>xvf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz \n\n<span class=\"c\"># 依存パッケージのインストール</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libncursesw5\n</code></pre></div></div>\n\n<p>PATHを通すため、<code class=\"language-plaintext highlighter-rouge\">~/.bashrc</code>に以下を追加</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># arm-gccのインストール先をpathに追加</span>\n<span class=\"nb\">export </span><span class=\"nv\">PATH</span><span class=\"o\">=</span>/proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin:<span class=\"nv\">$PATH</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nコンパイラだけなら<code class=\"language-plaintext highlighter-rouge\">apt install gcc-arm-none-eabi</code>でインストールできますが、\ngdbが入ってないので上のサイトからダウンロードして使用します。</p>\n</blockquote>\n\n<h2 id=\"その他インストール\">その他インストール</h2>\n<p>ターゲットプログラムのbuild時にcmakeも使用するのでインストールしておきます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>cmake\n</code></pre></div></div>\n\n<h1 id=\"デモの実行\">デモの実行</h1>\n<p>ドキュメントの<a href=\"https://renode.readthedocs.io/en/latest/introduction/demo.html\" target=\"_blank\">Running your first demo</a>\nにしたがって実行してみます。</p>\n\n<p>renodeを起動します。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode\n</code></pre></div></div>\n\n<p>renodeウィンドウが開くのでそこで以下を入力</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>s @scripts/single-node/stm32f4_discovery.resc\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]</p>\n\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>i @scripts/single-node/stm32f4_discovery.resc\ns\n</code></pre></div>  </div>\n  <p>と実行しても可。<br />\n<code class=\"language-plaintext highlighter-rouge\">i</code>は<code class=\"language-plaintext highlighter-rouge\">include</code>のalias<br />\n<code class=\"language-plaintext highlighter-rouge\">s</code>は<code class=\"language-plaintext highlighter-rouge\">start</code>のalias</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nrenode起動時に以下のようにパラメータとしてrescファイルを指定することもできます。<br />\nこれはincludeコマンドを実行するのと同義(というか起動時にincludeコマンドが実行されている)。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode /proj/renode_portable/scripts/single-node/stm32f4_discovery.resc\n</code></pre></div>  </div>\n  <p>rescファイルのパスは絶対パス/カレントディレクトリからの相対パスで指定可能。<br />\n<code class=\"language-plaintext highlighter-rouge\">@</code>を使ったrenodeインストールディレクトリからの相対パスは指定不可。</p>\n</blockquote>\n\n<p>プログラムが実行されると uart4ウィンドウが開いてなにやら色々表示されます。</p>\n\n<p>renodeウィンドウで<code class=\"language-plaintext highlighter-rouge\">quit</code>と入力する(CTRL+Dでも可)と終了します。</p>\n\n<h2 id=\"おまけ\">おまけ</h2>\n<h3 id=\"その1\">その1</h3>\n<p>renodeウィンドウが見難かったら以下のように<code class=\"language-plaintext highlighter-rouge\">-P</code>オプションでポート番号を指定して実行し、</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode <span class=\"nt\">-P</span> 1234\n</code></pre></div></div>\n\n<p>他のターミナルから以下のように実行すると普段使っているターミナルから制御できます。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>telnet localhost 1234\n</code></pre></div></div>\n\n<h3 id=\"その2\">その2</h3>\n<p>renode起動時に<code class=\"language-plaintext highlighter-rouge\">--console</code> オプションを指定すると、起動したターミナルがコンソールになります。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode <span class=\"nt\">--cnsole</span>\n</code></pre></div></div>\n<p>ログが同じターミナルに表示されるので見難くなったりするかもしれんけど</p>\n\n<h1 id=\"vscodeでデバッグ\">VScodeでデバッグ</h1>\n\n<p><a href=\"https://renode.readthedocs.io/en/latest/debugging/vscode.html\" target=\"_blank\">ドキュメント</a>\nの説明は分かり難いので、解説記事\n<a href=\"https://medium.com/@pc0is0me/getting-started-with-stm32f4-emulation-using-renode-f6cb158d27d1\" target=\"_blank\">Getting Started with STM32F4 Emulation using Renode</a>\nの手順を試してみます。</p>\n\n<h2 id=\"サンプルのリポジトリをclone\">サンプルのリポジトリをclone</h2>\n\n<p>まずはリポジトリをcloneします。<br />\n適当なディレクトリで以下のコマンドを実行します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/PhanCuong91/data.git\n</code></pre></div></div>\n\n<h2 id=\"とりあえず動作確認\">とりあえず動作確認</h2>\n\n<p>VScodeでデバッグする前にターゲットプログラムのbuildが行えるか、\nbuildしたバイナリが実行できるか確認しておきます。<br />\nプログラムのbuildは以下のコマンドで行います。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd </span>data/renode\nbash build.bat\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nbatファイルなので、Windowsのバッチファイルですが、\n中身はLinuxでもそのまま実行できる内容なので、\nそのままシェルスクリプトとして実行します。</p>\n</blockquote>\n\n<p>こんな感じでbuildが実行されます。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Release build.\n-- The C compiler identification is GNU 13.3.1\n-- The CXX compiler identification is GNU 13.3.1\n-- The ASM compiler identification is GNU\n-- Found assembler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc\n-- Detecting C compiler ABI info\n-- Detecting C compiler ABI info - done\n-- Check for working C compiler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc - skipped\n-- Detecting C compile features\n-- Detecting C compile features - done\n-- Detecting CXX compiler ABI info\n-- Detecting CXX compiler ABI info - done\n-- Check for working CXX compiler: /proj/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-g++ - skipped\n-- Detecting CXX compile features\n-- Detecting CXX compile features - done\n-- Configuring done\n-- Generating done\n-- Build files have been written to: /work/data/renode/build\n</code></pre></div></div>\n\n<p>正常にbuildできていれば<code class=\"language-plaintext highlighter-rouge\">build/src/STM32F4Template.elf</code>が出来ています。</p>\n\n<p>renodeを実行し、renodeターミナルで以下のように入力し、プログラムを実行します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mach create\nmachine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl\nsysbus LoadELF @/work/data/renode/build/src/STM32F4Template.elf \nshowAnalyzer sysbus.usart2\nstart\n</code></pre></div></div>\n\n<p>UART2ウィンドウに以下のように表示されればOK。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Hello World!\n</code></pre></div></div>\n\n<p>確認したらrenodeを終了します。</p>\n\n<p>次の作業に備えて、buildディレクトリを削除(またはrename)しておきます。</p>\n\n<h2 id=\"vscodeでのデバッグ\">VScodeでのデバッグ</h2>\n\n<h3 id=\"rescファイルの修正\">rescファイルの修正</h3>\n<p>フルパスで記述されている部分を修正します。</p>\n\n<p>修正内容は以下。<br />\n<code class=\"language-plaintext highlighter-rouge\">$ORIGIN</code>を使用してrescファイルからの相対パス指定に変更。<br />\nこれにより、ダブルクォーテーションで囲む必要はなくなる。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff --git a/renode/renode-config.resc b/renode/renode-config.resc\nindex 2729cd1..fcb4f34 100644\n</span><span class=\"gd\">--- a/renode/renode-config.resc\n</span><span class=\"gi\">+++ b/renode/renode-config.resc\n</span><span class=\"p\">@@ -2,8 +2,8 @@</span>\n :description: This script runs the usart_printf example on stm32f4 discovery\n\n $name?=\"STM32F4_Discovery\"\n<span class=\"gd\">-$cmm_repl?=\"C:\\working\\data\\renode\\add-ccm.repl\"\n-$bin_path?=\"C:\\working\\data\\renode\\build\\src\\STM32F4Template.elf\"\n</span><span class=\"gi\">+$cmm_repl?=$ORIGIN/add-ccm.repl\n+$bin_path?=$ORIGIN/build/src/STM32F4Template.elf\n</span>\n # create Socket Terminal for UART\n emulation CreateServerSocketTerminal 3456 \"term\" false\n</code></pre></div></div>\n\n<h3 id=\"buildスクリプトに実行属性を付与\">buildスクリプトに実行属性を付与</h3>\n<p>元がwindows用なので、linuxで実行できるように実行属性を付与します。<br />\n中身はそのまま。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">chmod</span> +x build-debug.bat\n</code></pre></div></div>\n\n<h3 id=\"vscodeを起動\">VScodeを起動</h3>\n<p>ホストOS側のVScodeを起動します。<br />\nWSLなので、ターミナルから以下のコマンドで起動してカレントディレクトリを開きます。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>code <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"vscodeの拡張機能のインストール\">VScodeの拡張機能のインストール</h3>\n<p>VScodeの拡張機能で</p>\n<ul>\n  <li>C/C++ Extension Pack をインストールします</li>\n  <li>念のため、CMakeを無効化しておきます</li>\n</ul>\n\n<h3 id=\"実行\">実行</h3>\n\n<p>エクスプローラサイドパネルから<code class=\"language-plaintext highlighter-rouge\">src/main.c</code>を開き、<code class=\"language-plaintext highlighter-rouge\">main()</code> のどこかにブレークポイントを設定。<br />\nデバッグサイドパネルで 「Debug application in Renode」 を選んで実行。<br />\nRenoteターミナルとUART2ウィンドウが開き、設定したブレークポイントで停止するはず。<br />\n実行を再開すると、UART2ウィンドウに<code class=\"language-plaintext highlighter-rouge\">Hello World!</code>と表示され、無限ループに入る。</p>\n\n<h1 id=\"renode-interactive-visualization-example\">Renode interactive visualization example</h1>\n<p>組み込みプログラムなので、ターゲットボードの動作を目で見たくなるのが人情…<br />\nということで、Renode interactive visualization exampleを実行してみます。</p>\n\n<blockquote>\n  <p>[!NOTE]\nWSLのネットワークモードは mirrored にしておきます\n(ほかのモードでも動くかもしれんけど、試してないので)</p>\n</blockquote>\n\n<p><a href=\"https://github.com/antmicro/renode-board-visualization\" target=\"_blank\">github</a>\nからソースを取得します。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/antmicro/renode-board-visualization.git\n<span class=\"nb\">cd </span>renode-board-visualization/\n</code></pre></div></div>\n\n<p>Renodeを実行します。<br />\n(バイナリファイルがあるのでbuildは不要。というよりソースファイルはない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>renode scripts/blinky.resc\n</code></pre></div></div>\n\n<p>rescファイルに<code class=\"language-plaintext highlighter-rouge\">start</code>コマンドが書いてあるので、\n起動と同時にターゲットプログラムが実行されます。</p>\n\n<p>renodeを起動したターミナルにはGPIOアクセスのログが以下のように表示されます。<br />\n(ログが表示されるか否かはPeripheralのエミュレーションプログラムによるので、\nどのCPUても表示されるわけではありません)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>11:28:31.6894 [NOISY] gpio0: Setting pin 24 output to False\n11:28:32.6891 [NOISY] gpio0: Setting pin 24 output to True\n11:28:33.6891 [NOISY] gpio0: Setting pin 24 output to False\n11:28:34.6892 [NOISY] gpio0: Setting pin 24 output to True\n11:28:35.6892 [NOISY] gpio0: Setting pin 24 output to False\n</code></pre></div></div>\n\n<p>renodeコンソールで以下のコマンドを実行します。<br />\nこれによりWebサーバが起動します。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>serveVisualization 8000\n</code></pre></div></div>\n\n<p>ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページが表示され、ボード左上のLED(赤色)が点滅しているのが確認できます。</p>\n\n<p>Webサーバを停止するため、renodeコンソールで以下のコマンドを実行します。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>stopVisualization\n</code></pre></div></div>\n\n<p>Renodeを終了します。</p>\n<blockquote>\n  <p>[!NOTE]\nWebサーバを停止せずにRenodeを終了しても構いません。<br />\n停止せずに終了すると終了時に python で たくさんEXCEPTIONが起こるので\n気持ち悪い人はWebサーバを停止してから終了しましょう。</p>\n</blockquote>\n\n<h1 id=\"自分の環境を作ってみた\">自分の環境を作ってみた</h1>\n\n<p>以上を踏まえて、一通り作ってみました。<br />\n(公式サンプルにはターゲットプログラムのソースがないので、\nソースからビルドする部分も含めて試してみたかった)</p>\n\n<p>作った環境はgithubに登録しておきました。<br />\n<a href=\"https://github.com/ippei8jp/renode_my_sample\" target=\"_blank\">https://github.com/ippei8jp/renode_my_sample</a></p>\n\n<h2 id=\"リポジトリのクローン\">リポジトリのクローン</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>git clone https://github.com/ippei8jp/renode_my_sample.git\n<span class=\"nb\">cd </span>renode_my_sample\n</code></pre></div></div>\n<h3 id=\"ソース構成\">ソース構成</h3>\n<p>srcディレクトリ下がプログラムソースです。</p>\n\n<h4 id=\"mainc\">main.c</h4>\n<p>メインルーチンと割り込みハンドラなど。</p>\n\n<h4 id=\"syscallsc\">syscalls.c</h4>\n<p>printf/scanfなどを使用するためのsyscallルーチンを定義。<br />\nコンソール入出力のための最低限の処理だけを定義しています。</p>\n\n<h4 id=\"startup_stm32f40_41xxxs\">startup_stm32f40_41xxx.s</h4>\n<p>bootルーチン、ベクタテーブル、デフォルト割り込みハンドラなど。</p>\n\n<h4 id=\"system_stm32f4xxc\">system_stm32f4xx.c</h4>\n<p>初期化処理(C言語部)</p>\n\n<h4 id=\"cmakeliststxt\">CMakeLists.txt</h4>\n<p>cmake処理定義ファイル。<br />\nソースファイルを追加したときなどはここに追加していく。</p>\n\n<h3 id=\"ビルド実行\">ビルド&実行</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir </span>build <span class=\"o\">&&</span> <span class=\"nb\">cd </span>build\ncmake ..\nmake\n<span class=\"nb\">cd</span> ..\nrenode script/renode-config.resc\n</code></pre></div></div>\n\n<h3 id=\"ブラウザで接続\">ブラウザで接続</h3>\n<p>GUI部品を表示するため、ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページにLEDとスイッチが表示されます。</p>\n\n<h3 id=\"ターゲットプログラム実行\">ターゲットプログラム実行</h3>\n<p>renodeターミナルで<code class=\"language-plaintext highlighter-rouge\">start</code>コマンドを実行するとターゲットプログラムが実行されます。</p>\n\n<h3 id=\"ブラウザの表示\">ブラウザの表示</h3>\n<p>ターゲットプログラムの動作に応じてLEDが順次点灯/消灯していきます。\nスイッチをクリックするとON/OFFがトグルします。<br />\nこのスイッチの情報はターゲットプログラムのメインループで表示されます。<br />\nまたON時は割り込みハンドラが起動され、UARTコンソールに割り込みメッセージが表示されます。</p>\n\n<h3 id=\"renode終了\">Renode終了</h3>\n<p>renodeターミナルで<code class=\"language-plaintext highlighter-rouge\">quit</code>コマンドを実行して Renodeを終了します。</p>\n\n<h2 id=\"vscodeでデバッグ-1\">VScodeでデバッグ</h2>\n\n<p>VScodeでデバッグする前にbuildディレクトリを削除しておいてください。</p>\n\n<h3 id=\"vscodeでcloneしたディレクトリを開く\">VScodeでcloneしたディレクトリを開く</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>code <span class=\"nb\">.</span>\n</code></pre></div></div>\n\n<h3 id=\"ビルド\">ビルド</h3>\n<p>VSCodeで</p>\n<ul>\n  <li>cmakeサイドパネルを開く\n    <ul>\n      <li>「構成」右側のアイコンをクリックし、「GCC XX.X.X arm-noen-eabi」選択\n        <ul>\n          <li>cmakeが実行される</li>\n        </ul>\n      </li>\n      <li>「ビルド」右側のアイコンをクリックしbuid実行\n        <ul>\n          <li>makeが実行される</li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n  <li>実行とデバッグサイドパネルを開く\n    <ul>\n      <li>Debug application in Renode を選んで実行</li>\n    </ul>\n  </li>\n</ul>\n\n<h3 id=\"ブラウザで接続-1\">ブラウザで接続</h3>\n<p>GUI部品を表示するため、ブラウザで 起動したWebサーバ(localhost:8000) にアクセスします。<br />\nページにLEDとスイッチが表示されます。</p>\n\n<h3 id=\"ブラウザの表示-1\">ブラウザの表示</h3>\n<p>ターゲットプログラムの動作に応じてLEDが順次点灯/消灯していきます。\nスイッチをクリックするとON/OFFがトグルします。<br />\nこのスイッチの情報はターゲットプログラムのメインループで表示されます。<br />\nまたON時は割り込みハンドラが起動され、UARTコンソールに割り込みメッセージが表示されます。</p>\n\n<h3 id=\"デバッグ\">デバッグ</h3>\n<p>デバッグは他の環境と同じなので、ここでは何も書きません。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "TkEasyGUI": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>TkEasyGUIを使ってみる</title>\n  </head>\n  <body>\n    <header>\n      <h1>TkEasyGUIを使ってみる</h1>\n      <p>pythonでGUIを簡単に作れる TkEasyGUI を使ってみる</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonでGUIを作るにはtkinterを使うが、とっても分かり難い。<br />\nそこで、簡単にGUIが作れるとウワサの TkEasyGUI を使ってみた。<br />\n参考:</p>\n<ul>\n  <li><a href=\"https://pypi.org/project/TkEasyGUI/0.1.4/\" target=\"_blank\">PyPI</a></li>\n  <li><a href=\"https://github.com/kujirahand/tkeasygui-python\" target=\"_blank\">GitHub</a></li>\n  <li><a href=\"https://note.com/sirodon_256/n/na73d3fdac68d?fbclid=IwY2xjawHpgzhleHRuA2FlbQIxMQABHWBZ650bkpcT7-r0B3xAXpeUoIWsjSZJjZ4lqPUtBrxxQp3mlsCzFtM7tA_aem_lSSEVGhwq5SisJRckTFZcw\" target=\"_blank\">TkEasyGUIライブラリの基本とサンプルコード解説</a></li>\n</ul>\n\n<h1 id=\"使ってみる\">使ってみる</h1>\n<p>使ってみようと思ってはみたものの 何を作れば良いか思いつかなかったので、\n以前にtkinterで作ったプログラムを TkEasyGUI を使って書き直して見ることにした。</p>\n\n<p>元にしたのは、\n<a href=\"https://gist.github.com/ippei8jp/b8af596718e357dce185b5279b3533b8\" target=\"_blank\">ketsuatsu_GUI.py</a><br />\nこれの <code class=\"language-plaintext highlighter-rouge\">ketsuatsu_GUI.py</code>だけを書き換えてみる。<br />\n(<code class=\"language-plaintext highlighter-rouge\">ketsuatsu_csv2xls.py</code>はそのまま使用)</p>\n\n<h1 id=\"作ってみた\">作ってみた</h1>\n<p>ということで、書き直してみた。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>TkEasyGUI のインストールは以下を実行するだけ。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>TkEasyGUI\n</code></pre></div></div>\n<p>TkEasyGUI と pyperclip がインストールされる。</p>\n\n<p>全体を実行するには、上の元ソースのREADMEを参照。</p>\n\n<h2 id=\"ソース\">ソース</h2>\n<p>ということで、作ってみたソースがこちら。<br />\n元のソースと比べても行数で半分以下になった。<br />\nまた、イベントによる実行がイベントハンドラで登録するのから\nイベントループでイベントを監視するように変更されたので、プログラムの見通しがよくなった。</p>\n\n<p>これを</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  ketsuatsu_easyGUI.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"n\">dont_write_bytecode</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>      <span class=\"c1\"># pycacheを作成しない\n</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">TkEasyGUI</span> <span class=\"k\">as</span> <span class=\"n\">eg</span>\n\n<span class=\"c1\"># CSV→エクセル変換処理\n</span><span class=\"kn\">from</span> <span class=\"nn\">ketsuatsu_csv2xls</span> <span class=\"kn\">import</span> <span class=\"n\">ketsuatsu_csv2xls</span>\n\n<span class=\"c1\"># フォント\n# FONT_NAME1 = \"MS ゴシック\"\n</span><span class=\"n\">FONT_NAME1</span> <span class=\"o\">=</span> <span class=\"s\">\"BIZ UDゴシック\"</span>\n<span class=\"n\">FONT_NAME2</span> <span class=\"o\">=</span> <span class=\"s\">\"Noto Sans CJK JP\"</span>\n\n<span class=\"n\">FONT_SIZE</span> <span class=\"o\">=</span> <span class=\"mi\">12</span>\n\n\n<span class=\"c1\"># レイアウト\n</span><span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Text</span><span class=\"p\">(</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"CSV file  \"</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Input</span><span class=\"p\">(</span>       <span class=\"s\">\"\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"s\">\"-csvfilepath-\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span> \n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">FileBrowse</span><span class=\"p\">(</span>  <span class=\"n\">button_text</span> <span class=\"o\">=</span> <span class=\"s\">\"Browse...\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"CSV file\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">file_types</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"s\">'CSV file'</span><span class=\"p\">,</span> <span class=\"s\">'*.csv'</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"s\">'all'</span><span class=\"p\">,</span> <span class=\"s\">'*.*'</span><span class=\"p\">)),</span>\n                     <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Text</span><span class=\"p\">(</span>        <span class=\"s\">\"Excel file\"</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Input</span><span class=\"p\">(</span>       <span class=\"s\">\"\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"s\">\"-excelfilepath-\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n                <span class=\"p\">),</span> \n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">FileBrowse</span><span class=\"p\">(</span>  <span class=\"n\">button_text</span> <span class=\"o\">=</span> <span class=\"s\">\"Browse...\"</span><span class=\"p\">,</span> \n                        <span class=\"n\">title</span> <span class=\"o\">=</span> <span class=\"s\">\"Excel file\"</span><span class=\"p\">,</span>\n                        <span class=\"n\">file_types</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"s\">'Excel file'</span><span class=\"p\">,</span> <span class=\"s\">'*.xlsx'</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"s\">'all'</span><span class=\"p\">,</span> <span class=\"s\">'*.*'</span><span class=\"p\">)),</span>\n                        <span class=\"n\">save_as</span> <span class=\"o\">=</span> <span class=\"bp\">True</span><span class=\"p\">,</span>\n                     <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Column</span><span class=\"p\">(</span>\n            <span class=\"n\">layout</span><span class=\"o\">=</span><span class=\"p\">[</span>\n                      <span class=\"p\">[</span>\n                        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Button</span><span class=\"p\">(</span>  <span class=\"s\">\"Convert\"</span><span class=\"p\">,</span>\n                                    <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">),</span>\n                                 <span class=\"p\">),</span> \n                        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Button</span><span class=\"p\">(</span>  <span class=\"s\">\"Exit\"</span><span class=\"p\">,</span>\n                                    <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">),</span>\n                                 <span class=\"p\">),</span>\n                      <span class=\"p\">]</span>\n                    <span class=\"p\">],</span>\n            <span class=\"n\">expand_x</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n            <span class=\"n\">expand_y</span><span class=\"o\">=</span><span class=\"bp\">True</span><span class=\"p\">,</span>\n            <span class=\"n\">text_align</span><span class=\"o\">=</span><span class=\"s\">\"right\"</span><span class=\"p\">,</span>\n            <span class=\"n\">vertical_alignment</span><span class=\"o\">=</span><span class=\"s\">\"bottom\"</span><span class=\"p\">,</span>\n        <span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n<span class=\"p\">]</span>\n\n\n<span class=\"c1\"># CSVファイルからexcelファイルへの変換処理をコールする\n</span><span class=\"k\">def</span> <span class=\"nf\">convert_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">):</span>\n    <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n\n    <span class=\"c1\"># パラメータエラーチェック\n</span>    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ファイルが指定されていない\n</span>        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"入力ファイルを指定してください\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># filedialog.askopenfilename()は存在するファイルしか選択できないが\n</span>    <span class=\"c1\"># エディットボックスを直接編集した場合のためにチェック\n</span>    <span class=\"k\">elif</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"入力ファイルを指定してください\"</span><span class=\"p\">,</span>  <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">output_filename</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># ファイルが指定されていない\n</span>        <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"出力ファイルを指定してください\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># この判定はfiledialog.asksaveasfilename()内で行うが\n</span>    <span class=\"c1\"># エディットボックスを直接編集した場合のためにチェック\n</span>    <span class=\"k\">elif</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">output_filename</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"n\">ret</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup_ok_cancel</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"出力ファイルが存在します</span><span class=\"se\">\\n</span><span class=\"s\">上書きしますか?\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"確認\"</span><span class=\"p\">)</span>\n        <span class=\"n\">execute_flag</span> <span class=\"o\">=</span> <span class=\"bp\">True</span> <span class=\"k\">if</span> <span class=\"n\">ret</span> <span class=\"o\">==</span> <span class=\"s\">'OK'</span> <span class=\"k\">else</span> <span class=\"bp\">False</span>\n    <span class=\"k\">if</span> <span class=\"n\">execute_flag</span> <span class=\"p\">:</span>\n        <span class=\"c1\"># 変換処理\n</span>        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"c1\"># CSVファイルからエクセルファイルを作成\n</span>            <span class=\"n\">ketsuatsu_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">)</span>\n            <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"変換終了\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"終了\"</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"nb\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">popup</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s\">\"</span><span class=\"si\">{</span><span class=\"n\">e</span><span class=\"si\">}</span><span class=\"s\">\"</span><span class=\"p\">,</span> <span class=\"n\">title</span><span class=\"o\">=</span><span class=\"s\">\"エラー\"</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">()</span> <span class=\"p\">:</span>\n\n    <span class=\"c1\"># 使用するフォントの設定\n</span>    <span class=\"n\">fonts</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">get_font_list</span><span class=\"p\">()</span>\n    <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n    <span class=\"n\">target_font_size</span> <span class=\"o\">=</span> <span class=\"n\">FONT_SIZE</span>\n\n    <span class=\"k\">if</span> <span class=\"n\">FONT_NAME1</span> <span class=\"ow\">in</span> <span class=\"n\">fonts</span> <span class=\"p\">:</span>\n        <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"n\">FONT_NAME1</span>\n    <span class=\"k\">elif</span> <span class=\"n\">FONT_NAME2</span> <span class=\"ow\">in</span> <span class=\"n\">fonts</span> <span class=\"p\">:</span>\n        <span class=\"n\">target_font_name</span> <span class=\"o\">=</span> <span class=\"n\">FONT_NAME2</span>\n\n\n    <span class=\"c1\"># window create\n</span>    <span class=\"n\">window</span> <span class=\"o\">=</span> <span class=\"n\">eg</span><span class=\"p\">.</span><span class=\"n\">Window</span><span class=\"p\">(</span><span class=\"s\">'血圧 CSV->excel'</span><span class=\"p\">,</span> \n                        <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"mi\">600</span><span class=\"p\">,</span> <span class=\"mi\">150</span><span class=\"p\">),</span>\n                        <span class=\"n\">font</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">target_font_name</span><span class=\"p\">,</span> <span class=\"n\">target_font_size</span><span class=\"p\">),</span>\n                        <span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"n\">layout</span>\n                    <span class=\"p\">)</span>\n\n    <span class=\"c1\"># event loop\n</span>    <span class=\"k\">while</span> <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">is_alive</span><span class=\"p\">():</span>\n        <span class=\"n\">event</span><span class=\"p\">,</span> <span class=\"n\">values</span> <span class=\"o\">=</span> <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"#\"</span><span class=\"p\">,</span> <span class=\"n\">event</span><span class=\"p\">,</span> <span class=\"n\">values</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">event</span> <span class=\"o\">==</span> <span class=\"s\">\"Exit\"</span> <span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n        <span class=\"k\">if</span> <span class=\"n\">event</span> <span class=\"o\">==</span> <span class=\"s\">\"Convert\"</span> <span class=\"p\">:</span>\n            <span class=\"c1\"># print(values)\n</span>            <span class=\"n\">input_filename</span>  <span class=\"o\">=</span> <span class=\"n\">values</span><span class=\"p\">[</span><span class=\"s\">'-csvfilepath-'</span><span class=\"p\">]</span>\n            <span class=\"n\">output_filename</span> <span class=\"o\">=</span> <span class=\"n\">values</span><span class=\"p\">[</span><span class=\"s\">'-excelfilepath-'</span><span class=\"p\">]</span>\n            <span class=\"n\">convert_csv2xls</span><span class=\"p\">(</span><span class=\"n\">input_filename</span><span class=\"p\">,</span> <span class=\"n\">output_filename</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># 終了\n</span>    <span class=\"n\">window</span><span class=\"p\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n\n\n<span class=\"c1\"># ======================================================\n</span><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">main</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h1 id=\"未対応項目\">未対応項目</h1>\n<h2 id=\"ドラッグアンドドロップ\">ドラッグアンドドロップ</h2>\n<p>TkEasyGUI は ドラッグアンドドロップに対応していないので、作成したプログラムも未対応。<br />\nissueはあがっていて、作者さんも「It seems we could easily support」と言っているので、近いうちにサポートされるかも。</p>\n<ul>\n  <li><a href=\"https://github.com/kujirahand/tkeasygui-python/issues/7\" target=\"_blank\">Drag & Drop files #7</a></li>\n</ul>\n\n<h2 id=\"テーマの使用\">テーマの使用</h2>\n<p>TkEasyGUI は ttkの使用に対応しているが、使い方によってはうまく動かない。<br />\n(今回は <code class=\"language-plaintext highlighter-rouge\">eg.Column</code> の中の <code class=\"language-plaintext highlighter-rouge\">eg.Button</code> で  <code class=\"language-plaintext highlighter-rouge\">use_ttk_buttons=True</code>を指定したらエラーになった。<br />\nなにか条件があるのかもしれんが。)<br />\nとりあえず「お手軽にGUI」が目的なので、テーマで見た目に凝らなくてもいいか、と対応はあきらめた。</p>\n\n<h1 id=\"まとめ\">まとめ</h1>\n<p>さらっと触っただけだけど、tkinterをそのまま使うよりかなり分かりやすい。<br />\nが、ちょっと凝ったことをやろうとすると、できなかったりすることも。<br />\nその辺は必須かどうか見極めて、あきらめるか、tkinterで泥沼にハマってでも実現するかを決めるしかないか。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "openpyxl": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>openpyxlのバグ</title>\n  </head>\n  <body>\n    <header>\n      <h1>openpyxlのバグ</h1>\n      <p>openpyxl(3.1.5)のバグ(ではないけど、あえてそう書いておく)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"内容\">内容</h1>\n<p>openpyxl(3.1.2)でExcelのグラフを作成するスクリプトを使っていたが、\nopenpyxlを現時点での最新版(3.1.5)にアップデートしたところ、表示されるグラフの見た目が変わってしまった。</p>\n\n<h1 id=\"原因\">原因</h1>\n<p>検索してみたところ、teratailに\n『<a href=\"https://teratail.com/questions/5q9cujzlc2307x\" target=\"_blank\">python openpyxl グラフ作成 グラフ書式が変わったのを治せない</a>』\nというエントリを見つけた。</p>\n\n<p>どうやら、Excelの仕様に厳密に従ったらExcelのバグに引っかかった ということらしい。<br />\n(バグが他のバグ回避になってた、みたいな感じ)</p>\n\n<h1 id=\"対策\">対策</h1>\n<p>Excelのバグの修正を待っててもしかたないので、なんとか出来る方法を探してみた。<br />\nこの部分は openpyxl の 3.1.4 で仕様変更されたようなので、3.1.3以前を使うというのも手なのだけど、<br />\n最新版を使いたい場合はExcelのバグに引っかかってる部分だけ元にもどしてやれば良い。</p>\n\n<p>ということで、上のページにあった変更点を出力している部分を探して修正してみた。</p>\n\n<p>結論から言うと、以下のパッチをインストールしたライブラリにあててやれば良い。</p>\n<div class=\"language-patch highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gh\">diff -urpN openpyxl.org/packaging/extended.py openpyxl/packaging/extended.py\n</span><span class=\"gd\">--- openpyxl.org/packaging/extended.py  2025-01-07 07:23:30.159676700 +0900\n</span><span class=\"gi\">+++ openpyxl/packaging/extended.py      2025-01-07 07:41:28.823592900 +0900\n</span><span class=\"p\">@@ -126,7 +126,8 @@</span> class ExtendedProperties(Serialisable):\n         self.HLinks = None\n         self.HyperlinksChanged = HyperlinksChanged\n         self.DigSig = None\n<span class=\"gd\">-        self.Application = f\"Microsoft Excel Compatible / Openpyxl {__version__}\"\n</span><span class=\"gi\">+        # self.Application = f\"Microsoft Excel Compatible / Openpyxl {__version__}\"\n+        self.Application = f\"Microsoft Excel\"\n</span>         self.AppVersion = \".\".join(__version__.split(\".\")[:-1])\n         self.DocSecurity = DocSecurity\n</code></pre></div></div>\n\n<p>で、試してみたところ うまくグラフが表示されるようになった。<br />\nメデタシメデタシ。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "MSYS2": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MSYS2とgccのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>MSYS2とgccのインストール</h1>\n      <p>WindowsにMSYS2とgccをインストールした時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows環境でLinuxライクな環境を使用できる<a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2</a><br />\ngcc は単体で配布されている <a href=\"https://github.com/niXman/mingw-builds-binaries/releases\" target=\"_blank\">MinGW-W64-binaries</a>を使っていたが、\nMSYS2で管理されているものに切り替えてみた。</p>\n\n<h1 id=\"msys2のインストール\">MSYS2のインストール</h1>\n<p>大体以下の感じでインストールできる。</p>\n<ul>\n  <li><a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2のページ</a> を開く</li>\n  <li>Installation セクションの Download the installer: に書かれているリンクからダウンロード(バージョンアップで更新されるのでここにはリンクを貼らないでおく)</li>\n  <li>ダウンロードしたファイルを実行</li>\n  <li>デフォルトのままNextをクリックして行き、Installをクリック</li>\n  <li>終わったらFinishをクリック</li>\n</ul>\n\n<h1 id=\"msys2の設定\">MSYS2の設定</h1>\n<p>後でWindowsTerminalから使えるようにするからやらなくても良いけど、ま、気持ちの問題なので。</p>\n<ul>\n  <li>msys2を起動(スタート→すべて→MSYS2→MSYS2 UCRT64)し、タイトルバーを右クリックし 「Options…」 を選択\n    <ul>\n      <li>Text の Font の Select.. をクリックしてフォントとサイズを変更</li>\n      <li>Text の Local で ja_JP と UTF8 を選択</li>\n      <li>Window の Default size で ウィンドウサイズが変更できる</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"最新版にアップデート\">最新版にアップデート</h1>\n<p>MSYS2を起動して以下を実行(ubuntuの<code class=\"language-plaintext highlighter-rouge\">apt update && apt upgrade</code>に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -Syuu\n</code></pre></div></div>\n\n<p>何か聞かれたらYを入力<br />\nウィンドウが閉じられたら再度MSYS2を起動<br />\n再度MSYS2を起動したらもう一回 <code class=\"language-plaintext highlighter-rouge\">pacman -Syuu</code> を実行</p>\n\n<h1 id=\"開発ツールのインストール\">開発ツールのインストール</h1>\n<p>MSYS2を起動して以下を実行<br />\n(make、gcc、gdbなどのインストール)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -S base-devel\npacman -S mingw-w64-ucrt-x86_64-gcc\npacman -S mingw-w64-ucrt-x86_64-gdb\n</code></pre></div></div>\n\n<h1 id=\"pathの変更\">PATHの変更</h1>\n<p>MSYS2のbashで実行する際はpathは設定済みだが、\nコマンドプロンプト等で実行するためにWindows側のPATHを変更する。</p>\n\n<ul>\n  <li>設定 → システム → バージョン情報</li>\n  <li>関連リンクの「システムの詳細設定」をクリック</li>\n  <li>開いたウィンドウの下のほうにある「環境変数(N)…」をクリック</li>\n  <li>上側のユーザ環境変数で「Path」を選択して「編集」をクリック</li>\n  <li>「新規」をクリックして以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>c:\\msys64\\ucrt64\\bin\nC:\\msys64\\usr\\bin\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\nc:\\msys64\\ucrt64\\bin にはpythonが入っているので、Windowsでインストールしたpythonを使用したい場合は\nそのPATHより後(下)に設定すること</p>\n    </blockquote>\n  </li>\n</ul>\n\n<p>念のためここでPCを再起動する。<br />\n(PATHの変更が有効にならない場合がある)</p>\n\n<h1 id=\"windowsterminal-にmsys2を登録\">WindowsTerminal にMSYS2を登録</h1>\n<p>MSY2のデフォルトのターミナルはminttyだが、いつも使っているWindowsTerminalで使えるようにする。</p>\n<ul>\n  <li>WindowsTerminalを起動</li>\n  <li>「新しいプロファイルを追加」を選択</li>\n  <li>「新しい空のプロファイル」をクリック\n    <ul>\n      <li>コマンドラインに以下を設定(ucrt64の場合。それ以外は最後のオプションを変更する)\n        <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>C:/msys64/msys2_shell.cmd -defterm -here -no-start -ucrt64\"  \n</code></pre></div>        </div>\n      </li>\n      <li>開始ディレクトリに MSYS2のhomeディレクトリ(<code class=\"language-plaintext highlighter-rouge\">cygpath.exe -w ~</code> で取得可能) を指定</li>\n      <li>アイコンは何でもいいけど、<code class=\"language-plaintext highlighter-rouge\">C:\\\\msys64\\\\ucrt64.ico</code>とかが良いかな</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"vs-codeのターミナルでmsys2のbashを使用する方法\">VS CodeのターミナルでMSYS2のBashを使用する方法</h1>\n<p>VS CodeのターミナルでもMSYS2を使えるようにしておく。<br />\n(別ウィンドウでWindowsTerminalから実行すればいいんだけど)</p>\n\n<ul>\n  <li>VSCodeを起動</li>\n  <li>設定(ファイル→ユーザ設定→設定)を開く</li>\n  <li>機能→ターミナルを選ぶ\n-「integrated > profiles:windows」 を探す(検索すれば良いんだけど)\n    <ul>\n      <li>「setting,jsonで編集」 をクリック\n        <ul>\n          <li>ひな型作って開いてくれる。</li>\n          <li>そこに 以下を追加\n            <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>          \"MSYS2 Bash\": {\n              \"path\": [\n                  \"C:\\\\msys64\\\\msys2_shell.cmd\"\n              ],\n              \"args\": [\n                  \"-defterm\",\n                  \"-here\",\n                  \"-no-start\",\n                  \"-ucrt64\"\n              ]\n          }\n</code></pre></div>            </div>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nファイルは ユーザだと、<code class=\"language-plaintext highlighter-rouge\">%APPDATA%\\code\\User\\settings.json</code><br />\nワークスペースだとワークスペース下の<code class=\"language-plaintext highlighter-rouge\">.vscode\\settings.json</code></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nデフォルトのプロファイルをBashにすると悲しい結果が待ち受けているのでやらない方が良さそう</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "gcc": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>MSYS2とgccのインストール</title>\n  </head>\n  <body>\n    <header>\n      <h1>MSYS2とgccのインストール</h1>\n      <p>WindowsにMSYS2とgccをインストールした時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Windows環境でLinuxライクな環境を使用できる<a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2</a><br />\ngcc は単体で配布されている <a href=\"https://github.com/niXman/mingw-builds-binaries/releases\" target=\"_blank\">MinGW-W64-binaries</a>を使っていたが、\nMSYS2で管理されているものに切り替えてみた。</p>\n\n<h1 id=\"msys2のインストール\">MSYS2のインストール</h1>\n<p>大体以下の感じでインストールできる。</p>\n<ul>\n  <li><a href=\"https://www.msys2.org/\" target=\"_blank\">MSYS2のページ</a> を開く</li>\n  <li>Installation セクションの Download the installer: に書かれているリンクからダウンロード(バージョンアップで更新されるのでここにはリンクを貼らないでおく)</li>\n  <li>ダウンロードしたファイルを実行</li>\n  <li>デフォルトのままNextをクリックして行き、Installをクリック</li>\n  <li>終わったらFinishをクリック</li>\n</ul>\n\n<h1 id=\"msys2の設定\">MSYS2の設定</h1>\n<p>後でWindowsTerminalから使えるようにするからやらなくても良いけど、ま、気持ちの問題なので。</p>\n<ul>\n  <li>msys2を起動(スタート→すべて→MSYS2→MSYS2 UCRT64)し、タイトルバーを右クリックし 「Options…」 を選択\n    <ul>\n      <li>Text の Font の Select.. をクリックしてフォントとサイズを変更</li>\n      <li>Text の Local で ja_JP と UTF8 を選択</li>\n      <li>Window の Default size で ウィンドウサイズが変更できる</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"最新版にアップデート\">最新版にアップデート</h1>\n<p>MSYS2を起動して以下を実行(ubuntuの<code class=\"language-plaintext highlighter-rouge\">apt update && apt upgrade</code>に相当)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -Syuu\n</code></pre></div></div>\n\n<p>何か聞かれたらYを入力<br />\nウィンドウが閉じられたら再度MSYS2を起動<br />\n再度MSYS2を起動したらもう一回 <code class=\"language-plaintext highlighter-rouge\">pacman -Syuu</code> を実行</p>\n\n<h1 id=\"開発ツールのインストール\">開発ツールのインストール</h1>\n<p>MSYS2を起動して以下を実行<br />\n(make、gcc、gdbなどのインストール)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pacman -S base-devel\npacman -S mingw-w64-ucrt-x86_64-gcc\npacman -S mingw-w64-ucrt-x86_64-gdb\n</code></pre></div></div>\n\n<h1 id=\"pathの変更\">PATHの変更</h1>\n<p>MSYS2のbashで実行する際はpathは設定済みだが、\nコマンドプロンプト等で実行するためにWindows側のPATHを変更する。</p>\n\n<ul>\n  <li>設定 → システム → バージョン情報</li>\n  <li>関連リンクの「システムの詳細設定」をクリック</li>\n  <li>開いたウィンドウの下のほうにある「環境変数(N)…」をクリック</li>\n  <li>上側のユーザ環境変数で「Path」を選択して「編集」をクリック</li>\n  <li>「新規」をクリックして以下を追加\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>c:\\msys64\\ucrt64\\bin\nC:\\msys64\\usr\\bin\n</code></pre></div>    </div>\n    <blockquote>\n      <p>[!NOTE]\nc:\\msys64\\ucrt64\\bin にはpythonが入っているので、Windowsでインストールしたpythonを使用したい場合は\nそのPATHより後(下)に設定すること</p>\n    </blockquote>\n  </li>\n</ul>\n\n<p>念のためここでPCを再起動する。<br />\n(PATHの変更が有効にならない場合がある)</p>\n\n<h1 id=\"windowsterminal-にmsys2を登録\">WindowsTerminal にMSYS2を登録</h1>\n<p>MSY2のデフォルトのターミナルはminttyだが、いつも使っているWindowsTerminalで使えるようにする。</p>\n<ul>\n  <li>WindowsTerminalを起動</li>\n  <li>「新しいプロファイルを追加」を選択</li>\n  <li>「新しい空のプロファイル」をクリック\n    <ul>\n      <li>コマンドラインに以下を設定(ucrt64の場合。それ以外は最後のオプションを変更する)\n        <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>C:/msys64/msys2_shell.cmd -defterm -here -no-start -ucrt64\"  \n</code></pre></div>        </div>\n      </li>\n      <li>開始ディレクトリに MSYS2のhomeディレクトリ(<code class=\"language-plaintext highlighter-rouge\">cygpath.exe -w ~</code> で取得可能) を指定</li>\n      <li>アイコンは何でもいいけど、<code class=\"language-plaintext highlighter-rouge\">C:\\\\msys64\\\\ucrt64.ico</code>とかが良いかな</li>\n    </ul>\n  </li>\n</ul>\n\n<h1 id=\"vs-codeのターミナルでmsys2のbashを使用する方法\">VS CodeのターミナルでMSYS2のBashを使用する方法</h1>\n<p>VS CodeのターミナルでもMSYS2を使えるようにしておく。<br />\n(別ウィンドウでWindowsTerminalから実行すればいいんだけど)</p>\n\n<ul>\n  <li>VSCodeを起動</li>\n  <li>設定(ファイル→ユーザ設定→設定)を開く</li>\n  <li>機能→ターミナルを選ぶ\n-「integrated > profiles:windows」 を探す(検索すれば良いんだけど)\n    <ul>\n      <li>「setting,jsonで編集」 をクリック\n        <ul>\n          <li>ひな型作って開いてくれる。</li>\n          <li>そこに 以下を追加\n            <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>          \"MSYS2 Bash\": {\n              \"path\": [\n                  \"C:\\\\msys64\\\\msys2_shell.cmd\"\n              ],\n              \"args\": [\n                  \"-defterm\",\n                  \"-here\",\n                  \"-no-start\",\n                  \"-ucrt64\"\n              ]\n          }\n</code></pre></div>            </div>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nファイルは ユーザだと、<code class=\"language-plaintext highlighter-rouge\">%APPDATA%\\code\\User\\settings.json</code><br />\nワークスペースだとワークスペース下の<code class=\"language-plaintext highlighter-rouge\">.vscode\\settings.json</code></p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\nデフォルトのプロファイルをBashにすると悲しい結果が待ち受けているのでやらない方が良さそう</p>\n</blockquote>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "Android": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>AndroidでpythonでBLE</title>\n  </head>\n  <body>\n    <header>\n      <h1>AndroidでpythonでBLE</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerでBLE通信アプリを作ってみたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2025/04/04/Buildozer_2.html\">Buildozerでブロック崩しを作る</a>ではゲームを作ってみたが、次はペリフェラルを使ってみたくなるのが人情というもの。<br />\n<a href=\"https://bleak.readthedocs.io/en/latest/\" target=\"_blank\">Bleak</a>というモジュールがクロスプラットフォームでAndroidでも使えるらしい。<br />\nということで、Bleakを使ってBLEを使用するアプリを作って、それをBuildozerでAndroidアプリ化してみる。</p>\n\n<p>以下、<a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>での環境構築が終わっているものとして進める。</p>\n\n<h1 id=\"準備\">準備</h1>\n<p>これまで使用してきたWSL環境だとBluetoothが使用できないので、開発にはRaspberryPi5を使用することにした(Pi3以降なら大丈夫だと思う)。<br />\npyenvで仮想環境作ってkivyとbleakをインストールしておく。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<h1 id=\"通信相手の準備\">通信相手の準備</h1>\n<p>通信相手は前に作ったランダム値を送るペリフェラルを使った。<br />\n<a href=\"https://github.com/ippei8jp/MultiBLE/tree/main/micropython\" target=\"_blank\">ここ</a>のble_RandomSensor3.py を\nRascberryPi PICO や ESP32 の micropython で動かしておく。</p>\n\n<p>micropythoの使い方は以前に書いた<a href=\"/memoBlog/2023/09/03/RasPiPico_1.html\" target=\"_blank\">Raspberry Pi Pico Wでmicropython with Visual Studio Code</a>\nが参考になるかも。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは下の「開く」をクリックすると表示されます。<br />\nダウンロードする場合は<a href=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1\" target=\"_blank\">こちら</a></p>\n\n<blockquote>\n  <p>[!NOTE]\nimportしている<code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>は\n<a href=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7\" target=\"_blank\">ここ</a>\nにあります。</p>\n</blockquote>\n\n<p>用意するファイルはこんな感じ。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── kivy_ble.py\n└── scrolllabel.py\n</code></pre></div></div>\n\n<p>↓をクリックするとソースが開きます。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n    <script src=\"https://gist.github.com/ippei8jp/b1d47be7bce11f9e4c6f70a626e5d1c1.js\"></script>\n</dev>\n\n<h1 id=\"raspberrypiで実行\">RaspberryPiで実行</h1>\n<p>まずはPythonスクリプトが動くことを確認するために、RaspBerryPiで動かしてみる。<br />\n通信相手がいないと動かないので、事前に上の通信相手を実行しておく。</p>\n\n<p>RaspberyPi上でkivy_ble.pyを実行するとウィンドウが開くので、connectボタンをクリックする。<br />\nペリフェラルをスキャンが開始され、最初に見つかったデバイスに接続される。<br />\nさらにDATA1とDATA2のNotifyハンドラが登録され、受信データがウィンドウ右上の表示領域に表示される。<br />\ndisconnectボタンをクリックすると切断される。<br />\nQUITボタンをクリックするとプログラム終了。<br />\nウィンドウ下半分のログ表示領域には情報が表示される。この領域はスクロール可能。</p>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>と同様の手順でAndroidアプリ化していく。</p>\n\n<h2 id=\"ファイルの準備\">ファイルの準備</h2>\n\n<ul>\n  <li>BuidozerがインストールされたWSLの仮想マシンに作業ディレクトリを作成</li>\n  <li>作業ディレクトリに 上で作成した<code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code> <code class=\"language-plaintext highlighter-rouge\">scrolllabel.py</code>をコピー</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">kivy_ble.py</code>を <code class=\"language-plaintext highlighter-rouge\">main.py</code> にリネーム</li>\n  <li>RaspberryPiの≪Bleakインストール先≫>/bleak/backends/p4android/recipes を 作業ディレクトリにコピー(ディレクトリまるごと)\n    <blockquote>\n      <p>[!NOTE]\nBleakのインストール先ディレクトリは以下のコマンドで確認できます</p>\n      <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip list <span class=\"nt\">-v</span> | <span class=\"nb\">grep</span> <span class=\"s2\">\"bleak \"</span>\n</code></pre></div>      </div>\n    </blockquote>\n  </li>\n</ul>\n\n<p>-または以下でもOK</p>\n<blockquote>\n  <p>[!NOTE]</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> recipes/bleak\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/__init__.py\nwget <span class=\"nt\">-P</span> recipes/bleak https://raw.githubusercontent.com/hbldh/bleak/refs/heads/develop/bleak/backends/p4android/recipes/bleak/fix_setup.py\n</code></pre></div>  </div>\n</blockquote>\n\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer init</code> を実行して<code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>を生成する</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code>に以下の修正を加える</li>\n</ul>\n\n<dev class=\"accordion_head\"></dev>\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- buildozer.spec.org  2025-04-09 07:58:44.836709400 +0900\n</span><span class=\"gi\">+++ buildozer.spec      2025-04-17 08:12:06.676451390 +0900\n</span><span class=\"p\">@@ -1,10 +1,10 @@</span>\n [app]\n\n # (str) Title of your application\n<span class=\"gd\">-title = My Application\n</span><span class=\"gi\">+title = BLE Demo\n</span>\n # (str) Package name\n<span class=\"gd\">-package.name = myapp\n</span><span class=\"gi\">+package.name = bledemo\n</span>\n # (str) Package domain (needed for android/ios packaging)\n package.domain = org.test\n<span class=\"p\">@@ -22,7 +22,7 @@</span>\n #source.exclude_exts = spec\n\n # (list) List of directory to exclude (let empty to not exclude anything)\n<span class=\"gd\">-#source.exclude_dirs = tests, bin, venv\n</span><span class=\"gi\">+source.exclude_dirs = tests, bin, venv, recipes\n</span>\n # (list) List of exclusions using pattern matching\n # Do not prefix with './'\n<span class=\"p\">@@ -37,7 +37,13 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements =\n+    python3,\n+    kivy,\n+    bleak,\n+    typing_extensions,\n+    async_to_sync,\n+    async-timeout\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n<span class=\"p\">@@ -95,7 +101,14 @@</span>\n\n # (list) Permissions\n # (See https://python-for-android.readthedocs.io/en/latest/buildoptions/#build-options-1 for all the supported syntaxes and properties)\n<span class=\"gd\">-#android.permissions = android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)\n</span><span class=\"gi\">+android.permissions =\n+    BLUETOOTH,\n+    BLUETOOTH_SCAN,\n+    BLUETOOTH_CONNECT,\n+    BLUETOOTH_ADMIN,\n+    ACCESS_FINE_LOCATION,\n+    ACCESS_COARSE_LOCATION,\n+    ACCESS_BACKGROUND_LOCATION\n</span>\n # (list) features (adds uses-feature -tags to manifest)\n #android.features = android.hardware.usb.host\n<span class=\"p\">@@ -330,7 +343,7 @@</span>\n #p4a.source_dir =\n\n # (str) The directory in which python-for-android should look for your own build recipes (if any)\n<span class=\"gd\">-#p4a.local_recipes =\n</span><span class=\"gi\">+p4a.local_recipes = ./recipes\n</span>\n # (str) Filename to the hook for p4a\n #p4a.hook =\n</code></pre></div></div>\n\n<ul>\n  <li>最終的に作業ディレクトリは以下のようになる\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>≪作業ディレクトリ≫\n├── buildozer.spec\n├── main.py\n├── scrolllabel.py\n└── recipes\n     └── bleak\n         ├── __init__.py\n         └── fix_setup.py\n</code></pre></div>    </div>\n    <h2 id=\"build\">build</h2>\n    <p>以下のコマンドでbuidする</p>\n    <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div>    </div>\n  </li>\n</ul>\n\n<h2 id=\"インストール実行\">インストール&実行</h2>\n<p>Windows側でadbサーバを起動しておき、以下を実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>connectボタンを最初にクリックした時、「この端末の位置情報へのアクセスをBLE Demoに許可しますか?」と聞かれたら「許可」をクリック\n(Androidのバージョンによって違うかもしれん。ターゲットAPIレベルで決まるんだっけ?)</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Buildozerでブロック崩しを作る</title>\n  </head>\n  <body>\n    <header>\n      <h1>Buildozerでブロック崩しを作る</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerでブロック崩しを作ってみたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>では訳も分からずとりあえずbuildして実行してみたが、\n少し何がどうなっているか調べてみたところ、\n実行の実体は<a href=\"https://github.com/kivy/python-for-android\" target=\"_blank\">python for android</a>\nというもので、Buildozerはこのプロジェクトをbuildするためのヘルパーらしい。</p>\n\n<p>で、githubのリポジトリを眺めていると<code class=\"language-plaintext highlighter-rouge\">pythonforandroid/recipes</code>にモジュールをbuildするためのレシピが置いてあるようだ。<br />\nそこに、<code class=\"language-plaintext highlighter-rouge\">pygame</code>というディレクトリがあったので、たぶんゲームを作るためのモジュールなんだろうとあたりをつけて\nぐぐってみた。</p>\n\n<p>で、<a href=\"https://python.joho.info/pygame/pygame-blockout/\" target=\"_blank\">【Pygame】ブロック崩しの作り方とサンプルコード(効果音付き)</a>\nにブロック崩しのプログラムの例があったので拝借してAndroidアプリ化してみることにした。</p>\n\n<p>今回は趣向を変えて、失敗事例も含めて書いてみる。</p>\n\n<p>以下、<a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>での環境構築が終わっているものとして進める。</p>\n\n<h1 id=\"使用したソース\">使用したソース</h1>\n<p><a href=\"https://python.joho.info/pygame/pygame-blockout/\" target=\"_blank\">【Pygame】ブロック崩しの作り方とサンプルコード(効果音付き)</a>\nのソースそのままでは動かなかったので、色々試行錯誤した結果のソースが以下。</p>\n\n<p>画像ファイルとオーディオファイルをプロジェクトフォルダに移動して\nアクセスするためのベースディレクトリを環境変数<code class=\"language-plaintext highlighter-rouge\">ANDROID_APP_PATH</code>から取得するようにした。<br />\n(相対パスだとうまく動かない。実行時のディレクトリがmain.pyがあるディレクトリと異なるため)</p>\n\n<p>あと、全画面表示にするため<code class=\"language-plaintext highlighter-rouge\">pygame.display.set_mode</code>に第2パラメータ<code class=\"language-plaintext highlighter-rouge\">(SCALED | FULLSCREEN)</code>を追加している。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">math</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pygame</span>\n<span class=\"kn\">from</span> <span class=\"nn\">pygame.locals</span> <span class=\"kn\">import</span> <span class=\"o\">*</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pygame.mixer</span>\n\n<span class=\"c1\"># ベースディレクトリの設定\n# Androidだとchdirされて相対パスでアクセスできなくなるので\n</span>\n<span class=\"n\">BASE_DIR</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getenv</span><span class=\"p\">(</span><span class=\"s\">'ANDROID_APP_PATH'</span><span class=\"p\">)</span>    <span class=\"c1\"># アプリケーションの格納されているパスを環境変数から取得\n</span><span class=\"k\">if</span> <span class=\"n\">BASE_DIR</span> <span class=\"ow\">is</span> <span class=\"bp\">None</span><span class=\"p\">:</span>\n    <span class=\"n\">BASE_DIR</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">getcwd</span><span class=\"p\">()</span>                  <span class=\"c1\"># 設定されていない(Androidでない)→ カレントディレクトリを設定\n</span>\n<span class=\"c1\"># 画面サイズ\n</span><span class=\"n\">WIDTH</span> <span class=\"o\">=</span> <span class=\"mi\">400</span>\n<span class=\"n\">HEIGHT</span> <span class=\"o\">=</span> <span class=\"mi\">400</span>\n<span class=\"n\">SCREEN</span> <span class=\"o\">=</span> <span class=\"n\">Rect</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">WIDTH</span><span class=\"p\">,</span> <span class=\"n\">HEIGHT</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># 画像ファイルのパス\n</span><span class=\"n\">PADDLE_IMG_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'paddle.png'</span><span class=\"p\">)</span>\n<span class=\"n\">BLOCK_IMG_PATH</span>  <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'block.png'</span><span class=\"p\">)</span>\n<span class=\"n\">BALL_IMG_PATH</span>   <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'images'</span><span class=\"p\">,</span><span class=\"s\">'ball.png'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># オーディオファイルのパス\n</span><span class=\"n\">PADDLE_SOUND_PATH</span>   <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'paddle_sound.mp3'</span><span class=\"p\">)</span>\n<span class=\"n\">BLOCK_SOUND_PATH</span>    <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'block_sound.mp3'</span><span class=\"p\">)</span>\n<span class=\"n\">GAMEOVER_SOUND_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"p\">.</span><span class=\"n\">path</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">BASE_DIR</span><span class=\"p\">,</span> <span class=\"s\">'sound'</span><span class=\"p\">,</span> <span class=\"s\">'gameover_sound.mp3'</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># バドルのスプライトクラス\n</span><span class=\"k\">class</span> <span class=\"nc\">Paddle</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"c1\"># コンストラクタ\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">-</span> <span class=\"mi\">20</span>          <span class=\"c1\"># パドルのy座標\n</span>\n    <span class=\"k\">def</span> <span class=\"nf\">update</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mouse</span><span class=\"p\">.</span><span class=\"n\">get_pos</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span>  <span class=\"c1\"># マウスのx座標をパドルのx座標に\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">clamp_ip</span><span class=\"p\">(</span><span class=\"n\">SCREEN</span><span class=\"p\">)</span>                     <span class=\"c1\"># ゲーム画面内のみで移動\n</span>\n<span class=\"c1\"># ボールのスプライトクラス\n</span><span class=\"k\">class</span> <span class=\"nc\">Ball</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"c1\"># コンストラクタ\n</span>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">paddle</span><span class=\"p\">,</span> <span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">,</span> <span class=\"n\">speed</span><span class=\"p\">,</span> <span class=\"n\">angle_left</span><span class=\"p\">,</span> <span class=\"n\">angle_right</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>  <span class=\"c1\"># ボールの速度\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span> <span class=\"o\">=</span> <span class=\"n\">paddle</span>  <span class=\"c1\"># パドルへの参照\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">blocks</span> <span class=\"o\">=</span> <span class=\"n\">blocks</span>  <span class=\"c1\"># ブロックグループへの参照\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">start</span> <span class=\"c1\"># ゲーム開始状態に更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">score</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 連続でブロックを壊した回数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">=</span> <span class=\"n\">speed</span> <span class=\"c1\"># ボールの初期速度\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_left</span> <span class=\"o\">=</span> <span class=\"n\">angle_left</span> <span class=\"c1\"># パドルの反射方向(左端:135度)\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_right</span> <span class=\"o\">=</span> <span class=\"n\">angle_right</span> <span class=\"c1\"># パドルの反射方向(右端:45度)\n</span>\n    <span class=\"c1\"># ゲーム開始状態(マウスを左クリック時するとボール射出)\n</span>    <span class=\"k\">def</span> <span class=\"nf\">start</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># ボールの初期位置(パドルの上)\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span>\n\n        <span class=\"c1\"># 左クリックでボール射出\n</span>        <span class=\"k\">if</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mouse</span><span class=\"p\">.</span><span class=\"n\">get_pressed</span><span class=\"p\">()[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">move</span>\n\n    <span class=\"c1\"># ボールの挙動\n</span>    <span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centerx</span> <span class=\"o\">+=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">centery</span> <span class=\"o\">+=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n        <span class=\"c1\"># 壁との反射\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span><span class=\"p\">:</span>    <span class=\"c1\"># 左側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>              <span class=\"c1\"># 速度を反転\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">></span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>  <span class=\"c1\"># 右側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">right</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span><span class=\"p\">:</span>      <span class=\"c1\"># 上側\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n        <span class=\"c1\"># パドルとの反射(左端:135度方向, 右端:45度方向, それ以外:線形補間)\n</span>        <span class=\"c1\"># 2つのspriteが接触しているかどうかの判定\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">colliderect</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">></span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>                                <span class=\"c1\"># 連続ヒットを0に戻す\n</span>            <span class=\"p\">(</span><span class=\"n\">x1</span><span class=\"p\">,</span> <span class=\"n\">y1</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">-</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">width</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_left</span><span class=\"p\">)</span>\n            <span class=\"p\">(</span><span class=\"n\">x2</span><span class=\"p\">,</span> <span class=\"n\">y2</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">angle_right</span><span class=\"p\">)</span>\n            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span>                          <span class=\"c1\"># ボールが当たった位置\n</span>            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"nb\">float</span><span class=\"p\">(</span><span class=\"n\">y2</span><span class=\"o\">-</span><span class=\"n\">y1</span><span class=\"p\">)</span><span class=\"o\">/</span><span class=\"p\">(</span><span class=\"n\">x2</span><span class=\"o\">-</span><span class=\"n\">x1</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">x1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">y1</span>  <span class=\"c1\"># 線形補間\n</span>            <span class=\"n\">angle</span> <span class=\"o\">=</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">radians</span><span class=\"p\">(</span><span class=\"n\">y</span><span class=\"p\">)</span>                     <span class=\"c1\"># 反射角度\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">*</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">cos</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">speed</span> <span class=\"o\">*</span> <span class=\"n\">math</span><span class=\"p\">.</span><span class=\"n\">sin</span><span class=\"p\">(</span><span class=\"n\">angle</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">paddle_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>                    <span class=\"c1\"># 反射音\n</span>\n        <span class=\"c1\"># ボールを落とした場合\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">></span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">start</span>                    <span class=\"c1\"># ボールを初期状態に\n</span>            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">gameover_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">set_score</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>                               <span class=\"c1\"># スコアを0点にする\n</span>            <span class=\"c1\">#self.score.add_score(-100)                  # スコア減点-100点\n</span>\n        <span class=\"c1\"># ボールと衝突したブロックリストを取得(Groupが格納しているSprite中から、指定したSpriteと接触しているものを探索)\n</span>        <span class=\"n\">blocks_collided</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">spritecollide</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">blocks_collided</span><span class=\"p\">:</span>  <span class=\"c1\"># 衝突ブロックがある場合\n</span>            <span class=\"n\">oldrect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span>\n            <span class=\"k\">for</span> <span class=\"n\">block</span> <span class=\"ow\">in</span> <span class=\"n\">blocks_collided</span><span class=\"p\">:</span>\n                <span class=\"c1\"># ボールが左からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"ow\">and</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n                    \n                <span class=\"c1\"># ボールが右からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"ow\">and</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">right</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">right</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dx</span>\n\n                <span class=\"c1\"># ボールが上からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"ow\">and</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\"><</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n\n                <span class=\"c1\"># ボールが下からブロックへ衝突した場合\n</span>                <span class=\"k\">if</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"ow\">and</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span> <span class=\"o\"><</span> <span class=\"n\">oldrect</span><span class=\"p\">.</span><span class=\"n\">bottom</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">block</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">bottom</span>\n                    <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">dy</span>\n                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">block_sound</span><span class=\"p\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>     <span class=\"c1\"># 効果音を鳴らす\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>               <span class=\"c1\"># 衝突回数をカウント\n</span>                <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">add_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">hit</span> <span class=\"o\">*</span> <span class=\"mi\">10</span><span class=\"p\">)</span>   <span class=\"c1\"># 衝突回数に応じてスコア加点\n</span>\n<span class=\"c1\"># ブロック\n</span><span class=\"k\">class</span> <span class=\"nc\">Block</span><span class=\"p\">(</span><span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>\n        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Sprite</span><span class=\"p\">.</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">containers</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">).</span><span class=\"n\">convert</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">image</span><span class=\"p\">.</span><span class=\"n\">get_rect</span><span class=\"p\">()</span>\n        <span class=\"c1\"># ブロックの左上座標\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">left</span> <span class=\"o\">+</span> <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">width</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">=</span> <span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">top</span> <span class=\"o\">+</span> <span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">rect</span><span class=\"p\">.</span><span class=\"n\">height</span>\n\n<span class=\"c1\"># スコア\n</span><span class=\"k\">class</span> <span class=\"nc\">Score</span><span class=\"p\">():</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">sysfont</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">font</span><span class=\"p\">.</span><span class=\"n\">SysFont</span><span class=\"p\">(</span><span class=\"bp\">None</span><span class=\"p\">,</span> <span class=\"mi\">20</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">draw</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">screen</span><span class=\"p\">):</span>\n        <span class=\"n\">img</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">sysfont</span><span class=\"p\">.</span><span class=\"n\">render</span><span class=\"p\">(</span><span class=\"s\">\"SCORE:\"</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span><span class=\"p\">),</span> <span class=\"bp\">True</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">255</span><span class=\"p\">,</span><span class=\"mi\">255</span><span class=\"p\">,</span><span class=\"mi\">250</span><span class=\"p\">))</span>\n        <span class=\"n\">screen</span><span class=\"p\">.</span><span class=\"n\">blit</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"p\">))</span>\n    <span class=\"k\">def</span> <span class=\"nf\">add_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">+=</span> <span class=\"n\">x</span>\n    <span class=\"k\">def</span> <span class=\"nf\">set_score</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">score</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\n    <span class=\"c1\"># 初期化\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># スクリーンの設定\n</span>    <span class=\"c1\"># screen = pygame.display.set_mode(SCREEN.size)\n</span>    <span class=\"n\">screen</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">display</span><span class=\"p\">.</span><span class=\"n\">set_mode</span><span class=\"p\">(</span><span class=\"n\">SCREEN</span><span class=\"p\">.</span><span class=\"n\">size</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">SCALED</span> <span class=\"o\">|</span> <span class=\"n\">FULLSCREEN</span><span class=\"p\">))</span>    <span class=\"c1\"># (SCALED | FULLSCREEN) で前画面に拡大表示できる\n</span>\n    <span class=\"c1\"># オーディオ初期化\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># 各種効果音の設定\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">paddle_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">PADDLE_SOUND_PATH</span><span class=\"p\">)</span>               <span class=\"c1\"># パドルにボールが衝突した時の効果音取得\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">block_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">BLOCK_SOUND_PATH</span><span class=\"p\">)</span>                 <span class=\"c1\"># ブロックにボールが衝突した時の効果音取得\n</span>    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">gameover_sound</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">mixer</span><span class=\"p\">.</span><span class=\"n\">Sound</span><span class=\"p\">(</span><span class=\"n\">GAMEOVER_SOUND_PATH</span><span class=\"p\">)</span>           <span class=\"c1\"># ゲームオーバー時の効果音取得\n</span>    \n    <span class=\"c1\"># 描画用のスプライトグループ\n</span>    <span class=\"n\">group</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">RenderUpdates</span><span class=\"p\">()</span>  \n\n    <span class=\"c1\"># 衝突判定用のスプライトグループ\n</span>    <span class=\"n\">blocks</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">sprite</span><span class=\"p\">.</span><span class=\"n\">Group</span><span class=\"p\">()</span>   \n\n    <span class=\"c1\"># スプライトグループに追加    \n</span>    <span class=\"n\">Paddle</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span>\n    <span class=\"n\">Ball</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span>\n    <span class=\"n\">Block</span><span class=\"p\">.</span><span class=\"n\">containers</span> <span class=\"o\">=</span> <span class=\"n\">group</span><span class=\"p\">,</span> <span class=\"n\">blocks</span>\n\n    <span class=\"c1\"># パドルの作成\n</span>    <span class=\"n\">paddle</span> <span class=\"o\">=</span> <span class=\"n\">Paddle</span><span class=\"p\">(</span><span class=\"n\">PADDLE_IMG_PATH</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ブロックの作成(14*10)\n</span>    <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">15</span><span class=\"p\">):</span>\n        <span class=\"k\">for</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">11</span><span class=\"p\">):</span>\n            <span class=\"n\">Block</span><span class=\"p\">(</span><span class=\"n\">BLOCK_IMG_PATH</span><span class=\"p\">,</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># スコアを画面(10, 10)に表示\n</span>    <span class=\"n\">score</span> <span class=\"o\">=</span> <span class=\"n\">Score</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>    \n\n    <span class=\"c1\"># ボールを作成\n</span>    <span class=\"n\">Ball</span><span class=\"p\">(</span><span class=\"n\">BALL_IMG_PATH</span><span class=\"p\">,</span> <span class=\"n\">paddle</span><span class=\"p\">,</span> <span class=\"n\">blocks</span><span class=\"p\">,</span> <span class=\"n\">score</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">135</span><span class=\"p\">,</span> <span class=\"mi\">45</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">clock</span> <span class=\"o\">=</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">time</span><span class=\"p\">.</span><span class=\"n\">Clock</span><span class=\"p\">()</span>\n\n    <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>  <span class=\"c1\"># ループ処理の実行を継続するフラグ\n</span>\n    <span class=\"k\">while</span> <span class=\"n\">running</span><span class=\"p\">:</span>\n        <span class=\"n\">clock</span><span class=\"p\">.</span><span class=\"n\">tick</span><span class=\"p\">(</span><span class=\"mi\">60</span><span class=\"p\">)</span>      <span class=\"c1\"># フレームレート(60fps)\n</span>        <span class=\"n\">screen</span><span class=\"p\">.</span><span class=\"n\">fill</span><span class=\"p\">((</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">20</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 全てのスプライトグループを更新\n</span>        <span class=\"n\">group</span><span class=\"p\">.</span><span class=\"n\">update</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 全てのスプライトグループを描画       \n</span>        <span class=\"n\">group</span><span class=\"p\">.</span><span class=\"n\">draw</span><span class=\"p\">(</span><span class=\"n\">screen</span><span class=\"p\">)</span>\n        <span class=\"c1\"># スコアを描画  \n</span>        <span class=\"n\">score</span><span class=\"p\">.</span><span class=\"n\">draw</span><span class=\"p\">(</span><span class=\"n\">screen</span><span class=\"p\">)</span> \n        <span class=\"c1\"># 画面更新 \n</span>        <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">display</span><span class=\"p\">.</span><span class=\"n\">update</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># イベント処理\n</span>        <span class=\"k\">for</span> <span class=\"n\">event</span> <span class=\"ow\">in</span> <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">event</span><span class=\"p\">.</span><span class=\"n\">get</span><span class=\"p\">():</span>\n            <span class=\"c1\"># 閉じるボタンが押されたら終了\n</span>            <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"nb\">type</span> <span class=\"o\">==</span> <span class=\"n\">QUIT</span><span class=\"p\">:</span> \n                <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n            <span class=\"c1\"># キーイベント\n</span>            <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"nb\">type</span> <span class=\"o\">==</span> <span class=\"n\">KEYDOWN</span><span class=\"p\">:</span>\n                <span class=\"c1\"># Escキーが押されたら終了\n</span>                <span class=\"k\">if</span> <span class=\"n\">event</span><span class=\"p\">.</span><span class=\"n\">key</span> <span class=\"o\">==</span> <span class=\"n\">K_ESCAPE</span><span class=\"p\">:</span>   \n                    <span class=\"n\">running</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n    <span class=\"c1\"># 終了処理\n</span>    <span class=\"n\">pygame</span><span class=\"p\">.</span><span class=\"n\">quit</span><span class=\"p\">()</span>\n    <span class=\"n\">sys</span><span class=\"p\">.</span><span class=\"nb\">exit</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">\"__main__\"</span><span class=\"p\">:</span>\n    <span class=\"n\">main</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>画像ファイルとオーディオファイルは参照元のページにあるリンクからダウンロードして以下のように配置する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.\n├── main.py\n├── images\n│   ├── ball.png\n│   ├── block.png\n│   └── paddle.png\n└── sound\n    ├── block_sound.mp3\n    ├── gameover_sound.mp3\n    └── paddle_sound.mp3\n</code></pre></div></div>\n\n<p>とりあえずホスト上で動作するか確認してみる。<br />\n(Android上のpython/pygameとバージョンが違うので厳密な動作確認にはならないけど、大体OKを確認したいだけなのでこれでいく)</p>\n\n<p>pygameのインストールは以下。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>pygame\n</code></pre></div></div>\n\n<p>WSLではデフォルトでオーディオ再生するためのライブラリ類がインストールされていないので、以下でインストールする。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>pulseaudio\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nWSLってオーディオ再生できるんだ。<br />\n初めて知った…</p>\n</blockquote>\n\n<p>で実行してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python main.py\n</code></pre></div></div>\n\n<p>全画面表示になるので、終了はESCキー押下で。</p>\n\n<h1 id=\"まずは何も考えずにbuildしてみる失敗\">まずは何も考えずにbuildしてみる(失敗)</h1>\n\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>とりあえず最低限必要な修正だけで試してみる。<br />\nbuildozer.spec を以下の内容で修正。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- block0/buildozer.spec       2025-04-04 07:08:53.520218478 +0900\n</span><span class=\"gi\">+++ block1/buildozer.spec       2025-04-04 06:25:27.858934801 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n</code></pre></div></div>\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<p>しばらくするとエラーで止まる。<br />\nmk.logを確認してみると、以下のようなエラーメッセージがあった。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/work/Buildozer/biock1/.buildozer/android/platform/build-arm64-v8a_armeabi-v7a/build/other_builds/pygame/arm64-v8a__ndk_target_21/pygame/setup.py:70: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives\n・・・\nsrc_c/_sdl2/sdl2.c:211:12: fatal error: 'longintrepr.h' file not found\n</code></pre></div></div>\n\n<p>どうやらpygameのbuuild中に<code class=\"language-plaintext highlighter-rouge\">longintrepr.h</code>が見つからなくてエラーになっているらしい。<br />\n「longintrepr.h」でぐぐってみると、python 3.10 → 3.11 の変更で削除されたファイルらしい。</p>\n\n<h1 id=\"それならばpygameのバージョンを新しくしてbuildしてみる失敗\">それならばpygameのバージョンを新しくしてbuildしてみる(失敗)</h1>\n\n<p>pygameをpython 3.11に対応しているバージョンに変更して試してみる。<br />\n調べてみると、2.1.3からpython 3.11 に対応しているようである。</p>\n\n<p>作成済みのファイルを削除<br />\n<code class=\"language-plaintext highlighter-rouge\">buildozer android clean</code>でも良さそうだけど、念のため全部消して最初からやってみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> .buildozer bin buildozer.spec mk.log\n</code></pre></div></div>\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>buildozer.spec を以下の内容で修正。<br />\npygameのバージョンを2.1.3指定している。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- block0/buildozer.spec       2025-04-04 07:08:53.520218478 +0900\n</span><span class=\"gi\">+++ block2/buildozer.spec       2025-04-04 09:32:40.050228726 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame==2.1.3\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n</code></pre></div></div>\n\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n<p>しばらく待つと、以下のように表示されたので、buildは成功したようである。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Android packaging done!\n# APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<p>なので、実行してみる。<br />\nWindows側でadbサーバを起動しておき、以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>起動はするが、すぐに落ちてしまう。<br />\nなにやらエラーが発生している模様。ログで何が起こっているか確認する。<br />\n無関係なログも多く含まれているので、python関連のログだけ抜き出してみる</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">grep</span> <span class=\"nt\">-i</span> python run.log <span class=\"o\">></span> run_python.log\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n<code class=\"language-plaintext highlighter-rouge\">buildozer.spec</code> に以下を追加するとlogcatのフィルタが有効になるので、設定しておくと良いかもしれない。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>android.logcat_filters = *:S python:V pythonutil:V PythonActivity:V\n</code></pre></div>  </div>\n  <p>コマンドラインで指定できると良いのがだが…\nadbを直接起動すればコマンドラインで設定できるけど。</p>\n\n  <p>タグ<code class=\"language-plaintext highlighter-rouge\">python</code>がpythonプログラム内のログ、その他は実行時の制御を行っている部分らしい。<br />\nまた、プログラム内のprintによるメッセージ出力もここに表示される。</p>\n</blockquote>\n\n<p>ログファイルの最後の部分には以下のように出力されている。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> I python  : Traceback (most recent call last):\n I python  :   File \"/work/Buildozer/block2/.buildozer/android/app/main.py\", line 34, in <module>\n I python  :   File \"/work/Buildozer/block2/.buildozer/android/platform/build-arm64-v8a_armeabi-v7a/build/python-installs/myapp/arm64-v8a/pygame/__init__.py\", line 70, in __getattr__\n I python  : NotImplementedError: sprite module not available (ImportError: dlopen failed: cannot locate symbol \"alphablit_alpha_sse2_argb_surf_alpha\" referenced by \"/data/data/org.test.myapp/files/app/_python_bundle/site-packages/pygame/surface.so\"...)\n I python  : Python for android ended.\n</code></pre></div></div>\n\n<p>どうやらpygameの初期化時に<code class=\"language-plaintext highlighter-rouge\">alphablit_alpha_sse2_argb_surf_alpha</code>が見つからないということらしい。<br />\n単にバージョン変えるだけではダメで、ちゃんとレシピも修正しないといけないらしい。</p>\n\n<h1 id=\"python-for-androidのバージョンを下げてみる成功\">python for androidのバージョンを下げてみる(成功)</h1>\n\n<p>python 3.10以下にして試してみることも考えたが、同様にレシピの変更なしで動くとは思えないので\npython for androidのバージョンを下げて試してみることにする。</p>\n\n<p>作成済みのファイルを削除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">rm</span> <span class=\"nt\">-fr</span> .buildozer bin buildozer.spec mk.log\n</code></pre></div></div>\n<p>buildozer.spec の生成</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>buildozer.spec を以下の内容で修正。<br />\n<code class=\"language-plaintext highlighter-rouge\">p4a.branch = release-2022.12.20</code> と指定してrelease-2022.12.20を使用するように設定している。<br />\nこのバージョンは python 3.9.9 を使用している。</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gi\">+++ block3/buildozer.spec       2025-04-04 12:28:23.302885362 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,mp3\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*,images/*.png,sound/*.mp3\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n<span class=\"p\">@@ -37,7 +37,7 @@</span>\n\n # (list) Application requirements\n # comma separated e.g. requirements = sqlite3,kivy\n<span class=\"gd\">-requirements = python3,kivy\n</span><span class=\"gi\">+requirements = python3,kivy,pygame\n</span>\n # (str) Custom source folders for requirements\n # Sets custom source for any requirements with recipes\n<span class=\"p\">@@ -321,7 +321,7 @@</span>\n #p4a.fork = kivy\n\n # (str) python-for-android branch to use, defaults to master\n<span class=\"gd\">-#p4a.branch = master\n</span><span class=\"gi\">+p4a.branch = release-2022.12.20\n</span>\n # (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch\n #p4a.commit = HEAD\n</code></pre></div></div>\n\n<p>build実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n<p>しばらく待つと、以下のように表示されたので、buildは成功したようである。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># Android packaging done!\n# APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<p>なので、実行してみる。<br />\nWindows側でadbサーバを起動しておき(前のセクションで起動してれば再度実行する必要なし)、以下を実行。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、動いた。<br />\nメデタシメデタシ。<br />\nログがファイルに格納され続けてしまうので、早めにCTRL+Cで止めておきましょう。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>Buildozerをお試し</title>\n  </head>\n  <body>\n    <header>\n      <h1>Buildozerをお試し</h1>\n      <p>PythonプログラムをAndroidアプリ化できるBuildozerをお試ししたときのメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>pythonプログラムをAndroid アプリ化できる Buildozer を試してみた時のメモ<br />\n(iOSもできるみたいだけど試してないのでわからん)<br />\n参考:<br />\n<a href=\"https://buildozer.readthedocs.io/en/latest/installation.html\" target=\"_blank\">公式サイト</a><br />\n<a href=\"https://qiita.com/kouzimiso/items/1332ab62791ca5d81c5f\" target=\"_blank\">BuildozerでAndroidアプリを作る 2024 WSL2</a><br />\n<a href=\"https://paloma69.hatenablog.com/entry/2022/07/05/195915\" target=\"_blank\">pythonでAndroidの野良アプリを作りたい2 buildozerでコンパイル編</a></p>\n\n<h1 id=\"準備\">準備</h1>\n<p>環境はWSL で Ubuntu 24.04を使用した。<br />\n(公式では20.04 or 22.04 となってるけど、24.04でも動いた)<br />\n以下ディストリビューション情報</p>\n\n<p>Andoridはちょっと古いけど ZenFone Max Pro (M2) Android9<br />\n新しいAndroidでも動くかどうかわからん。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>~<span class=\"nv\">$ </span>lsb_release <span class=\"nt\">-a</span>\nNo LSB modules are available.\nDistributor ID: Ubuntu\nDescription:    Ubuntu 24.04.2 LTS\nRelease:        24.04\nCodename:       noble\n</code></pre></div></div>\n\n<h2 id=\"pyenvのインストール\">pyenvのインストール</h2>\n\n<p><a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a>参照</p>\n\n<h2 id=\"pyenvでpythonインストール\">pyenvでpythonインストール</h2>\n<p>公式では python は 3.8 以降となっているので、3.12を使うこととした。</p>\n\n<blockquote>\n  <p>[!NOTE]\n3.12では<code class=\"language-plaintext highlighter-rouge\">distutils</code>が廃止されているので、<code class=\"language-plaintext highlighter-rouge\">setuptools</code>のインストールが必須。<br />\n参考:<a href=\"https://openillumi.com/python-3-12-distutils-error-fix-guide/\" target=\"_blank\">Python 3.12での「ModuleNotFoundError: distutilsが見つかりません」を解決する方法</a></p>\n</blockquote>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pyenv <span class=\"nb\">install </span>3.12.9 \npyenv shell 3.12.9 \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\npyenv shell <span class=\"nt\">--unset</span> \n</code></pre></div></div>\n\n<h2 id=\"pyenvで仮想環境構築\">pyenvで仮想環境構築</h2>\n<p>お約束で仮想環境を作っておく。<br />\n(そのまま3.12.xにインストールしてもいいけど)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> <span class=\"nt\">-p</span> /work/Buildozer <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Buildozer\npyenv virtualenv 3.12.9 Buildozer\npyenv <span class=\"nb\">local </span>Buildozer \npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> pip setuptools wheel\n</code></pre></div></div>\n\n<h2 id=\"必要なツール類のインストール\">必要なツール類のインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>zip unzip openjdk-17-jdk autoconf libtool pkg-config zlib1g-dev cmake libffi-dev libssl-dev\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n公式サイトで指定されているライブラリのうち以下は24.04では存在しない。<br />\n<code class=\"language-plaintext highlighter-rouge\">libncurses5-dev libncursesw5-dev libtinfo5</code><br />\nWSL2のUbuntu24.04ではデフォルトで後継のlibncurses-dev、libtinfo6が入ってるので気にしなくても大丈夫</p>\n</blockquote>\n\n<h2 id=\"buildozer関連のモジュールのインストール\">Buildozer関連のモジュールのインストール</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> buildozer\npip <span class=\"nb\">install</span> <span class=\"nt\">--upgrade</span> <span class=\"nv\">Cython</span><span class=\"o\">==</span>0.29.33 virtualenv\n</code></pre></div></div>\n\n<h2 id=\"使用するフォントのインストール\">使用するフォントのインストール</h2>\n<p>どっかからダウンロードしてきてもいいけど、お手軽にaptでインストール<br />\n(あとで作業ディレクトリにコピーする)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n\n<h2 id=\"ubuntu上でアプリ実行するとき必要なライブラリのインストール\">Ubuntu上でアプリ実行するとき必要なライブラリのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libmtdev-dev\n</code></pre></div></div>\n\n<h2 id=\"アプリで使うモジュールのインストール\">アプリで使うモジュールのインストール</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pip <span class=\"nb\">install </span>kivy\n</code></pre></div></div>\n\n<h1 id=\"アプリの作成\">アプリの作成</h1>\n\n<h2 id=\"作業ディレクトリの作成\">作業ディレクトリの作成</h2>\n\n<p>どこでも良いけど、先に作ったpyenvの仮想環境<code class=\"language-plaintext highlighter-rouge\">Buildozer</code>が使えるh場所で。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mkdir</span> /work/Buildozer/app <span class=\"o\">&&</span> <span class=\"nb\">cd</span> /work/Buildozer/app\n</code></pre></div></div>\n\n<h2 id=\"フォントのコピー\">フォントのコピー</h2>\n<p>先ほどインストールしたフォントを作業ディレクトリにコピー</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir assets\ncp /usr/share/fonts/truetype/fonts-japanese-gothic.ttf assets/\n</code></pre></div></div>\n\n<h2 id=\"mainpyを作成\">main.pyを作成</h2>\n\n<p><a href=\"https://qiita.com/kouzimiso/items/1332ab62791ca5d81c5f\" target=\"_blank\">参考にしたサイト</a>\nにあったプログラムを使わせてもらった(ちょっち変更あり)。</p>\n\n<p style=\"padding:0 30px 0 10px; margin:0 0 0 30px; display: inline-block; background:#ccc; color:#222;\">\n  main.py\n</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.app</span> <span class=\"kn\">import</span> <span class=\"n\">App</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.button</span> <span class=\"kn\">import</span> <span class=\"n\">Button</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.label</span> <span class=\"kn\">import</span> <span class=\"n\">Label</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.boxlayout</span> <span class=\"kn\">import</span> <span class=\"n\">BoxLayout</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"kn\">from</span> <span class=\"nn\">kivy.utils</span> <span class=\"kn\">import</span> <span class=\"n\">platform</span>\n\n<span class=\"c1\"># フォントのパスを指定してフォントを設定する\n</span><span class=\"k\">if</span> <span class=\"n\">platform</span> <span class=\"o\">==</span> <span class=\"s\">'win'</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Windowsの場合はシステムフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">\"C:/Windows/Fonts/YuGothR.ttc\"</span><span class=\"p\">)</span>\n<span class=\"k\">elif</span> <span class=\"n\">platform</span> <span class=\"o\">==</span> <span class=\"s\">'android'</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Androidの場合はassetsフォルダ内のフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'assets/fonts-japanese-gothic.ttf'</span><span class=\"p\">)</span>\n<span class=\"k\">else</span><span class=\"p\">:</span>\n    <span class=\"c1\"># その他のプラットフォームではデフォルトフォントを使用\n</span>    <span class=\"c1\"># LabelBase.register(DEFAULT_FONT, fn_regular='DejaVuSans.ttf')\n</span>    <span class=\"c1\"># その他の場合もassetsフォルダ内のフォントを使用\n</span>    <span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'assets/fonts-japanese-gothic.ttf'</span><span class=\"p\">)</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MyApp</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># レイアウトの生成\n</span>        <span class=\"n\">layout</span> <span class=\"o\">=</span> <span class=\"n\">BoxLayout</span><span class=\"p\">(</span><span class=\"n\">orientation</span><span class=\"o\">=</span><span class=\"s\">'vertical'</span><span class=\"p\">,</span> <span class=\"n\">spacing</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">padding</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ボタンの生成\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span> <span class=\"o\">=</span> <span class=\"n\">Button</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"o\">=</span><span class=\"s\">'クリックしてください'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ボタンにコールバックを設定\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"n\">on_press</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">on_button_press</span><span class=\"p\">,</span> <span class=\"n\">on_release</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">on_button_release</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># ラベルの生成\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span> <span class=\"o\">=</span> <span class=\"n\">Label</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"o\">=</span><span class=\"s\">'ボタンがクリックされるとここに表示されます'</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># layoutにボタンとラベルを配置\n</span>        <span class=\"n\">layout</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button</span><span class=\"p\">)</span>\n        <span class=\"n\">layout</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">layout</span>\n\n    <span class=\"c1\"># ボタンが押されたたときのコールバック処理\n</span>    <span class=\"k\">def</span> <span class=\"nf\">on_button_press</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">instance</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">'ボタンが押されました!'</span>\n    \n    <span class=\"c1\"># ボタンが離されたたときのコールバック処理\n</span>    <span class=\"k\">def</span> <span class=\"nf\">on_button_release</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">instance</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">'ボタンが離されました!'</span>\n\n<span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"n\">MyApp</span><span class=\"p\">().</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"とりあえずununtu上で試してみる\">とりあえずUnuntu上で試してみる</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>python main.py\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n上半分がボタン、下半分がラベル<br />\nボタンを押す/離すとラベルの表示が変わる<br />\nXボタンで終了</p>\n</blockquote>\n\n<h2 id=\"buildozer初期化\">Buildozer初期化</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n<p>buildozer.spec が生成される</p>\n\n<h2 id=\"buildozerspecファイルの修正\">buildozer.specファイルの修正</h2>\n<p>以下の修正を行う</p>\n\n<div class=\"language-diff highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"gd\">--- buildozer.spec.org  2025-03-28 11:44:32.382972664 +0900\n</span><span class=\"gi\">+++ buildozer.spec      2025-03-28 11:52:18.977717226 +0900\n</span><span class=\"p\">@@ -13,10 +13,10 @@</span>\n source.dir = .\n\n # (list) Source files to include (let empty to include all the files)\n<span class=\"gd\">-source.include_exts = py,png,jpg,kv,atlas\n</span><span class=\"gi\">+source.include_exts = py,png,jpg,kv,atlas,ttf\n</span>\n # (list) List of inclusions using pattern matching\n<span class=\"gd\">-#source.include_patterns = assets/*,images/*.png\n</span><span class=\"gi\">+source.include_patterns = assets/*.ttf\n</span>\n # (list) Source files to exclude (let empty to not exclude anything)\n #source.exclude_exts = spec\n</code></pre></div></div>\n\n<h2 id=\"clean--build\">clean & build</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer android clean     <span class=\"c\"># 初回はやらなくてOK(FileNotFoundErrorになる)</span>\nbuildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee</span> <span class=\"nt\">-a</span> buildozer.log\n</code></pre></div></div>\n\n<p>正常にbuildが終了したら以下のように表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n初回は途中ライセンスに同意を求められるので同意するならyを入力(同意しないと終わっちゃうけど)<br />\n終了まで15分ほどかかった(環境依存なのであまりあてにしないで)<br />\n初回はダウンロードが入るのでもうちょっとかかる</p>\n</blockquote>\n\n<h1 id=\"実行\">実行</h1>\n<h2 id=\"android側の準備\">Android側の準備</h2>\n<p>adbが接続できるようになんか準備が必要(デバッグモードを有効にするとか?)だった気がするけど\n忘れちゃったので良きに計らってちょ\n(<a href=\"https://developer.android.com/studio/debug/dev-options?hl=ja\" target=\"_blank\">このへん?</a>)</p>\n\n<p>で、PCとUSBで接続しておく。</p>\n\n<h2 id=\"windows用-adbのダウンロード\">Windows用 adbのダウンロード</h2>\n<p><a href=\"https://developer.android.com/tools/releases/platform-tools?hl=ja\" target=\"_blank\">SDK Platform-Tools リリースノート</a><br />\n「ダウンロード」セクションの「SDK Platform-Tools for Windowsをダウンロード」からダウンロードし、適当なディレクトリに展開\n(例:C:\\Android_tools )</p>\n\n<blockquote>\n  <p>[!NOTE]\nPATHを通してもいいけど、AndroidStudio使うときに不安なので通さないでcdしてから実行するようにした</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nAndroidStudioが入っているのであれば、そっちを使っても可。<br />\n その場合、adb.exeは<code class=\"language-plaintext highlighter-rouge\">%LOCALAPPDATA%\\Android\\Sdk\\platform-tools</code>にある。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!NOTE]\n公式の情報ではWindowsのadbとUbuntuのadbのバージョンが同じでないとダメと書いてあるが、多少違っても大丈夫っぽい。<br />\n(てか、古いバージョンダウンロードできるんだろか?と思ったら、\n<a href=\"https://qiita.com/azumagoro/items/3a44fad53d88b3b2817b\" target=\"_blank\">Android SDK platform-tools 旧バージョン インストール</a>\nに手順書いてあった。メンドクサイけど…)</p>\n</blockquote>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動するためだと思う)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪上で展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!IMPORTANT]\n最初のadbの実行はWindows側。コマンドプロンプトやpowershellで実行する。</p>\n</blockquote>\n\n<p>以下のように表示されるはず</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>* daemon not running; starting now at tcp:XXXX\n* daemon started successfully\nList of devices attached\n== 接続されているデバイスが表示される ==\n</code></pre></div></div>\n\n<p>ちなみにサーバを停止するには以下</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>adb kill-server\n</code></pre></div></div>\n\n<h2 id=\"ダウンロードと実行\">ダウンロードと実行</h2>\n\n<p>WSL側のターミナルに戻って以下を実行</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run \n</code></pre></div></div>\n\n<p>これでプログラムがAndroidにダウンロードされて実行される。</p>\n\n<p>logcatを表示したいときは以下</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\n上記のコマンドを実行すると内部でadbが実行されるようだ。</p>\n</blockquote>\n\n<h2 id=\"usb接続せずに実行したい場合\">USB接続せずに実行したい場合</h2>\n<p>USB接続せずに実行したい場合は以下のように実行してWebサーバを起動する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer serve\n</code></pre></div></div>\n<p>WEBサーバが立ち上がったら、Androidのchrome等からアクセスし、apkファイルをダウンロードしてインストール<br />\n…できるんだけど、通常firewallが動いていてアクセスが弾かれるのでfirewallの設定変更しないといけない。<br />\n変更方法は<a href=\"https://www.fmworld.net/cs/azbyclub/qanavi/jsp/qacontents.jsp?PID=0111-2966\" target=\"_blank\">このへん</a><br />\n(試してないけど)</p>\n\n<h2 id=\"その他の方法\">その他の方法</h2>\n<p>quickshreを使うとか、USBのファイル転送モードを使えばapkファイルを転送できるので、\nあとはFiles等で表示してapkファイルとタップすればインストールできる。<br />\n(なんか野良アプリのインストール許可とか色々許可しないといけなかった気がする)</p>\n\n<h1 id=\"まとめ\">まとめ</h1>\n<p>とりあえずなんか実行できるものができたけど、実用に堪えるかはビミョー。<br />\nファイルアクセスとかネットワークアクセスとか出来るのかな?<br />\nBluetoothはどうなんだろ?<br />\nアクセス権限とかいろいろメンドクサイ処理が必要だったけど、そこまで対応してるんだろか?<br />\n気が向いたらもうちょっと調べてみるかも…</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ],
    "kivy": [
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyでドラッグで並べ替えできるリスト</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyでドラッグで並べ替えできるリスト</h1>\n      <p>kivyでドラッグで並べ替えできるリストを作った時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nドラッグで並べ替えできるリスト(AndroidでよくあるUI、<code class=\"language-plaintext highlighter-rouge\">RecycleView</code>と<code class=\"language-plaintext highlighter-rouge\">ItemTouchHelper</code>で作るんだったかな?)\nを作ってみた時のメモ。<br />\n<a href=\"https://maausa.marurm.com/wp-content/uploads/RecyclerView.gif\" target=\"_blank\">ちょっと違うけど、大体こんな感じ</a></p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nreorderablelist.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=reorderablelist.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>ソースは、表示する項目を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>と\nリスト全体を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>で構成される。<br />\n(あと、単体実行で動作するテストプログラム)<br />\n動作としては、</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>に<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を追加していきリスト化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code> をドラッグすることで並べ替え</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を左右にスワイプすることでハンドラ実行(デフォルトでは右スワイプで項目削除)\nといった感じ。</li>\n</ul>\n\n<p>テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>を<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>で囲んでスクロール可能にしています。\nスクロール不要ならそのまま配置しても可(テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">with_scroll</code>を<code class=\"language-plaintext highlighter-rouge\">False</code>に設定)。</p>\n\n<h2 id=\"reorderablelist\">ReorderableList</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>はリスト全体を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承したクラス。</p>\n\n<h3 id=\"追加したプロパティ\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>item_bg</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>item_fg</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>list_bg</td>\n      <td>リストの背景色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\n(<code class=\"language-plaintext highlighter-rouge\">orientation</code>は<code class=\"language-plaintext highlighter-rouge\">\"vertical\"</code>固定(項目を縦方向に並べるため)、\n<code class=\"language-plaintext highlighter-rouge\">size_hint_y</code>は<code class=\"language-plaintext highlighter-rouge\">None</code>固定(ScrollViewに包むため))\nのほか、<br />\n背景色の設定と、スクロール可能にするためminimum_height変更時の処理のbindを行っている。</p>\n\n<h3 id=\"項目追加処理\">項目追加処理</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">add_item</code>が項目追加処理。<br />\nパラメータは<code class=\"language-plaintext highlighter-rouge\">cls</code>で項目表示に使用するクラス(デフォルトは<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>)と、項目表示クラスの初期化パラメータを受け取る。<br />\nこれは項目に表示する内容を柔軟に切り替えられるよう、項目表示クラスを<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を継承したクラスに切り替えられるようにするため。</p>\n\n<h3 id=\"レイアウト処理\">レイアウト処理</h3>\n<p>kivyでは、レイアウトの変更命令と実際に変更が行われるまでにディレイがある。<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">add_widget(wid)</code> して直後にwid.posを読み出すと実際に追加されたあとの位置が読み出せない。<br />\nこれは、<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>では処理の予約だけ行い、実際に描画が行われるのは別のところ(<code class=\"language-plaintext highlighter-rouge\">mainloop</code>?)で\n他のウィジェットのレイアウト結果を五月雨式に反映していくため、\n描画結果がposに反映されるまでタイムラグが発生するためと思われる。</p>\n\n<p>そこで、<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>のレイアウトが変更され、処理が終了したタイミングで子ウィジェットに\nレイアウト完了を通知できるよう<code class=\"language-plaintext highlighter-rouge\">do_layout()</code>をオーバライドし、基底クラスの処理が完了した後\n各子ウィジェットの<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>をコールしている。</p>\n\n<h2 id=\"reorderableitem\">ReorderableItem</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>はリストに表示する項目を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスと<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承している。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスはドラッグ処理を実現するクラス。<br />\nもう一つの基底クラスを<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>とすることで、派生クラスのレイアウトを柔軟に設定できるようにしている。</p>\n\n<h3 id=\"追加したプロパティ-1\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>text</td>\n      <td>項目に表示する文字列</td>\n    </tr>\n    <tr>\n      <td>bg_color</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>fg_color</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ-1\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\nのほか、<br />\n項目内部の構築(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)、\n背景色の設定と、pos/size変更時にドラッグ範囲を変更する処理のbind、\nインスタンス変数の設定を行っている</p>\n\n<h3 id=\"内部ウィジェットの追加処理add_inner_widget\">内部ウィジェットの追加処理(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)</h3>\n<p>項目の内部の表示を構築する処理。<br />\nデフォルトではLabelを1個追加している。<br />\n項目の表示内容を変更したい場合は、派生クラスでこの処理をオーバライドし、\n必要な内容を追加していく。</p>\n\n<h3 id=\"ドラッグ開始処理on_touch_down\">ドラッグ開始処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_down()</code>)</h3>\n<p>まず、基底クラスのドラッグ開始処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ対象としての処理(インスタンス変数の設定)を行い、<br />\n自身の描画Canvasを親ウィジェット(<code class=\"language-plaintext highlighter-rouge\">self.parent</code>)のcanvasからcanvas.afterに繋ぎかえる。\nこれはドラッグ中の表示が前面に表示されるようにするためである。</p>\n\n<blockquote>\n  <p>[!NOTE]\n通常、add_widget()すると追加されたウィジェットの描画Canvasは親ウィジェットのCanvasに繋がれる。<br />\nこの親ウィジェットのCanvasに繋がれた描画ウィジェットは後から繋がれたものが前面に表示される。<br />\n(縦方向のBoxLayoutの場合下に表示されているウィジェットが前に表示される)<br />\n重ならない表示であれば問題ないが、ドラッグを行うとドラッグ中のウィジェットが背面に表示されることがある。<br />\nそこで、ドラッグ中のウィジェット他のウィジェットより前面に表示するため、CanvasからCanvas.afterに繋ぎかえ、前面に表示されるようにする。<br />\n仕様を読む限り、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index, canvas='after')</code>でadd_widget時にcanvas.afterに接続できるようなのだが、\n実際にはバグ(仕様制限?)により、indexが0のときのみcanvasパラメータが有効になるらしい。<br />\nこれを回避するため、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index)</code>で通常通りウィジェットを追加した後、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">after</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>として描画Canvasを繋ぎかえている。\ncanvas.afterに繋いだ描画Canvasをcanvasに戻す場合は、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">cur_index</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">children</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>    <span class=\"c1\"># canvas.after から canvasへ繋ぎかえるため\n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">remove_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>                 <span class=\"c1\"># 一旦削除して(canvasかcanvas.afterは自動的に判別してくれる) \n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"o\">=</span><span class=\"n\">cur_index</span><span class=\"p\">)</span>   <span class=\"c1\"># 再度同じ場所に挿入\n</span></code></pre></div>  </div>\n  <p>と実行する。  <code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>は描画Canvasがどこに繋がっていても探して削除してくれるので、\nそのまま実行して問題ない。</p>\n</blockquote>\n\n<h3 id=\"ドラッグ中処理on_touch_move\">ドラッグ中処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_move()</code>)</h3>\n<p>まず、基底クラスのドラッグ中処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ中の処理を行う。<br />\n親ウィジェットに繋がっている子ウィジェットをサーチして、自分以外で自分の中心がウィジェットの表示範囲内に入っているウィジェットを探す\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>)<br />\n自分の上端が対象ウィジェットの上端を超えたか、自分の下端が対象ウィジェットの下端を超えた場合は自分と対象ウィジェットを入れ替える。<br />\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>だけで判断すると、自分より高さが高いウィジェットと入れ替えるときに不都合が起こる)<br />\n位置を交換するには、自分を一旦削除(<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>)して、対象ウィジェットの位置(<code class=\"language-plaintext highlighter-rouge\">i</code>)に繋ぐ(<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>)。<br />\nその後、ドラッグを継続するので、ドラッグ開始時と同様に描画Canvasをcanvas.afterに繋ぎかえる。</p>\n\n<h3 id=\"ドラッグ終了処理on_touch_up\">ドラッグ終了処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_up()</code>)</h3>\n\n<p>まず、基底クラスのドラッグ終了処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ終了の処理を行う。<br />\nドラッグ開始/ドラッグ中処理でcanvas.afterに繋ぎかえた描画Canvasをcanvasに戻すために一旦<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>してから\n<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>する(これによりドラッグにより表示が移動していた対象ウィジェットが通常位置に戻る)。<br />\nその後、対象ウィジェットの表示位置がドラッグ開始時と変わっていなく、ドラッグした距離が設定値を超えている場合は\nスワイプ処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>または<code class=\"language-plaintext highlighter-rouge\">do_swipe_left()</code>)を実行する。</p>\n\n<h3 id=\"右へswipeしたときの処理do_swipe_right\">右へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、対象ウィジェットを削除する。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"左へswipeしたときの処理do_swipe_right\">左へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、デバッグ用にログ出力のみ。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"親ウィジェットのレイアウト完了時処理done_parent_layout\">親ウィジェットのレイアウト完了時処理(<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>)</h3>\n<p>親ウィジェットのレイアウト完了時に子ウィジェットすべてのこのメソッドがコールされる。<br />\nドラッグ中であれば必要な処理(現在位置の記憶とドラッグ中位置への移動)を行う。</p>\n\n<h1 id=\"サンプルプルグラム\">サンプルプルグラム</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nサンプルプルグラム</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=test1.py\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyで画面遷移</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyで画面遷移</h1>\n      <p>kivyで画面遷移する方法について</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\n実行時に画面を切り替えて使用する方法について試した時のメモ。<br />\nついでにAndroidアプリ化もしてみた。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\n(multi_screenって名前はなんか違う気もするけど、複数画面を制御するってことでヨシとしとこう)</p>\n\n<h2 id=\"メイン処理スクリーンマネージャのソース\">メイン処理/スクリーンマネージャのソース</h2>\n<p>multi_screen.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=multi_screen.py\"></script>\n</dev>\n\n<h2 id=\"第1画面のソース\">第1画面のソース</h2>\n<p>screen1.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen1.py\"></script>\n</dev>\n\n<h2 id=\"第2画面のソース\">第2画面のソース</h2>\n<p>screen2.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen2.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyで画面を切り替えて使用するには、<code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承したクラスを使用し、ここに各画面を登録し、\n<code class=\"language-plaintext highlighter-rouge\">self.current</code>に表示する画面の名前(<code class=\"language-plaintext highlighter-rouge\">name</code>)を設定することで切り替えるらしい。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>今回は日本語を使ってみようと思うので、日本語フォントをインストール。<br />\n有名どころではNotoSansCJKとかTAKAOとか。<br />\nubuntuだと以下でインストールできる。<br />\nNotoSansCJK は Androidでもインストールされていることが多いのかな?(手元のちょっと古いAndroidには入ってた)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n<span class=\"c\"># または</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n<p>あと、テキスト入力も試してみるので、クリップボード操作のためのライブラリをインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>xclip\n</code></pre></div></div>\n\n<h2 id=\"multi_screenpy\">multi_screen.py</h2>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">multi_screen.py</code>の内容について。</p>\n\n<p>今回は日本語を使ってみるので、フォントディレクトリの登録と日本語対応フォントをデフォルトフォントに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">get_system_fonts_dir</span><span class=\"p\">()</span>                                        <span class=\"c1\"># フォントディレクトリにシステムフォントディレクトリを登録\n</span><span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'NotoSansCJK-Regular.ttc'</span><span class=\"p\">)</span>  <span class=\"c1\"># デフォルトフォントを設定\n</span></code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承した<code class=\"language-plaintext highlighter-rouge\">ControlScreenManager</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ControlScreenManager</span><span class=\"p\">(</span><span class=\"n\">ScreenManager</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">ControlScreenManager</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># 画面間で共有する変数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n</code></pre></div></div>\n<p>ネットで検索すると画面間で共有する変数を画面間で直接やりとりする例があったが、\nソースの再利用性などを考えてスクリーンマネージャで管理することにした。<br />\nそのための設定/取得メソッド</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ターゲット文字列の設定\n</span>    <span class=\"k\">def</span> <span class=\"nf\">set_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"n\">text</span>\n    \n    <span class=\"c1\"># ターゲット文字列の取得\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span>\n</code></pre></div></div>\n\n<p>画面切り替え処理<br />\nこれも画面から他の画面に直接遷移している例があるけど、\n一旦スクリーンマネージャでうけとってから\n遷移した方が分かりやすいと思う。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># screen1への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">SlideTransition</span><span class=\"p\">(</span><span class=\"n\">direction</span><span class=\"o\">=</span><span class=\"s\">'left'</span><span class=\"p\">,</span> <span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen1'</span>\n        \n    <span class=\"c1\"># screen2への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen2</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">FadeTransition</span><span class=\"p\">(</span><span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen2'</span>\n</code></pre></div></div>\n\n<p>アプリケーションクラス</p>\n\n<p>アプリケーションクラスのbuildメソッドでは上で定義したスクリーンマネージャのインスタンスに\n各画面のインスタンスを登録し、そのインスタンスをリターンする。</p>\n\n<p>KV言語で書く方法もあるけど、画面切り替えのときに使用する名前をここで定義できるので\nソースの見通しが良くなって好み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ScreenManager1</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># スクリーンマネージャの生成\n</span>        <span class=\"n\">sm</span> <span class=\"o\">=</span> <span class=\"n\">ControlScreenManager</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 画面1を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen1</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen1'</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 画面2を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen2</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen2'</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">sm</span>\n</code></pre></div></div>\n\n<h2 id=\"screen1py\">screen1.py</h2>\n\n<p>レイアウトの定義</p>\n\n<p>kvファイルにレイアウトを書く例が多いけど、こう書くとレイアウトと処理をまとめて書けるので好み。</p>\n\n<blockquote>\n  <p>[!NOTE]\n最近知ったけど、色指定は(rr, gg, bb, aa)(各値は0~1)と書かれている例が多いけど、\n色名(“black”とか”red”とか。指定できる色名は kivyインストールディレクトリの<code class=\"language-plaintext highlighter-rouge\">util.py</code>で定義されている<code class=\"language-plaintext highlighter-rouge\">hex_colormap</code>を参照)\nの他、”#RRGGBBAA”でも指定可能(AAは省略可能)。\nどちらも文字列指定なのでダブルクォーテーションまたはシングルクォーテーションで囲む必要あり。</p>\n\n  <p>また、サイズ類は<code class=\"language-plaintext highlighter-rouge\">dp(36)</code>みたいな書き方もできるけど、文字列で<code class=\"language-plaintext highlighter-rouge\">\"36dp\"</code>と書くこともできる。\nサイズ類は数値で指定すると単位は<code class=\"language-plaintext highlighter-rouge\">px</code>になる。</p>\n</blockquote>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen1>:\n    ・・・・\n            bg_color_normal : \"#585858ff\"       # \"coloe_name\" or \"#RRGGBB\" or \"#RRGGBAA\" or (rr, gg, bb, aa) で指定\n    ・・・・\n            item_height          : '36dp'   # 数値で指定したときの単位はpx\n    ・・・・\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nAndroidアプリ化する場合、テキスト入力が下の方にあるとソフトキーボードが出てきたときに見えなくなるので\n上の方に配置しておく方が無難。<br />\nなんかうまくやる方法があるのかもしれんけど、現状分かってない。</p>\n</blockquote>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>class Screen1(Screen):\n</code></pre></div></div>\n\n<p>あとは<code class=\"language-plaintext highlighter-rouge\">Screen1</code>クラス内で動作を定義していけば良い。<br />\n画面切り替え処理はkv言語で直接スクリーンマネージャの処理をコールすると訳わかめになるので\n一旦このクラス内で受け取ってスクリーンマネージャの処理をコールするようにしている。<br />\nこの辺は好みの問題なので、お好きにどうぞ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'switch_to_screen1'</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">switch_to_screen1</span><span class=\"p\">()</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nスクリーンマネージャはScreen派生クラスの<code class=\"language-plaintext highlighter-rouge\">self.manager</code>で取得できる。</p>\n</blockquote>\n\n<h2 id=\"screen2py\">screen2.py</h2>\n\n<p>こちらも同様にレイアウトを定義しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen2>:\n    ・・・・\n</span></code></pre></div></div>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">Screen2</span><span class=\"p\">(</span><span class=\"n\">Screen</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>画面が切り替わる前にScreen1で設定した文字列を取得したいので、<code class=\"language-plaintext highlighter-rouge\">on_pre_enter()</code>をオーバーライドする。<br />\n文字列をScreen1から直接取ると画面構成変えた時に困るので、スクリーンマネージャ経由で取得するようにしている。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">on_pre_enter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"c1\"># 表示用ラベルを書き換え\n</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">get_target_string</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"NONE\"</span>       <span class=\"c1\"># 空文字が来たらNONEに書き換え\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">text</span><span class=\"si\">}</span><span class=\"s\"> が選択されました'</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">python multi_screen.py</code>で実行。<br />\n一番上のドロップダウンリストで項目を選択し、2番目の「Go to Screen 2」ボタンを押すとScreen2に切り替わる。<br />\nScreen2では画面下側の領域にScreen1のドロップダウンリストで選択した文字列が表示される。\n「Go to Screen 1」ボタンでScreen1に戻る。<br />\nScreen1のテキスト入力欄に文字列を入力し、「ADD」ボタンをクリックするとドロップダウンリストに入力した文字列が追加される。<br />\nもちろん、その文字列を選択してScreen2に切り替えればその文字列が表示される。</p>\n\n<blockquote>\n  <p>[!NOTE]\nLunuxでは日本語入力できないみたい。ただしコピペは可能なので他のところで入力してコピペすればOK。<br />\nAndroidではそのまま日本語も入力できる。</p>\n</blockquote>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>の手順でAndroidアプリ化もできる。<br />\nここの準備が終わっていれば以下のコマンドでOK。</p>\n\n<h2 id=\"multi_screenpyをリネーム\">multi_screen.pyをリネーム</h2>\n<p>python for androidはエントリーポイントがmain.pyに固定らしいので、リネーム</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mv </span>multi_screen.py main.py\n</code></pre></div></div>\n\n<h2 id=\"buildozerspec-の生成\">buildozer.spec の生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>今回は特に編集の必要なし。\n<code class=\"language-plaintext highlighter-rouge\">title</code>、<code class=\"language-plaintext highlighter-rouge\">package.name</code>、<code class=\"language-plaintext highlighter-rouge\">package.domain</code>なんかは必要なら変更してちょ。</p>\n\n<h2 id=\"build実行\">build実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動する)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪SDK Platform-Tools <span class=\"k\">for </span>Windowsを展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>で、実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、Android上で動作した。メデタシメデタシ。<br />\n文字入力もちゃんと動いてるし、改造したボタンやスピナーも動いてる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのSpinnerをカスタマイズ</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのSpinnerをカスタマイズ</h1>\n      <p>kivyのSpinner(ドロップダウンリスト)をカスタマイズする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nSpinner(ドロップダウンリスト)の項目の表示がすべて同じ色で現在選択されている項目がどれか一目で分からなかったので\n選択されている項目の色が変わるようにカスタマイズしてみた。</p>\n\n<p><a href=\"/memoBlog/2025/04/26/kivy_2.html\">kivyのButtonの色を変更する</a>ではButtonをカスタマイズして\n簡単に背景色を変更できるようにしたので、それを使えばわりとお手軽にできそうな感じ。</p>\n\n<h1 id=\"カスタマイズ内容\">カスタマイズ内容</h1>\n<ul>\n  <li>ドロップダウンの項目の表示色を選択中のものとそれ以外のもので分ける</li>\n  <li>それらの色(背景/文字)はプロパティで指定する</li>\n  <li>ドロップダウンの項目の表示高さをプロパティで指定する</li>\n</ul>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7.js\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyではドロップダウンリスト(クリックすると選択項目がぺろっと出てくるやつ)を表示するのにSpinnerウィジェットを使う。<br />\nで、クリックすると設定された項目が表示されるのだけれど、すべて同じ色(通常時、クリックした時、無効化した時の色はそれぞれ画像で指定できる)\nで表示され、現在どれを選択しているのかが分かり難い。<br />\nそこで、現在選択されている項目の色(画像でなく)を変更できるようにカスタマイズする。</p>\n\n<p>色指定に関して、<code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと項目を表示するための<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスはどちらも<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスを継承しているので、\n<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを同時に継承することで<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスに関連する処理を置き換えられる。</p>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスを作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスは特に追加する処理などはない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinnerOption</span><span class=\"p\">(</span><span class=\"n\">SpinnerOption</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n    <span class=\"k\">pass</span>\n</code></pre></div></div>\n\n<p>次に <code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinner</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinner</span><span class=\"p\">(</span><span class=\"n\">Spinner</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>追加するプロパティ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">item_selected_bg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の背景色\n</span>    <span class=\"n\">item_selected_fg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_unselected_bg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 非選択項目の背景色\n</span>    <span class=\"n\">item_unselected_fg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_height</span>          <span class=\"o\">=</span> <span class=\"n\">NumericProperty</span><span class=\"p\">(</span><span class=\"s\">'48dp'</span><span class=\"p\">)</span>               <span class=\"c1\"># 項目の高さ(デフォルトは48dp)\n</span></code></pre></div></div>\n\n<p>コンストラクタでは<code class=\"language-plaintext highlighter-rouge\">option_cls</code>のデフォルト値を<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>に設定し、基底クラスのコンストラクタを実行。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"s\">'option_cls'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">kwargs</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 項目表示用クラスが指定されていなければCustomSpinnerOptionを指定\n</span>            <span class=\"n\">kwargs</span><span class=\"p\">[</span><span class=\"s\">'option_cls'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">CustomSpinnerOption</span>\n        \n        <span class=\"c1\"># 基底クラスの初期化\n</span>        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">CustomSpinner</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>その後、追加した各プロパティと<code class=\"language-plaintext highlighter-rouge\">text</code>プロパティの変更時の処理をバインドする。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span>\n                    <span class=\"n\">text</span>                <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_bg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_bg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_fg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_fg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_height</span>         <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 項目高さ\n</span>                <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの項目の色などを変更する処理を追加。<br />\nこの処理が各プロパティの変更時の処理としてバインドされる。</p>\n\n<p>項目の一覧は<code class=\"language-plaintext highlighter-rouge\">self._dropdown.container.children</code>か<code class=\"language-plaintext highlighter-rouge\">self._dropdown.children</code>にあるので判断して取得。</p>\n\n<p>選択されている項目か否かは各項目の<code class=\"language-plaintext highlighter-rouge\">text</code>と<code class=\"language-plaintext highlighter-rouge\">self.text</code>が一致しているかどうかで判断できるので、\nこの条件で設定する色を変更。<br />\nまた、項目すべてをループするので、ついでに項目高さ(<code class=\"language-plaintext highlighter-rouge\">height</code>)も変更しておく。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ドロップダウン内の項目の高さ/背景色/文字色を更新\n</span>    <span class=\"k\">def</span> <span class=\"nf\">update_dropdown_background</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">text</span>\n        <span class=\"c1\"># 項目のリストを取得\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        \n        <span class=\"c1\"># 各項目の背景色/文字色を変更\n</span>        <span class=\"k\">for</span> <span class=\"n\">item</span> <span class=\"ow\">in</span> <span class=\"n\">items</span><span class=\"p\">:</span>\n            <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_height</span>                      <span class=\"c1\"># 項目高さ\n</span>            <span class=\"k\">if</span> <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">==</span> <span class=\"n\">text</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_bg</span>    <span class=\"c1\"># 選択中の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_fg</span>    <span class=\"c1\"># 選択中の文字色\n</span>            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_bg</span>  <span class=\"c1\"># 非選択の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_fg</span>  <span class=\"c1\"># 非選択中の文字色\n</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの更新処理をオーバーライド。<br />\nこの処理はドロップダウンの新規作成時や項目追加時にコールされる。<br />\nここに上のドロップダウンの項目の色などを変更する処理のコールを追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">_update_dropdown</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">_update_dropdown</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 項目の背景色等を更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>ついでに項目の追加処理を追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># 項目の追加\n</span>    <span class=\"k\">def</span> <span class=\"nf\">add_item</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">values</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>以上でカスタマイズは終了。</p>\n\n<h1 id=\"動作確認プログラム\">動作確認プログラム</h1>\n<p>このファイルを単体で実行すれば動作確認プログラムが動作する。<br />\n動作確認ではAddボタンをクリックする度にドロップダウンリストの項目が追加されるようになっている。<br />\nSpinnerのボタンをクリックするとドロップダウンリストが表示され、現在選択されている項目が他の色で表示されている。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのButtonの色を変更する</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのButtonの色を変更する</h1>\n      <p>kivyのButtonの色を変更する方法あれこれ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nボタン<code class=\"language-plaintext highlighter-rouge\">Button</code>の色を変更しようとすると、なかなか大変なので色々試してみたメモ。</p>\n\n<h1 id=\"画像ファイルを使用して変更する\">画像ファイルを使用して変更する</h1>\n\n<p>これが通常の方法。<br />\nプロパティ<code class=\"language-plaintext highlighter-rouge\">background_normal</code>、<code class=\"language-plaintext highlighter-rouge\">background_down</code>、<code class=\"language-plaintext highlighter-rouge\">background_disabled_normal</code>、<code class=\"language-plaintext highlighter-rouge\">background_disabled_down</code>に\nそれぞれに表示する画像ファイルを指定する。<br />\n単色で表示するなら1✕1pixelの画像ファイルでかまわない。</p>\n\n<h2 id=\"ソース\">ソース</h2>\n<p>ソースはこんな感じ。<br />\n別途画像ファイル<code class=\"language-plaintext highlighter-rouge\">lightgray.png'</code>、<code class=\"language-plaintext highlighter-rouge\">red.png</code>、<code class=\"language-plaintext highlighter-rouge\">gray.png</code>をカレントディレクトリに用意しておく。</p>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。</p>\n<dev class=\"accordion_head_close\"></dev>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">if</span> <span class=\"n\">__name__</span> <span class=\"o\">==</span> <span class=\"s\">'__main__'</span><span class=\"p\">:</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.app</span> <span class=\"kn\">import</span> <span class=\"n\">App</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.uix.button</span> <span class=\"kn\">import</span> <span class=\"n\">Button</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">kivy.lang</span> <span class=\"kn\">import</span> <span class=\"n\">Builder</span>\n\n    <span class=\"c1\"># GUIlレイアウト\n</span>    <span class=\"n\">Layout</span> <span class=\"o\">=</span> <span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">'''\n# この中はインデントに意味があるので余計なインデントを入れてはいけない\nBoxLayout:\n    orientation:'horizontal'\n    \n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n    Button:\n        id              : button_test\n        text            : \"TEST\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_test()\n        background_normal: 'lightgray.png'\n        background_down: 'red.png'\n        background_disabled_normal: 'gray.png'\n        background_disabled_down: 'gray.png'\n\n    Button:\n        id              : button_ctrl\n        text            : \"Ena/Dis\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_ctrl()\n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n'''</span>\n    <span class=\"p\">)</span>\n\n    <span class=\"k\">class</span> <span class=\"nc\">MyApp</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n        <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n            <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">__init__</span><span class=\"p\">()</span>\n            \n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span> <span class=\"o\">=</span> <span class=\"n\">Layout</span><span class=\"p\">.</span><span class=\"n\">ids</span><span class=\"p\">.</span><span class=\"n\">button_test</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_ctrl</span> <span class=\"o\">=</span> <span class=\"n\">Layout</span><span class=\"p\">.</span><span class=\"n\">ids</span><span class=\"p\">.</span><span class=\"n\">button_ctrl</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"n\">Layout</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">on_test</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'pressed'</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">def</span> <span class=\"nf\">on_ctrl</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span><span class=\"p\">.</span><span class=\"n\">disabled</span> <span class=\"o\">=</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">button_test</span><span class=\"p\">.</span><span class=\"n\">disabled</span>\n            \n    <span class=\"n\">MyApp</span><span class=\"p\">().</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<h2 id=\"動作\">動作</h2>\n\n<p>実行すると、Buttonが2つ表示され、TESTボタンが指定されたファイルのイメージで表示される。<br />\nEna/DisボタンをクリックするとTESTボタンのDisable/Enableが切り替えらる。</p>\n\n<h1 id=\"base64エンコードデータで指定\">Base64エンコードデータで指定</h1>\n\n<p>画像ファイルを使用すると、使用する色の分だけ画像ファイルを用意し、処理を流用する度に\n忘れずにすべてのファイルをコピーしないといけない。<br />\nそこで、画像ファイルをbase64エンコードした文字列をpyファイル(またはkvファイル)に保存する方法を試してみる。</p>\n\n<p>まず、上で用意したpngファイルを以下のコマンドでbase64エンコード(前に特定の文字列を付加)する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">echo</span> <span class=\"s2\">\"data:image/png;base64,</span><span class=\"sb\">`</span><span class=\"nb\">base64</span> <span class=\"nt\">-w</span> 0 ≪pngファイル≫<span class=\"sb\">`</span><span class=\"s2\">\"</span>\n</code></pre></div></div>\n<p>付加されている<code class=\"language-plaintext highlighter-rouge\">data:image/png;base64,</code>は続くデータがpngイメージであることを示している。</p>\n\n<p>出力された文字列を以下のようにファイル名の代わりに記載する。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        background_normal           : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2M4fPjwfwAH3wNJzT7giwAAAABJRU5ErkJggg=='\n        background_down             : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAANSURBVBhXY3gro/IfAAVUAi3GPZKdAAAAAElFTkSuQmCC'\n        background_disabled_normal  : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2Oor6//DwAFewJ9z0FqqgAAAABJRU5ErkJggg=='\n        background_disabled_down    : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGHaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj48dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPjwvcmRmOkRlc2NyaXB0aW9uPjwvcmRmOlJERj48L3g6eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz4slJgLAAAADUlEQVQYV2Oor6//DwAFewJ9z0FqqgAAAABJRU5ErkJggg=='\n</code></pre></div></div>\n\n<p>これにより、pngファイルを削除しても動作するようになる。</p>\n\n<p>ただし、pyファイル(またはkvファイル)が大きくなってしまうことと、一目で指定されている色が把握できないというデメリットがある。</p>\n\n<h1 id=\"canvasbefor-で指定する\">canvas.befor で指定する</h1>\n\n<p>画像ファイルを用意すること自体面倒なので、RGBA値で指定する方法はないかと考えてみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">Label</code>と同様に<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>で背景色を指定してみることを試してみたが、うまくいかなかった。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    Button:\n        ・・・\n        canvas.before:\n            Color:\n                rgba    : (1,0,0,1)\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n</code></pre></div></div>\n<p>これは<code class=\"language-plaintext highlighter-rouge\">Button</code>が<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>をサポートしていないわけではなく、\nちゃんと指定通りに描画しているが、\nその前面に<code class=\"language-plaintext highlighter-rouge\">Button</code>のBackground_XXXが表示されているためらしい。</p>\n\n<p>それならば、Buttonの表示を透明にしてやれば<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>の表示が見えるはずである。<br />\n以下のように変更して試してみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">background_color : (0, 0, 0, 0)</code>が透明色にしている部分で、<br />\n<code class=\"language-plaintext highlighter-rouge\">background_XXX</code>をヌル文字列にしているのはすべてのピクセルを(255,255,255,255)にするためであるが、\n透明になるのであまり関係ないかもしれない。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    Button:\n        ・・・\n        background_normal           : ''\n        background_down             : ''\n        background_disabled_normal  : ''\n        background_disabled_down    : ''\n        background_color            : (0, 0, 0, 0) # 透明\n        canvas.before:\n            Color:\n                rgba    : (1,0,0,1)\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n</code></pre></div></div>\n<p>これでボタンが赤色になった。<br />\nしかし、これでばボタンを押下した時やDisableにした時に色が変化しない。</p>\n\n<p>そこで、さらに以下のようにして押下した時やDisableにした時に色が変わるようにしてみた。<br />\n<code class=\"language-plaintext highlighter-rouge\">canvas.before.Color.rgba</code>を <code class=\"language-plaintext highlighter-rouge\">self.disabled</code>と<code class=\"language-plaintext highlighter-rouge\">self.state</code>によって変更している。<br />\n下にGUIリソース定義部分全体を記載しておく。</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># 分かりやすいようにグローバル変数で定義しておく\n#:set BG_COLOR_NORMAL   (0.75, 0.75, 0.75, 1.0)\n#:set BG_COLOR_DOWN     (1.00, 0.00, 0.00, 1.0)\n#:set BG_COLOR_DISABLED (0.50, 0.50, 0.50, 1.0)\n\nBoxLayout:\n    orientation:'horizontal'\n    \n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n    Button:\n        id              : button_test\n        text            : \"TEST\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_test()\n        background_normal           : ''\n        background_down             : ''\n        background_disabled_normal  : ''\n        background_disabled_down    : ''\n        background_color            : (0, 0, 0, 0) # 透明\n        canvas.before:\n            Color:\n                rgba    : BG_COLOR_DISABLED if self.disabled else BG_COLOR_NORMAL if self.state == 'normal' else BG_COLOR_DOWN\n            Rectangle:\n                pos     : self.pos\n                size    : self.size\n    Button:\n        id              : button_ctrl\n        text            : \"Ena/Dis\"\n        size_hint       : (0.2, 0.1)\n        pos_hint        : {'center_x': 0.5, 'center_y': 0.5}\n        on_press        : app.on_ctrl()\n    BoxLayout:\n        orientation     : 'vertical'\n        size_hint       : (0.3, 0.1)\n</code></pre></div></div>\n\n<h1 id=\"カスタムボタンウィジェットを作成する\">カスタムボタンウィジェットを作成する</h1>\n\n<p>上でとりあえず目的は達成されたが、ボタンを配置する度に上記のような設定を書くのは面倒なので、\nカスタムボタンウィジェットを作成してみる。</p>\n\n<h2 id=\"ソース-1\">ソース</h2>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/98907d88de7106b1c30a0be4b39aa77f\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/98907d88de7106b1c30a0be4b39aa77f.js\"></script>\n</dev>\n\n<h2 id=\"解説\">解説</h2>\n<p>上の「canvas.befor で指定する」の方法をkv言語を使用せずpythonで定義している。<br />\nそれぞれの色を自由に変更できるようにプロパティを用意した。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_normal</code>   通常時の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_down</code>     押下時の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg_color_disabled</code> 無効時の色</li>\n</ul>\n\n<p>また、そのままだとボタンを並べて表示したときに境界が分からなくなるので、枠線を描画するため、以下のプロパティを用意した。<br />\nデフォルトは黒で幅1。</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">border_color</code>    枠線の色</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">border_width</code>    枠線の幅</li>\n</ul>\n\n<p>初期化時にボタン本体の背景を透明にし、<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>に描画命令を追加して背景の描画(背景色と枠線)することと、\n状態、位置、プロパティが変化したときに描画パラメータを再設定する処理をbindしている。<br />\nbindした処理では状態や位置に合わせて<code class=\"language-plaintext highlighter-rouge\">canvas.before</code>の処理のパラメータを変更している。</p>\n\n<p>枠線を描画するための<code class=\"language-plaintext highlighter-rouge\">Line</code>はwidth×2の幅で描画されるようなので、本来の矩形のwidthの半分だけ内側に描画されるようにしている。</p>\n\n<p>GUIレイアウトを定義するときは、通常のButtonと同様のプロパティ設定で配置できる。<br />\nもちろん、上の通常時の色、押下時の色、無効時の色を変更したい場合は追加で指定すれば良い。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのスクロール可能なラベルのカスタムウィジェット</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのスクロール可能なラベルのカスタムウィジェット</h1>\n      <p>PythonプログラムでGUIを作成するkivyでスクロール可能なラベルのカスタムウィジェットを作ったメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>でお試しプログラムを作っていた時、\nログ出力をスクロール可能にしたい(TeraTermみたいなターミナル表示のイメージ)と思い作ってみたけれど、\n汎用的に使えそうな気がしたのでカスタムウィジェットとしてまとめてみた。</p>\n\n<h1 id=\"解説\">解説</h1>\n<p>解説するほど理解してないけど…<br />\nkivyでは文字列を表示するのにLabelウィジェットを使うらしい(AndroidStudioでいうことろのTextView?)。<br />\nで、表示をスクロールするにはScrollViewウィジェットを使う(AndroidStudioでもScrollView)。<br />\n文字列をスクロールするには、ScrollViewの中にLabelを配置してやれば良いのだけれど、「配置しておしまい」という訳でもなく、\n色々と細々と下処理が必要になる。</p>\n\n<p>まずは、表示をどの程度残すか。TeraTermやWindowsTerminalでもスクロールバッファ行数や履歴のサイズとして指定する項目。<br />\nこれを設定できないと際限なく表示が増えてしまうので。<br />\nこれを実現するため、表示内容をdequeに保存し、新規行を追加した際にあふれた分を自動的に破棄するようにしている。</p>\n\n<p>また、テキストが表示領域からあふれた際に自動的にスクロールするようにするため、ラベルの<code class=\"language-plaintext highlighter-rouge\">texture_size</code>プロパティが変更された際に\nイベントハンドラ<code class=\"language-plaintext highlighter-rouge\">update_label_size</code>がコールされるように設定。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span><span class=\"n\">texture_size</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_label_size</span><span class=\"p\">)</span>\n</code></pre></div></div>\n<p>ここでラベルのサイズをテクスチャサイズに合わせて変更している。<br />\nまた、このときラベルサイズがスクロールビューのサイズを超えた時、<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>に設定することで\n最下行を表示できるようにしている。<br />\nなお、ラベルサイズがスクロールビューのサイズ以下の時に<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>にしてしまうと下付き表示になってしまうため、\nこの条件では<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">1,0</code>にしている。<br />\nラベルサイズがスクロールビューのサイズ以上の時に常に<code class=\"language-plaintext highlighter-rouge\">self.scroll_y</code>を<code class=\"language-plaintext highlighter-rouge\">0,0</code>にすると\n以前の内容を確認するためにスクロールしている状態で新しい行が表示されると最下行までスクロールしてしまうので、\n<code class=\"language-plaintext highlighter-rouge\">0.0</code>に設定するのはスクロールビューのサイズを超えた時だけにしている。</p>\n\n<h1 id=\"使い方\">使い方</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">ScrollLabel</code>クラスをインポートして使ってください。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">scrolllabel</span> <span class=\"kn\">import</span> <span class=\"n\">ScrollLabel</span>\n</code></pre></div></div>\n\n<p>設定できるプロパティは<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>のプロパティに<code class=\"language-plaintext highlighter-rouge\">rows</code>(バッファ行数)を追加しています。<br />\nプロパティに<code class=\"language-plaintext highlighter-rouge\">rows</code>は初期化時にのみ変更可能です。\n初期化後(実際は最初のテキスト出力後)は変更してもバッファ行数に反映されません。</p>\n\n<p>テキストを追加するには<code class=\"language-plaintext highlighter-rouge\">add_text(text)</code>を使用します。\n引数<code class=\"language-plaintext highlighter-rouge\">end</code>を指定することで行末文字を変更できます(デフォルトは<code class=\"language-plaintext highlighter-rouge\">\\n</code>)。  <br />\nテキストを消去するには<code class=\"language-plaintext highlighter-rouge\">clear_text()</code>を使用します。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>gistにupしたので、gistの埋め込みリンク貼っとく。<br />\nもしダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n\n<dev class=\"accordion_head\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6c3880bd0c844cad2279e3a4c45d15e7.js?file=scrolllabel.py\"></script>\n</dev>\n\n<p>また、gistには実際に使用する際の例(レイアウトに Kv language使用/python使用)も載せてあるのでよろしかったら見てください。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n"
    ]
  },
  "static_files": [
    {
      "name": "jquery.floatingscroll.css",
      "collection": null,
      "path": "/assets/css/jquery.floatingscroll.css",
      "basename": "jquery.floatingscroll",
      "extname": ".css",
      "modified_time": "2025-06-09 04:55:52 +0000"
    },
    {
      "name": "jquery.floatingscroll.min.js",
      "collection": null,
      "path": "/assets/js/jquery.floatingscroll.min.js",
      "basename": "jquery.floatingscroll.min",
      "extname": ".js",
      "modified_time": "2025-06-09 04:55:52 +0000"
    },
    {
      "name": "main.js",
      "collection": null,
      "path": "/assets/js/main.js",
      "basename": "main",
      "extname": ".js",
      "modified_time": "2025-06-09 04:55:52 +0000"
    },
    {
      "name": "favicon.ico",
      "collection": null,
      "path": "/favicon.ico",
      "basename": "favicon",
      "extname": ".ico",
      "modified_time": "2025-06-09 04:55:52 +0000"
    },
    {
      "name": "install.cmd",
      "collection": null,
      "path": "/install.cmd",
      "basename": "install",
      "extname": ".cmd",
      "modified_time": "2025-06-09 04:55:52 +0000"
    },
    {
      "name": "TinyYOLO_2_1.png",
      "collection": null,
      "path": "/misc/TinyYOLO_2_1.png",
      "basename": "TinyYOLO_2_1",
      "extname": ".png",
      "modified_time": "2025-06-09 04:55:52 +0000"
    },
    {
      "name": "WEB_BT_API_2024-07-29_075522.mp4",
      "collection": null,
      "path": "/misc/WEB_BT_API_2024-07-29_075522.mp4",
      "basename": "WEB_BT_API_2024-07-29_075522",
      "extname": ".mp4",
      "modified_time": "2025-06-09 04:55:52 +0000"
    },
    {
      "name": "diskimage_shrink.sh",
      "collection": null,
      "path": "/misc/stock/diskimage_shrink.sh",
      "basename": "diskimage_shrink",
      "extname": ".sh",
      "modified_time": "2025-06-09 04:55:52 +0000"
    },
    {
      "name": "expand_partition.sh",
      "collection": null,
      "path": "/misc/stock/expand_partition.sh",
      "basename": "expand_partition",
      "extname": ".sh",
      "modified_time": "2025-06-09 04:55:52 +0000"
    },
    {
      "name": "copse-regular-webfont.eot",
      "collection": null,
      "path": "/assets/fonts/copse-regular-webfont.eot",
      "basename": "copse-regular-webfont",
      "extname": ".eot",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "copse-regular-webfont.svg",
      "collection": null,
      "path": "/assets/fonts/copse-regular-webfont.svg",
      "basename": "copse-regular-webfont",
      "extname": ".svg",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "copse-regular-webfont.ttf",
      "collection": null,
      "path": "/assets/fonts/copse-regular-webfont.ttf",
      "basename": "copse-regular-webfont",
      "extname": ".ttf",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "copse-regular-webfont.woff",
      "collection": null,
      "path": "/assets/fonts/copse-regular-webfont.woff",
      "basename": "copse-regular-webfont",
      "extname": ".woff",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-bold-webfont.eot",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-bold-webfont.eot",
      "basename": "quattrocentosans-bold-webfont",
      "extname": ".eot",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-bold-webfont.svg",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-bold-webfont.svg",
      "basename": "quattrocentosans-bold-webfont",
      "extname": ".svg",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-bold-webfont.ttf",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-bold-webfont.ttf",
      "basename": "quattrocentosans-bold-webfont",
      "extname": ".ttf",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-bold-webfont.woff",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-bold-webfont.woff",
      "basename": "quattrocentosans-bold-webfont",
      "extname": ".woff",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-bolditalic-webfont.eot",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-bolditalic-webfont.eot",
      "basename": "quattrocentosans-bolditalic-webfont",
      "extname": ".eot",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-bolditalic-webfont.svg",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-bolditalic-webfont.svg",
      "basename": "quattrocentosans-bolditalic-webfont",
      "extname": ".svg",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-bolditalic-webfont.ttf",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-bolditalic-webfont.ttf",
      "basename": "quattrocentosans-bolditalic-webfont",
      "extname": ".ttf",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-bolditalic-webfont.woff",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-bolditalic-webfont.woff",
      "basename": "quattrocentosans-bolditalic-webfont",
      "extname": ".woff",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-italic-webfont.eot",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-italic-webfont.eot",
      "basename": "quattrocentosans-italic-webfont",
      "extname": ".eot",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-italic-webfont.svg",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-italic-webfont.svg",
      "basename": "quattrocentosans-italic-webfont",
      "extname": ".svg",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-italic-webfont.ttf",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-italic-webfont.ttf",
      "basename": "quattrocentosans-italic-webfont",
      "extname": ".ttf",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-italic-webfont.woff",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-italic-webfont.woff",
      "basename": "quattrocentosans-italic-webfont",
      "extname": ".woff",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-regular-webfont.eot",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-regular-webfont.eot",
      "basename": "quattrocentosans-regular-webfont",
      "extname": ".eot",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-regular-webfont.svg",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-regular-webfont.svg",
      "basename": "quattrocentosans-regular-webfont",
      "extname": ".svg",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-regular-webfont.ttf",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-regular-webfont.ttf",
      "basename": "quattrocentosans-regular-webfont",
      "extname": ".ttf",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "quattrocentosans-regular-webfont.woff",
      "collection": null,
      "path": "/assets/fonts/quattrocentosans-regular-webfont.woff",
      "basename": "quattrocentosans-regular-webfont",
      "extname": ".woff",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "background.png",
      "collection": null,
      "path": "/assets/images/background.png",
      "basename": "background",
      "extname": ".png",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "body-background.png",
      "collection": null,
      "path": "/assets/images/body-background.png",
      "basename": "body-background",
      "extname": ".png",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "bullet.png",
      "collection": null,
      "path": "/assets/images/bullet.png",
      "basename": "bullet",
      "extname": ".png",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "hr.gif",
      "collection": null,
      "path": "/assets/images/hr.gif",
      "basename": "hr",
      "extname": ".gif",
      "modified_time": "2024-08-06 23:48:55 +0000"
    },
    {
      "name": "octocat-logo.svg",
      "collection": null,
      "path": "/assets/images/octocat-logo.svg",
      "basename": "octocat-logo",
      "extname": ".svg",
      "modified_time": "2024-08-06 23:48:55 +0000"
    }
  ],
  "source": "/github/workspace/.",
  "destination": "/github/workspace/./_site",
  "collections_dir": "",
  "plugins_dir": "010c7930c1c005d5bb438403b773f481",
  "layouts_dir": "_layouts",
  "data_dir": "_data",
  "includes_dir": "_includes",
  "safe": true,
  "include": [
    ".htaccess"
  ],
  "exclude": [
    "gems",
    "Gemfile",
    "Gemfile.lock",
    "compile.sh",
    "server.sh",
    "compile.cmd",
    "server.cmd"
  ],
  "keep_files": [
    ".git",
    ".svn"
  ],
  "encoding": "utf-8",
  "markdown_ext": "markdown,mkdown,mkdn,mkd,md",
  "strict_front_matter": false,
  "show_drafts": null,
  "limit_posts": 0,
  "future": false,
  "unpublished": false,
  "whitelist": [
    "jekyll-coffeescript",
    "jekyll-commonmark-ghpages",
    "jekyll-feed",
    "jekyll-gist",
    "jekyll-github-metadata",
    "jekyll-paginate",
    "jekyll-redirect-from",
    "jekyll-seo-tag",
    "jekyll-sitemap",
    "jekyll-avatar",
    "jemoji",
    "jekyll-mentions",
    "jekyll-relative-links",
    "jekyll-optional-front-matter",
    "jekyll-readme-index",
    "jekyll-default-layout",
    "jekyll-titles-from-headings",
    "jekyll-include-cache",
    "jekyll-octicons",
    "jekyll-remote-theme"
  ],
  "plugins": [
    "jekyll-github-metadata",
    "jekyll-coffeescript",
    "jekyll-commonmark-ghpages",
    "jekyll-gist",
    "jekyll-paginate",
    "jekyll-relative-links",
    "jekyll-optional-front-matter",
    "jekyll-readme-index",
    "jekyll-default-layout",
    "jekyll-titles-from-headings"
  ],
  "markdown": "kramdown",
  "highlighter": "rouge",
  "lsi": false,
  "excerpt_separator": "\n\n",
  "incremental": false,
  "detach": false,
  "port": "4000",
  "host": "127.0.0.1",
  "baseurl": "/memoBlog",
  "show_dir_listing": false,
  "permalink": "date",
  "paginate_path": "/page:num",
  "timezone": null,
  "quiet": false,
  "verbose": true,
  "defaults": [

  ],
  "liquid": {
    "error_mode": "warn",
    "strict_filters": false,
    "strict_variables": false
  },
  "rdiscount": {
    "extensions": [

    ]
  },
  "redcarpet": {
    "extensions": [

    ]
  },
  "kramdown": {
    "auto_ids": true,
    "toc_levels": "1..6",
    "entity_output": "as_char",
    "smart_quotes": "lsquo,rsquo,ldquo,rdquo",
    "input": "GFM",
    "hard_wrap": false,
    "guess_lang": true,
    "footnote_nr": 1,
    "show_warnings": false,
    "gfm_quirks": "paragraph_end",
    "syntax_highlighter_opts": {
      "default_lang": "plaintext",
      "guess_lang": true
    },
    "template": "",
    "math_engine": "mathjax",
    "syntax_highlighter": "rouge",
    "coderay": {
    },
    "auto_ids": true,
    "toc_levels": "1..6",
    "entity_output": "as_char",
    "smart_quotes": "lsquo,rsquo,ldquo,rdquo",
    "input": "GFM",
    "hard_wrap": false,
    "guess_lang": true,
    "footnote_nr": 1,
    "show_warnings": false,
    "gfm_quirks": "paragraph_end",
    "syntax_highlighter_opts": {
      "default_lang": "plaintext",
      "guess_lang": true
    },
    "template": "",
    "math_engine": "mathjax",
    "syntax_highlighter": "rouge",
    "coderay": {
    }
  },
  "jailed": false,
  "theme": "jekyll-theme-leap-day",
  "sass": {
    "style": "compressed"
  },
  "encding": "utf-8",
  "title": "いっぺーちゃんのメモブログ",
  "description": "作業メモ",
  "show_downloads": false,
  "gist": {
    "noscript": false
  },
  "url": "https://ippei8jp.github.io",
  "github": {
    "api_url": "https://api.github.com",
    "archived": false,
    "baseurl": "/memoBlog",
    "build_revision": "078fa3dd47f4f14e9744e0be22d8dfdc26067cdd",
    "clone_url": "https://github.com/ippei8jp/memoBlog.git",
    "contributors": [
      {
        "login": "ippei8jp",
        "id": 48367499,
        "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
        "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
        "gravatar_id": "",
        "url": "https://api.github.com/users/ippei8jp",
        "html_url": "https://github.com/ippei8jp",
        "followers_url": "https://api.github.com/users/ippei8jp/followers",
        "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
        "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
        "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
        "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
        "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
        "repos_url": "https://api.github.com/users/ippei8jp/repos",
        "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
        "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
        "type": "User",
        "user_view_type": "public",
        "site_admin": false,
        "contributions": 321
      }
    ],
    "disabled": false,
    "environment": "production",
    "help_url": "https://docs.github.com",
    "hostname": "github.com",
    "is_project_page": true,
    "is_user_page": false,
    "issues_url": "https://github.com/ippei8jp/memoBlog/issues",
    "language": "SCSS",
    "latest_release": false,
    "license": null,
    "organization_members": null,
    "owner": {
      "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
      "bio": null,
      "blog": "",
      "collaborators": null,
      "company": null,
      "created_at": "2019-03-08 21:12:28 UTC",
      "description": null,
      "email": null,
      "followers": 0,
      "following": 0,
      "has_organization_projects": null,
      "has_repository_projects": null,
      "hireable": null,
      "html_url": "https://github.com/ippei8jp",
      "id": 48367499,
      "is_verified": null,
      "location": null,
      "login": "ippei8jp",
      "name": "いっぺーちゃん",
      "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
      "public_gists": 26,
      "public_repos": 29,
      "type": "User",
      "updated_at": "2025-03-07 02:07:53 UTC"
    },
    "owner_display_name": "いっぺーちゃん",
    "owner_gravatar_url": "https://github.com/ippei8jp.png",
    "owner_name": "ippei8jp",
    "owner_url": "https://github.com/ippei8jp",
    "pages_env": "production",
    "pages_hostname": "github.io",
    "private": false,
    "project_tagline": null,
    "project_title": "memoBlog",
    "public_repositories": [
      {
        "id": 184473642,
        "node_id": "MDEwOlJlcG9zaXRvcnkxODQ0NzM2NDI=",
        "name": "3Dweb_mouse",
        "full_name": "ippei8jp/3Dweb_mouse",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/3Dweb_mouse",
        "description": "WEB 3D表示テストプログラム",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse",
        "forks_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse/deployments",
        "created_at": "2019-05-01 19:58:32 UTC",
        "updated_at": "2019-05-19 03:45:51 UTC",
        "pushed_at": "2019-05-19 03:45:49 UTC",
        "git_url": "git://github.com/ippei8jp/3Dweb_mouse.git",
        "ssh_url": "git@github.com:ippei8jp/3Dweb_mouse.git",
        "clone_url": "https://github.com/ippei8jp/3Dweb_mouse.git",
        "svn_url": "https://github.com/ippei8jp/3Dweb_mouse",
        "homepage": null,
        "size": 11276,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "JavaScript",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 4
          }
        ]
      },
      {
        "id": 188333291,
        "node_id": "MDEwOlJlcG9zaXRvcnkxODgzMzMyOTE=",
        "name": "3Dweb_mouse_electron",
        "full_name": "ippei8jp/3Dweb_mouse_electron",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/3Dweb_mouse_electron",
        "description": "WEB 3D表示テストプログラム electron対応版",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron",
        "forks_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/3Dweb_mouse_electron/deployments",
        "created_at": "2019-05-24 01:45:23 UTC",
        "updated_at": "2019-05-26 22:54:20 UTC",
        "pushed_at": "2020-07-07 05:56:51 UTC",
        "git_url": "git://github.com/ippei8jp/3Dweb_mouse_electron.git",
        "ssh_url": "git@github.com:ippei8jp/3Dweb_mouse_electron.git",
        "clone_url": "https://github.com/ippei8jp/3Dweb_mouse_electron.git",
        "svn_url": "https://github.com/ippei8jp/3Dweb_mouse_electron",
        "homepage": null,
        "size": 11265,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "JavaScript",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 4
          }
        ]
      },
      {
        "id": 455697685,
        "node_id": "R_kgDOGyllFQ",
        "name": "BLE_PARAM_CONFIG",
        "full_name": "ippei8jp/BLE_PARAM_CONFIG",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/BLE_PARAM_CONFIG",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG",
        "forks_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/BLE_PARAM_CONFIG/deployments",
        "created_at": "2022-02-04 21:10:53 UTC",
        "updated_at": "2022-02-07 03:04:33 UTC",
        "pushed_at": "2022-02-07 03:04:30 UTC",
        "git_url": "git://github.com/ippei8jp/BLE_PARAM_CONFIG.git",
        "ssh_url": "git@github.com:ippei8jp/BLE_PARAM_CONFIG.git",
        "clone_url": "https://github.com/ippei8jp/BLE_PARAM_CONFIG.git",
        "svn_url": "https://github.com/ippei8jp/BLE_PARAM_CONFIG",
        "homepage": null,
        "size": 50,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "C",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "main",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 2
          }
        ]
      },
      {
        "id": 194766723,
        "node_id": "MDEwOlJlcG9zaXRvcnkxOTQ3NjY3MjM=",
        "name": "BlogTest3",
        "full_name": "ippei8jp/BlogTest3",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/BlogTest3",
        "description": "ブログテスト その3",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/BlogTest3",
        "forks_url": "https://api.github.com/repos/ippei8jp/BlogTest3/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/BlogTest3/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/BlogTest3/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/BlogTest3/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/BlogTest3/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/BlogTest3/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/BlogTest3/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/BlogTest3/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/BlogTest3/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/BlogTest3/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/BlogTest3/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/BlogTest3/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/BlogTest3/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/BlogTest3/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/BlogTest3/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/BlogTest3/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/BlogTest3/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/BlogTest3/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/BlogTest3/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/BlogTest3/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/BlogTest3/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/BlogTest3/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/BlogTest3/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/BlogTest3/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/BlogTest3/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/BlogTest3/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/BlogTest3/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/BlogTest3/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/BlogTest3/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/BlogTest3/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/BlogTest3/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/BlogTest3/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/BlogTest3/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/BlogTest3/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/BlogTest3/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/BlogTest3/deployments",
        "created_at": "2019-07-02 01:32:29 UTC",
        "updated_at": "2019-07-16 05:49:20 UTC",
        "pushed_at": "2019-07-16 05:49:18 UTC",
        "git_url": "git://github.com/ippei8jp/BlogTest3.git",
        "ssh_url": "git@github.com:ippei8jp/BlogTest3.git",
        "clone_url": "https://github.com/ippei8jp/BlogTest3.git",
        "svn_url": "https://github.com/ippei8jp/BlogTest3",
        "homepage": null,
        "size": 72,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "CSS",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": true,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 43
          }
        ]
      },
      {
        "id": 461639304,
        "node_id": "R_kgDOG4QOiA",
        "name": "BT_SPP_CB",
        "full_name": "ippei8jp/BT_SPP_CB",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/BT_SPP_CB",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB",
        "forks_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/BT_SPP_CB/deployments",
        "created_at": "2022-02-20 22:59:18 UTC",
        "updated_at": "2022-02-21 03:38:30 UTC",
        "pushed_at": "2022-02-21 03:38:26 UTC",
        "git_url": "git://github.com/ippei8jp/BT_SPP_CB.git",
        "ssh_url": "git@github.com:ippei8jp/BT_SPP_CB.git",
        "clone_url": "https://github.com/ippei8jp/BT_SPP_CB.git",
        "svn_url": "https://github.com/ippei8jp/BT_SPP_CB",
        "homepage": null,
        "size": 36,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "C",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "main",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 2
          }
        ]
      },
      {
        "id": 459412181,
        "node_id": "R_kgDOG2IS1Q",
        "name": "BT_SPP_VFS",
        "full_name": "ippei8jp/BT_SPP_VFS",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/BT_SPP_VFS",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS",
        "forks_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/BT_SPP_VFS/deployments",
        "created_at": "2022-02-15 03:23:36 UTC",
        "updated_at": "2022-02-16 03:51:43 UTC",
        "pushed_at": "2022-02-21 05:43:16 UTC",
        "git_url": "git://github.com/ippei8jp/BT_SPP_VFS.git",
        "ssh_url": "git@github.com:ippei8jp/BT_SPP_VFS.git",
        "clone_url": "https://github.com/ippei8jp/BT_SPP_VFS.git",
        "svn_url": "https://github.com/ippei8jp/BT_SPP_VFS",
        "homepage": null,
        "size": 59,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "C",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "main",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 8
          }
        ]
      },
      {
        "id": 275068951,
        "node_id": "MDEwOlJlcG9zaXRvcnkyNzUwNjg5NTE=",
        "name": "CustomVisionExport",
        "full_name": "ippei8jp/CustomVisionExport",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/CustomVisionExport",
        "description": "Azure CustomVisionで作成した分類器のモデルをExportしたデータをTensrflowLiteやopenVINOで使用できるようにコンバートする",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/CustomVisionExport",
        "forks_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/CustomVisionExport/deployments",
        "created_at": "2020-06-26 03:56:04 UTC",
        "updated_at": "2021-04-06 20:39:27 UTC",
        "pushed_at": "2023-03-01 20:35:28 UTC",
        "git_url": "git://github.com/ippei8jp/CustomVisionExport.git",
        "ssh_url": "git@github.com:ippei8jp/CustomVisionExport.git",
        "clone_url": "https://github.com/ippei8jp/CustomVisionExport.git",
        "svn_url": "https://github.com/ippei8jp/CustomVisionExport",
        "homepage": null,
        "size": 47,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 15,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 15,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 11
          }
        ]
      },
      {
        "id": 193180225,
        "node_id": "MDEwOlJlcG9zaXRvcnkxOTMxODAyMjU=",
        "name": "GitPressBlog",
        "full_name": "ippei8jp/GitPressBlog",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/GitPressBlog",
        "description": "GitPressで公開するブログ",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/GitPressBlog",
        "forks_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/GitPressBlog/deployments",
        "created_at": "2019-06-22 02:05:51 UTC",
        "updated_at": "2019-07-06 22:27:00 UTC",
        "pushed_at": "2019-07-06 22:26:58 UTC",
        "git_url": "git://github.com/ippei8jp/GitPressBlog.git",
        "ssh_url": "git@github.com:ippei8jp/GitPressBlog.git",
        "clone_url": "https://github.com/ippei8jp/GitPressBlog.git",
        "svn_url": "https://github.com/ippei8jp/GitPressBlog",
        "homepage": null,
        "size": 42,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": null,
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 28
          }
        ]
      },
      {
        "id": 374290824,
        "node_id": "MDEwOlJlcG9zaXRvcnkzNzQyOTA4MjQ=",
        "name": "keras_ssd_test0",
        "full_name": "ippei8jp/keras_ssd_test0",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/keras_ssd_test0",
        "description": "rykov8/ssd_keras のTensorflow2対応化",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0",
        "forks_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test0/deployments",
        "created_at": "2021-06-06 07:00:13 UTC",
        "updated_at": "2021-06-06 23:23:18 UTC",
        "pushed_at": "2021-06-06 22:39:12 UTC",
        "git_url": "git://github.com/ippei8jp/keras_ssd_test0.git",
        "ssh_url": "git@github.com:ippei8jp/keras_ssd_test0.git",
        "clone_url": "https://github.com/ippei8jp/keras_ssd_test0.git",
        "svn_url": "https://github.com/ippei8jp/keras_ssd_test0",
        "homepage": "",
        "size": 7,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": null,
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 1
          }
        ]
      },
      {
        "id": 374268308,
        "node_id": "MDEwOlJlcG9zaXRvcnkzNzQyNjgzMDg=",
        "name": "keras_ssd_test1",
        "full_name": "ippei8jp/keras_ssd_test1",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/keras_ssd_test1",
        "description": "pierluigiferrari/ssd_keras のTensorflow2対応化",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1",
        "forks_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/keras_ssd_test1/deployments",
        "created_at": "2021-06-06 04:36:34 UTC",
        "updated_at": "2021-06-06 23:27:42 UTC",
        "pushed_at": "2021-06-06 05:21:55 UTC",
        "git_url": "git://github.com/ippei8jp/keras_ssd_test1.git",
        "ssh_url": "git@github.com:ippei8jp/keras_ssd_test1.git",
        "clone_url": "https://github.com/ippei8jp/keras_ssd_test1.git",
        "svn_url": "https://github.com/ippei8jp/keras_ssd_test1",
        "homepage": "",
        "size": 13,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 1
          }
        ]
      },
      {
        "id": 370472567,
        "node_id": "MDEwOlJlcG9zaXRvcnkzNzA0NzI1Njc=",
        "name": "keras_TransferLearning1",
        "full_name": "ippei8jp/keras_TransferLearning1",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/keras_TransferLearning1",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1",
        "forks_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/keras_TransferLearning1/deployments",
        "created_at": "2021-05-24 20:09:13 UTC",
        "updated_at": "2021-05-26 03:28:12 UTC",
        "pushed_at": "2021-05-26 03:28:10 UTC",
        "git_url": "git://github.com/ippei8jp/keras_TransferLearning1.git",
        "ssh_url": "git@github.com:ippei8jp/keras_TransferLearning1.git",
        "clone_url": "https://github.com/ippei8jp/keras_TransferLearning1.git",
        "svn_url": "https://github.com/ippei8jp/keras_TransferLearning1",
        "homepage": null,
        "size": 14,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 3
          }
        ]
      },
      {
        "id": 382158552,
        "node_id": "MDEwOlJlcG9zaXRvcnkzODIxNTg1NTI=",
        "name": "keras_yolo",
        "full_name": "ippei8jp/keras_yolo",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/keras_yolo",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/keras_yolo",
        "forks_url": "https://api.github.com/repos/ippei8jp/keras_yolo/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/keras_yolo/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/keras_yolo/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/keras_yolo/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/keras_yolo/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/keras_yolo/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/keras_yolo/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/keras_yolo/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/keras_yolo/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/keras_yolo/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/keras_yolo/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/keras_yolo/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/keras_yolo/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/keras_yolo/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/keras_yolo/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/keras_yolo/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/keras_yolo/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/keras_yolo/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/keras_yolo/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/keras_yolo/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/keras_yolo/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/keras_yolo/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/keras_yolo/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/keras_yolo/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/keras_yolo/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/keras_yolo/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/keras_yolo/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/keras_yolo/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/keras_yolo/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/keras_yolo/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/keras_yolo/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/keras_yolo/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/keras_yolo/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/keras_yolo/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/keras_yolo/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/keras_yolo/deployments",
        "created_at": "2021-07-01 21:18:03 UTC",
        "updated_at": "2021-07-04 22:27:53 UTC",
        "pushed_at": "2021-07-04 22:27:50 UTC",
        "git_url": "git://github.com/ippei8jp/keras_yolo.git",
        "ssh_url": "git@github.com:ippei8jp/keras_yolo.git",
        "clone_url": "https://github.com/ippei8jp/keras_yolo.git",
        "svn_url": "https://github.com/ippei8jp/keras_yolo",
        "homepage": null,
        "size": 14,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Shell",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 1
          }
        ]
      },
      {
        "id": 571062267,
        "node_id": "R_kgDOIgm3-w",
        "name": "LINE_Notify_javascript",
        "full_name": "ippei8jp/LINE_Notify_javascript",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/LINE_Notify_javascript",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript",
        "forks_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_javascript/deployments",
        "created_at": "2022-11-27 02:58:38 UTC",
        "updated_at": "2022-11-27 05:12:05 UTC",
        "pushed_at": "2022-11-27 05:26:47 UTC",
        "git_url": "git://github.com/ippei8jp/LINE_Notify_javascript.git",
        "ssh_url": "git@github.com:ippei8jp/LINE_Notify_javascript.git",
        "clone_url": "https://github.com/ippei8jp/LINE_Notify_javascript.git",
        "svn_url": "https://github.com/ippei8jp/LINE_Notify_javascript",
        "homepage": null,
        "size": 9,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "JavaScript",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "main",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 3
          }
        ]
      },
      {
        "id": 577165180,
        "node_id": "R_kgDOImbXfA",
        "name": "LINE_Notify_python",
        "full_name": "ippei8jp/LINE_Notify_python",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/LINE_Notify_python",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python",
        "forks_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/LINE_Notify_python/deployments",
        "created_at": "2022-12-12 05:39:31 UTC",
        "updated_at": "2022-12-12 05:58:42 UTC",
        "pushed_at": "2022-12-12 05:58:37 UTC",
        "git_url": "git://github.com/ippei8jp/LINE_Notify_python.git",
        "ssh_url": "git@github.com:ippei8jp/LINE_Notify_python.git",
        "clone_url": "https://github.com/ippei8jp/LINE_Notify_python.git",
        "svn_url": "https://github.com/ippei8jp/LINE_Notify_python",
        "homepage": null,
        "size": 12,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "main",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 2
          }
        ]
      },
      {
        "id": 197259478,
        "node_id": "MDEwOlJlcG9zaXRvcnkxOTcyNTk0Nzg=",
        "name": "memoBlog",
        "full_name": "ippei8jp/memoBlog",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/memoBlog",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/memoBlog",
        "forks_url": "https://api.github.com/repos/ippei8jp/memoBlog/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/memoBlog/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/memoBlog/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/memoBlog/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/memoBlog/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/memoBlog/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/memoBlog/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/memoBlog/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/memoBlog/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/memoBlog/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/memoBlog/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/memoBlog/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/memoBlog/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/memoBlog/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/memoBlog/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/memoBlog/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/memoBlog/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/memoBlog/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/memoBlog/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/memoBlog/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/memoBlog/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/memoBlog/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/memoBlog/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/memoBlog/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/memoBlog/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/memoBlog/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/memoBlog/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/memoBlog/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/memoBlog/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/memoBlog/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/memoBlog/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/memoBlog/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/memoBlog/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/memoBlog/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/memoBlog/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/memoBlog/deployments",
        "created_at": "2019-07-16 20:02:19 UTC",
        "updated_at": "2025-06-09 04:55:34 UTC",
        "pushed_at": "2025-06-09 04:55:29 UTC",
        "git_url": "git://github.com/ippei8jp/memoBlog.git",
        "ssh_url": "git@github.com:ippei8jp/memoBlog.git",
        "clone_url": "https://github.com/ippei8jp/memoBlog.git",
        "svn_url": "https://github.com/ippei8jp/memoBlog",
        "homepage": null,
        "size": 10531,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "SCSS",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": true,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 321
          }
        ]
      },
      {
        "id": 843686108,
        "node_id": "R_kgDOMkmg3A",
        "name": "MultiBLE",
        "full_name": "ippei8jp/MultiBLE",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/MultiBLE",
        "description": "Androidで複数のBLEデバイスと通信",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/MultiBLE",
        "forks_url": "https://api.github.com/repos/ippei8jp/MultiBLE/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/MultiBLE/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/MultiBLE/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/MultiBLE/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/MultiBLE/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/MultiBLE/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/MultiBLE/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/MultiBLE/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/MultiBLE/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/MultiBLE/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/MultiBLE/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/MultiBLE/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/MultiBLE/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/MultiBLE/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/MultiBLE/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/MultiBLE/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/MultiBLE/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/MultiBLE/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/MultiBLE/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/MultiBLE/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/MultiBLE/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/MultiBLE/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/MultiBLE/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/MultiBLE/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/MultiBLE/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/MultiBLE/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/MultiBLE/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/MultiBLE/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/MultiBLE/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/MultiBLE/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/MultiBLE/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/MultiBLE/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/MultiBLE/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/MultiBLE/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/MultiBLE/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/MultiBLE/deployments",
        "created_at": "2024-08-17 05:32:30 UTC",
        "updated_at": "2024-08-20 02:44:14 UTC",
        "pushed_at": "2024-08-20 02:44:11 UTC",
        "git_url": "git://github.com/ippei8jp/MultiBLE.git",
        "ssh_url": "git@github.com:ippei8jp/MultiBLE.git",
        "clone_url": "https://github.com/ippei8jp/MultiBLE.git",
        "svn_url": "https://github.com/ippei8jp/MultiBLE",
        "homepage": null,
        "size": 147,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Java",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "main",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 5
          }
        ]
      },
      {
        "id": 299446895,
        "node_id": "MDEwOlJlcG9zaXRvcnkyOTk0NDY4OTU=",
        "name": "ov_facedetect",
        "full_name": "ippei8jp/ov_facedetect",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/ov_facedetect",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/ov_facedetect",
        "forks_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/ov_facedetect/deployments",
        "created_at": "2020-09-28 22:33:25 UTC",
        "updated_at": "2021-04-06 20:36:42 UTC",
        "pushed_at": "2021-04-06 20:36:40 UTC",
        "git_url": "git://github.com/ippei8jp/ov_facedetect.git",
        "ssh_url": "git@github.com:ippei8jp/ov_facedetect.git",
        "clone_url": "https://github.com/ippei8jp/ov_facedetect.git",
        "svn_url": "https://github.com/ippei8jp/ov_facedetect",
        "homepage": null,
        "size": 222,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 2
          }
        ]
      },
      {
        "id": 301243508,
        "node_id": "MDEwOlJlcG9zaXRvcnkzMDEyNDM1MDg=",
        "name": "ov_image",
        "full_name": "ippei8jp/ov_image",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/ov_image",
        "description": "openVINO使用画像認識色々",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/ov_image",
        "forks_url": "https://api.github.com/repos/ippei8jp/ov_image/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/ov_image/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/ov_image/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/ov_image/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/ov_image/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/ov_image/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/ov_image/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/ov_image/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/ov_image/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/ov_image/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/ov_image/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/ov_image/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/ov_image/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/ov_image/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/ov_image/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/ov_image/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/ov_image/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/ov_image/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/ov_image/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/ov_image/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/ov_image/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/ov_image/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/ov_image/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/ov_image/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/ov_image/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/ov_image/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/ov_image/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/ov_image/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/ov_image/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/ov_image/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/ov_image/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/ov_image/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/ov_image/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/ov_image/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/ov_image/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/ov_image/deployments",
        "created_at": "2020-10-04 22:55:11 UTC",
        "updated_at": "2021-06-23 05:08:38 UTC",
        "pushed_at": "2021-06-23 05:08:36 UTC",
        "git_url": "git://github.com/ippei8jp/ov_image.git",
        "ssh_url": "git@github.com:ippei8jp/ov_image.git",
        "clone_url": "https://github.com/ippei8jp/ov_image.git",
        "svn_url": "https://github.com/ippei8jp/ov_image",
        "homepage": null,
        "size": 385,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 21
          }
        ]
      },
      {
        "id": 273651086,
        "node_id": "MDEwOlJlcG9zaXRvcnkyNzM2NTEwODY=",
        "name": "ov_trial",
        "full_name": "ippei8jp/ov_trial",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/ov_trial",
        "description": "openVINO お試しプログラム",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/ov_trial",
        "forks_url": "https://api.github.com/repos/ippei8jp/ov_trial/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/ov_trial/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/ov_trial/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/ov_trial/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/ov_trial/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/ov_trial/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/ov_trial/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/ov_trial/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/ov_trial/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/ov_trial/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/ov_trial/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/ov_trial/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/ov_trial/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/ov_trial/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/ov_trial/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/ov_trial/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/ov_trial/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/ov_trial/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/ov_trial/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/ov_trial/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/ov_trial/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/ov_trial/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/ov_trial/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/ov_trial/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/ov_trial/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/ov_trial/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/ov_trial/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/ov_trial/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/ov_trial/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/ov_trial/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/ov_trial/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/ov_trial/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/ov_trial/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/ov_trial/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/ov_trial/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/ov_trial/deployments",
        "created_at": "2020-06-20 06:21:43 UTC",
        "updated_at": "2021-10-16 04:12:13 UTC",
        "pushed_at": "2023-03-01 20:35:21 UTC",
        "git_url": "git://github.com/ippei8jp/ov_trial.git",
        "ssh_url": "git@github.com:ippei8jp/ov_trial.git",
        "clone_url": "https://github.com/ippei8jp/ov_trial.git",
        "svn_url": "https://github.com/ippei8jp/ov_trial",
        "homepage": null,
        "size": 36,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 7,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 7,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 5
          }
        ]
      },
      {
        "id": 526434412,
        "node_id": "R_kgDOH2DAbA",
        "name": "ov_trial_2022.1",
        "full_name": "ippei8jp/ov_trial_2022.1",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/ov_trial_2022.1",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1",
        "forks_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/ov_trial_2022.1/deployments",
        "created_at": "2022-08-19 02:13:47 UTC",
        "updated_at": "2022-08-19 02:46:10 UTC",
        "pushed_at": "2022-09-24 03:17:32 UTC",
        "git_url": "git://github.com/ippei8jp/ov_trial_2022.1.git",
        "ssh_url": "git@github.com:ippei8jp/ov_trial_2022.1.git",
        "clone_url": "https://github.com/ippei8jp/ov_trial_2022.1.git",
        "svn_url": "https://github.com/ippei8jp/ov_trial_2022.1",
        "homepage": null,
        "size": 138,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 24
          }
        ]
      },
      {
        "id": 189516794,
        "node_id": "MDEwOlJlcG9zaXRvcnkxODk1MTY3OTQ=",
        "name": "remark-editor",
        "full_name": "ippei8jp/remark-editor",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/remark-editor",
        "description": "Electron勉強用",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/remark-editor",
        "forks_url": "https://api.github.com/repos/ippei8jp/remark-editor/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/remark-editor/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/remark-editor/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/remark-editor/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/remark-editor/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/remark-editor/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/remark-editor/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/remark-editor/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/remark-editor/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/remark-editor/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/remark-editor/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/remark-editor/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/remark-editor/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/remark-editor/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/remark-editor/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/remark-editor/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/remark-editor/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/remark-editor/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/remark-editor/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/remark-editor/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/remark-editor/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/remark-editor/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/remark-editor/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/remark-editor/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/remark-editor/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/remark-editor/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/remark-editor/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/remark-editor/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/remark-editor/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/remark-editor/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/remark-editor/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/remark-editor/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/remark-editor/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/remark-editor/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/remark-editor/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/remark-editor/deployments",
        "created_at": "2019-05-31 02:51:42 UTC",
        "updated_at": "2019-06-13 21:23:22 UTC",
        "pushed_at": "2020-07-07 05:55:45 UTC",
        "git_url": "git://github.com/ippei8jp/remark-editor.git",
        "ssh_url": "git@github.com:ippei8jp/remark-editor.git",
        "clone_url": "https://github.com/ippei8jp/remark-editor.git",
        "svn_url": "https://github.com/ippei8jp/remark-editor",
        "homepage": null,
        "size": 116,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "JavaScript",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 6
          }
        ]
      },
      {
        "id": 871816571,
        "node_id": "R_kgDOM_bdew",
        "name": "renode_my_sample",
        "full_name": "ippei8jp/renode_my_sample",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/renode_my_sample",
        "description": "renodeお試し用環境",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/renode_my_sample",
        "forks_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/renode_my_sample/deployments",
        "created_at": "2024-10-13 02:45:56 UTC",
        "updated_at": "2024-10-13 04:51:00 UTC",
        "pushed_at": "2024-10-13 04:50:57 UTC",
        "git_url": "git://github.com/ippei8jp/renode_my_sample.git",
        "ssh_url": "git@github.com:ippei8jp/renode_my_sample.git",
        "clone_url": "https://github.com/ippei8jp/renode_my_sample.git",
        "svn_url": "https://github.com/ippei8jp/renode_my_sample",
        "homepage": null,
        "size": 853,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "C",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "main",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 2
          }
        ]
      },
      {
        "id": 854813061,
        "node_id": "R_kgDOMvNphQ",
        "name": "RPI-Pico_PIO_statemachine_emulator",
        "full_name": "ippei8jp/RPI-Pico_PIO_statemachine_emulator",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/RPI-Pico_PIO_statemachine_emulator",
        "description": "Raspberry Pi Pico PIO statemachine emulator",
        "fork": true,
        "url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator",
        "forks_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/RPI-Pico_PIO_statemachine_emulator/deployments",
        "created_at": "2024-09-09 20:23:34 UTC",
        "updated_at": "2024-09-24 05:00:52 UTC",
        "pushed_at": "2024-09-24 05:00:48 UTC",
        "git_url": "git://github.com/ippei8jp/RPI-Pico_PIO_statemachine_emulator.git",
        "ssh_url": "git@github.com:ippei8jp/RPI-Pico_PIO_statemachine_emulator.git",
        "clone_url": "https://github.com/ippei8jp/RPI-Pico_PIO_statemachine_emulator.git",
        "svn_url": "https://github.com/ippei8jp/RPI-Pico_PIO_statemachine_emulator",
        "homepage": null,
        "size": 5544,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": false,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": {
          "key": "mit",
          "name": "MIT License",
          "spdx_id": "MIT",
          "url": "https://api.github.com/licenses/mit",
          "node_id": "MDc6TGljZW5zZTEz"
        },
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "main",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "GitJer",
            "id": 21146803,
            "node_id": "MDQ6VXNlcjIxMTQ2ODAz",
            "avatar_url": "https://avatars.githubusercontent.com/u/21146803?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/GitJer",
            "html_url": "https://github.com/GitJer",
            "followers_url": "https://api.github.com/users/GitJer/followers",
            "following_url": "https://api.github.com/users/GitJer/following{/other_user}",
            "gists_url": "https://api.github.com/users/GitJer/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/GitJer/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/GitJer/subscriptions",
            "organizations_url": "https://api.github.com/users/GitJer/orgs",
            "repos_url": "https://api.github.com/users/GitJer/repos",
            "events_url": "https://api.github.com/users/GitJer/events{/privacy}",
            "received_events_url": "https://api.github.com/users/GitJer/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 92
          },
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 19
          },
          {
            "login": "GabG6",
            "id": 97483291,
            "node_id": "U_kgDOBc96Gw",
            "avatar_url": "https://avatars.githubusercontent.com/u/97483291?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/GabG6",
            "html_url": "https://github.com/GabG6",
            "followers_url": "https://api.github.com/users/GabG6/followers",
            "following_url": "https://api.github.com/users/GabG6/following{/other_user}",
            "gists_url": "https://api.github.com/users/GabG6/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/GabG6/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/GabG6/subscriptions",
            "organizations_url": "https://api.github.com/users/GabG6/orgs",
            "repos_url": "https://api.github.com/users/GabG6/repos",
            "events_url": "https://api.github.com/users/GabG6/events{/privacy}",
            "received_events_url": "https://api.github.com/users/GabG6/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 1
          }
        ]
      },
      {
        "id": 211992421,
        "node_id": "MDEwOlJlcG9zaXRvcnkyMTE5OTI0MjE=",
        "name": "spreadsheet_serviceaccount",
        "full_name": "ippei8jp/spreadsheet_serviceaccount",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/spreadsheet_serviceaccount",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount",
        "forks_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/spreadsheet_serviceaccount/deployments",
        "created_at": "2019-10-01 01:42:45 UTC",
        "updated_at": "2019-10-01 05:05:37 UTC",
        "pushed_at": "2019-10-01 05:05:35 UTC",
        "git_url": "git://github.com/ippei8jp/spreadsheet_serviceaccount.git",
        "ssh_url": "git@github.com:ippei8jp/spreadsheet_serviceaccount.git",
        "clone_url": "https://github.com/ippei8jp/spreadsheet_serviceaccount.git",
        "svn_url": "https://github.com/ippei8jp/spreadsheet_serviceaccount",
        "homepage": null,
        "size": 5,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "JavaScript",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 1
          }
        ]
      },
      {
        "id": 428412884,
        "node_id": "R_kgDOGYkP1A",
        "name": "ssd_assort",
        "full_name": "ippei8jp/ssd_assort",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/ssd_assort",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/ssd_assort",
        "forks_url": "https://api.github.com/repos/ippei8jp/ssd_assort/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/ssd_assort/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/ssd_assort/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/ssd_assort/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/ssd_assort/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/ssd_assort/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/ssd_assort/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/ssd_assort/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/ssd_assort/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/ssd_assort/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/ssd_assort/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/ssd_assort/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/ssd_assort/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/ssd_assort/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/ssd_assort/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/ssd_assort/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/ssd_assort/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/ssd_assort/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/ssd_assort/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/ssd_assort/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/ssd_assort/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/ssd_assort/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/ssd_assort/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/ssd_assort/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/ssd_assort/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/ssd_assort/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/ssd_assort/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/ssd_assort/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/ssd_assort/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/ssd_assort/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/ssd_assort/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/ssd_assort/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/ssd_assort/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/ssd_assort/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/ssd_assort/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/ssd_assort/deployments",
        "created_at": "2021-11-15 20:32:05 UTC",
        "updated_at": "2021-11-16 00:11:45 UTC",
        "pushed_at": "2021-11-16 00:11:42 UTC",
        "git_url": "git://github.com/ippei8jp/ssd_assort.git",
        "ssh_url": "git@github.com:ippei8jp/ssd_assort.git",
        "clone_url": "https://github.com/ippei8jp/ssd_assort.git",
        "svn_url": "https://github.com/ippei8jp/ssd_assort",
        "homepage": null,
        "size": 1,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": null,
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 1
          }
        ]
      },
      {
        "id": 944231767,
        "node_id": "R_kgDOOEfVVw",
        "name": "test_shell",
        "full_name": "ippei8jp/test_shell",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/test_shell",
        "description": " test shellのひな型",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/test_shell",
        "forks_url": "https://api.github.com/repos/ippei8jp/test_shell/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/test_shell/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/test_shell/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/test_shell/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/test_shell/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/test_shell/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/test_shell/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/test_shell/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/test_shell/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/test_shell/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/test_shell/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/test_shell/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/test_shell/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/test_shell/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/test_shell/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/test_shell/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/test_shell/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/test_shell/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/test_shell/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/test_shell/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/test_shell/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/test_shell/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/test_shell/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/test_shell/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/test_shell/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/test_shell/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/test_shell/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/test_shell/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/test_shell/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/test_shell/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/test_shell/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/test_shell/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/test_shell/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/test_shell/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/test_shell/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/test_shell/deployments",
        "created_at": "2025-03-07 02:07:39 UTC",
        "updated_at": "2025-03-07 03:16:04 UTC",
        "pushed_at": "2025-03-07 03:16:00 UTC",
        "git_url": "git://github.com/ippei8jp/test_shell.git",
        "ssh_url": "git@github.com:ippei8jp/test_shell.git",
        "clone_url": "https://github.com/ippei8jp/test_shell.git",
        "svn_url": "https://github.com/ippei8jp/test_shell",
        "homepage": null,
        "size": 14,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "C",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "main",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 3
          }
        ]
      },
      {
        "id": 361638447,
        "node_id": "MDEwOlJlcG9zaXRvcnkzNjE2Mzg0NDc=",
        "name": "tf1_TransferLearning",
        "full_name": "ippei8jp/tf1_TransferLearning",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/tf1_TransferLearning",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning",
        "forks_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/tf1_TransferLearning/deployments",
        "created_at": "2021-04-26 06:16:07 UTC",
        "updated_at": "2021-05-20 02:17:52 UTC",
        "pushed_at": "2021-05-20 02:17:50 UTC",
        "git_url": "git://github.com/ippei8jp/tf1_TransferLearning.git",
        "ssh_url": "git@github.com:ippei8jp/tf1_TransferLearning.git",
        "clone_url": "https://github.com/ippei8jp/tf1_TransferLearning.git",
        "svn_url": "https://github.com/ippei8jp/tf1_TransferLearning",
        "homepage": null,
        "size": 32,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 7
          }
        ]
      },
      {
        "id": 357670311,
        "node_id": "MDEwOlJlcG9zaXRvcnkzNTc2NzAzMTE=",
        "name": "tf2_TransferLearning",
        "full_name": "ippei8jp/tf2_TransferLearning",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/tf2_TransferLearning",
        "description": null,
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning",
        "forks_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/tf2_TransferLearning/deployments",
        "created_at": "2021-04-13 19:44:49 UTC",
        "updated_at": "2021-05-17 21:43:05 UTC",
        "pushed_at": "2021-05-17 21:43:02 UTC",
        "git_url": "git://github.com/ippei8jp/tf2_TransferLearning.git",
        "ssh_url": "git@github.com:ippei8jp/tf2_TransferLearning.git",
        "clone_url": "https://github.com/ippei8jp/tf2_TransferLearning.git",
        "svn_url": "https://github.com/ippei8jp/tf2_TransferLearning",
        "homepage": null,
        "size": 34,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 0,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 0,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 8
          }
        ]
      },
      {
        "id": 271922700,
        "node_id": "MDEwOlJlcG9zaXRvcnkyNzE5MjI3MDA=",
        "name": "tflite_trial",
        "full_name": "ippei8jp/tflite_trial",
        "private": false,
        "owner": {
          "login": "ippei8jp",
          "id": 48367499,
          "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
          "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
          "gravatar_id": "",
          "url": "https://api.github.com/users/ippei8jp",
          "html_url": "https://github.com/ippei8jp",
          "followers_url": "https://api.github.com/users/ippei8jp/followers",
          "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
          "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
          "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
          "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
          "repos_url": "https://api.github.com/users/ippei8jp/repos",
          "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
          "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
          "type": "User",
          "user_view_type": "public",
          "site_admin": false
        },
        "html_url": "https://github.com/ippei8jp/tflite_trial",
        "description": "Tensorflow Lite お試しプログラム",
        "fork": false,
        "url": "https://api.github.com/repos/ippei8jp/tflite_trial",
        "forks_url": "https://api.github.com/repos/ippei8jp/tflite_trial/forks",
        "keys_url": "https://api.github.com/repos/ippei8jp/tflite_trial/keys{/key_id}",
        "collaborators_url": "https://api.github.com/repos/ippei8jp/tflite_trial/collaborators{/collaborator}",
        "teams_url": "https://api.github.com/repos/ippei8jp/tflite_trial/teams",
        "hooks_url": "https://api.github.com/repos/ippei8jp/tflite_trial/hooks",
        "issue_events_url": "https://api.github.com/repos/ippei8jp/tflite_trial/issues/events{/number}",
        "events_url": "https://api.github.com/repos/ippei8jp/tflite_trial/events",
        "assignees_url": "https://api.github.com/repos/ippei8jp/tflite_trial/assignees{/user}",
        "branches_url": "https://api.github.com/repos/ippei8jp/tflite_trial/branches{/branch}",
        "tags_url": "https://api.github.com/repos/ippei8jp/tflite_trial/tags",
        "blobs_url": "https://api.github.com/repos/ippei8jp/tflite_trial/git/blobs{/sha}",
        "git_tags_url": "https://api.github.com/repos/ippei8jp/tflite_trial/git/tags{/sha}",
        "git_refs_url": "https://api.github.com/repos/ippei8jp/tflite_trial/git/refs{/sha}",
        "trees_url": "https://api.github.com/repos/ippei8jp/tflite_trial/git/trees{/sha}",
        "statuses_url": "https://api.github.com/repos/ippei8jp/tflite_trial/statuses/{sha}",
        "languages_url": "https://api.github.com/repos/ippei8jp/tflite_trial/languages",
        "stargazers_url": "https://api.github.com/repos/ippei8jp/tflite_trial/stargazers",
        "contributors_url": "https://api.github.com/repos/ippei8jp/tflite_trial/contributors",
        "subscribers_url": "https://api.github.com/repos/ippei8jp/tflite_trial/subscribers",
        "subscription_url": "https://api.github.com/repos/ippei8jp/tflite_trial/subscription",
        "commits_url": "https://api.github.com/repos/ippei8jp/tflite_trial/commits{/sha}",
        "git_commits_url": "https://api.github.com/repos/ippei8jp/tflite_trial/git/commits{/sha}",
        "comments_url": "https://api.github.com/repos/ippei8jp/tflite_trial/comments{/number}",
        "issue_comment_url": "https://api.github.com/repos/ippei8jp/tflite_trial/issues/comments{/number}",
        "contents_url": "https://api.github.com/repos/ippei8jp/tflite_trial/contents/{+path}",
        "compare_url": "https://api.github.com/repos/ippei8jp/tflite_trial/compare/{base}...{head}",
        "merges_url": "https://api.github.com/repos/ippei8jp/tflite_trial/merges",
        "archive_url": "https://api.github.com/repos/ippei8jp/tflite_trial/{archive_format}{/ref}",
        "downloads_url": "https://api.github.com/repos/ippei8jp/tflite_trial/downloads",
        "issues_url": "https://api.github.com/repos/ippei8jp/tflite_trial/issues{/number}",
        "pulls_url": "https://api.github.com/repos/ippei8jp/tflite_trial/pulls{/number}",
        "milestones_url": "https://api.github.com/repos/ippei8jp/tflite_trial/milestones{/number}",
        "notifications_url": "https://api.github.com/repos/ippei8jp/tflite_trial/notifications{?since,all,participating}",
        "labels_url": "https://api.github.com/repos/ippei8jp/tflite_trial/labels{/name}",
        "releases_url": "https://api.github.com/repos/ippei8jp/tflite_trial/releases{/id}",
        "deployments_url": "https://api.github.com/repos/ippei8jp/tflite_trial/deployments",
        "created_at": "2020-06-13 01:55:26 UTC",
        "updated_at": "2021-04-06 20:41:28 UTC",
        "pushed_at": "2023-03-24 21:54:07 UTC",
        "git_url": "git://github.com/ippei8jp/tflite_trial.git",
        "ssh_url": "git@github.com:ippei8jp/tflite_trial.git",
        "clone_url": "https://github.com/ippei8jp/tflite_trial.git",
        "svn_url": "https://github.com/ippei8jp/tflite_trial",
        "homepage": null,
        "size": 27,
        "stargazers_count": 0,
        "watchers_count": 0,
        "language": "Python",
        "has_issues": true,
        "has_projects": true,
        "has_downloads": true,
        "has_wiki": true,
        "has_pages": false,
        "has_discussions": false,
        "forks_count": 0,
        "mirror_url": null,
        "archived": false,
        "disabled": false,
        "open_issues_count": 6,
        "license": null,
        "allow_forking": true,
        "is_template": false,
        "web_commit_signoff_required": false,
        "topics": [

        ],
        "visibility": "public",
        "forks": 0,
        "open_issues": 6,
        "watchers": 0,
        "default_branch": "master",
        "permissions": {
          "admin": false,
          "maintain": false,
          "push": false,
          "triage": false,
          "pull": false
        },
        "releases": [

        ],
        "contributors": [
          {
            "login": "ippei8jp",
            "id": 48367499,
            "node_id": "MDQ6VXNlcjQ4MzY3NDk5",
            "avatar_url": "https://avatars.githubusercontent.com/u/48367499?v=4",
            "gravatar_id": "",
            "url": "https://api.github.com/users/ippei8jp",
            "html_url": "https://github.com/ippei8jp",
            "followers_url": "https://api.github.com/users/ippei8jp/followers",
            "following_url": "https://api.github.com/users/ippei8jp/following{/other_user}",
            "gists_url": "https://api.github.com/users/ippei8jp/gists{/gist_id}",
            "starred_url": "https://api.github.com/users/ippei8jp/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/ippei8jp/subscriptions",
            "organizations_url": "https://api.github.com/users/ippei8jp/orgs",
            "repos_url": "https://api.github.com/users/ippei8jp/repos",
            "events_url": "https://api.github.com/users/ippei8jp/events{/privacy}",
            "received_events_url": "https://api.github.com/users/ippei8jp/received_events",
            "type": "User",
            "user_view_type": "public",
            "site_admin": false,
            "contributions": 8
          }
        ]
      }
    ],
    "releases": [

    ],
    "releases_url": "https://github.com/ippei8jp/memoBlog/releases",
    "repository_name": "memoBlog",
    "repository_nwo": "ippei8jp/memoBlog",
    "repository_url": "https://github.com/ippei8jp/memoBlog",
    "show_downloads": true,
    "source": {
      "branch": "master",
      "path": "/"
    },
    "tar_url": "https://github.com/ippei8jp/memoBlog/tarball/master",
    "url": "https://ippei8jp.github.io/memoBlog",
    "versions": {
      "jekyll": "3.10.0",
      "jekyll-sass-converter": "1.5.2",
      "kramdown": "2.4.0",
      "kramdown-parser-gfm": "1.1.0",
      "jekyll-commonmark-ghpages": "0.5.1",
      "liquid": "4.0.4",
      "rouge": "3.30.0",
      "github-pages-health-check": "1.18.2",
      "jekyll-redirect-from": "0.16.0",
      "jekyll-sitemap": "1.4.0",
      "jekyll-feed": "0.17.0",
      "jekyll-gist": "1.5.0",
      "jekyll-paginate": "1.1.0",
      "jekyll-coffeescript": "1.2.2",
      "jekyll-seo-tag": "2.8.0",
      "jekyll-github-metadata": "2.16.1",
      "jekyll-avatar": "0.8.0",
      "jekyll-remote-theme": "0.4.3",
      "jekyll-include-cache": "0.2.1",
      "jemoji": "0.13.0",
      "jekyll-mentions": "1.6.0",
      "jekyll-relative-links": "0.6.1",
      "jekyll-optional-front-matter": "0.3.2",
      "jekyll-readme-index": "0.3.0",
      "jekyll-default-layout": "0.1.5",
      "jekyll-titles-from-headings": "0.5.3",
      "minima": "2.5.1",
      "jekyll-swiss": "1.0.0",
      "jekyll-theme-primer": "0.6.0",
      "jekyll-theme-architect": "0.2.0",
      "jekyll-theme-cayman": "0.2.0",
      "jekyll-theme-dinky": "0.2.0",
      "jekyll-theme-hacker": "0.2.0",
      "jekyll-theme-leap-day": "0.2.0",
      "jekyll-theme-merlot": "0.2.0",
      "jekyll-theme-midnight": "0.2.0",
      "jekyll-theme-minimal": "0.2.0",
      "jekyll-theme-modernist": "0.2.0",
      "jekyll-theme-slate": "0.2.0",
      "jekyll-theme-tactile": "0.2.0",
      "jekyll-theme-time-machine": "0.2.0",
      "ruby": "3.3.4",
      "github-pages": "232",
      "html-pipeline": "2.14.3",
      "sass": "3.7.4",
      "safe_yaml": "1.0.5",
      "nokogiri": "1.16.7"
    },
    "wiki_url": "https://github.com/ippei8jp/memoBlog/wiki",
    "zip_url": "https://github.com/ippei8jp/memoBlog/zipball/master"
  }
}

site.tags変数

site.tags = 
{"Ubuntu"=>[#<Jekyll::Document _posts/2024-07-21-install2404.md collection=posts>, #<Jekyll::Document _posts/2023-11-14-install2204.md collection=posts>, #<Jekyll::Document _posts/2022-09-09-openVINO_build_2022_2.md collection=posts>, #<Jekyll::Document _posts/2022-09-06-openVINO_2022_build_1.md collection=posts>, #<Jekyll::Document _posts/2022-07-24-install2204.md collection=posts>, #<Jekyll::Document _posts/2022-06-22-Python_console_input.md collection=posts>, #<Jekyll::Document _posts/2022-03-10-openVINO_build_3.md collection=posts>, #<Jekyll::Document _posts/2022-03-07-openVINO_build_2.md collection=posts>, #<Jekyll::Document _posts/2021-10-20-openVINO_build.md collection=posts>, #<Jekyll::Document _posts/2021-10-20-Docker_openVINO.md collection=posts>, #<Jekyll::Document _posts/2021-10-12-VSCode_remoteDocker.md collection=posts>, #<Jekyll::Document _posts/2021-10-11-SSH_setup.md collection=posts>, #<Jekyll::Document _posts/2021-10-10-Docker_gui.md collection=posts>, #<Jekyll::Document _posts/2021-10-09-VSCode_Docker_python.md collection=posts>, #<Jekyll::Document _posts/2021-10-08-Docker_install.md collection=posts>, #<Jekyll::Document _posts/2021-07-15-install2004_native.md collection=posts>, #<Jekyll::Document _posts/2021-03-21-keras.md collection=posts>, #<Jekyll::Document _posts/2021-03-20-openVINO_pypi.md collection=posts>, #<Jekyll::Document _posts/2021-03-10-openVINO_on_WSL.md collection=posts>, #<Jekyll::Document _posts/2021-03-02-install2004.md collection=posts>, #<Jekyll::Document _posts/2020-10-18-openVINO_ubuntu_3.md collection=posts>, #<Jekyll::Document _posts/2020-09-02-wireshark_3.md collection=posts>, #<Jekyll::Document _posts/2020-08-30-wireshark_2.md collection=posts>, #<Jekyll::Document _posts/2020-08-30-wireshark_1.md collection=posts>, #<Jekyll::Document _posts/2020-06-29-pyenv_bug.md collection=posts>, #<Jekyll::Document _posts/2020-06-17-coral_6.md collection=posts>, #<Jekyll::Document _posts/2020-06-16-openVINO_ubuntu_2.md collection=posts>, #<Jekyll::Document _posts/2020-05-27-coral_5.md collection=posts>, #<Jekyll::Document _posts/2020-05-23-coral_4.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_3.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_2.md collection=posts>, #<Jekyll::Document _posts/2020-05-15-coral_1.md collection=posts>, #<Jekyll::Document _posts/2020-05-08-ubuntu_native.md collection=posts>, #<Jekyll::Document _posts/2019-12-18-openVINO_SSD_2.md collection=posts>, #<Jekyll::Document _posts/2019-12-08-openVINO_face.md collection=posts>, #<Jekyll::Document _posts/2019-11-11-openVINO_YOLO2.md collection=posts>, #<Jekyll::Document _posts/2019-11-10-openVINO_SSD.md collection=posts>, #<Jekyll::Document _posts/2019-10-31-openVINO_YOLO _C++.md collection=posts>, #<Jekyll::Document _posts/2019-10-30-openVINO_YOLO.md collection=posts>, #<Jekyll::Document _posts/2019-10-17-openVINO_ubuntu.md collection=posts>, #<Jekyll::Document _posts/2019-09-16-node-red_6.md collection=posts>, #<Jekyll::Document _posts/2019-09-12-node-red_6.md collection=posts>, #<Jekyll::Document _posts/2019-09-11-node-red_5.md collection=posts>, #<Jekyll::Document _posts/2019-09-11-node-red_4.md collection=posts>, #<Jekyll::Document _posts/2019-09-10-node-red_3.md collection=posts>, #<Jekyll::Document _posts/2019-09-04-node-red_1.md collection=posts>, #<Jekyll::Document _posts/2019-07-23-git_samba.md collection=posts>, #<Jekyll::Document _posts/2019-07-17-githubpages.md collection=posts>, #<Jekyll::Document _posts/2019-07-07-rbenv.md collection=posts>, #<Jekyll::Document _posts/2019-06-29-install1604.md collection=posts>, #<Jekyll::Document _posts/2019-06-28-nodenv.md collection=posts>, #<Jekyll::Document _posts/2019-06-27-pyenv.md collection=posts>, #<Jekyll::Document _posts/2019-06-26-install1804.md collection=posts>, #<Jekyll::Document _posts/2019-06-22-asyncawait.md collection=posts>], "RaspberryPi"=>[#<Jekyll::Document _posts/2024-05-14-raspios_bookworm_install.md collection=posts>, #<Jekyll::Document _posts/2024-05-14-raspi_python_tts.md collection=posts>, #<Jekyll::Document _posts/2022-09-09-openVINO_build_2022_2.md collection=posts>, #<Jekyll::Document _posts/2022-06-28-raspios_64_Imager.md collection=posts>, #<Jekyll::Document _posts/2022-06-22-Python_console_input.md collection=posts>, #<Jekyll::Document _posts/2022-03-21-RasPi_pwm.md collection=posts>, #<Jekyll::Document _posts/2022-03-10-openVINO_build_3.md collection=posts>, #<Jekyll::Document _posts/2022-03-07-openVINO_build_2.md collection=posts>, #<Jekyll::Document _posts/2022-02-25-raspios_64_20220128.md collection=posts>, #<Jekyll::Document _posts/2022-02-07-ESP32_BLE_5.md collection=posts>, #<Jekyll::Document _posts/2022-01-31-ESP32_BLE_4.md collection=posts>, #<Jekyll::Document _posts/2022-01-28-ESP32_BLE_3.md collection=posts>, #<Jekyll::Document _posts/2021-10-20-openVINO_build.md collection=posts>, #<Jekyll::Document _posts/2021-07-18-sd_image_2.md collection=posts>, #<Jekyll::Document _posts/2021-07-17-raspios_20210507.md collection=posts>, #<Jekyll::Document _posts/2020-10-25-Jetson_nano_backup.md collection=posts>, #<Jekyll::Document _posts/2020-09-02-wireshark_3.md collection=posts>, #<Jekyll::Document _posts/2020-08-30-wireshark_2.md collection=posts>, #<Jekyll::Document _posts/2020-08-30-wireshark_1.md collection=posts>, #<Jekyll::Document _posts/2020-06-29-pyenv_bug.md collection=posts>, #<Jekyll::Document _posts/2020-06-17-coral_6.md collection=posts>, #<Jekyll::Document _posts/2020-05-27-coral_5.md collection=posts>, #<Jekyll::Document _posts/2020-05-23-coral_4.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_3.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_2.md collection=posts>, #<Jekyll::Document _posts/2020-05-15-coral_1.md collection=posts>, #<Jekyll::Document _posts/2019-12-18-openVINO_SSD_2.md collection=posts>, #<Jekyll::Document _posts/2019-12-08-openVINO_face.md collection=posts>, #<Jekyll::Document _posts/2019-11-27-RaspbianArchives.md collection=posts>, #<Jekyll::Document _posts/2019-11-11-openVINO_YOLO2.md collection=posts>, #<Jekyll::Document _posts/2019-11-10-openVINO_SSD.md collection=posts>, #<Jekyll::Document _posts/2019-10-31-openVINO_YOLO _C++.md collection=posts>, #<Jekyll::Document _posts/2019-10-30-openVINO_YOLO.md collection=posts>, #<Jekyll::Document _posts/2019-10-12-NCS_2.md collection=posts>, #<Jekyll::Document _posts/2019-10-04-node-red_9.md collection=posts>, #<Jekyll::Document _posts/2019-10-03-node-red_8.md collection=posts>, #<Jekyll::Document _posts/2019-10-01-spreadsheet.md collection=posts>, #<Jekyll::Document _posts/2019-09-16-node-red_6.md collection=posts>, #<Jekyll::Document _posts/2019-09-15-sd_image.md collection=posts>, #<Jekyll::Document _posts/2019-09-13-raspbian_buster_2.md collection=posts>, #<Jekyll::Document _posts/2019-09-12-node-red_6.md collection=posts>, #<Jekyll::Document _posts/2019-09-12-mobilehotspot.md collection=posts>, #<Jekyll::Document _posts/2019-09-11-node-red_5.md collection=posts>, #<Jekyll::Document _posts/2019-09-11-node-red_4.md collection=posts>, #<Jekyll::Document _posts/2019-09-10-node-red_3.md collection=posts>, #<Jekyll::Document _posts/2019-09-09-node-red_2.md collection=posts>, #<Jekyll::Document _posts/2019-09-04-node-red_1.md collection=posts>, #<Jekyll::Document _posts/2019-09-03-WebIOPi.md collection=posts>, #<Jekyll::Document _posts/2019-08-31-raspbian_buster_1.md collection=posts>, #<Jekyll::Document _posts/2019-07-29-PastBlogs1.md collection=posts>, #<Jekyll::Document _posts/2019-06-28-nodenv.md collection=posts>, #<Jekyll::Document _posts/2019-06-27-pyenv.md collection=posts>, #<Jekyll::Document _posts/2019-06-22-asyncawait.md collection=posts>], "Windows"=>[#<Jekyll::Document _posts/2025-3-24-MSYS2_1.md collection=posts>, #<Jekyll::Document _posts/2022-09-09-openVINO_build_2022_2.md collection=posts>, #<Jekyll::Document _posts/2022-06-22-Python_console_input.md collection=posts>, #<Jekyll::Document _posts/2022-03-10-openVINO_build_3.md collection=posts>, #<Jekyll::Document _posts/2022-03-07-openVINO_build_2.md collection=posts>, #<Jekyll::Document _posts/2021-10-20-openVINO_build.md collection=posts>, #<Jekyll::Document _posts/2021-10-20-Docker_openVINO.md collection=posts>, #<Jekyll::Document _posts/2021-10-12-VSCode_remoteDocker.md collection=posts>, #<Jekyll::Document _posts/2021-10-11-SSH_setup.md collection=posts>, #<Jekyll::Document _posts/2021-10-10-Docker_gui.md collection=posts>, #<Jekyll::Document _posts/2021-10-09-VSCode_Docker_python.md collection=posts>, #<Jekyll::Document _posts/2021-10-08-Docker_install.md collection=posts>, #<Jekyll::Document _posts/2020-08-30-wireshark_2.md collection=posts>, #<Jekyll::Document _posts/2020-06-29-git_winmerge.md collection=posts>, #<Jekyll::Document _posts/2019-11-26-VcXsrv.md collection=posts>, #<Jekyll::Document _posts/2019-09-12-mobilehotspot.md collection=posts>, #<Jekyll::Document _posts/2019-07-29-PastBlogs2.md collection=posts>, #<Jekyll::Document _posts/2019-07-26-githubpages.md collection=posts>, #<Jekyll::Document _posts/2019-06-22-asyncawait.md collection=posts>], "python"=>[#<Jekyll::Document _posts/2025-5-19-kivy_5.md collection=posts>, #<Jekyll::Document _posts/2025-4-30-kivy_4.md collection=posts>, #<Jekyll::Document _posts/2025-4-29-kivy_3 .md collection=posts>, #<Jekyll::Document _posts/2025-4-26-kivy_2.md collection=posts>, #<Jekyll::Document _posts/2025-4-21-Buildozer_3.md collection=posts>, #<Jekyll::Document _posts/2025-4-16-kivy_1.md collection=posts>, #<Jekyll::Document _posts/2025-4-4-Buildozer_2.md collection=posts>, #<Jekyll::Document _posts/2025-3-31-Buildozer_1.md collection=posts>, #<Jekyll::Document _posts/2025-1-7-openpuxl_bug.md collection=posts>, #<Jekyll::Document _posts/2025-1-7-TkEasyGUI_1.md collection=posts>, #<Jekyll::Document _posts/2024-09-16-tkinter_canvas_1.md collection=posts>, #<Jekyll::Document _posts/2024-09-14-tkinter_event_1.md collection=posts>, #<Jekyll::Document _posts/2024-05-14-raspi_python_tts.md collection=posts>, #<Jekyll::Document _posts/2023-05-19-key_commander_2.md collection=posts>, #<Jekyll::Document _posts/2023-05-17-test_shell_2.md collection=posts>, #<Jekyll::Document _posts/2022-06-22-Python_console_input.md collection=posts>, #<Jekyll::Document _posts/2022-03-21-RasPi_pwm.md collection=posts>, #<Jekyll::Document _posts/2022-03-18-mediapipe_hands_2.md collection=posts>, #<Jekyll::Document _posts/2022-03-17-mediapipe_hands.md collection=posts>, #<Jekyll::Document _posts/2022-02-07-ESP32_BLE_5.md collection=posts>, #<Jekyll::Document _posts/2022-01-31-ESP32_BLE_4.md collection=posts>, #<Jekyll::Document _posts/2020-10-31-Jetson_pyenv.md collection=posts>, #<Jekyll::Document _posts/2020-06-29-pyenv_bug.md collection=posts>, #<Jekyll::Document _posts/2020-06-29-junk.md collection=posts>, #<Jekyll::Document _posts/2020-06-29-csv2xls.md collection=posts>, #<Jekyll::Document _posts/2019-10-22-openCV_MPEG.md collection=posts>, #<Jekyll::Document _posts/2019-10-12-NCS_2.md collection=posts>, #<Jekyll::Document _posts/2019-09-03-WebIOPi.md collection=posts>, #<Jekyll::Document _posts/2019-06-27-pyenv.md collection=posts>, #<Jekyll::Document _posts/2019-06-22-asyncawait.md collection=posts>], "setup"=>[#<Jekyll::Document _posts/2024-07-21-install2404.md collection=posts>, #<Jekyll::Document _posts/2024-05-14-raspios_bookworm_install.md collection=posts>, #<Jekyll::Document _posts/2023-11-14-install2204.md collection=posts>, #<Jekyll::Document _posts/2022-07-24-install2204.md collection=posts>, #<Jekyll::Document _posts/2022-06-28-raspios_64_Imager.md collection=posts>, #<Jekyll::Document _posts/2022-02-25-raspios_64_20220128.md collection=posts>, #<Jekyll::Document _posts/2021-07-18-sd_image_2.md collection=posts>, #<Jekyll::Document _posts/2021-07-17-raspios_20210507.md collection=posts>, #<Jekyll::Document _posts/2021-07-15-install2004_native.md collection=posts>, #<Jekyll::Document _posts/2021-03-02-install2004.md collection=posts>, #<Jekyll::Document _posts/2020-05-08-ubuntu_native.md collection=posts>, #<Jekyll::Document _posts/2019-11-27-RaspbianArchives.md collection=posts>, #<Jekyll::Document _posts/2019-09-15-sd_image.md collection=posts>, #<Jekyll::Document _posts/2019-09-13-raspbian_buster_2.md collection=posts>, #<Jekyll::Document _posts/2019-08-31-raspbian_buster_1.md collection=posts>, #<Jekyll::Document _posts/2019-06-29-install1604.md collection=posts>, #<Jekyll::Document _posts/2019-06-26-install1804.md collection=posts>], "Node.js"=>[#<Jekyll::Document _posts/2019-10-04-node-red_9.md collection=posts>, #<Jekyll::Document _posts/2019-10-03-node-red_8.md collection=posts>, #<Jekyll::Document _posts/2019-10-01-spreadsheet.md collection=posts>, #<Jekyll::Document _posts/2019-09-16-node-red_6.md collection=posts>, #<Jekyll::Document _posts/2019-09-12-node-red_6.md collection=posts>, #<Jekyll::Document _posts/2019-09-11-node-red_5.md collection=posts>, #<Jekyll::Document _posts/2019-09-11-node-red_4.md collection=posts>, #<Jekyll::Document _posts/2019-09-10-node-red_3.md collection=posts>, #<Jekyll::Document _posts/2019-09-09-node-red_2.md collection=posts>, #<Jekyll::Document _posts/2019-09-04-node-red_1.md collection=posts>, #<Jekyll::Document _posts/2019-07-29-PastBlogs1.md collection=posts>, #<Jekyll::Document _posts/2019-06-28-nodenv.md collection=posts>], "Ruby"=>[#<Jekyll::Document _posts/2019-07-26-githubpages.md collection=posts>, #<Jekyll::Document _posts/2019-07-17-githubpages.md collection=posts>, #<Jekyll::Document _posts/2019-07-07-rbenv.md collection=posts>], "github"=>[#<Jekyll::Document _posts/2020-07-03-github_security.md collection=posts>, #<Jekyll::Document _posts/2019-07-26-githubpages.md collection=posts>, #<Jekyll::Document _posts/2019-07-17-githubpages.md collection=posts>], "samba"=>[#<Jekyll::Document _posts/2019-07-23-git_samba.md collection=posts>], "git"=>[#<Jekyll::Document _posts/2020-06-29-git_winmerge.md collection=posts>, #<Jekyll::Document _posts/2019-07-23-git_samba.md collection=posts>], "BME280"=>[#<Jekyll::Document _posts/2019-07-29-PastBlogs1.md collection=posts>], "BMX055"=>[#<Jekyll::Document _posts/2019-07-29-PastBlogs1.md collection=posts>], "I2C"=>[#<Jekyll::Document _posts/2019-07-29-PastBlogs1.md collection=posts>], "GPIO"=>[#<Jekyll::Document _posts/2022-03-21-RasPi_pwm.md collection=posts>, #<Jekyll::Document _posts/2019-07-29-PastBlogs1.md collection=posts>], "3D"=>[#<Jekyll::Document _posts/2019-07-29-PastBlogs1.md collection=posts>], "VSCode"=>[#<Jekyll::Document _posts/2023-09-03-RasPiPico_1.md collection=posts>, #<Jekyll::Document _posts/2021-10-12-VSCode_remoteDocker.md collection=posts>, #<Jekyll::Document _posts/2021-10-09-VSCode_Docker_python.md collection=posts>, #<Jekyll::Document _posts/2021-04-02-jupyter_on_VSCODE.md collection=posts>, #<Jekyll::Document _posts/2019-07-29-PastBlogs2.md collection=posts>], "リモートデバッグ"=>[#<Jekyll::Document _posts/2021-04-02-jupyter_on_VSCODE.md collection=posts>, #<Jekyll::Document _posts/2019-07-29-PastBlogs2.md collection=posts>], "DeepLearning"=>[#<Jekyll::Document _posts/2021-12-15-donkeycar_3.md collection=posts>, #<Jekyll::Document _posts/2021-12-09-donkeycar_2.md collection=posts>, #<Jekyll::Document _posts/2021-12-06-donkeycar_1.md collection=posts>, #<Jekyll::Document _posts/2021-09-14-Jetson_usb_boot.md collection=posts>, #<Jekyll::Document _posts/2021-09-14-Jetson_tigerVNC.md collection=posts>, #<Jekyll::Document _posts/2021-09-13-Jetson_nano_install.md collection=posts>, #<Jekyll::Document _posts/2021-05-12-tf2_transferlearning.md collection=posts>, #<Jekyll::Document _posts/2021-03-21-keras.md collection=posts>, #<Jekyll::Document _posts/2021-03-20-openVINO_pypi.md collection=posts>, #<Jekyll::Document _posts/2021-03-10-openVINO_on_WSL.md collection=posts>, #<Jekyll::Document _posts/2020-10-31-Jetson_pyenv.md collection=posts>, #<Jekyll::Document _posts/2020-10-30-Jetson_usb_boot.md collection=posts>, #<Jekyll::Document _posts/2020-10-25-Jetson_nano_backup.md collection=posts>, #<Jekyll::Document _posts/2020-10-23-Jetson_nano_install.md collection=posts>, #<Jekyll::Document _posts/2020-10-18-openVINO_ubuntu_3.md collection=posts>, #<Jekyll::Document _posts/2020-06-17-coral_6.md collection=posts>, #<Jekyll::Document _posts/2020-06-16-openVINO_ubuntu_2.md collection=posts>, #<Jekyll::Document _posts/2020-05-27-coral_5.md collection=posts>, #<Jekyll::Document _posts/2020-05-23-coral_4.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_3.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_2.md collection=posts>, #<Jekyll::Document _posts/2020-05-15-coral_1.md collection=posts>, #<Jekyll::Document _posts/2019-12-18-openVINO_SSD_2.md collection=posts>, #<Jekyll::Document _posts/2019-12-08-openVINO_face.md collection=posts>, #<Jekyll::Document _posts/2019-11-11-openVINO_YOLO2.md collection=posts>, #<Jekyll::Document _posts/2019-11-10-openVINO_SSD.md collection=posts>, #<Jekyll::Document _posts/2019-10-31-openVINO_YOLO _C++.md collection=posts>, #<Jekyll::Document _posts/2019-10-30-openVINO_YOLO.md collection=posts>, #<Jekyll::Document _posts/2019-10-17-openVINO_ubuntu.md collection=posts>, #<Jekyll::Document _posts/2019-10-12-NCS_2.md collection=posts>, #<Jekyll::Document _posts/2019-09-01-NCS_1.md collection=posts>, #<Jekyll::Document _posts/2019-08-22-TinyYOLO_src.md collection=posts>, #<Jekyll::Document _posts/2019-08-22-TinyYOLO_5.md collection=posts>, #<Jekyll::Document _posts/2019-08-22-TinyYOLO_4.md collection=posts>, #<Jekyll::Document _posts/2019-08-22-TinyYOLO_3.md collection=posts>, #<Jekyll::Document _posts/2019-08-22-TinyYOLO_2.md collection=posts>, #<Jekyll::Document _posts/2019-08-22-TinyYOLO_1.md collection=posts>], "TinyYOLO"=>[#<Jekyll::Document _posts/2019-08-22-TinyYOLO_src.md collection=posts>, #<Jekyll::Document _posts/2019-08-22-TinyYOLO_5.md collection=posts>, #<Jekyll::Document _posts/2019-08-22-TinyYOLO_4.md collection=posts>, #<Jekyll::Document _posts/2019-08-22-TinyYOLO_3.md collection=posts>, #<Jekyll::Document _posts/2019-08-22-TinyYOLO_2.md collection=posts>, #<Jekyll::Document _posts/2019-08-22-TinyYOLO_1.md collection=posts>], "NCStick2"=>[#<Jekyll::Document _posts/2022-09-06-openVINO_2022_build_1.md collection=posts>, #<Jekyll::Document _posts/2020-10-18-openVINO_ubuntu_3.md collection=posts>, #<Jekyll::Document _posts/2020-06-16-openVINO_ubuntu_2.md collection=posts>, #<Jekyll::Document _posts/2019-10-12-NCS_2.md collection=posts>, #<Jekyll::Document _posts/2019-09-01-NCS_1.md collection=posts>], "openVINO"=>[#<Jekyll::Document _posts/2022-09-09-openVINO_build_2022_2.md collection=posts>, #<Jekyll::Document _posts/2022-09-06-openVINO_2022_build_1.md collection=posts>, #<Jekyll::Document _posts/2022-03-10-openVINO_build_3.md collection=posts>, #<Jekyll::Document _posts/2022-03-07-openVINO_build_2.md collection=posts>, #<Jekyll::Document _posts/2021-10-20-openVINO_build.md collection=posts>, #<Jekyll::Document _posts/2021-10-20-Docker_openVINO.md collection=posts>, #<Jekyll::Document _posts/2021-03-20-openVINO_pypi.md collection=posts>, #<Jekyll::Document _posts/2021-03-10-openVINO_on_WSL.md collection=posts>, #<Jekyll::Document _posts/2020-10-18-openVINO_ubuntu_3.md collection=posts>, #<Jekyll::Document _posts/2020-06-16-openVINO_ubuntu_2.md collection=posts>, #<Jekyll::Document _posts/2019-12-18-openVINO_SSD_2.md collection=posts>, #<Jekyll::Document _posts/2019-12-08-openVINO_face.md collection=posts>, #<Jekyll::Document _posts/2019-11-11-openVINO_YOLO2.md collection=posts>, #<Jekyll::Document _posts/2019-11-10-openVINO_SSD.md collection=posts>, #<Jekyll::Document _posts/2019-10-31-openVINO_YOLO _C++.md collection=posts>, #<Jekyll::Document _posts/2019-10-30-openVINO_YOLO.md collection=posts>, #<Jekyll::Document _posts/2019-10-17-openVINO_ubuntu.md collection=posts>, #<Jekyll::Document _posts/2019-10-12-NCS_2.md collection=posts>, #<Jekyll::Document _posts/2019-09-01-NCS_1.md collection=posts>], "WebIOPi"=>[#<Jekyll::Document _posts/2019-09-03-WebIOPi.md collection=posts>], "Node-RED"=>[#<Jekyll::Document _posts/2019-10-04-node-red_9.md collection=posts>, #<Jekyll::Document _posts/2019-10-03-node-red_8.md collection=posts>, #<Jekyll::Document _posts/2019-09-16-node-red_6.md collection=posts>, #<Jekyll::Document _posts/2019-09-12-node-red_6.md collection=posts>, #<Jekyll::Document _posts/2019-09-11-node-red_5.md collection=posts>, #<Jekyll::Document _posts/2019-09-11-node-red_4.md collection=posts>, #<Jekyll::Document _posts/2019-09-10-node-red_3.md collection=posts>, #<Jekyll::Document _posts/2019-09-09-node-red_2.md collection=posts>, #<Jekyll::Document _posts/2019-09-04-node-red_1.md collection=posts>], "Google"=>[#<Jekyll::Document _posts/2021-02-22-GAS_gmail.md collection=posts>, #<Jekyll::Document _posts/2021-02-18-GAS_LINE.md collection=posts>, #<Jekyll::Document _posts/2021-02-16-spreadsheet_RESET_2.md collection=posts>, #<Jekyll::Document _posts/2021-02-15-spreadsheet_RESET.md collection=posts>, #<Jekyll::Document _posts/2019-10-04-node-red_9.md collection=posts>, #<Jekyll::Document _posts/2019-10-03-node-red_8.md collection=posts>, #<Jekyll::Document _posts/2019-10-01-spreadsheet.md collection=posts>], "openCV"=>[#<Jekyll::Document _posts/2019-10-22-openCV_MPEG.md collection=posts>], "YOLOv3"=>[#<Jekyll::Document _posts/2019-10-23-YOLO_trial.md collection=posts>], "VcXsrv"=>[#<Jekyll::Document _posts/2021-03-13-WSL_Xwindow.md collection=posts>, #<Jekyll::Document _posts/2019-11-26-VcXsrv.md collection=posts>], "Google Coral USB Accelerator"=>[#<Jekyll::Document _posts/2020-05-15-coral_1.md collection=posts>], "tflite"=>[#<Jekyll::Document _posts/2020-06-17-coral_6.md collection=posts>, #<Jekyll::Document _posts/2020-05-27-coral_5.md collection=posts>, #<Jekyll::Document _posts/2020-05-23-coral_4.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_3.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_2.md collection=posts>, #<Jekyll::Document _posts/2020-05-15-coral_1.md collection=posts>], "Edge-TPU"=>[#<Jekyll::Document _posts/2020-06-17-coral_6.md collection=posts>, #<Jekyll::Document _posts/2020-05-27-coral_5.md collection=posts>, #<Jekyll::Document _posts/2020-05-23-coral_4.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_3.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_2.md collection=posts>, #<Jekyll::Document _posts/2020-05-15-coral_1.md collection=posts>], "Coral USB Accelerator"=>[#<Jekyll::Document _posts/2020-06-17-coral_6.md collection=posts>, #<Jekyll::Document _posts/2020-05-27-coral_5.md collection=posts>, #<Jekyll::Document _posts/2020-05-23-coral_4.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_3.md collection=posts>, #<Jekyll::Document _posts/2020-05-16-coral_2.md collection=posts>], "WSL"=>[#<Jekyll::Document _posts/2025-6-9-WSL_USB_1.md collection=posts>, #<Jekyll::Document _posts/2024-07-24-WSL_memo2.md collection=posts>, #<Jekyll::Document _posts/2024-07-13-wsl_usb_3.md collection=posts>, #<Jekyll::Document _posts/2024-07-11-wsl_kernel_build.md collection=posts>, #<Jekyll::Document _posts/2024-07-03-wsl_usb_1.md collection=posts>, #<Jekyll::Document _posts/2021-04-02-jupyter_on_VSCODE.md collection=posts>, #<Jekyll::Document _posts/2021-03-21-keras.md collection=posts>, #<Jekyll::Document _posts/2021-03-20-openVINO_pypi.md collection=posts>, #<Jekyll::Document _posts/2021-03-13-WSL_Xwindow.md collection=posts>, #<Jekyll::Document _posts/2021-03-10-openVINO_on_WSL.md collection=posts>, #<Jekyll::Document _posts/2021-03-03-WSL_memo.md collection=posts>, #<Jekyll::Document _posts/2020-06-29-git_winmerge.md collection=posts>], "wireshark"=>[#<Jekyll::Document _posts/2020-09-02-wireshark_3.md collection=posts>, #<Jekyll::Document _posts/2020-08-30-wireshark_2.md collection=posts>, #<Jekyll::Document _posts/2020-08-30-wireshark_1.md collection=posts>], "Jetson nano"=>[#<Jekyll::Document _posts/2021-09-14-Jetson_usb_boot.md collection=posts>, #<Jekyll::Document _posts/2021-09-14-Jetson_tigerVNC.md collection=posts>, #<Jekyll::Document _posts/2021-09-13-Jetson_nano_install.md collection=posts>, #<Jekyll::Document _posts/2020-10-31-Jetson_pyenv.md collection=posts>, #<Jekyll::Document _posts/2020-10-30-Jetson_usb_boot.md collection=posts>, #<Jekyll::Document _posts/2020-10-25-Jetson_nano_backup.md collection=posts>, #<Jekyll::Document _posts/2020-10-23-Jetson_nano_install.md collection=posts>], "Keras"=>[#<Jekyll::Document _posts/2021-03-21-keras.md collection=posts>], "Tensorflow"=>[#<Jekyll::Document _posts/2021-12-09-donkeycar_2.md collection=posts>, #<Jekyll::Document _posts/2021-12-06-donkeycar_1.md collection=posts>, #<Jekyll::Document _posts/2021-05-12-tf2_transferlearning.md collection=posts>, #<Jekyll::Document _posts/2021-03-21-keras.md collection=posts>], "Docker"=>[#<Jekyll::Document _posts/2022-09-09-openVINO_build_2022_2.md collection=posts>, #<Jekyll::Document _posts/2022-03-10-openVINO_build_3.md collection=posts>, #<Jekyll::Document _posts/2022-03-07-openVINO_build_2.md collection=posts>, #<Jekyll::Document _posts/2021-10-20-openVINO_build.md collection=posts>, #<Jekyll::Document _posts/2021-10-20-Docker_openVINO.md collection=posts>, #<Jekyll::Document _posts/2021-10-12-VSCode_remoteDocker.md collection=posts>, #<Jekyll::Document _posts/2021-10-11-SSH_setup.md collection=posts>, #<Jekyll::Document _posts/2021-10-10-Docker_gui.md collection=posts>, #<Jekyll::Document _posts/2021-10-09-VSCode_Docker_python.md collection=posts>, #<Jekyll::Document _posts/2021-10-08-Docker_install.md collection=posts>], "pytorch"=>[#<Jekyll::Document _posts/2021-12-15-donkeycar_3.md collection=posts>], "ESP32"=>[#<Jekyll::Document _posts/2022-02-16-ESP32_BT_SPP_1.md collection=posts>, #<Jekyll::Document _posts/2022-02-07-ESP32_BLE_5.md collection=posts>, #<Jekyll::Document _posts/2022-01-31-ESP32_BLE_4.md collection=posts>, #<Jekyll::Document _posts/2022-01-28-ESP32_BLE_3.md collection=posts>, #<Jekyll::Document _posts/2022-01-21-ESP32_BLE_2.md collection=posts>, #<Jekyll::Document _posts/2022-01-19-ESP32_BLE_1.md collection=posts>, #<Jekyll::Document _posts/2021-12-27-ESP32_JTAG.md collection=posts>], "BLE"=>[#<Jekyll::Document _posts/2025-4-21-Buildozer_3.md collection=posts>, #<Jekyll::Document _posts/2024-07-29-web_bt_api.md collection=posts>, #<Jekyll::Document _posts/2022-02-07-ESP32_BLE_5.md collection=posts>, #<Jekyll::Document _posts/2022-01-31-ESP32_BLE_4.md collection=posts>, #<Jekyll::Document _posts/2022-01-28-ESP32_BLE_3.md collection=posts>, #<Jekyll::Document _posts/2022-01-21-ESP32_BLE_2.md collection=posts>, #<Jekyll::Document _posts/2022-01-19-ESP32_BLE_1.md collection=posts>], "Bluetooth classic"=>[#<Jekyll::Document _posts/2022-02-16-ESP32_BT_SPP_1.md collection=posts>], "MediaPipe"=>[#<Jekyll::Document _posts/2022-03-18-mediapipe_hands_2.md collection=posts>, #<Jekyll::Document _posts/2022-03-17-mediapipe_hands.md collection=posts>], "linux"=>[#<Jekyll::Document _posts/2023-05-19-key_commander_2.md collection=posts>, #<Jekyll::Document _posts/2023-05-18-key_commander_1.md collection=posts>, #<Jekyll::Document _posts/2023-05-17-test_shell_2.md collection=posts>, #<Jekyll::Document _posts/2023-05-15-test_shell_1.md collection=posts>], "sample program"=>[#<Jekyll::Document _posts/2023-05-19-key_commander_2.md collection=posts>, #<Jekyll::Document _posts/2023-05-18-key_commander_1.md collection=posts>, #<Jekyll::Document _posts/2023-05-17-test_shell_2.md collection=posts>, #<Jekyll::Document _posts/2023-05-15-test_shell_1.md collection=posts>], "RaspberryPiPICO"=>[#<Jekyll::Document _posts/2024-08-30-RasPiPico_i2c_slave_2.md collection=posts>, #<Jekyll::Document _posts/2024-07-29-web_bt_api.md collection=posts>, #<Jekyll::Document _posts/2023-10-28-RasPiPico_i2c_slave.md collection=posts>, #<Jekyll::Document _posts/2023-10-23-RasPiPico_3.md collection=posts>, #<Jekyll::Document _posts/2023-10-11-RasPiPico_2.md collection=posts>, #<Jekyll::Document _posts/2023-09-03-RasPiPico_1.md collection=posts>], "micropython"=>[#<Jekyll::Document _posts/2023-09-03-RasPiPico_1.md collection=posts>], "HTML"=>[#<Jekyll::Document _posts/2024-07-28-HTML_pseudo_toast.md collection=posts>], " micropython"=>[#<Jekyll::Document _posts/2024-07-29-web_bt_api.md collection=posts>], "tkinter"=>[#<Jekyll::Document _posts/2024-09-16-tkinter_canvas_1.md collection=posts>, #<Jekyll::Document _posts/2024-09-14-tkinter_event_1.md collection=posts>], "renode"=>[#<Jekyll::Document _posts/2024-10-13-renode_1.md collection=posts>], "STM32"=>[#<Jekyll::Document _posts/2024-10-13-renode_1.md collection=posts>], "TkEasyGUI"=>[#<Jekyll::Document _posts/2025-1-7-TkEasyGUI_1.md collection=posts>], "openpyxl"=>[#<Jekyll::Document _posts/2025-1-7-openpuxl_bug.md collection=posts>], "MSYS2"=>[#<Jekyll::Document _posts/2025-3-24-MSYS2_1.md collection=posts>], "gcc"=>[#<Jekyll::Document _posts/2025-3-24-MSYS2_1.md collection=posts>], "Android"=>[#<Jekyll::Document _posts/2025-4-21-Buildozer_3.md collection=posts>, #<Jekyll::Document _posts/2025-4-4-Buildozer_2.md collection=posts>, #<Jekyll::Document _posts/2025-3-31-Buildozer_1.md collection=posts>], "kivy"=>[#<Jekyll::Document _posts/2025-5-19-kivy_5.md collection=posts>, #<Jekyll::Document _posts/2025-4-30-kivy_4.md collection=posts>, #<Jekyll::Document _posts/2025-4-29-kivy_3 .md collection=posts>, #<Jekyll::Document _posts/2025-4-26-kivy_2.md collection=posts>, #<Jekyll::Document _posts/2025-4-16-kivy_1.md collection=posts>]}

site.tags のキー 一覧

["Ubuntu", "RaspberryPi", "Windows", "python", "setup", "Node.js", "Ruby", "github", "samba", "git", "BME280", "BMX055", "I2C", "GPIO", "3D", "VSCode", "リモートデバッグ", "DeepLearning", "TinyYOLO", "NCStick2", "openVINO", "WebIOPi", "Node-RED", "Google", "openCV", "YOLOv3", "VcXsrv", "Google Coral USB Accelerator", "tflite", "Edge-TPU", "Coral USB Accelerator", "WSL", "wireshark", "Jetson nano", "Keras", "Tensorflow", "Docker", "pytorch", "ESP32", "BLE", "Bluetooth classic", "MediaPipe", "linux", "sample program", "RaspberryPiPICO", "micropython", "HTML", " micropython", "tkinter", "renode", "STM32", "TkEasyGUI", "openpyxl", "MSYS2", "gcc", "Android", "kivy"]

site.posts[1]変数

site.posts[1] = 
{
  "path": "_posts/2025-5-19-kivy_5.md",
  "relative_path": "_posts/2025-5-19-kivy_5.md",
  "excerpt": "kivyでドラッグで並べ替えできるリストを作った時のメモ",
  "previous": {
    "path": "_posts/2025-4-30-kivy_4.md",
    "relative_path": "_posts/2025-4-30-kivy_4.md",
    "excerpt": "kivyで画面遷移する方法について",
    "previous": {
      "path": "_posts/2025-4-29-kivy_3 .md",
      "relative_path": "_posts/2025-4-29-kivy_3 .md",
      "excerpt": "kivyのSpinner(ドロップダウンリスト)をカスタマイズする",
      "previous": {
        "path": "_posts/2025-4-26-kivy_2.md",
        "relative_path": "_posts/2025-4-26-kivy_2.md",
        "id": "/2025/04/26/kivy_2",
        "collection": "posts",
        "url": "/2025/04/26/kivy_2.html",
        "draft": false,
        "categories": [

        ],
        "title": "kivyのButtonの色を変更する",
        "date": "2025-04-26 00:00:00 +0000",
        "tags": [
          "kivy",
          "python"
        ],
        "layout": "default",
        "slug": "kivy_2",
        "ext": ".md"
      },
      "id": "/2025/04/29/kivy_3 ",
      "collection": "posts",
      "next": {
        "path": "_posts/2025-4-30-kivy_4.md",
        "relative_path": "_posts/2025-4-30-kivy_4.md",
        "id": "/2025/04/30/kivy_4",
        "collection": "posts",
        "url": "/2025/04/30/kivy_4.html",
        "draft": false,
        "categories": [

        ],
        "title": "kivyで画面遷移",
        "date": "2025-04-30 00:00:00 +0000",
        "tags": [
          "kivy",
          "python"
        ],
        "layout": "default",
        "slug": "kivy_4",
        "ext": ".md"
      },
      "output": "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyのSpinnerをカスタマイズ</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyのSpinnerをカスタマイズ</h1>\n      <p>kivyのSpinner(ドロップダウンリスト)をカスタマイズする</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nSpinner(ドロップダウンリスト)の項目の表示がすべて同じ色で現在選択されている項目がどれか一目で分からなかったので\n選択されている項目の色が変わるようにカスタマイズしてみた。</p>\n\n<p><a href=\"/memoBlog/2025/04/26/kivy_2.html\">kivyのButtonの色を変更する</a>ではButtonをカスタマイズして\n簡単に背景色を変更できるようにしたので、それを使えばわりとお手軽にできそうな感じ。</p>\n\n<h1 id=\"カスタマイズ内容\">カスタマイズ内容</h1>\n<ul>\n  <li>ドロップダウンの項目の表示色を選択中のものとそれ以外のもので分ける</li>\n  <li>それらの色(背景/文字)はプロパティで指定する</li>\n  <li>ドロップダウンの項目の表示高さをプロパティで指定する</li>\n</ul>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7.js\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyではドロップダウンリスト(クリックすると選択項目がぺろっと出てくるやつ)を表示するのにSpinnerウィジェットを使う。<br />\nで、クリックすると設定された項目が表示されるのだけれど、すべて同じ色(通常時、クリックした時、無効化した時の色はそれぞれ画像で指定できる)\nで表示され、現在どれを選択しているのかが分かり難い。<br />\nそこで、現在選択されている項目の色(画像でなく)を変更できるようにカスタマイズする。</p>\n\n<p>色指定に関して、<code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと項目を表示するための<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスはどちらも<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスを継承しているので、\n<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを同時に継承することで<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスに関連する処理を置き換えられる。</p>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスを作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスは特に追加する処理などはない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinnerOption</span><span class=\"p\">(</span><span class=\"n\">SpinnerOption</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n    <span class=\"k\">pass</span>\n</code></pre></div></div>\n\n<p>次に <code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinner</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinner</span><span class=\"p\">(</span><span class=\"n\">Spinner</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>追加するプロパティ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">item_selected_bg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の背景色\n</span>    <span class=\"n\">item_selected_fg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_unselected_bg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 非選択項目の背景色\n</span>    <span class=\"n\">item_unselected_fg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_height</span>          <span class=\"o\">=</span> <span class=\"n\">NumericProperty</span><span class=\"p\">(</span><span class=\"s\">'48dp'</span><span class=\"p\">)</span>               <span class=\"c1\"># 項目の高さ(デフォルトは48dp)\n</span></code></pre></div></div>\n\n<p>コンストラクタでは<code class=\"language-plaintext highlighter-rouge\">option_cls</code>のデフォルト値を<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>に設定し、基底クラスのコンストラクタを実行。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"s\">'option_cls'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">kwargs</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 項目表示用クラスが指定されていなければCustomSpinnerOptionを指定\n</span>            <span class=\"n\">kwargs</span><span class=\"p\">[</span><span class=\"s\">'option_cls'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">CustomSpinnerOption</span>\n        \n        <span class=\"c1\"># 基底クラスの初期化\n</span>        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">CustomSpinner</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>その後、追加した各プロパティと<code class=\"language-plaintext highlighter-rouge\">text</code>プロパティの変更時の処理をバインドする。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span>\n                    <span class=\"n\">text</span>                <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_bg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_bg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_fg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_fg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_height</span>         <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 項目高さ\n</span>                <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの項目の色などを変更する処理を追加。<br />\nこの処理が各プロパティの変更時の処理としてバインドされる。</p>\n\n<p>項目の一覧は<code class=\"language-plaintext highlighter-rouge\">self._dropdown.container.children</code>か<code class=\"language-plaintext highlighter-rouge\">self._dropdown.children</code>にあるので判断して取得。</p>\n\n<p>選択されている項目か否かは各項目の<code class=\"language-plaintext highlighter-rouge\">text</code>と<code class=\"language-plaintext highlighter-rouge\">self.text</code>が一致しているかどうかで判断できるので、\nこの条件で設定する色を変更。<br />\nまた、項目すべてをループするので、ついでに項目高さ(<code class=\"language-plaintext highlighter-rouge\">height</code>)も変更しておく。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ドロップダウン内の項目の高さ/背景色/文字色を更新\n</span>    <span class=\"k\">def</span> <span class=\"nf\">update_dropdown_background</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">text</span>\n        <span class=\"c1\"># 項目のリストを取得\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        \n        <span class=\"c1\"># 各項目の背景色/文字色を変更\n</span>        <span class=\"k\">for</span> <span class=\"n\">item</span> <span class=\"ow\">in</span> <span class=\"n\">items</span><span class=\"p\">:</span>\n            <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_height</span>                      <span class=\"c1\"># 項目高さ\n</span>            <span class=\"k\">if</span> <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">==</span> <span class=\"n\">text</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_bg</span>    <span class=\"c1\"># 選択中の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_fg</span>    <span class=\"c1\"># 選択中の文字色\n</span>            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_bg</span>  <span class=\"c1\"># 非選択の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_fg</span>  <span class=\"c1\"># 非選択中の文字色\n</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの更新処理をオーバーライド。<br />\nこの処理はドロップダウンの新規作成時や項目追加時にコールされる。<br />\nここに上のドロップダウンの項目の色などを変更する処理のコールを追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">_update_dropdown</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">_update_dropdown</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 項目の背景色等を更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>ついでに項目の追加処理を追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># 項目の追加\n</span>    <span class=\"k\">def</span> <span class=\"nf\">add_item</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">values</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>以上でカスタマイズは終了。</p>\n\n<h1 id=\"動作確認プログラム\">動作確認プログラム</h1>\n<p>このファイルを単体で実行すれば動作確認プログラムが動作する。<br />\n動作確認ではAddボタンをクリックする度にドロップダウンリストの項目が追加されるようになっている。<br />\nSpinnerのボタンをクリックするとドロップダウンリストが表示され、現在選択されている項目が他の色で表示されている。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "content": "<h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nSpinner(ドロップダウンリスト)の項目の表示がすべて同じ色で現在選択されている項目がどれか一目で分からなかったので\n選択されている項目の色が変わるようにカスタマイズしてみた。</p>\n\n<p><a href=\"/memoBlog/2025/04/26/kivy_2.html\">kivyのButtonの色を変更する</a>ではButtonをカスタマイズして\n簡単に背景色を変更できるようにしたので、それを使えばわりとお手軽にできそうな感じ。</p>\n\n<h1 id=\"カスタマイズ内容\">カスタマイズ内容</h1>\n<ul>\n  <li>ドロップダウンの項目の表示色を選択中のものとそれ以外のもので分ける</li>\n  <li>それらの色(背景/文字)はプロパティで指定する</li>\n  <li>ドロップダウンの項目の表示高さをプロパティで指定する</li>\n</ul>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7\" target=\"_blank\">こちら</a>\nからどうぞ。</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/6eec7b2ff580f2c0a3ff9706476f93e7.js\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyではドロップダウンリスト(クリックすると選択項目がぺろっと出てくるやつ)を表示するのにSpinnerウィジェットを使う。<br />\nで、クリックすると設定された項目が表示されるのだけれど、すべて同じ色(通常時、クリックした時、無効化した時の色はそれぞれ画像で指定できる)\nで表示され、現在どれを選択しているのかが分かり難い。<br />\nそこで、現在選択されている項目の色(画像でなく)を変更できるようにカスタマイズする。</p>\n\n<p>色指定に関して、<code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと項目を表示するための<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスはどちらも<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスを継承しているので、\n<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを同時に継承することで<code class=\"language-plaintext highlighter-rouge\">Button</code>クラスに関連する処理を置き換えられる。</p>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">SpinnerOption</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスを作成する。<br />\n<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>クラスは特に追加する処理などはない。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinnerOption</span><span class=\"p\">(</span><span class=\"n\">SpinnerOption</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n    <span class=\"k\">pass</span>\n</code></pre></div></div>\n\n<p>次に <code class=\"language-plaintext highlighter-rouge\">Spinner</code>クラスと<code class=\"language-plaintext highlighter-rouge\">CustomButton</code>クラスを継承した<code class=\"language-plaintext highlighter-rouge\">CustomSpinner</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">CustomSpinner</span><span class=\"p\">(</span><span class=\"n\">Spinner</span><span class=\"p\">,</span> <span class=\"n\">CustomButton</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>追加するプロパティ</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">item_selected_bg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の背景色\n</span>    <span class=\"n\">item_selected_fg</span>     <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_unselected_bg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 非選択項目の背景色\n</span>    <span class=\"n\">item_unselected_fg</span>   <span class=\"o\">=</span> <span class=\"n\">ColorProperty</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>   <span class=\"c1\"># 選択項目の文字色\n</span>    <span class=\"n\">item_height</span>          <span class=\"o\">=</span> <span class=\"n\">NumericProperty</span><span class=\"p\">(</span><span class=\"s\">'48dp'</span><span class=\"p\">)</span>               <span class=\"c1\"># 項目の高さ(デフォルトは48dp)\n</span></code></pre></div></div>\n\n<p>コンストラクタでは<code class=\"language-plaintext highlighter-rouge\">option_cls</code>のデフォルト値を<code class=\"language-plaintext highlighter-rouge\">CustomSpinnerOption</code>に設定し、基底クラスのコンストラクタを実行。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"s\">'option_cls'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">kwargs</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 項目表示用クラスが指定されていなければCustomSpinnerOptionを指定\n</span>            <span class=\"n\">kwargs</span><span class=\"p\">[</span><span class=\"s\">'option_cls'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">CustomSpinnerOption</span>\n        \n        <span class=\"c1\"># 基底クラスの初期化\n</span>        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">CustomSpinner</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>その後、追加した各プロパティと<code class=\"language-plaintext highlighter-rouge\">text</code>プロパティの変更時の処理をバインドする。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">bind</span><span class=\"p\">(</span>\n                    <span class=\"n\">text</span>                <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_bg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_bg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_selected_fg</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_unselected_fg</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 非選択項目の背景色変更時に背景色を更新\n</span>                    <span class=\"n\">item_height</span>         <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">,</span>  <span class=\"c1\"># 項目高さ\n</span>                <span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの項目の色などを変更する処理を追加。<br />\nこの処理が各プロパティの変更時の処理としてバインドされる。</p>\n\n<p>項目の一覧は<code class=\"language-plaintext highlighter-rouge\">self._dropdown.container.children</code>か<code class=\"language-plaintext highlighter-rouge\">self._dropdown.children</code>にあるので判断して取得。</p>\n\n<p>選択されている項目か否かは各項目の<code class=\"language-plaintext highlighter-rouge\">text</code>と<code class=\"language-plaintext highlighter-rouge\">self.text</code>が一致しているかどうかで判断できるので、\nこの条件で設定する色を変更。<br />\nまた、項目すべてをループするので、ついでに項目高さ(<code class=\"language-plaintext highlighter-rouge\">height</code>)も変更しておく。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ドロップダウン内の項目の高さ/背景色/文字色を更新\n</span>    <span class=\"k\">def</span> <span class=\"nf\">update_dropdown_background</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">text</span>\n        <span class=\"c1\"># 項目のリストを取得\n</span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">container</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">_dropdown</span><span class=\"p\">.</span><span class=\"n\">children</span>\n        \n        <span class=\"c1\"># 各項目の背景色/文字色を変更\n</span>        <span class=\"k\">for</span> <span class=\"n\">item</span> <span class=\"ow\">in</span> <span class=\"n\">items</span><span class=\"p\">:</span>\n            <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_height</span>                      <span class=\"c1\"># 項目高さ\n</span>            <span class=\"k\">if</span> <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">==</span> <span class=\"n\">text</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_bg</span>    <span class=\"c1\"># 選択中の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_selected_fg</span>    <span class=\"c1\"># 選択中の文字色\n</span>            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">bg_color_normal</span>    <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_bg</span>  <span class=\"c1\"># 非選択の背景色\n</span>                <span class=\"n\">item</span><span class=\"p\">.</span><span class=\"n\">color</span>              <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">item_unselected_fg</span>  <span class=\"c1\"># 非選択中の文字色\n</span>\n</code></pre></div></div>\n\n<p>ドロップダウンの更新処理をオーバーライド。<br />\nこの処理はドロップダウンの新規作成時や項目追加時にコールされる。<br />\nここに上のドロップダウンの項目の色などを変更する処理のコールを追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">_update_dropdown</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">().</span><span class=\"n\">_update_dropdown</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">largs</span><span class=\"p\">)</span>\n        \n        <span class=\"c1\"># 項目の背景色等を更新\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">update_dropdown_background</span><span class=\"p\">()</span>\n</code></pre></div></div>\n\n<p>ついでに項目の追加処理を追加。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># 項目の追加\n</span>    <span class=\"k\">def</span> <span class=\"nf\">add_item</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">values</span><span class=\"p\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<p>以上でカスタマイズは終了。</p>\n\n<h1 id=\"動作確認プログラム\">動作確認プログラム</h1>\n<p>このファイルを単体で実行すれば動作確認プログラムが動作する。<br />\n動作確認ではAddボタンをクリックする度にドロップダウンリストの項目が追加されるようになっている。<br />\nSpinnerのボタンをクリックするとドロップダウンリストが表示され、現在選択されている項目が他の色で表示されている。</p>\n",
      "url": "/2025/04/29/kivy_3.html",
      "draft": false,
      "categories": [

      ],
      "title": "kivyのSpinnerをカスタマイズ",
      "date": "2025-04-29 00:00:00 +0000",
      "tags": [
        "kivy",
        "python"
      ],
      "layout": "default",
      "slug": "kivy_3 ",
      "ext": ".md"
    },
    "id": "/2025/04/30/kivy_4",
    "collection": "posts",
    "next": {
      "path": "_posts/2025-5-19-kivy_5.md",
      "relative_path": "_posts/2025-5-19-kivy_5.md",
      "excerpt": "kivyでドラッグで並べ替えできるリストを作った時のメモ",
      "previous": {
        "path": "_posts/2025-4-30-kivy_4.md",
        "relative_path": "_posts/2025-4-30-kivy_4.md",
        "id": "/2025/04/30/kivy_4",
        "collection": "posts",
        "url": "/2025/04/30/kivy_4.html",
        "draft": false,
        "categories": [

        ],
        "title": "kivyで画面遷移",
        "date": "2025-04-30 00:00:00 +0000",
        "tags": [
          "kivy",
          "python"
        ],
        "layout": "default",
        "slug": "kivy_4",
        "ext": ".md"
      },
      "id": "/2025/05/19/kivy_5",
      "collection": "posts",
      "next": {
        "path": "_posts/2025-6-9-WSL_USB_1.md",
        "relative_path": "_posts/2025-6-9-WSL_USB_1.md",
        "id": "/2025/06/09/WSL_USB_1",
        "collection": "posts",
        "url": "/2025/06/09/WSL_USB_1.html",
        "draft": false,
        "categories": [

        ],
        "title": "WSLでUSB",
        "date": "2025-06-09 00:00:00 +0000",
        "tags": [
          "WSL"
        ],
        "layout": "default",
        "slug": "WSL_USB_1",
        "ext": ".md"
      },
      "output": "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyでドラッグで並べ替えできるリスト</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyでドラッグで並べ替えできるリスト</h1>\n      <p>kivyでドラッグで並べ替えできるリストを作った時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nドラッグで並べ替えできるリスト(AndroidでよくあるUI、<code class=\"language-plaintext highlighter-rouge\">RecycleView</code>と<code class=\"language-plaintext highlighter-rouge\">ItemTouchHelper</code>で作るんだったかな?)\nを作ってみた時のメモ。<br />\n<a href=\"https://maausa.marurm.com/wp-content/uploads/RecyclerView.gif\" target=\"_blank\">ちょっと違うけど、大体こんな感じ</a></p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nreorderablelist.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=reorderablelist.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>ソースは、表示する項目を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>と\nリスト全体を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>で構成される。<br />\n(あと、単体実行で動作するテストプログラム)<br />\n動作としては、</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>に<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を追加していきリスト化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code> をドラッグすることで並べ替え</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を左右にスワイプすることでハンドラ実行(デフォルトでは右スワイプで項目削除)\nといった感じ。</li>\n</ul>\n\n<p>テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>を<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>で囲んでスクロール可能にしています。\nスクロール不要ならそのまま配置しても可(テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">with_scroll</code>を<code class=\"language-plaintext highlighter-rouge\">False</code>に設定)。</p>\n\n<h2 id=\"reorderablelist\">ReorderableList</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>はリスト全体を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承したクラス。</p>\n\n<h3 id=\"追加したプロパティ\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>item_bg</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>item_fg</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>list_bg</td>\n      <td>リストの背景色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\n(<code class=\"language-plaintext highlighter-rouge\">orientation</code>は<code class=\"language-plaintext highlighter-rouge\">\"vertical\"</code>固定(項目を縦方向に並べるため)、\n<code class=\"language-plaintext highlighter-rouge\">size_hint_y</code>は<code class=\"language-plaintext highlighter-rouge\">None</code>固定(ScrollViewに包むため))\nのほか、<br />\n背景色の設定と、スクロール可能にするためminimum_height変更時の処理のbindを行っている。</p>\n\n<h3 id=\"項目追加処理\">項目追加処理</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">add_item</code>が項目追加処理。<br />\nパラメータは<code class=\"language-plaintext highlighter-rouge\">cls</code>で項目表示に使用するクラス(デフォルトは<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>)と、項目表示クラスの初期化パラメータを受け取る。<br />\nこれは項目に表示する内容を柔軟に切り替えられるよう、項目表示クラスを<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を継承したクラスに切り替えられるようにするため。</p>\n\n<h3 id=\"レイアウト処理\">レイアウト処理</h3>\n<p>kivyでは、レイアウトの変更命令と実際に変更が行われるまでにディレイがある。<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">add_widget(wid)</code> して直後にwid.posを読み出すと実際に追加されたあとの位置が読み出せない。<br />\nこれは、<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>では処理の予約だけ行い、実際に描画が行われるのは別のところ(<code class=\"language-plaintext highlighter-rouge\">mainloop</code>?)で\n他のウィジェットのレイアウト結果を五月雨式に反映していくため、\n描画結果がposに反映されるまでタイムラグが発生するためと思われる。</p>\n\n<p>そこで、<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>のレイアウトが変更され、処理が終了したタイミングで子ウィジェットに\nレイアウト完了を通知できるよう<code class=\"language-plaintext highlighter-rouge\">do_layout()</code>をオーバライドし、基底クラスの処理が完了した後\n各子ウィジェットの<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>をコールしている。</p>\n\n<h2 id=\"reorderableitem\">ReorderableItem</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>はリストに表示する項目を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスと<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承している。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスはドラッグ処理を実現するクラス。<br />\nもう一つの基底クラスを<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>とすることで、派生クラスのレイアウトを柔軟に設定できるようにしている。</p>\n\n<h3 id=\"追加したプロパティ-1\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>text</td>\n      <td>項目に表示する文字列</td>\n    </tr>\n    <tr>\n      <td>bg_color</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>fg_color</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ-1\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\nのほか、<br />\n項目内部の構築(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)、\n背景色の設定と、pos/size変更時にドラッグ範囲を変更する処理のbind、\nインスタンス変数の設定を行っている</p>\n\n<h3 id=\"内部ウィジェットの追加処理add_inner_widget\">内部ウィジェットの追加処理(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)</h3>\n<p>項目の内部の表示を構築する処理。<br />\nデフォルトではLabelを1個追加している。<br />\n項目の表示内容を変更したい場合は、派生クラスでこの処理をオーバライドし、\n必要な内容を追加していく。</p>\n\n<h3 id=\"ドラッグ開始処理on_touch_down\">ドラッグ開始処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_down()</code>)</h3>\n<p>まず、基底クラスのドラッグ開始処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ対象としての処理(インスタンス変数の設定)を行い、<br />\n自身の描画Canvasを親ウィジェット(<code class=\"language-plaintext highlighter-rouge\">self.parent</code>)のcanvasからcanvas.afterに繋ぎかえる。\nこれはドラッグ中の表示が前面に表示されるようにするためである。</p>\n\n<blockquote>\n  <p>[!NOTE]\n通常、add_widget()すると追加されたウィジェットの描画Canvasは親ウィジェットのCanvasに繋がれる。<br />\nこの親ウィジェットのCanvasに繋がれた描画ウィジェットは後から繋がれたものが前面に表示される。<br />\n(縦方向のBoxLayoutの場合下に表示されているウィジェットが前に表示される)<br />\n重ならない表示であれば問題ないが、ドラッグを行うとドラッグ中のウィジェットが背面に表示されることがある。<br />\nそこで、ドラッグ中のウィジェット他のウィジェットより前面に表示するため、CanvasからCanvas.afterに繋ぎかえ、前面に表示されるようにする。<br />\n仕様を読む限り、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index, canvas='after')</code>でadd_widget時にcanvas.afterに接続できるようなのだが、\n実際にはバグ(仕様制限?)により、indexが0のときのみcanvasパラメータが有効になるらしい。<br />\nこれを回避するため、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index)</code>で通常通りウィジェットを追加した後、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">after</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>として描画Canvasを繋ぎかえている。\ncanvas.afterに繋いだ描画Canvasをcanvasに戻す場合は、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">cur_index</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">children</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>    <span class=\"c1\"># canvas.after から canvasへ繋ぎかえるため\n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">remove_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>                 <span class=\"c1\"># 一旦削除して(canvasかcanvas.afterは自動的に判別してくれる) \n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"o\">=</span><span class=\"n\">cur_index</span><span class=\"p\">)</span>   <span class=\"c1\"># 再度同じ場所に挿入\n</span></code></pre></div>  </div>\n  <p>と実行する。  <code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>は描画Canvasがどこに繋がっていても探して削除してくれるので、\nそのまま実行して問題ない。</p>\n</blockquote>\n\n<h3 id=\"ドラッグ中処理on_touch_move\">ドラッグ中処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_move()</code>)</h3>\n<p>まず、基底クラスのドラッグ中処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ中の処理を行う。<br />\n親ウィジェットに繋がっている子ウィジェットをサーチして、自分以外で自分の中心がウィジェットの表示範囲内に入っているウィジェットを探す\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>)<br />\n自分の上端が対象ウィジェットの上端を超えたか、自分の下端が対象ウィジェットの下端を超えた場合は自分と対象ウィジェットを入れ替える。<br />\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>だけで判断すると、自分より高さが高いウィジェットと入れ替えるときに不都合が起こる)<br />\n位置を交換するには、自分を一旦削除(<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>)して、対象ウィジェットの位置(<code class=\"language-plaintext highlighter-rouge\">i</code>)に繋ぐ(<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>)。<br />\nその後、ドラッグを継続するので、ドラッグ開始時と同様に描画Canvasをcanvas.afterに繋ぎかえる。</p>\n\n<h3 id=\"ドラッグ終了処理on_touch_up\">ドラッグ終了処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_up()</code>)</h3>\n\n<p>まず、基底クラスのドラッグ終了処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ終了の処理を行う。<br />\nドラッグ開始/ドラッグ中処理でcanvas.afterに繋ぎかえた描画Canvasをcanvasに戻すために一旦<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>してから\n<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>する(これによりドラッグにより表示が移動していた対象ウィジェットが通常位置に戻る)。<br />\nその後、対象ウィジェットの表示位置がドラッグ開始時と変わっていなく、ドラッグした距離が設定値を超えている場合は\nスワイプ処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>または<code class=\"language-plaintext highlighter-rouge\">do_swipe_left()</code>)を実行する。</p>\n\n<h3 id=\"右へswipeしたときの処理do_swipe_right\">右へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、対象ウィジェットを削除する。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"左へswipeしたときの処理do_swipe_right\">左へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、デバッグ用にログ出力のみ。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"親ウィジェットのレイアウト完了時処理done_parent_layout\">親ウィジェットのレイアウト完了時処理(<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>)</h3>\n<p>親ウィジェットのレイアウト完了時に子ウィジェットすべてのこのメソッドがコールされる。<br />\nドラッグ中であれば必要な処理(現在位置の記憶とドラッグ中位置への移動)を行う。</p>\n\n<h1 id=\"サンプルプルグラム\">サンプルプルグラム</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nサンプルプルグラム</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=test1.py\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "content": "<h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nドラッグで並べ替えできるリスト(AndroidでよくあるUI、<code class=\"language-plaintext highlighter-rouge\">RecycleView</code>と<code class=\"language-plaintext highlighter-rouge\">ItemTouchHelper</code>で作るんだったかな?)\nを作ってみた時のメモ。<br />\n<a href=\"https://maausa.marurm.com/wp-content/uploads/RecyclerView.gif\" target=\"_blank\">ちょっと違うけど、大体こんな感じ</a></p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nreorderablelist.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=reorderablelist.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>ソースは、表示する項目を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>と\nリスト全体を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>で構成される。<br />\n(あと、単体実行で動作するテストプログラム)<br />\n動作としては、</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>に<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を追加していきリスト化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code> をドラッグすることで並べ替え</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を左右にスワイプすることでハンドラ実行(デフォルトでは右スワイプで項目削除)\nといった感じ。</li>\n</ul>\n\n<p>テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>を<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>で囲んでスクロール可能にしています。\nスクロール不要ならそのまま配置しても可(テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">with_scroll</code>を<code class=\"language-plaintext highlighter-rouge\">False</code>に設定)。</p>\n\n<h2 id=\"reorderablelist\">ReorderableList</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>はリスト全体を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承したクラス。</p>\n\n<h3 id=\"追加したプロパティ\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>item_bg</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>item_fg</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>list_bg</td>\n      <td>リストの背景色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\n(<code class=\"language-plaintext highlighter-rouge\">orientation</code>は<code class=\"language-plaintext highlighter-rouge\">\"vertical\"</code>固定(項目を縦方向に並べるため)、\n<code class=\"language-plaintext highlighter-rouge\">size_hint_y</code>は<code class=\"language-plaintext highlighter-rouge\">None</code>固定(ScrollViewに包むため))\nのほか、<br />\n背景色の設定と、スクロール可能にするためminimum_height変更時の処理のbindを行っている。</p>\n\n<h3 id=\"項目追加処理\">項目追加処理</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">add_item</code>が項目追加処理。<br />\nパラメータは<code class=\"language-plaintext highlighter-rouge\">cls</code>で項目表示に使用するクラス(デフォルトは<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>)と、項目表示クラスの初期化パラメータを受け取る。<br />\nこれは項目に表示する内容を柔軟に切り替えられるよう、項目表示クラスを<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を継承したクラスに切り替えられるようにするため。</p>\n\n<h3 id=\"レイアウト処理\">レイアウト処理</h3>\n<p>kivyでは、レイアウトの変更命令と実際に変更が行われるまでにディレイがある。<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">add_widget(wid)</code> して直後にwid.posを読み出すと実際に追加されたあとの位置が読み出せない。<br />\nこれは、<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>では処理の予約だけ行い、実際に描画が行われるのは別のところ(<code class=\"language-plaintext highlighter-rouge\">mainloop</code>?)で\n他のウィジェットのレイアウト結果を五月雨式に反映していくため、\n描画結果がposに反映されるまでタイムラグが発生するためと思われる。</p>\n\n<p>そこで、<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>のレイアウトが変更され、処理が終了したタイミングで子ウィジェットに\nレイアウト完了を通知できるよう<code class=\"language-plaintext highlighter-rouge\">do_layout()</code>をオーバライドし、基底クラスの処理が完了した後\n各子ウィジェットの<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>をコールしている。</p>\n\n<h2 id=\"reorderableitem\">ReorderableItem</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>はリストに表示する項目を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスと<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承している。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスはドラッグ処理を実現するクラス。<br />\nもう一つの基底クラスを<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>とすることで、派生クラスのレイアウトを柔軟に設定できるようにしている。</p>\n\n<h3 id=\"追加したプロパティ-1\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>text</td>\n      <td>項目に表示する文字列</td>\n    </tr>\n    <tr>\n      <td>bg_color</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>fg_color</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ-1\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\nのほか、<br />\n項目内部の構築(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)、\n背景色の設定と、pos/size変更時にドラッグ範囲を変更する処理のbind、\nインスタンス変数の設定を行っている</p>\n\n<h3 id=\"内部ウィジェットの追加処理add_inner_widget\">内部ウィジェットの追加処理(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)</h3>\n<p>項目の内部の表示を構築する処理。<br />\nデフォルトではLabelを1個追加している。<br />\n項目の表示内容を変更したい場合は、派生クラスでこの処理をオーバライドし、\n必要な内容を追加していく。</p>\n\n<h3 id=\"ドラッグ開始処理on_touch_down\">ドラッグ開始処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_down()</code>)</h3>\n<p>まず、基底クラスのドラッグ開始処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ対象としての処理(インスタンス変数の設定)を行い、<br />\n自身の描画Canvasを親ウィジェット(<code class=\"language-plaintext highlighter-rouge\">self.parent</code>)のcanvasからcanvas.afterに繋ぎかえる。\nこれはドラッグ中の表示が前面に表示されるようにするためである。</p>\n\n<blockquote>\n  <p>[!NOTE]\n通常、add_widget()すると追加されたウィジェットの描画Canvasは親ウィジェットのCanvasに繋がれる。<br />\nこの親ウィジェットのCanvasに繋がれた描画ウィジェットは後から繋がれたものが前面に表示される。<br />\n(縦方向のBoxLayoutの場合下に表示されているウィジェットが前に表示される)<br />\n重ならない表示であれば問題ないが、ドラッグを行うとドラッグ中のウィジェットが背面に表示されることがある。<br />\nそこで、ドラッグ中のウィジェット他のウィジェットより前面に表示するため、CanvasからCanvas.afterに繋ぎかえ、前面に表示されるようにする。<br />\n仕様を読む限り、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index, canvas='after')</code>でadd_widget時にcanvas.afterに接続できるようなのだが、\n実際にはバグ(仕様制限?)により、indexが0のときのみcanvasパラメータが有効になるらしい。<br />\nこれを回避するため、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index)</code>で通常通りウィジェットを追加した後、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">after</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>として描画Canvasを繋ぎかえている。\ncanvas.afterに繋いだ描画Canvasをcanvasに戻す場合は、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">cur_index</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">children</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>    <span class=\"c1\"># canvas.after から canvasへ繋ぎかえるため\n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">remove_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>                 <span class=\"c1\"># 一旦削除して(canvasかcanvas.afterは自動的に判別してくれる) \n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"o\">=</span><span class=\"n\">cur_index</span><span class=\"p\">)</span>   <span class=\"c1\"># 再度同じ場所に挿入\n</span></code></pre></div>  </div>\n  <p>と実行する。  <code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>は描画Canvasがどこに繋がっていても探して削除してくれるので、\nそのまま実行して問題ない。</p>\n</blockquote>\n\n<h3 id=\"ドラッグ中処理on_touch_move\">ドラッグ中処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_move()</code>)</h3>\n<p>まず、基底クラスのドラッグ中処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ中の処理を行う。<br />\n親ウィジェットに繋がっている子ウィジェットをサーチして、自分以外で自分の中心がウィジェットの表示範囲内に入っているウィジェットを探す\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>)<br />\n自分の上端が対象ウィジェットの上端を超えたか、自分の下端が対象ウィジェットの下端を超えた場合は自分と対象ウィジェットを入れ替える。<br />\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>だけで判断すると、自分より高さが高いウィジェットと入れ替えるときに不都合が起こる)<br />\n位置を交換するには、自分を一旦削除(<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>)して、対象ウィジェットの位置(<code class=\"language-plaintext highlighter-rouge\">i</code>)に繋ぐ(<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>)。<br />\nその後、ドラッグを継続するので、ドラッグ開始時と同様に描画Canvasをcanvas.afterに繋ぎかえる。</p>\n\n<h3 id=\"ドラッグ終了処理on_touch_up\">ドラッグ終了処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_up()</code>)</h3>\n\n<p>まず、基底クラスのドラッグ終了処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ終了の処理を行う。<br />\nドラッグ開始/ドラッグ中処理でcanvas.afterに繋ぎかえた描画Canvasをcanvasに戻すために一旦<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>してから\n<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>する(これによりドラッグにより表示が移動していた対象ウィジェットが通常位置に戻る)。<br />\nその後、対象ウィジェットの表示位置がドラッグ開始時と変わっていなく、ドラッグした距離が設定値を超えている場合は\nスワイプ処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>または<code class=\"language-plaintext highlighter-rouge\">do_swipe_left()</code>)を実行する。</p>\n\n<h3 id=\"右へswipeしたときの処理do_swipe_right\">右へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、対象ウィジェットを削除する。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"左へswipeしたときの処理do_swipe_right\">左へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、デバッグ用にログ出力のみ。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"親ウィジェットのレイアウト完了時処理done_parent_layout\">親ウィジェットのレイアウト完了時処理(<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>)</h3>\n<p>親ウィジェットのレイアウト完了時に子ウィジェットすべてのこのメソッドがコールされる。<br />\nドラッグ中であれば必要な処理(現在位置の記憶とドラッグ中位置への移動)を行う。</p>\n\n<h1 id=\"サンプルプルグラム\">サンプルプルグラム</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nサンプルプルグラム</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=test1.py\"></script>\n</dev>\n\n",
      "url": "/2025/05/19/kivy_5.html",
      "draft": false,
      "categories": [

      ],
      "title": "kivyでドラッグで並べ替えできるリスト",
      "date": "2025-05-19 00:00:00 +0000",
      "tags": [
        "kivy",
        "python"
      ],
      "layout": "default",
      "slug": "kivy_5",
      "ext": ".md"
    },
    "output": "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyで画面遷移</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyで画面遷移</h1>\n      <p>kivyで画面遷移する方法について</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\n実行時に画面を切り替えて使用する方法について試した時のメモ。<br />\nついでにAndroidアプリ化もしてみた。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\n(multi_screenって名前はなんか違う気もするけど、複数画面を制御するってことでヨシとしとこう)</p>\n\n<h2 id=\"メイン処理スクリーンマネージャのソース\">メイン処理/スクリーンマネージャのソース</h2>\n<p>multi_screen.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=multi_screen.py\"></script>\n</dev>\n\n<h2 id=\"第1画面のソース\">第1画面のソース</h2>\n<p>screen1.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen1.py\"></script>\n</dev>\n\n<h2 id=\"第2画面のソース\">第2画面のソース</h2>\n<p>screen2.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen2.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyで画面を切り替えて使用するには、<code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承したクラスを使用し、ここに各画面を登録し、\n<code class=\"language-plaintext highlighter-rouge\">self.current</code>に表示する画面の名前(<code class=\"language-plaintext highlighter-rouge\">name</code>)を設定することで切り替えるらしい。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>今回は日本語を使ってみようと思うので、日本語フォントをインストール。<br />\n有名どころではNotoSansCJKとかTAKAOとか。<br />\nubuntuだと以下でインストールできる。<br />\nNotoSansCJK は Androidでもインストールされていることが多いのかな?(手元のちょっと古いAndroidには入ってた)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n<span class=\"c\"># または</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n<p>あと、テキスト入力も試してみるので、クリップボード操作のためのライブラリをインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>xclip\n</code></pre></div></div>\n\n<h2 id=\"multi_screenpy\">multi_screen.py</h2>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">multi_screen.py</code>の内容について。</p>\n\n<p>今回は日本語を使ってみるので、フォントディレクトリの登録と日本語対応フォントをデフォルトフォントに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">get_system_fonts_dir</span><span class=\"p\">()</span>                                        <span class=\"c1\"># フォントディレクトリにシステムフォントディレクトリを登録\n</span><span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'NotoSansCJK-Regular.ttc'</span><span class=\"p\">)</span>  <span class=\"c1\"># デフォルトフォントを設定\n</span></code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承した<code class=\"language-plaintext highlighter-rouge\">ControlScreenManager</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ControlScreenManager</span><span class=\"p\">(</span><span class=\"n\">ScreenManager</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">ControlScreenManager</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># 画面間で共有する変数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n</code></pre></div></div>\n<p>ネットで検索すると画面間で共有する変数を画面間で直接やりとりする例があったが、\nソースの再利用性などを考えてスクリーンマネージャで管理することにした。<br />\nそのための設定/取得メソッド</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ターゲット文字列の設定\n</span>    <span class=\"k\">def</span> <span class=\"nf\">set_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"n\">text</span>\n    \n    <span class=\"c1\"># ターゲット文字列の取得\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span>\n</code></pre></div></div>\n\n<p>画面切り替え処理<br />\nこれも画面から他の画面に直接遷移している例があるけど、\n一旦スクリーンマネージャでうけとってから\n遷移した方が分かりやすいと思う。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># screen1への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">SlideTransition</span><span class=\"p\">(</span><span class=\"n\">direction</span><span class=\"o\">=</span><span class=\"s\">'left'</span><span class=\"p\">,</span> <span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen1'</span>\n        \n    <span class=\"c1\"># screen2への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen2</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">FadeTransition</span><span class=\"p\">(</span><span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen2'</span>\n</code></pre></div></div>\n\n<p>アプリケーションクラス</p>\n\n<p>アプリケーションクラスのbuildメソッドでは上で定義したスクリーンマネージャのインスタンスに\n各画面のインスタンスを登録し、そのインスタンスをリターンする。</p>\n\n<p>KV言語で書く方法もあるけど、画面切り替えのときに使用する名前をここで定義できるので\nソースの見通しが良くなって好み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ScreenManager1</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># スクリーンマネージャの生成\n</span>        <span class=\"n\">sm</span> <span class=\"o\">=</span> <span class=\"n\">ControlScreenManager</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 画面1を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen1</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen1'</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 画面2を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen2</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen2'</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">sm</span>\n</code></pre></div></div>\n\n<h2 id=\"screen1py\">screen1.py</h2>\n\n<p>レイアウトの定義</p>\n\n<p>kvファイルにレイアウトを書く例が多いけど、こう書くとレイアウトと処理をまとめて書けるので好み。</p>\n\n<blockquote>\n  <p>[!NOTE]\n最近知ったけど、色指定は(rr, gg, bb, aa)(各値は0~1)と書かれている例が多いけど、\n色名(“black”とか”red”とか。指定できる色名は kivyインストールディレクトリの<code class=\"language-plaintext highlighter-rouge\">util.py</code>で定義されている<code class=\"language-plaintext highlighter-rouge\">hex_colormap</code>を参照)\nの他、”#RRGGBBAA”でも指定可能(AAは省略可能)。\nどちらも文字列指定なのでダブルクォーテーションまたはシングルクォーテーションで囲む必要あり。</p>\n\n  <p>また、サイズ類は<code class=\"language-plaintext highlighter-rouge\">dp(36)</code>みたいな書き方もできるけど、文字列で<code class=\"language-plaintext highlighter-rouge\">\"36dp\"</code>と書くこともできる。\nサイズ類は数値で指定すると単位は<code class=\"language-plaintext highlighter-rouge\">px</code>になる。</p>\n</blockquote>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen1>:\n    ・・・・\n            bg_color_normal : \"#585858ff\"       # \"coloe_name\" or \"#RRGGBB\" or \"#RRGGBAA\" or (rr, gg, bb, aa) で指定\n    ・・・・\n            item_height          : '36dp'   # 数値で指定したときの単位はpx\n    ・・・・\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nAndroidアプリ化する場合、テキスト入力が下の方にあるとソフトキーボードが出てきたときに見えなくなるので\n上の方に配置しておく方が無難。<br />\nなんかうまくやる方法があるのかもしれんけど、現状分かってない。</p>\n</blockquote>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>class Screen1(Screen):\n</code></pre></div></div>\n\n<p>あとは<code class=\"language-plaintext highlighter-rouge\">Screen1</code>クラス内で動作を定義していけば良い。<br />\n画面切り替え処理はkv言語で直接スクリーンマネージャの処理をコールすると訳わかめになるので\n一旦このクラス内で受け取ってスクリーンマネージャの処理をコールするようにしている。<br />\nこの辺は好みの問題なので、お好きにどうぞ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'switch_to_screen1'</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">switch_to_screen1</span><span class=\"p\">()</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nスクリーンマネージャはScreen派生クラスの<code class=\"language-plaintext highlighter-rouge\">self.manager</code>で取得できる。</p>\n</blockquote>\n\n<h2 id=\"screen2py\">screen2.py</h2>\n\n<p>こちらも同様にレイアウトを定義しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen2>:\n    ・・・・\n</span></code></pre></div></div>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">Screen2</span><span class=\"p\">(</span><span class=\"n\">Screen</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>画面が切り替わる前にScreen1で設定した文字列を取得したいので、<code class=\"language-plaintext highlighter-rouge\">on_pre_enter()</code>をオーバーライドする。<br />\n文字列をScreen1から直接取ると画面構成変えた時に困るので、スクリーンマネージャ経由で取得するようにしている。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">on_pre_enter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"c1\"># 表示用ラベルを書き換え\n</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">get_target_string</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"NONE\"</span>       <span class=\"c1\"># 空文字が来たらNONEに書き換え\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">text</span><span class=\"si\">}</span><span class=\"s\"> が選択されました'</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">python multi_screen.py</code>で実行。<br />\n一番上のドロップダウンリストで項目を選択し、2番目の「Go to Screen 2」ボタンを押すとScreen2に切り替わる。<br />\nScreen2では画面下側の領域にScreen1のドロップダウンリストで選択した文字列が表示される。\n「Go to Screen 1」ボタンでScreen1に戻る。<br />\nScreen1のテキスト入力欄に文字列を入力し、「ADD」ボタンをクリックするとドロップダウンリストに入力した文字列が追加される。<br />\nもちろん、その文字列を選択してScreen2に切り替えればその文字列が表示される。</p>\n\n<blockquote>\n  <p>[!NOTE]\nLunuxでは日本語入力できないみたい。ただしコピペは可能なので他のところで入力してコピペすればOK。<br />\nAndroidではそのまま日本語も入力できる。</p>\n</blockquote>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>の手順でAndroidアプリ化もできる。<br />\nここの準備が終わっていれば以下のコマンドでOK。</p>\n\n<h2 id=\"multi_screenpyをリネーム\">multi_screen.pyをリネーム</h2>\n<p>python for androidはエントリーポイントがmain.pyに固定らしいので、リネーム</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mv </span>multi_screen.py main.py\n</code></pre></div></div>\n\n<h2 id=\"buildozerspec-の生成\">buildozer.spec の生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>今回は特に編集の必要なし。\n<code class=\"language-plaintext highlighter-rouge\">title</code>、<code class=\"language-plaintext highlighter-rouge\">package.name</code>、<code class=\"language-plaintext highlighter-rouge\">package.domain</code>なんかは必要なら変更してちょ。</p>\n\n<h2 id=\"build実行\">build実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動する)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪SDK Platform-Tools <span class=\"k\">for </span>Windowsを展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>で、実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、Android上で動作した。メデタシメデタシ。<br />\n文字入力もちゃんと動いてるし、改造したボタンやスピナーも動いてる。</p>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "content": "<h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\n実行時に画面を切り替えて使用する方法について試した時のメモ。<br />\nついでにAndroidアプリ化もしてみた。</p>\n\n<h1 id=\"ソース\">ソース</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\n(multi_screenって名前はなんか違う気もするけど、複数画面を制御するってことでヨシとしとこう)</p>\n\n<h2 id=\"メイン処理スクリーンマネージャのソース\">メイン処理/スクリーンマネージャのソース</h2>\n<p>multi_screen.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=multi_screen.py\"></script>\n</dev>\n\n<h2 id=\"第1画面のソース\">第1画面のソース</h2>\n<p>screen1.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen1.py\"></script>\n</dev>\n\n<h2 id=\"第2画面のソース\">第2画面のソース</h2>\n<p>screen2.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/e2121504808792dbd59c36b44affd2e4.js?file=screen2.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>kivyで画面を切り替えて使用するには、<code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承したクラスを使用し、ここに各画面を登録し、\n<code class=\"language-plaintext highlighter-rouge\">self.current</code>に表示する画面の名前(<code class=\"language-plaintext highlighter-rouge\">name</code>)を設定することで切り替えるらしい。</p>\n\n<h2 id=\"準備\">準備</h2>\n<p>今回は日本語を使ってみようと思うので、日本語フォントをインストール。<br />\n有名どころではNotoSansCJKとかTAKAOとか。<br />\nubuntuだと以下でインストールできる。<br />\nNotoSansCJK は Androidでもインストールされていることが多いのかな?(手元のちょっと古いAndroidには入ってた)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n<span class=\"c\"># または</span>\n<span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-takao\n</code></pre></div></div>\n<p>あと、テキスト入力も試してみるので、クリップボード操作のためのライブラリをインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>xclip\n</code></pre></div></div>\n\n<h2 id=\"multi_screenpy\">multi_screen.py</h2>\n\n<p>まず、<code class=\"language-plaintext highlighter-rouge\">multi_screen.py</code>の内容について。</p>\n\n<p>今回は日本語を使ってみるので、フォントディレクトリの登録と日本語対応フォントをデフォルトフォントに設定する。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">from</span> <span class=\"nn\">kivy.core.text</span> <span class=\"kn\">import</span> <span class=\"n\">LabelBase</span><span class=\"p\">,</span> <span class=\"n\">DEFAULT_FONT</span>\n<span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">get_system_fonts_dir</span><span class=\"p\">()</span>                                        <span class=\"c1\"># フォントディレクトリにシステムフォントディレクトリを登録\n</span><span class=\"n\">LabelBase</span><span class=\"p\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_FONT</span><span class=\"p\">,</span> <span class=\"n\">fn_regular</span><span class=\"o\">=</span><span class=\"s\">'NotoSansCJK-Regular.ttc'</span><span class=\"p\">)</span>  <span class=\"c1\"># デフォルトフォントを設定\n</span></code></pre></div></div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ScreenManager</code>を継承した<code class=\"language-plaintext highlighter-rouge\">ControlScreenManager</code>クラスを生成。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ControlScreenManager</span><span class=\"p\">(</span><span class=\"n\">ScreenManager</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">ControlScreenManager</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">).</span><span class=\"n\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># 画面間で共有する変数\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span>\n</code></pre></div></div>\n<p>ネットで検索すると画面間で共有する変数を画面間で直接やりとりする例があったが、\nソースの再利用性などを考えてスクリーンマネージャで管理することにした。<br />\nそのための設定/取得メソッド</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># ターゲット文字列の設定\n</span>    <span class=\"k\">def</span> <span class=\"nf\">set_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span> <span class=\"o\">=</span> <span class=\"n\">text</span>\n    \n    <span class=\"c1\"># ターゲット文字列の取得\n</span>    <span class=\"k\">def</span> <span class=\"nf\">get_target_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">target_string</span>\n</code></pre></div></div>\n\n<p>画面切り替え処理<br />\nこれも画面から他の画面に直接遷移している例があるけど、\n一旦スクリーンマネージャでうけとってから\n遷移した方が分かりやすいと思う。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"c1\"># screen1への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">SlideTransition</span><span class=\"p\">(</span><span class=\"n\">direction</span><span class=\"o\">=</span><span class=\"s\">'left'</span><span class=\"p\">,</span> <span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen1'</span>\n        \n    <span class=\"c1\"># screen2への切り替え\n</span>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen2</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">transition</span> <span class=\"o\">=</span> <span class=\"n\">FadeTransition</span><span class=\"p\">(</span><span class=\"n\">duration</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"s\">'screen2'</span>\n</code></pre></div></div>\n\n<p>アプリケーションクラス</p>\n\n<p>アプリケーションクラスのbuildメソッドでは上で定義したスクリーンマネージャのインスタンスに\n各画面のインスタンスを登録し、そのインスタンスをリターンする。</p>\n\n<p>KV言語で書く方法もあるけど、画面切り替えのときに使用する名前をここで定義できるので\nソースの見通しが良くなって好み。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">ScreenManager1</span><span class=\"p\">(</span><span class=\"n\">App</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">build</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># スクリーンマネージャの生成\n</span>        <span class=\"n\">sm</span> <span class=\"o\">=</span> <span class=\"n\">ControlScreenManager</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 画面1を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen1</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen1'</span><span class=\"p\">))</span>\n        <span class=\"c1\"># 画面2を追加\n</span>        <span class=\"n\">sm</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">Screen2</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s\">'screen2'</span><span class=\"p\">))</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">sm</span>\n</code></pre></div></div>\n\n<h2 id=\"screen1py\">screen1.py</h2>\n\n<p>レイアウトの定義</p>\n\n<p>kvファイルにレイアウトを書く例が多いけど、こう書くとレイアウトと処理をまとめて書けるので好み。</p>\n\n<blockquote>\n  <p>[!NOTE]\n最近知ったけど、色指定は(rr, gg, bb, aa)(各値は0~1)と書かれている例が多いけど、\n色名(“black”とか”red”とか。指定できる色名は kivyインストールディレクトリの<code class=\"language-plaintext highlighter-rouge\">util.py</code>で定義されている<code class=\"language-plaintext highlighter-rouge\">hex_colormap</code>を参照)\nの他、”#RRGGBBAA”でも指定可能(AAは省略可能)。\nどちらも文字列指定なのでダブルクォーテーションまたはシングルクォーテーションで囲む必要あり。</p>\n\n  <p>また、サイズ類は<code class=\"language-plaintext highlighter-rouge\">dp(36)</code>みたいな書き方もできるけど、文字列で<code class=\"language-plaintext highlighter-rouge\">\"36dp\"</code>と書くこともできる。\nサイズ類は数値で指定すると単位は<code class=\"language-plaintext highlighter-rouge\">px</code>になる。</p>\n</blockquote>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen1>:\n    ・・・・\n            bg_color_normal : \"#585858ff\"       # \"coloe_name\" or \"#RRGGBB\" or \"#RRGGBAA\" or (rr, gg, bb, aa) で指定\n    ・・・・\n            item_height          : '36dp'   # 数値で指定したときの単位はpx\n    ・・・・\n</span></code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\nAndroidアプリ化する場合、テキスト入力が下の方にあるとソフトキーボードが出てきたときに見えなくなるので\n上の方に配置しておく方が無難。<br />\nなんかうまくやる方法があるのかもしれんけど、現状分かってない。</p>\n</blockquote>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>class Screen1(Screen):\n</code></pre></div></div>\n\n<p>あとは<code class=\"language-plaintext highlighter-rouge\">Screen1</code>クラス内で動作を定義していけば良い。<br />\n画面切り替え処理はkv言語で直接スクリーンマネージャの処理をコールすると訳わかめになるので\n一旦このクラス内で受け取ってスクリーンマネージャの処理をコールするようにしている。<br />\nこの辺は好みの問題なので、お好きにどうぞ。</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">switch_to_screen1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">'switch_to_screen1'</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">switch_to_screen1</span><span class=\"p\">()</span>\n</code></pre></div></div>\n<blockquote>\n  <p>[!NOTE]\nスクリーンマネージャはScreen派生クラスの<code class=\"language-plaintext highlighter-rouge\">self.manager</code>で取得できる。</p>\n</blockquote>\n\n<h2 id=\"screen2py\">screen2.py</h2>\n\n<p>こちらも同様にレイアウトを定義しておく。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">Builder</span><span class=\"p\">.</span><span class=\"n\">load_string</span><span class=\"p\">(</span>\n<span class=\"s\">\"\"\"\n<Screen2>:\n    ・・・・\n</span></code></pre></div></div>\n\n<p>Screen派生クラスの定義</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class</span> <span class=\"nc\">Screen2</span><span class=\"p\">(</span><span class=\"n\">Screen</span><span class=\"p\">):</span>\n</code></pre></div></div>\n\n<p>画面が切り替わる前にScreen1で設定した文字列を取得したいので、<code class=\"language-plaintext highlighter-rouge\">on_pre_enter()</code>をオーバーライドする。<br />\n文字列をScreen1から直接取ると画面構成変えた時に困るので、スクリーンマネージャ経由で取得するようにしている。</p>\n\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"k\">def</span> <span class=\"nf\">on_pre_enter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"c1\"># 表示用ラベルを書き換え\n</span>        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">manager</span><span class=\"p\">.</span><span class=\"n\">get_target_string</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"p\">:</span>\n            <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"s\">\"NONE\"</span>       <span class=\"c1\"># 空文字が来たらNONEに書き換え\n</span>        <span class=\"bp\">self</span><span class=\"p\">.</span><span class=\"n\">label</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s\">'</span><span class=\"si\">{</span><span class=\"n\">text</span><span class=\"si\">}</span><span class=\"s\"> が選択されました'</span>\n</code></pre></div></div>\n\n<h1 id=\"実行\">実行</h1>\n<p><code class=\"language-plaintext highlighter-rouge\">python multi_screen.py</code>で実行。<br />\n一番上のドロップダウンリストで項目を選択し、2番目の「Go to Screen 2」ボタンを押すとScreen2に切り替わる。<br />\nScreen2では画面下側の領域にScreen1のドロップダウンリストで選択した文字列が表示される。\n「Go to Screen 1」ボタンでScreen1に戻る。<br />\nScreen1のテキスト入力欄に文字列を入力し、「ADD」ボタンをクリックするとドロップダウンリストに入力した文字列が追加される。<br />\nもちろん、その文字列を選択してScreen2に切り替えればその文字列が表示される。</p>\n\n<blockquote>\n  <p>[!NOTE]\nLunuxでは日本語入力できないみたい。ただしコピペは可能なので他のところで入力してコピペすればOK。<br />\nAndroidではそのまま日本語も入力できる。</p>\n</blockquote>\n\n<h1 id=\"androidアプリ化\">Androidアプリ化</h1>\n<p><a href=\"/memoBlog/2025/03/31/Buildozer_1.html\">Buildozerをお試し</a>の手順でAndroidアプリ化もできる。<br />\nここの準備が終わっていれば以下のコマンドでOK。</p>\n\n<h2 id=\"multi_screenpyをリネーム\">multi_screen.pyをリネーム</h2>\n<p>python for androidはエントリーポイントがmain.pyに固定らしいので、リネーム</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">mv </span>multi_screen.py main.py\n</code></pre></div></div>\n\n<h2 id=\"buildozerspec-の生成\">buildozer.spec の生成</h2>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer init\n</code></pre></div></div>\n\n<p>今回は特に編集の必要なし。\n<code class=\"language-plaintext highlighter-rouge\">title</code>、<code class=\"language-plaintext highlighter-rouge\">package.name</code>、<code class=\"language-plaintext highlighter-rouge\">package.domain</code>なんかは必要なら変更してちょ。</p>\n\n<h2 id=\"build実行\">build実行</h2>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android debug 2>&1 | <span class=\"nb\">tee </span>mk.log\n</code></pre></div></div>\n\n<h2 id=\"adbサーバの起動\">adbサーバの起動</h2>\n<p>Windows側(コマンドプロンプト等)から以下を実行(サーバを起動する)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> ≪SDK Platform-Tools <span class=\"k\">for </span>Windowsを展開したディレクトリ≫<span class=\"se\">\\p</span>latform-tools\nadb.exe devices <span class=\"nt\">-l</span>\n</code></pre></div></div>\n\n<h2 id=\"実行-1\">実行</h2>\n\n<p>で、実行</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>buildozer <span class=\"nt\">-v</span> android deploy run logcat 2>&1 | <span class=\"nb\">tee </span>run.log\n</code></pre></div></div>\n\n<p>で、Android上で動作した。メデタシメデタシ。<br />\n文字入力もちゃんと動いてるし、改造したボタンやスピナーも動いてる。</p>\n\n",
    "url": "/2025/04/30/kivy_4.html",
    "draft": false,
    "categories": [

    ],
    "title": "kivyで画面遷移",
    "date": "2025-04-30 00:00:00 +0000",
    "tags": [
      "kivy",
      "python"
    ],
    "layout": "default",
    "slug": "kivy_4",
    "ext": ".md"
  },
  "id": "/2025/05/19/kivy_5",
  "collection": "posts",
  "next": {
    "path": "_posts/2025-6-9-WSL_USB_1.md",
    "relative_path": "_posts/2025-6-9-WSL_USB_1.md",
    "excerpt": "WSLでUSBを使った時のメモ(バージョン 2.5.7.0)",
    "previous": {
      "path": "_posts/2025-5-19-kivy_5.md",
      "relative_path": "_posts/2025-5-19-kivy_5.md",
      "excerpt": "kivyでドラッグで並べ替えできるリストを作った時のメモ",
      "previous": {
        "path": "_posts/2025-4-30-kivy_4.md",
        "relative_path": "_posts/2025-4-30-kivy_4.md",
        "id": "/2025/04/30/kivy_4",
        "collection": "posts",
        "url": "/2025/04/30/kivy_4.html",
        "draft": false,
        "categories": [

        ],
        "title": "kivyで画面遷移",
        "date": "2025-04-30 00:00:00 +0000",
        "tags": [
          "kivy",
          "python"
        ],
        "layout": "default",
        "slug": "kivy_4",
        "ext": ".md"
      },
      "id": "/2025/05/19/kivy_5",
      "collection": "posts",
      "next": {
        "path": "_posts/2025-6-9-WSL_USB_1.md",
        "relative_path": "_posts/2025-6-9-WSL_USB_1.md",
        "id": "/2025/06/09/WSL_USB_1",
        "collection": "posts",
        "url": "/2025/06/09/WSL_USB_1.html",
        "draft": false,
        "categories": [

        ],
        "title": "WSLでUSB",
        "date": "2025-06-09 00:00:00 +0000",
        "tags": [
          "WSL"
        ],
        "layout": "default",
        "slug": "WSL_USB_1",
        "ext": ".md"
      },
      "output": "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyでドラッグで並べ替えできるリスト</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyでドラッグで並べ替えできるリスト</h1>\n      <p>kivyでドラッグで並べ替えできるリストを作った時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nドラッグで並べ替えできるリスト(AndroidでよくあるUI、<code class=\"language-plaintext highlighter-rouge\">RecycleView</code>と<code class=\"language-plaintext highlighter-rouge\">ItemTouchHelper</code>で作るんだったかな?)\nを作ってみた時のメモ。<br />\n<a href=\"https://maausa.marurm.com/wp-content/uploads/RecyclerView.gif\" target=\"_blank\">ちょっと違うけど、大体こんな感じ</a></p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nreorderablelist.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=reorderablelist.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>ソースは、表示する項目を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>と\nリスト全体を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>で構成される。<br />\n(あと、単体実行で動作するテストプログラム)<br />\n動作としては、</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>に<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を追加していきリスト化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code> をドラッグすることで並べ替え</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を左右にスワイプすることでハンドラ実行(デフォルトでは右スワイプで項目削除)\nといった感じ。</li>\n</ul>\n\n<p>テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>を<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>で囲んでスクロール可能にしています。\nスクロール不要ならそのまま配置しても可(テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">with_scroll</code>を<code class=\"language-plaintext highlighter-rouge\">False</code>に設定)。</p>\n\n<h2 id=\"reorderablelist\">ReorderableList</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>はリスト全体を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承したクラス。</p>\n\n<h3 id=\"追加したプロパティ\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>item_bg</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>item_fg</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>list_bg</td>\n      <td>リストの背景色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\n(<code class=\"language-plaintext highlighter-rouge\">orientation</code>は<code class=\"language-plaintext highlighter-rouge\">\"vertical\"</code>固定(項目を縦方向に並べるため)、\n<code class=\"language-plaintext highlighter-rouge\">size_hint_y</code>は<code class=\"language-plaintext highlighter-rouge\">None</code>固定(ScrollViewに包むため))\nのほか、<br />\n背景色の設定と、スクロール可能にするためminimum_height変更時の処理のbindを行っている。</p>\n\n<h3 id=\"項目追加処理\">項目追加処理</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">add_item</code>が項目追加処理。<br />\nパラメータは<code class=\"language-plaintext highlighter-rouge\">cls</code>で項目表示に使用するクラス(デフォルトは<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>)と、項目表示クラスの初期化パラメータを受け取る。<br />\nこれは項目に表示する内容を柔軟に切り替えられるよう、項目表示クラスを<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を継承したクラスに切り替えられるようにするため。</p>\n\n<h3 id=\"レイアウト処理\">レイアウト処理</h3>\n<p>kivyでは、レイアウトの変更命令と実際に変更が行われるまでにディレイがある。<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">add_widget(wid)</code> して直後にwid.posを読み出すと実際に追加されたあとの位置が読み出せない。<br />\nこれは、<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>では処理の予約だけ行い、実際に描画が行われるのは別のところ(<code class=\"language-plaintext highlighter-rouge\">mainloop</code>?)で\n他のウィジェットのレイアウト結果を五月雨式に反映していくため、\n描画結果がposに反映されるまでタイムラグが発生するためと思われる。</p>\n\n<p>そこで、<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>のレイアウトが変更され、処理が終了したタイミングで子ウィジェットに\nレイアウト完了を通知できるよう<code class=\"language-plaintext highlighter-rouge\">do_layout()</code>をオーバライドし、基底クラスの処理が完了した後\n各子ウィジェットの<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>をコールしている。</p>\n\n<h2 id=\"reorderableitem\">ReorderableItem</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>はリストに表示する項目を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスと<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承している。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスはドラッグ処理を実現するクラス。<br />\nもう一つの基底クラスを<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>とすることで、派生クラスのレイアウトを柔軟に設定できるようにしている。</p>\n\n<h3 id=\"追加したプロパティ-1\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>text</td>\n      <td>項目に表示する文字列</td>\n    </tr>\n    <tr>\n      <td>bg_color</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>fg_color</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ-1\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\nのほか、<br />\n項目内部の構築(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)、\n背景色の設定と、pos/size変更時にドラッグ範囲を変更する処理のbind、\nインスタンス変数の設定を行っている</p>\n\n<h3 id=\"内部ウィジェットの追加処理add_inner_widget\">内部ウィジェットの追加処理(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)</h3>\n<p>項目の内部の表示を構築する処理。<br />\nデフォルトではLabelを1個追加している。<br />\n項目の表示内容を変更したい場合は、派生クラスでこの処理をオーバライドし、\n必要な内容を追加していく。</p>\n\n<h3 id=\"ドラッグ開始処理on_touch_down\">ドラッグ開始処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_down()</code>)</h3>\n<p>まず、基底クラスのドラッグ開始処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ対象としての処理(インスタンス変数の設定)を行い、<br />\n自身の描画Canvasを親ウィジェット(<code class=\"language-plaintext highlighter-rouge\">self.parent</code>)のcanvasからcanvas.afterに繋ぎかえる。\nこれはドラッグ中の表示が前面に表示されるようにするためである。</p>\n\n<blockquote>\n  <p>[!NOTE]\n通常、add_widget()すると追加されたウィジェットの描画Canvasは親ウィジェットのCanvasに繋がれる。<br />\nこの親ウィジェットのCanvasに繋がれた描画ウィジェットは後から繋がれたものが前面に表示される。<br />\n(縦方向のBoxLayoutの場合下に表示されているウィジェットが前に表示される)<br />\n重ならない表示であれば問題ないが、ドラッグを行うとドラッグ中のウィジェットが背面に表示されることがある。<br />\nそこで、ドラッグ中のウィジェット他のウィジェットより前面に表示するため、CanvasからCanvas.afterに繋ぎかえ、前面に表示されるようにする。<br />\n仕様を読む限り、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index, canvas='after')</code>でadd_widget時にcanvas.afterに接続できるようなのだが、\n実際にはバグ(仕様制限?)により、indexが0のときのみcanvasパラメータが有効になるらしい。<br />\nこれを回避するため、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index)</code>で通常通りウィジェットを追加した後、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">after</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>として描画Canvasを繋ぎかえている。\ncanvas.afterに繋いだ描画Canvasをcanvasに戻す場合は、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">cur_index</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">children</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>    <span class=\"c1\"># canvas.after から canvasへ繋ぎかえるため\n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">remove_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>                 <span class=\"c1\"># 一旦削除して(canvasかcanvas.afterは自動的に判別してくれる) \n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"o\">=</span><span class=\"n\">cur_index</span><span class=\"p\">)</span>   <span class=\"c1\"># 再度同じ場所に挿入\n</span></code></pre></div>  </div>\n  <p>と実行する。  <code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>は描画Canvasがどこに繋がっていても探して削除してくれるので、\nそのまま実行して問題ない。</p>\n</blockquote>\n\n<h3 id=\"ドラッグ中処理on_touch_move\">ドラッグ中処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_move()</code>)</h3>\n<p>まず、基底クラスのドラッグ中処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ中の処理を行う。<br />\n親ウィジェットに繋がっている子ウィジェットをサーチして、自分以外で自分の中心がウィジェットの表示範囲内に入っているウィジェットを探す\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>)<br />\n自分の上端が対象ウィジェットの上端を超えたか、自分の下端が対象ウィジェットの下端を超えた場合は自分と対象ウィジェットを入れ替える。<br />\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>だけで判断すると、自分より高さが高いウィジェットと入れ替えるときに不都合が起こる)<br />\n位置を交換するには、自分を一旦削除(<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>)して、対象ウィジェットの位置(<code class=\"language-plaintext highlighter-rouge\">i</code>)に繋ぐ(<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>)。<br />\nその後、ドラッグを継続するので、ドラッグ開始時と同様に描画Canvasをcanvas.afterに繋ぎかえる。</p>\n\n<h3 id=\"ドラッグ終了処理on_touch_up\">ドラッグ終了処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_up()</code>)</h3>\n\n<p>まず、基底クラスのドラッグ終了処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ終了の処理を行う。<br />\nドラッグ開始/ドラッグ中処理でcanvas.afterに繋ぎかえた描画Canvasをcanvasに戻すために一旦<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>してから\n<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>する(これによりドラッグにより表示が移動していた対象ウィジェットが通常位置に戻る)。<br />\nその後、対象ウィジェットの表示位置がドラッグ開始時と変わっていなく、ドラッグした距離が設定値を超えている場合は\nスワイプ処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>または<code class=\"language-plaintext highlighter-rouge\">do_swipe_left()</code>)を実行する。</p>\n\n<h3 id=\"右へswipeしたときの処理do_swipe_right\">右へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、対象ウィジェットを削除する。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"左へswipeしたときの処理do_swipe_right\">左へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、デバッグ用にログ出力のみ。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"親ウィジェットのレイアウト完了時処理done_parent_layout\">親ウィジェットのレイアウト完了時処理(<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>)</h3>\n<p>親ウィジェットのレイアウト完了時に子ウィジェットすべてのこのメソッドがコールされる。<br />\nドラッグ中であれば必要な処理(現在位置の記憶とドラッグ中位置への移動)を行う。</p>\n\n<h1 id=\"サンプルプルグラム\">サンプルプルグラム</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nサンプルプルグラム</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=test1.py\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
      "content": "<h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nドラッグで並べ替えできるリスト(AndroidでよくあるUI、<code class=\"language-plaintext highlighter-rouge\">RecycleView</code>と<code class=\"language-plaintext highlighter-rouge\">ItemTouchHelper</code>で作るんだったかな?)\nを作ってみた時のメモ。<br />\n<a href=\"https://maausa.marurm.com/wp-content/uploads/RecyclerView.gif\" target=\"_blank\">ちょっと違うけど、大体こんな感じ</a></p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nreorderablelist.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=reorderablelist.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>ソースは、表示する項目を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>と\nリスト全体を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>で構成される。<br />\n(あと、単体実行で動作するテストプログラム)<br />\n動作としては、</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>に<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を追加していきリスト化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code> をドラッグすることで並べ替え</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を左右にスワイプすることでハンドラ実行(デフォルトでは右スワイプで項目削除)\nといった感じ。</li>\n</ul>\n\n<p>テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>を<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>で囲んでスクロール可能にしています。\nスクロール不要ならそのまま配置しても可(テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">with_scroll</code>を<code class=\"language-plaintext highlighter-rouge\">False</code>に設定)。</p>\n\n<h2 id=\"reorderablelist\">ReorderableList</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>はリスト全体を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承したクラス。</p>\n\n<h3 id=\"追加したプロパティ\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>item_bg</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>item_fg</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>list_bg</td>\n      <td>リストの背景色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\n(<code class=\"language-plaintext highlighter-rouge\">orientation</code>は<code class=\"language-plaintext highlighter-rouge\">\"vertical\"</code>固定(項目を縦方向に並べるため)、\n<code class=\"language-plaintext highlighter-rouge\">size_hint_y</code>は<code class=\"language-plaintext highlighter-rouge\">None</code>固定(ScrollViewに包むため))\nのほか、<br />\n背景色の設定と、スクロール可能にするためminimum_height変更時の処理のbindを行っている。</p>\n\n<h3 id=\"項目追加処理\">項目追加処理</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">add_item</code>が項目追加処理。<br />\nパラメータは<code class=\"language-plaintext highlighter-rouge\">cls</code>で項目表示に使用するクラス(デフォルトは<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>)と、項目表示クラスの初期化パラメータを受け取る。<br />\nこれは項目に表示する内容を柔軟に切り替えられるよう、項目表示クラスを<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を継承したクラスに切り替えられるようにするため。</p>\n\n<h3 id=\"レイアウト処理\">レイアウト処理</h3>\n<p>kivyでは、レイアウトの変更命令と実際に変更が行われるまでにディレイがある。<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">add_widget(wid)</code> して直後にwid.posを読み出すと実際に追加されたあとの位置が読み出せない。<br />\nこれは、<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>では処理の予約だけ行い、実際に描画が行われるのは別のところ(<code class=\"language-plaintext highlighter-rouge\">mainloop</code>?)で\n他のウィジェットのレイアウト結果を五月雨式に反映していくため、\n描画結果がposに反映されるまでタイムラグが発生するためと思われる。</p>\n\n<p>そこで、<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>のレイアウトが変更され、処理が終了したタイミングで子ウィジェットに\nレイアウト完了を通知できるよう<code class=\"language-plaintext highlighter-rouge\">do_layout()</code>をオーバライドし、基底クラスの処理が完了した後\n各子ウィジェットの<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>をコールしている。</p>\n\n<h2 id=\"reorderableitem\">ReorderableItem</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>はリストに表示する項目を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスと<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承している。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスはドラッグ処理を実現するクラス。<br />\nもう一つの基底クラスを<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>とすることで、派生クラスのレイアウトを柔軟に設定できるようにしている。</p>\n\n<h3 id=\"追加したプロパティ-1\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>text</td>\n      <td>項目に表示する文字列</td>\n    </tr>\n    <tr>\n      <td>bg_color</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>fg_color</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ-1\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\nのほか、<br />\n項目内部の構築(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)、\n背景色の設定と、pos/size変更時にドラッグ範囲を変更する処理のbind、\nインスタンス変数の設定を行っている</p>\n\n<h3 id=\"内部ウィジェットの追加処理add_inner_widget\">内部ウィジェットの追加処理(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)</h3>\n<p>項目の内部の表示を構築する処理。<br />\nデフォルトではLabelを1個追加している。<br />\n項目の表示内容を変更したい場合は、派生クラスでこの処理をオーバライドし、\n必要な内容を追加していく。</p>\n\n<h3 id=\"ドラッグ開始処理on_touch_down\">ドラッグ開始処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_down()</code>)</h3>\n<p>まず、基底クラスのドラッグ開始処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ対象としての処理(インスタンス変数の設定)を行い、<br />\n自身の描画Canvasを親ウィジェット(<code class=\"language-plaintext highlighter-rouge\">self.parent</code>)のcanvasからcanvas.afterに繋ぎかえる。\nこれはドラッグ中の表示が前面に表示されるようにするためである。</p>\n\n<blockquote>\n  <p>[!NOTE]\n通常、add_widget()すると追加されたウィジェットの描画Canvasは親ウィジェットのCanvasに繋がれる。<br />\nこの親ウィジェットのCanvasに繋がれた描画ウィジェットは後から繋がれたものが前面に表示される。<br />\n(縦方向のBoxLayoutの場合下に表示されているウィジェットが前に表示される)<br />\n重ならない表示であれば問題ないが、ドラッグを行うとドラッグ中のウィジェットが背面に表示されることがある。<br />\nそこで、ドラッグ中のウィジェット他のウィジェットより前面に表示するため、CanvasからCanvas.afterに繋ぎかえ、前面に表示されるようにする。<br />\n仕様を読む限り、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index, canvas='after')</code>でadd_widget時にcanvas.afterに接続できるようなのだが、\n実際にはバグ(仕様制限?)により、indexが0のときのみcanvasパラメータが有効になるらしい。<br />\nこれを回避するため、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index)</code>で通常通りウィジェットを追加した後、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">after</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>として描画Canvasを繋ぎかえている。\ncanvas.afterに繋いだ描画Canvasをcanvasに戻す場合は、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">cur_index</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">children</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>    <span class=\"c1\"># canvas.after から canvasへ繋ぎかえるため\n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">remove_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>                 <span class=\"c1\"># 一旦削除して(canvasかcanvas.afterは自動的に判別してくれる) \n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"o\">=</span><span class=\"n\">cur_index</span><span class=\"p\">)</span>   <span class=\"c1\"># 再度同じ場所に挿入\n</span></code></pre></div>  </div>\n  <p>と実行する。  <code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>は描画Canvasがどこに繋がっていても探して削除してくれるので、\nそのまま実行して問題ない。</p>\n</blockquote>\n\n<h3 id=\"ドラッグ中処理on_touch_move\">ドラッグ中処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_move()</code>)</h3>\n<p>まず、基底クラスのドラッグ中処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ中の処理を行う。<br />\n親ウィジェットに繋がっている子ウィジェットをサーチして、自分以外で自分の中心がウィジェットの表示範囲内に入っているウィジェットを探す\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>)<br />\n自分の上端が対象ウィジェットの上端を超えたか、自分の下端が対象ウィジェットの下端を超えた場合は自分と対象ウィジェットを入れ替える。<br />\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>だけで判断すると、自分より高さが高いウィジェットと入れ替えるときに不都合が起こる)<br />\n位置を交換するには、自分を一旦削除(<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>)して、対象ウィジェットの位置(<code class=\"language-plaintext highlighter-rouge\">i</code>)に繋ぐ(<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>)。<br />\nその後、ドラッグを継続するので、ドラッグ開始時と同様に描画Canvasをcanvas.afterに繋ぎかえる。</p>\n\n<h3 id=\"ドラッグ終了処理on_touch_up\">ドラッグ終了処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_up()</code>)</h3>\n\n<p>まず、基底クラスのドラッグ終了処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ終了の処理を行う。<br />\nドラッグ開始/ドラッグ中処理でcanvas.afterに繋ぎかえた描画Canvasをcanvasに戻すために一旦<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>してから\n<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>する(これによりドラッグにより表示が移動していた対象ウィジェットが通常位置に戻る)。<br />\nその後、対象ウィジェットの表示位置がドラッグ開始時と変わっていなく、ドラッグした距離が設定値を超えている場合は\nスワイプ処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>または<code class=\"language-plaintext highlighter-rouge\">do_swipe_left()</code>)を実行する。</p>\n\n<h3 id=\"右へswipeしたときの処理do_swipe_right\">右へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、対象ウィジェットを削除する。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"左へswipeしたときの処理do_swipe_right\">左へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、デバッグ用にログ出力のみ。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"親ウィジェットのレイアウト完了時処理done_parent_layout\">親ウィジェットのレイアウト完了時処理(<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>)</h3>\n<p>親ウィジェットのレイアウト完了時に子ウィジェットすべてのこのメソッドがコールされる。<br />\nドラッグ中であれば必要な処理(現在位置の記憶とドラッグ中位置への移動)を行う。</p>\n\n<h1 id=\"サンプルプルグラム\">サンプルプルグラム</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nサンプルプルグラム</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=test1.py\"></script>\n</dev>\n\n",
      "url": "/2025/05/19/kivy_5.html",
      "draft": false,
      "categories": [

      ],
      "title": "kivyでドラッグで並べ替えできるリスト",
      "date": "2025-05-19 00:00:00 +0000",
      "tags": [
        "kivy",
        "python"
      ],
      "layout": "default",
      "slug": "kivy_5",
      "ext": ".md"
    },
    "id": "/2025/06/09/WSL_USB_1",
    "collection": "posts",
    "next": null,
    "output": "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>WSLでUSB</title>\n  </head>\n  <body>\n    <header>\n      <h1>WSLでUSB</h1>\n      <p>WSLでUSBを使った時のメモ(バージョン 2.5.7.0)</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>WSLのバージョンが2.5.7.0でカーネルバージョンが6.6.87.1-1になってカーネルの再ビルドしなくても\n色々なUSBデバイスが使えるようになったので試してみた時のメモ。</p>\n\n<p>参考:<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb\" target=\"_blank\">USB デバイスを接続する</a></p>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"windows側の準備\">windows側の準備</h2>\n<h3 id=\"usbipd-winのインストール\">usbipd-winのインストール</h3>\n<p><a href=\"https://github.com/dorssel/usbipd-win/releases\" target=\"_blank\">usbipd-winのgithub</a>からダウンロード(使用したのは5.10)<br />\nインストールはファイルをダウンロードして実行するだけ。<br />\nWindowsTerminarが開いている場合は一旦すべて閉じる(PATHの変更を有効にするため)</p>\n\n<h2 id=\"ubuntu側の準備\">Ubuntu側の準備</h2>\n<h3 id=\"systemdの有効化\">systemdの有効化</h3>\n\n<p>systemdを有効にするため、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に以下の設定を追加。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<h3 id=\"仮想usbホストコントローラインタフェースのインストール\">仮想USBホストコントローラインタフェースのインストール</h3>\n<p>ネットワーク経由でUSBデバイスを共有することを可能にするため、仮想USBホストコントローラインタフェース(vhci-hcd)をインストール\n(ドライバの組み込み)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/modules-load.d/usb.conf</code> (ファイル名は何でも可)を以下の内容で作成し、WSLの再起動。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vhci-hcd\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nお試しで1回だけ読み込むなら以下。この場合は再起動不要(というか再起動したら消える)。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo modprobe vhci-hcd\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"usbユーティリティのインストール\">USBユーティリティのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">lsusb</code>とか使いたいので、インストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>usbutils\n</code></pre></div></div>\n\n<h3 id=\"仮想マシンの再起動\">仮想マシンの再起動</h3>\n<p>設定を有効にするため、仮想マシンを再起動する。<br />\n開いているすべての仮想マシンを閉じた後、Windwos側で <code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行し、<br />\n<code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>ですべて仮想マシンのSTATEが<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていることを確認し仮想マシンを再度実行。</p>\n\n<h4 id=\"systemdが起動していることを確認する\">systemdが起動していることを確認する</h4>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>systemctl\n</code></pre></div></div>\n<p>起動していればサービス一覧が表示される。<br />\n起動していなければ以下のようなメッセージが表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>System has not been booted with systemd as init system (PID 1). Can't operate.\nFailed to connect to bus: ホストが落ちています\n</code></pre></div></div>\n\n<h4 id=\"vhci-hcdが組み込まれていることを確認する\">vhci-hcdが組み込まれていることを確認する</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsmod\n</code></pre></div></div>\n<p>表示の中に<code class=\"language-plaintext highlighter-rouge\">vhci_hcd</code>があることを確認。<br />\nなければ組み込みの設定を確認。</p>\n\n<h1 id=\"usbカメラを使ってみる\">USBカメラを使ってみる</h1>\n<p>今回は エレコムの UCAM-DLA200HBK を使用。<br />\nかなり古いカメラなのでもう売ってないけど…<br />\nUVC仕様のカメラなら基本的に同じはず。</p>\n\n<h2 id=\"ubuntu側の準備-1\">Ubuntu側の準備</h2>\n<p>今回はカメラなので、自身にvideoグループを追加<br />\n(要 再ログイン、シャットダウンは不要)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> video\n</code></pre></div></div>\n\n<h3 id=\"guvcviewのインストール\">guvcviewのインストール</h3>\n<p>表示ツールは何でもいいけど、とりあえずguvcviewで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>guvcview \n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-1\">Windows側の準備</h2>\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行\">Ubuntu側の実行</h2>\n\n<p>USB機器が割り当てられたことを確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 002: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n</code></pre></div></div>\n\n<p>デバイスノードも確認しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> <span class=\"nt\">-la</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1\n</code></pre></div></div>\n\n<p>実際に表示してみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">LANG</code>が<code class=\"language-plaintext highlighter-rouge\">ja_JP.UTF8</code>とかのままだと文字化けしてしまうので、Cに変更して実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示されるが、何も表示されない\nコンソールには「V4L2_CORE: Could not grab image (select timeout): リソースが一時的に利用できません」と表示され続ける</p>\n\n<p>GuvcviewウィンドウのVideo Controls をクリックし、</p>\n<ul>\n  <li>Frame Rate を15/1 fps</li>\n  <li>Rsolution を 160x120</li>\n  <li>Camera Output を MJPEG<br />\nにすると表示されるけど、あまり実用的ではない…</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nこれらのパラメータが選択できるかは使用するカメラによる。<br />\nPCのスペック等によって、もうちょっと大きいサイズでも表示できることがある。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n日本語で表示するには、例えば以下のように日本語フォントをインストールして\nLANGを指定せずに実行すれば良い。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"windows側の後始末\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n<h2 id=\"ということで\">ということで</h2>\n<p>あまり実用的とは言い難い結果となってしまった。</p>\n\n<h1 id=\"usbカメラをubuntu-pcからエクスポートしてみる\">USBカメラをUbuntu PCからエクスポートしてみる</h1>\n<p>試しに、Ubuntu PCからUSBカメラをエクスポートしてWSLで表示してみる。</p>\n\n<blockquote>\n  <p>[!NOTE]\n「Netive UbuntuあるならWSL使わんでも良いやん」という気もするが…</p>\n</blockquote>\n\n<h2 id=\"navive-ubuntuの準備\">Navive Ubuntuの準備</h2>\n\n<h3 id=\"カメラを接続\">カメラを接続</h3>\n<p>USBカメラを接続し、認識されているか確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 003 Device 006: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>デバイスノードの確認。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ。<br />\nカメラが他にも接続されているので2×2表示されてるけど…<br />\n今回接続されたのは2と3のはず(今はこれを使わないので気にしない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1  /dev/video2  /dev/video3\n</code></pre></div></div>\n\n<p>必要ならguvcviewをインストールして試してみてちょ。</p>\n\n<h3 id=\"linux-toolsのインストール\">linux-toolsのインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div></div>\n<p>usbipを実行してみる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div></div>\n\n<p>※ linux-tools-≪バージョン≫-generic をインストールしろと言われたら従う。例えば</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-6.5.0-41-generic\n</code></pre></div></div>\n\n<h3 id=\"ドライバの組み込みとdaemonの起動\">ドライバの組み込みとdaemonの起動</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbip-host        <span class=\"c\"># ドライバ組み込み</span>\n<span class=\"nb\">sudo </span>usbipd <span class=\"nt\">-D</span>                  <span class=\"c\"># daemon起動</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n起動時に自動で組み込み&実行したいときはsystemdでサービス登録するとできそうだけど、<br />\n本筋じゃないのでやめとく。<br />\n<a href=\"https://github.com/furbrain/systemd-usbip/blob/master/usbipd.service\" target=\"_blank\">ここ</a>\nとか参考になるかも。</p>\n</blockquote>\n\n<h3 id=\"接続されているデバイスを表示\">接続されているデバイスを表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip list <span class=\"nt\">--local</span>         <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<p>こんな感じで表示される</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\n - busid 3-11 (056e:700a)\n   Elecom Co., Ltd : unknown product (056e:700a)\n・・・\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n表示される製品名等が不明確な場合は<code class=\"language-plaintext highlighter-rouge\">lsusb</code>の結果と突き合わせてみると良い。<br />\n(IDはどちらも表示されているので、これを頼りに)</p>\n</blockquote>\n\n<h3 id=\"バインド\">バインド</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip <span class=\"nb\">bind</span> <span class=\"nt\">--busid</span> 3-11    <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<h2 id=\"wsl-ubuntuでの操作\">WSL Ubuntuでの操作</h2>\n\n<h3 id=\"linux-toolsのインストール-1\">linux-toolsのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">usbip</code>はWindows側でインストールしたusbipd-winに含まれているのでインストール不要。<br />\n別途aptでインストールしても使えるけど結構メンドクサイ。<br />\n使いたくなることもあるかもしれんので、手順は残しておく。</p>\n\n<blockquote>\n  <p>[!NOTE]</p>\n\n  <p>usbipが入っているパッケージをインストール</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div>  </div>\n  <p>usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>たぶんこんなメッセージが出る</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>WARNING: usbip not found for kernel 6.6.87.1-microsoft\n\n  You may need to install the following packages for this specific kernel:\n    linux-tools-6.6.87.1-microsoft-standard-WSL2\n    linux-cloud-tools-6.6.87.1-microsoft-standard-WSL2\n\n  You may also want to install one of the following packages to keep up to date:\n    linux-tools-standard-WSL2\n    linux-cloud-tools-standard-WSL2\n</code></pre></div>  </div>\n  <p>しかし、指定されたパッケージをインストールしようとしても「そんなもんはない」と怒られる。<br />\nしかたないのでゴマカシ。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /usr/lib/linux-tools\n\n<span class=\"nb\">ls</span> <span class=\"nt\">-la</span>\n合計 12\ndrwxr-xr-x  3 root root 4096  6月  6 13:11 <span class=\"nb\">.</span>\ndrwxr-xr-x 65 root root 4096  6月  6 13:11 ..\ndrwxr-xr-x  2 root root 4096  6月  6 13:11 6.8.0-60-generic    ← これを覚えておく\n</code></pre></div>  </div>\n  <p>isbipを実行した時のメッセージとlsしたときのディレクトリ名から以下のようなシンボリックリンクを作成する<br />\n(カーネルバージョンが変わると変更しないといけないので注意)</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ln</span> <span class=\"nt\">-s</span> 6.8.0-60-generic 6.6.87.1-microsoft-standard-WSL2\n</code></pre></div>  </div>\n\n  <p>再度usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>USAGEが表示されたらOK。<br />\nまたWARNINGが表示されたらシンボリックリンクの名前が間違っていると思うので、再確認。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nusbipコマンドへのpathを設定してもsudoで実行するときは無効なので、設定せずfullpathで指定する</p>\n</blockquote>\n\n<h3 id=\"アタッチ可能なバス番号を調べる\">アタッチ可能なバス番号を調べる</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip list <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫\n</code></pre></div></div>\n<p>こんな感じで表示される(BUSIDは例。以下同じ)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Exportable USB devices\n======================\n - ≪UbuntuPCのIPアドレス≫\n       3-11: Elecom Co., Ltd : unknown product (056e:700a)\n           : /sys/devices/pci0000:00/0000:00:14.0/usb3/3-11\n           : Miscellaneous Device / ? / Interface Association (ef/02/01)\n</code></pre></div></div>\n<h3 id=\"アタッチする\">アタッチする</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip attach <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫ <span class=\"nt\">--busid</span> 3-11\n</code></pre></div></div>\n\n<h3 id=\"確認\">確認</h3>\n<p>アタッチできたか確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 001 Device 003: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>前と同様にguvcviewを実行してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示され、画像が表示される。<br />\nそれなりに大きなサイズに切り替えても表示できている。</p>\n\n<h3 id=\"後片付け\">後片付け</h3>\n<p>usbipのポートの確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip port\n</code></pre></div></div>\n<p>こんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Imported USB devices\n====================\nPort 00: <Port in Use> at High Speed(480Mbps)\n       Elecom Co., Ltd : unknown product (056e:700a)\n       1-1 -> unknown host, remote port and remote busid\n           -> remote bus/dev 003/006\n</code></pre></div></div>\n<p>ポートは0であることが分かる。</p>\n\n<p>デタッチする</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo /mnt/c/Program\\ Files/usbipd-win/WSL/usbip detach --port 0\n</code></pre></div></div>\n\n<h3 id=\"まとめ\">まとめ</h3>\n<p>ということで、どうも、USBIPD-WINの転送速度が遅いようだ。</p>\n\n<h1 id=\"bluetoothを使ってみる\">Bluetoothを使ってみる</h1>\n<p>カメラはビミョーな結果だったので、今度はBluetoothで試してみる。\n使用したのは Buffalo BSBT4D09BK(4.0+EDR/LEのアダプタ、中身はCSR製)。<br />\nこれも結構古いのでもう売ってない。  中身がCSRのアダプタなら動く可能性高い。<br />\nRealtekのも使えそうだけど、試してないのでなんとも…</p>\n\n<h2 id=\"ubuntu側の準備-2\">Ubuntu側の準備</h2>\n<p>今回はBluetoothなのでBluetooth関連のライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>bluez\n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-2\">Windows側の準備</h2>\n<p>USBipd-win</p>\n\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行-1\">Ubuntu側の実行</h2>\n\n<h3 id=\"usb機器が割り当てられたことを確認する\">USB機器が割り当てられたことを確認する。</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 003: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)\n</code></pre></div></div>\n\n<h3 id=\"動かしてみる\">動かしてみる</h3>\n<p>ローカルデバイスの一覧表示をしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>hcitool dev\n</code></pre></div></div>\n<p>例えばこんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Devices:\n        hci0    XX:XX:XX:XX:XX:XX\n</code></pre></div></div>\n\n<p>スキャンしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bluetoothctl\n</code></pre></div></div>\n<p>bluetoothctlが起動され、プロンプトが<code class=\"language-plaintext highlighter-rouge\">[bluetooth]#</code>になる。<br />\nスキャンしてデバイス一覧を見てみる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>scan on\n≪スキャンされたデバイスが表示される≫\n≪しばらく待つ≫\nscan off\n≪表示が止まる≫\n\nlist\n≪スキャンされたデバイスが表示される≫\n\nexit\n≪終了してshellに戻る≫\n</code></pre></div></div>\n\n<h3 id=\"pythonで動かしてみる\">pythonで動かしてみる。</h3>\n<p>pyenvでpythonをインストールする場合は\n<a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a>\n の注意書きにあるように、コンパイル前に以下を実行しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<p>新しくプログラム作るのは面倒なので以前作った <br />\n<a href=\"/memoBlog/2025/04/21/Buildozer_3.html\" target=\"_blank\">AndroidでpythonでBLE</a> <br />\nを実行してみる。</p>\n\n<p>必要なモジュール類をインストールして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libmtdev-dev\npip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<p>実行</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">python</span> <span class=\"n\">kivy_ble</span><span class=\"p\">.</span><span class=\"n\">py</span>\n</code></pre></div></div>\n\n<p>動いた。メデタシメデタシ。</p>\n\n<h2 id=\"windows側の後始末-1\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n<p>USB接続のSDカードリーダを使えばRaspberryPiのブート用SDカードをWSLにマウントして操作することも可能なはず。<br />\nメンドクサくなってきたので試すのはやめておくけど。</p>\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
    "content": "<h1 id=\"概要\">概要</h1>\n<p>WSLのバージョンが2.5.7.0でカーネルバージョンが6.6.87.1-1になってカーネルの再ビルドしなくても\n色々なUSBデバイスが使えるようになったので試してみた時のメモ。</p>\n\n<p>参考:<a href=\"https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb\" target=\"_blank\">USB デバイスを接続する</a></p>\n\n<h1 id=\"準備\">準備</h1>\n<h2 id=\"windows側の準備\">windows側の準備</h2>\n<h3 id=\"usbipd-winのインストール\">usbipd-winのインストール</h3>\n<p><a href=\"https://github.com/dorssel/usbipd-win/releases\" target=\"_blank\">usbipd-winのgithub</a>からダウンロード(使用したのは5.10)<br />\nインストールはファイルをダウンロードして実行するだけ。<br />\nWindowsTerminarが開いている場合は一旦すべて閉じる(PATHの変更を有効にするため)</p>\n\n<h2 id=\"ubuntu側の準備\">Ubuntu側の準備</h2>\n<h3 id=\"systemdの有効化\">systemdの有効化</h3>\n\n<p>systemdを有効にするため、<code class=\"language-plaintext highlighter-rouge\">/etc/wsl.conf</code> に以下の設定を追加。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[boot]\nsystemd=true\n</code></pre></div></div>\n\n<h3 id=\"仮想usbホストコントローラインタフェースのインストール\">仮想USBホストコントローラインタフェースのインストール</h3>\n<p>ネットワーク経由でUSBデバイスを共有することを可能にするため、仮想USBホストコントローラインタフェース(vhci-hcd)をインストール\n(ドライバの組み込み)。</p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">/etc/modules-load.d/usb.conf</code> (ファイル名は何でも可)を以下の内容で作成し、WSLの再起動。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>vhci-hcd\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\nお試しで1回だけ読み込むなら以下。この場合は再起動不要(というか再起動したら消える)。</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo modprobe vhci-hcd\n</code></pre></div>  </div>\n</blockquote>\n\n<h3 id=\"usbユーティリティのインストール\">USBユーティリティのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">lsusb</code>とか使いたいので、インストール。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>usbutils\n</code></pre></div></div>\n\n<h3 id=\"仮想マシンの再起動\">仮想マシンの再起動</h3>\n<p>設定を有効にするため、仮想マシンを再起動する。<br />\n開いているすべての仮想マシンを閉じた後、Windwos側で <code class=\"language-plaintext highlighter-rouge\">wsl --shutdown</code>を実行し、<br />\n<code class=\"language-plaintext highlighter-rouge\">wsl -l -v</code>ですべて仮想マシンのSTATEが<code class=\"language-plaintext highlighter-rouge\">Stopped</code>になっていることを確認し仮想マシンを再度実行。</p>\n\n<h4 id=\"systemdが起動していることを確認する\">systemdが起動していることを確認する</h4>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>systemctl\n</code></pre></div></div>\n<p>起動していればサービス一覧が表示される。<br />\n起動していなければ以下のようなメッセージが表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>System has not been booted with systemd as init system (PID 1). Can't operate.\nFailed to connect to bus: ホストが落ちています\n</code></pre></div></div>\n\n<h4 id=\"vhci-hcdが組み込まれていることを確認する\">vhci-hcdが組み込まれていることを確認する</h4>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsmod\n</code></pre></div></div>\n<p>表示の中に<code class=\"language-plaintext highlighter-rouge\">vhci_hcd</code>があることを確認。<br />\nなければ組み込みの設定を確認。</p>\n\n<h1 id=\"usbカメラを使ってみる\">USBカメラを使ってみる</h1>\n<p>今回は エレコムの UCAM-DLA200HBK を使用。<br />\nかなり古いカメラなのでもう売ってないけど…<br />\nUVC仕様のカメラなら基本的に同じはず。</p>\n\n<h2 id=\"ubuntu側の準備-1\">Ubuntu側の準備</h2>\n<p>今回はカメラなので、自身にvideoグループを追加<br />\n(要 再ログイン、シャットダウンは不要)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>gpasswd <span class=\"nt\">-a</span> <span class=\"nv\">$USER</span> video\n</code></pre></div></div>\n\n<h3 id=\"guvcviewのインストール\">guvcviewのインストール</h3>\n<p>表示ツールは何でもいいけど、とりあえずguvcviewで。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>guvcview \n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-1\">Windows側の準備</h2>\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行\">Ubuntu側の実行</h2>\n\n<p>USB機器が割り当てられたことを確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 002: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n</code></pre></div></div>\n\n<p>デバイスノードも確認しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> <span class=\"nt\">-la</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1\n</code></pre></div></div>\n\n<p>実際に表示してみる。<br />\n<code class=\"language-plaintext highlighter-rouge\">LANG</code>が<code class=\"language-plaintext highlighter-rouge\">ja_JP.UTF8</code>とかのままだと文字化けしてしまうので、Cに変更して実行。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示されるが、何も表示されない\nコンソールには「V4L2_CORE: Could not grab image (select timeout): リソースが一時的に利用できません」と表示され続ける</p>\n\n<p>GuvcviewウィンドウのVideo Controls をクリックし、</p>\n<ul>\n  <li>Frame Rate を15/1 fps</li>\n  <li>Rsolution を 160x120</li>\n  <li>Camera Output を MJPEG<br />\nにすると表示されるけど、あまり実用的ではない…</li>\n</ul>\n\n<blockquote>\n  <p>[!NOTE]\nこれらのパラメータが選択できるかは使用するカメラによる。<br />\nPCのスペック等によって、もうちょっと大きいサイズでも表示できることがある。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\n日本語で表示するには、例えば以下のように日本語フォントをインストールして\nLANGを指定せずに実行すれば良い。</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>fonts-noto-cjk\n</code></pre></div>  </div>\n</blockquote>\n\n<h2 id=\"windows側の後始末\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n<h2 id=\"ということで\">ということで</h2>\n<p>あまり実用的とは言い難い結果となってしまった。</p>\n\n<h1 id=\"usbカメラをubuntu-pcからエクスポートしてみる\">USBカメラをUbuntu PCからエクスポートしてみる</h1>\n<p>試しに、Ubuntu PCからUSBカメラをエクスポートしてWSLで表示してみる。</p>\n\n<blockquote>\n  <p>[!NOTE]\n「Netive UbuntuあるならWSL使わんでも良いやん」という気もするが…</p>\n</blockquote>\n\n<h2 id=\"navive-ubuntuの準備\">Navive Ubuntuの準備</h2>\n\n<h3 id=\"カメラを接続\">カメラを接続</h3>\n<p>USBカメラを接続し、認識されているか確認する。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb \n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 003 Device 006: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>デバイスノードの確認。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ls</span> /dev/video<span class=\"k\">*</span>\n</code></pre></div></div>\n<p>こんな感じ。<br />\nカメラが他にも接続されているので2×2表示されてるけど…<br />\n今回接続されたのは2と3のはず(今はこれを使わないので気にしない)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/dev/video0  /dev/video1  /dev/video2  /dev/video3\n</code></pre></div></div>\n\n<p>必要ならguvcviewをインストールして試してみてちょ。</p>\n\n<h3 id=\"linux-toolsのインストール\">linux-toolsのインストール</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div></div>\n<p>usbipを実行してみる</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div></div>\n\n<p>※ linux-tools-≪バージョン≫-generic をインストールしろと言われたら従う。例えば</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-6.5.0-41-generic\n</code></pre></div></div>\n\n<h3 id=\"ドライバの組み込みとdaemonの起動\">ドライバの組み込みとdaemonの起動</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>modprobe usbip-host        <span class=\"c\"># ドライバ組み込み</span>\n<span class=\"nb\">sudo </span>usbipd <span class=\"nt\">-D</span>                  <span class=\"c\"># daemon起動</span>\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n起動時に自動で組み込み&実行したいときはsystemdでサービス登録するとできそうだけど、<br />\n本筋じゃないのでやめとく。<br />\n<a href=\"https://github.com/furbrain/systemd-usbip/blob/master/usbipd.service\" target=\"_blank\">ここ</a>\nとか参考になるかも。</p>\n</blockquote>\n\n<h3 id=\"接続されているデバイスを表示\">接続されているデバイスを表示</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip list <span class=\"nt\">--local</span>         <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<p>こんな感じで表示される</p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\n - busid 3-11 (056e:700a)\n   Elecom Co., Ltd : unknown product (056e:700a)\n・・・\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE]\n表示される製品名等が不明確な場合は<code class=\"language-plaintext highlighter-rouge\">lsusb</code>の結果と突き合わせてみると良い。<br />\n(IDはどちらも表示されているので、これを頼りに)</p>\n</blockquote>\n\n<h3 id=\"バインド\">バインド</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>usbip <span class=\"nb\">bind</span> <span class=\"nt\">--busid</span> 3-11    <span class=\"c\"># ※ usbipdではないので注意</span>\n</code></pre></div></div>\n\n<h2 id=\"wsl-ubuntuでの操作\">WSL Ubuntuでの操作</h2>\n\n<h3 id=\"linux-toolsのインストール-1\">linux-toolsのインストール</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">usbip</code>はWindows側でインストールしたusbipd-winに含まれているのでインストール不要。<br />\n別途aptでインストールしても使えるけど結構メンドクサイ。<br />\n使いたくなることもあるかもしれんので、手順は残しておく。</p>\n\n<blockquote>\n  <p>[!NOTE]</p>\n\n  <p>usbipが入っているパッケージをインストール</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>linux-tools-generic\n</code></pre></div>  </div>\n  <p>usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>たぶんこんなメッセージが出る</p>\n  <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>WARNING: usbip not found for kernel 6.6.87.1-microsoft\n\n  You may need to install the following packages for this specific kernel:\n    linux-tools-6.6.87.1-microsoft-standard-WSL2\n    linux-cloud-tools-6.6.87.1-microsoft-standard-WSL2\n\n  You may also want to install one of the following packages to keep up to date:\n    linux-tools-standard-WSL2\n    linux-cloud-tools-standard-WSL2\n</code></pre></div>  </div>\n  <p>しかし、指定されたパッケージをインストールしようとしても「そんなもんはない」と怒られる。<br />\nしかたないのでゴマカシ。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">cd</span> /usr/lib/linux-tools\n\n<span class=\"nb\">ls</span> <span class=\"nt\">-la</span>\n合計 12\ndrwxr-xr-x  3 root root 4096  6月  6 13:11 <span class=\"nb\">.</span>\ndrwxr-xr-x 65 root root 4096  6月  6 13:11 ..\ndrwxr-xr-x  2 root root 4096  6月  6 13:11 6.8.0-60-generic    ← これを覚えておく\n</code></pre></div>  </div>\n  <p>isbipを実行した時のメッセージとlsしたときのディレクトリ名から以下のようなシンボリックリンクを作成する<br />\n(カーネルバージョンが変わると変更しないといけないので注意)</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">ln</span> <span class=\"nt\">-s</span> 6.8.0-60-generic 6.6.87.1-microsoft-standard-WSL2\n</code></pre></div>  </div>\n\n  <p>再度usbipを実行してみる</p>\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbip\n</code></pre></div>  </div>\n  <p>USAGEが表示されたらOK。<br />\nまたWARNINGが表示されたらシンボリックリンクの名前が間違っていると思うので、再確認。</p>\n</blockquote>\n\n<blockquote>\n  <p>[!TIP]\nusbipコマンドへのpathを設定してもsudoで実行するときは無効なので、設定せずfullpathで指定する</p>\n</blockquote>\n\n<h3 id=\"アタッチ可能なバス番号を調べる\">アタッチ可能なバス番号を調べる</h3>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip list <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫\n</code></pre></div></div>\n<p>こんな感じで表示される(BUSIDは例。以下同じ)</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Exportable USB devices\n======================\n - ≪UbuntuPCのIPアドレス≫\n       3-11: Elecom Co., Ltd : unknown product (056e:700a)\n           : /sys/devices/pci0000:00/0000:00:14.0/usb3/3-11\n           : Miscellaneous Device / ? / Interface Association (ef/02/01)\n</code></pre></div></div>\n<h3 id=\"アタッチする\">アタッチする</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo</span> /mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip attach <span class=\"nt\">-r</span> ≪UbuntuPCのIPアドレス≫ <span class=\"nt\">--busid</span> 3-11\n</code></pre></div></div>\n\n<h3 id=\"確認\">確認</h3>\n<p>アタッチできたか確認する</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>・・・\nBus 001 Device 003: ID 056e:700a Elecom Co., Ltd Venus USB2.0 Camera\n・・・\n</code></pre></div></div>\n\n<p>前と同様にguvcviewを実行してみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nv\">LANG</span><span class=\"o\">=</span><span class=\"s2\">\"C\"</span> guvcview\n</code></pre></div></div>\n<p>別ウィンドウが表示され、画像が表示される。<br />\nそれなりに大きなサイズに切り替えても表示できている。</p>\n\n<h3 id=\"後片付け\">後片付け</h3>\n<p>usbipのポートの確認</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>/mnt/c/Program<span class=\"se\">\\ </span>Files/usbipd-win/WSL/usbip port\n</code></pre></div></div>\n<p>こんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Imported USB devices\n====================\nPort 00: <Port in Use> at High Speed(480Mbps)\n       Elecom Co., Ltd : unknown product (056e:700a)\n       1-1 -> unknown host, remote port and remote busid\n           -> remote bus/dev 003/006\n</code></pre></div></div>\n<p>ポートは0であることが分かる。</p>\n\n<p>デタッチする</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo /mnt/c/Program\\ Files/usbipd-win/WSL/usbip detach --port 0\n</code></pre></div></div>\n\n<h3 id=\"まとめ\">まとめ</h3>\n<p>ということで、どうも、USBIPD-WINの転送速度が遅いようだ。</p>\n\n<h1 id=\"bluetoothを使ってみる\">Bluetoothを使ってみる</h1>\n<p>カメラはビミョーな結果だったので、今度はBluetoothで試してみる。\n使用したのは Buffalo BSBT4D09BK(4.0+EDR/LEのアダプタ、中身はCSR製)。<br />\nこれも結構古いのでもう売ってない。  中身がCSRのアダプタなら動く可能性高い。<br />\nRealtekのも使えそうだけど、試してないのでなんとも…</p>\n\n<h2 id=\"ubuntu側の準備-2\">Ubuntu側の準備</h2>\n<p>今回はBluetoothなのでBluetooth関連のライブラリ類をインストールしておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>bluez\n</code></pre></div></div>\n\n<h2 id=\"windows側の準備-2\">Windows側の準備</h2>\n<p>USBipd-win</p>\n\n<p>PowerShellやコマンドプロンプト等を管理者として開く。<br />\nUSBデバイスのリストを表示<br />\n(今回はカメラを使うのでそこだけ抜粋。IDとか名前は例)<br />\n<code class=\"language-plaintext highlighter-rouge\">Not shared</code>になっている。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Not shared\n・・・・\n</code></pre></div></div>\n\n<p>bindする(busidは上で調べたものを使用)</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--busid</span> 9-2\nまたは \nusbipd.exe <span class=\"nb\">bind</span>  <span class=\"nt\">--force</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!NOTE] \nUSBPcapがインストールされている(wiresharkなど)とwarningが表示されてbindできないので<br />\n<code class=\"language-plaintext highlighter-rouge\">--force</code>オプションを追加して実行する。<br />\n(warningで–forceオプションを付けろと教えてくれる)</p>\n</blockquote>\n\n<p>確認<br />\n<code class=\"language-plaintext highlighter-rouge\">Shared</code> または <code class=\"language-plaintext highlighter-rouge\">Shared (forced)</code>になっている。</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    0a12:0001  Generic Bluetooth Radio       Shared <span class=\"o\">(</span>forced<span class=\"o\">)</span>\n・・・・\n</code></pre></div></div>\n\n<p>attachする(attachする前にWSLの仮想マシンが起動していること)</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<blockquote>\n  <p>[!TIP]\n以下のようにbindするとUSB挿抜する度に自動でattachしてくれるらしい。確認してないけど。</p>\n\n  <div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe attach <span class=\"nt\">--wsl</span> <span class=\"nt\">--busid</span> 2-1 <span class=\"nt\">--auto-attach</span>\n</code></pre></div>  </div>\n</blockquote>\n\n<p>確認する<br />\n<code class=\"language-plaintext highlighter-rouge\">Attached</code>になっている</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe list\n・・・・\n9-2    056e:700a  Venus USB2.0 Camera   Attached\n・・・・\n</code></pre></div></div>\n\n<h2 id=\"ubuntu側の実行-1\">Ubuntu側の実行</h2>\n\n<h3 id=\"usb機器が割り当てられたことを確認する\">USB機器が割り当てられたことを確認する。</h3>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>lsusb\n</code></pre></div></div>\n<p>こんな感じで表示される</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Bus 001 Device 003: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)\n</code></pre></div></div>\n\n<h3 id=\"動かしてみる\">動かしてみる</h3>\n<p>ローカルデバイスの一覧表示をしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>hcitool dev\n</code></pre></div></div>\n<p>例えばこんな感じで表示される。</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Devices:\n        hci0    XX:XX:XX:XX:XX:XX\n</code></pre></div></div>\n\n<p>スキャンしてみる。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bluetoothctl\n</code></pre></div></div>\n<p>bluetoothctlが起動され、プロンプトが<code class=\"language-plaintext highlighter-rouge\">[bluetooth]#</code>になる。<br />\nスキャンしてデバイス一覧を見てみる</p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>scan on\n≪スキャンされたデバイスが表示される≫\n≪しばらく待つ≫\nscan off\n≪表示が止まる≫\n\nlist\n≪スキャンされたデバイスが表示される≫\n\nexit\n≪終了してshellに戻る≫\n</code></pre></div></div>\n\n<h3 id=\"pythonで動かしてみる\">pythonで動かしてみる。</h3>\n<p>pyenvでpythonをインストールする場合は\n<a href=\"/memoBlog/2019/06/27/pyenv.html\" target=\"_blank\">pyenvのインストール</a>\n の注意書きにあるように、コンパイル前に以下を実行しておく。</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libbluetooth-dev libglib2.0-dev libboost-python-dev libboost-thread-dev\n</code></pre></div></div>\n\n<p>新しくプログラム作るのは面倒なので以前作った <br />\n<a href=\"/memoBlog/2025/04/21/Buildozer_3.html\" target=\"_blank\">AndroidでpythonでBLE</a> <br />\nを実行してみる。</p>\n\n<p>必要なモジュール類をインストールして</p>\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">sudo </span>apt <span class=\"nb\">install </span>libmtdev-dev\npip <span class=\"nb\">install </span>kivy bleak\n</code></pre></div></div>\n\n<p>実行</p>\n<div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">python</span> <span class=\"n\">kivy_ble</span><span class=\"p\">.</span><span class=\"n\">py</span>\n</code></pre></div></div>\n\n<p>動いた。メデタシメデタシ。</p>\n\n<h2 id=\"windows側の後始末-1\">Windows側の後始末</h2>\n<p>USBカメラを取り外すためにアタッチ解除とバインド解除</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>usbipd.exe detach <span class=\"nt\">--busid</span> 9-2\nusbipd.exe unbind  <span class=\"nt\">--busid</span> 9-2\n</code></pre></div></div>\n\n<h1 id=\"その他\">その他</h1>\n<p>USB接続のSDカードリーダを使えばRaspberryPiのブート用SDカードをWSLにマウントして操作することも可能なはず。<br />\nメンドクサくなってきたので試すのはやめておくけど。</p>\n",
    "url": "/2025/06/09/WSL_USB_1.html",
    "draft": false,
    "categories": [

    ],
    "title": "WSLでUSB",
    "date": "2025-06-09 00:00:00 +0000",
    "tags": [
      "WSL"
    ],
    "layout": "default",
    "slug": "WSL_USB_1",
    "ext": ".md"
  },
  "output": "<!doctype html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/style.css?v=078fa3dd47f4f14e9744e0be22d8dfdc26067cdd\">\n    <script src=\"https://code.jquery.com/jquery-3.3.0.min.js\" integrity=\"sha256-RTQy8VOmNlT6b2PIRur37p6JEBZUE7o8wPgMvu18MC4=\" crossorigin=\"anonymous\"></script>\n    <script src=\"/memoBlog/assets/js/jquery.floatingscroll.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/memoBlog/assets/css/jquery.floatingscroll.css\">\n    <script src=\"/memoBlog/assets/js/main.js\"></script>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <title>kivyでドラッグで並べ替えできるリスト</title>\n  </head>\n  <body>\n    <header>\n      <h1>kivyでドラッグで並べ替えできるリスト</h1>\n      <p>kivyでドラッグで並べ替えできるリストを作った時のメモ</p>\n    </header>\n\n    <nav>\n      <div class=\"outline\">\n        <ul></ul>\n      </div>\n      <p class=\"to_top\">\n        <a href=\"/memoBlog/\">トップページ</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: 0                   },1500); return false;\">最初</a>    \n        <a href=\"#\" onClick=\"$('body,html').animate({scrollTop: $(document).height()},1500); return false;\">最後</a>\n      </p>\n    </nav>\n    <div class=\"wrapper\">\n      <section>\n        <h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nドラッグで並べ替えできるリスト(AndroidでよくあるUI、<code class=\"language-plaintext highlighter-rouge\">RecycleView</code>と<code class=\"language-plaintext highlighter-rouge\">ItemTouchHelper</code>で作るんだったかな?)\nを作ってみた時のメモ。<br />\n<a href=\"https://maausa.marurm.com/wp-content/uploads/RecyclerView.gif\" target=\"_blank\">ちょっと違うけど、大体こんな感じ</a></p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nreorderablelist.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=reorderablelist.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>ソースは、表示する項目を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>と\nリスト全体を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>で構成される。<br />\n(あと、単体実行で動作するテストプログラム)<br />\n動作としては、</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>に<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を追加していきリスト化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code> をドラッグすることで並べ替え</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を左右にスワイプすることでハンドラ実行(デフォルトでは右スワイプで項目削除)\nといった感じ。</li>\n</ul>\n\n<p>テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>を<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>で囲んでスクロール可能にしています。\nスクロール不要ならそのまま配置しても可(テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">with_scroll</code>を<code class=\"language-plaintext highlighter-rouge\">False</code>に設定)。</p>\n\n<h2 id=\"reorderablelist\">ReorderableList</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>はリスト全体を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承したクラス。</p>\n\n<h3 id=\"追加したプロパティ\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>item_bg</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>item_fg</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>list_bg</td>\n      <td>リストの背景色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\n(<code class=\"language-plaintext highlighter-rouge\">orientation</code>は<code class=\"language-plaintext highlighter-rouge\">\"vertical\"</code>固定(項目を縦方向に並べるため)、\n<code class=\"language-plaintext highlighter-rouge\">size_hint_y</code>は<code class=\"language-plaintext highlighter-rouge\">None</code>固定(ScrollViewに包むため))\nのほか、<br />\n背景色の設定と、スクロール可能にするためminimum_height変更時の処理のbindを行っている。</p>\n\n<h3 id=\"項目追加処理\">項目追加処理</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">add_item</code>が項目追加処理。<br />\nパラメータは<code class=\"language-plaintext highlighter-rouge\">cls</code>で項目表示に使用するクラス(デフォルトは<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>)と、項目表示クラスの初期化パラメータを受け取る。<br />\nこれは項目に表示する内容を柔軟に切り替えられるよう、項目表示クラスを<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を継承したクラスに切り替えられるようにするため。</p>\n\n<h3 id=\"レイアウト処理\">レイアウト処理</h3>\n<p>kivyでは、レイアウトの変更命令と実際に変更が行われるまでにディレイがある。<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">add_widget(wid)</code> して直後にwid.posを読み出すと実際に追加されたあとの位置が読み出せない。<br />\nこれは、<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>では処理の予約だけ行い、実際に描画が行われるのは別のところ(<code class=\"language-plaintext highlighter-rouge\">mainloop</code>?)で\n他のウィジェットのレイアウト結果を五月雨式に反映していくため、\n描画結果がposに反映されるまでタイムラグが発生するためと思われる。</p>\n\n<p>そこで、<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>のレイアウトが変更され、処理が終了したタイミングで子ウィジェットに\nレイアウト完了を通知できるよう<code class=\"language-plaintext highlighter-rouge\">do_layout()</code>をオーバライドし、基底クラスの処理が完了した後\n各子ウィジェットの<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>をコールしている。</p>\n\n<h2 id=\"reorderableitem\">ReorderableItem</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>はリストに表示する項目を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスと<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承している。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスはドラッグ処理を実現するクラス。<br />\nもう一つの基底クラスを<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>とすることで、派生クラスのレイアウトを柔軟に設定できるようにしている。</p>\n\n<h3 id=\"追加したプロパティ-1\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>text</td>\n      <td>項目に表示する文字列</td>\n    </tr>\n    <tr>\n      <td>bg_color</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>fg_color</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ-1\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\nのほか、<br />\n項目内部の構築(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)、\n背景色の設定と、pos/size変更時にドラッグ範囲を変更する処理のbind、\nインスタンス変数の設定を行っている</p>\n\n<h3 id=\"内部ウィジェットの追加処理add_inner_widget\">内部ウィジェットの追加処理(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)</h3>\n<p>項目の内部の表示を構築する処理。<br />\nデフォルトではLabelを1個追加している。<br />\n項目の表示内容を変更したい場合は、派生クラスでこの処理をオーバライドし、\n必要な内容を追加していく。</p>\n\n<h3 id=\"ドラッグ開始処理on_touch_down\">ドラッグ開始処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_down()</code>)</h3>\n<p>まず、基底クラスのドラッグ開始処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ対象としての処理(インスタンス変数の設定)を行い、<br />\n自身の描画Canvasを親ウィジェット(<code class=\"language-plaintext highlighter-rouge\">self.parent</code>)のcanvasからcanvas.afterに繋ぎかえる。\nこれはドラッグ中の表示が前面に表示されるようにするためである。</p>\n\n<blockquote>\n  <p>[!NOTE]\n通常、add_widget()すると追加されたウィジェットの描画Canvasは親ウィジェットのCanvasに繋がれる。<br />\nこの親ウィジェットのCanvasに繋がれた描画ウィジェットは後から繋がれたものが前面に表示される。<br />\n(縦方向のBoxLayoutの場合下に表示されているウィジェットが前に表示される)<br />\n重ならない表示であれば問題ないが、ドラッグを行うとドラッグ中のウィジェットが背面に表示されることがある。<br />\nそこで、ドラッグ中のウィジェット他のウィジェットより前面に表示するため、CanvasからCanvas.afterに繋ぎかえ、前面に表示されるようにする。<br />\n仕様を読む限り、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index, canvas='after')</code>でadd_widget時にcanvas.afterに接続できるようなのだが、\n実際にはバグ(仕様制限?)により、indexが0のときのみcanvasパラメータが有効になるらしい。<br />\nこれを回避するため、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index)</code>で通常通りウィジェットを追加した後、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">after</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>として描画Canvasを繋ぎかえている。\ncanvas.afterに繋いだ描画Canvasをcanvasに戻す場合は、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">cur_index</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">children</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>    <span class=\"c1\"># canvas.after から canvasへ繋ぎかえるため\n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">remove_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>                 <span class=\"c1\"># 一旦削除して(canvasかcanvas.afterは自動的に判別してくれる) \n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"o\">=</span><span class=\"n\">cur_index</span><span class=\"p\">)</span>   <span class=\"c1\"># 再度同じ場所に挿入\n</span></code></pre></div>  </div>\n  <p>と実行する。  <code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>は描画Canvasがどこに繋がっていても探して削除してくれるので、\nそのまま実行して問題ない。</p>\n</blockquote>\n\n<h3 id=\"ドラッグ中処理on_touch_move\">ドラッグ中処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_move()</code>)</h3>\n<p>まず、基底クラスのドラッグ中処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ中の処理を行う。<br />\n親ウィジェットに繋がっている子ウィジェットをサーチして、自分以外で自分の中心がウィジェットの表示範囲内に入っているウィジェットを探す\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>)<br />\n自分の上端が対象ウィジェットの上端を超えたか、自分の下端が対象ウィジェットの下端を超えた場合は自分と対象ウィジェットを入れ替える。<br />\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>だけで判断すると、自分より高さが高いウィジェットと入れ替えるときに不都合が起こる)<br />\n位置を交換するには、自分を一旦削除(<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>)して、対象ウィジェットの位置(<code class=\"language-plaintext highlighter-rouge\">i</code>)に繋ぐ(<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>)。<br />\nその後、ドラッグを継続するので、ドラッグ開始時と同様に描画Canvasをcanvas.afterに繋ぎかえる。</p>\n\n<h3 id=\"ドラッグ終了処理on_touch_up\">ドラッグ終了処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_up()</code>)</h3>\n\n<p>まず、基底クラスのドラッグ終了処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ終了の処理を行う。<br />\nドラッグ開始/ドラッグ中処理でcanvas.afterに繋ぎかえた描画Canvasをcanvasに戻すために一旦<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>してから\n<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>する(これによりドラッグにより表示が移動していた対象ウィジェットが通常位置に戻る)。<br />\nその後、対象ウィジェットの表示位置がドラッグ開始時と変わっていなく、ドラッグした距離が設定値を超えている場合は\nスワイプ処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>または<code class=\"language-plaintext highlighter-rouge\">do_swipe_left()</code>)を実行する。</p>\n\n<h3 id=\"右へswipeしたときの処理do_swipe_right\">右へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、対象ウィジェットを削除する。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"左へswipeしたときの処理do_swipe_right\">左へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、デバッグ用にログ出力のみ。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"親ウィジェットのレイアウト完了時処理done_parent_layout\">親ウィジェットのレイアウト完了時処理(<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>)</h3>\n<p>親ウィジェットのレイアウト完了時に子ウィジェットすべてのこのメソッドがコールされる。<br />\nドラッグ中であれば必要な処理(現在位置の記憶とドラッグ中位置への移動)を行う。</p>\n\n<h1 id=\"サンプルプルグラム\">サンプルプルグラム</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nサンプルプルグラム</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=test1.py\"></script>\n</dev>\n\n\n      </section>\n    </div>\n    <footer>\n      <p class=\"right\">\n  <a href=\"/memoBlog/misc/debug\">debug</a>   \n  <a href=\"/memoBlog/misc/sample\">sample</a>\n</p>\n<p class=\"copyright\">いっぺーちゃんのメモブログ maintained by <a href=\"https://github.com/ippei8jp/memoBlog\">ippei8jp/memoBlog</a></p>\n<p class=\"cl\"></p>\n\n    </footer>\n  </body>\n</html>\n",
  "content": "<h1 id=\"概要\">概要</h1>\n<p>Pythonのマルチプラットフォーム向けGUIライブラリ<a href=\"https://kivy.org/#home\" target=\"_blank\">kivy</a>で\nドラッグで並べ替えできるリスト(AndroidでよくあるUI、<code class=\"language-plaintext highlighter-rouge\">RecycleView</code>と<code class=\"language-plaintext highlighter-rouge\">ItemTouchHelper</code>で作るんだったかな?)\nを作ってみた時のメモ。<br />\n<a href=\"https://maausa.marurm.com/wp-content/uploads/RecyclerView.gif\" target=\"_blank\">ちょっと違うけど、大体こんな感じ</a></p>\n\n<h1 id=\"ソース\">ソース</h1>\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nreorderablelist.py</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=reorderablelist.py\"></script>\n</dev>\n\n<h1 id=\"解説\">解説</h1>\n<p>ソースは、表示する項目を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>と\nリスト全体を制御するクラス<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>で構成される。<br />\n(あと、単体実行で動作するテストプログラム)<br />\n動作としては、</p>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>に<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を追加していきリスト化</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code> をドラッグすることで並べ替え</li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を左右にスワイプすることでハンドラ実行(デフォルトでは右スワイプで項目削除)\nといった感じ。</li>\n</ul>\n\n<p>テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>を<code class=\"language-plaintext highlighter-rouge\">ScrollView</code>で囲んでスクロール可能にしています。\nスクロール不要ならそのまま配置しても可(テストプログラムでは<code class=\"language-plaintext highlighter-rouge\">with_scroll</code>を<code class=\"language-plaintext highlighter-rouge\">False</code>に設定)。</p>\n\n<h2 id=\"reorderablelist\">ReorderableList</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>はリスト全体を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承したクラス。</p>\n\n<h3 id=\"追加したプロパティ\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>item_bg</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>item_fg</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>list_bg</td>\n      <td>リストの背景色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\n(<code class=\"language-plaintext highlighter-rouge\">orientation</code>は<code class=\"language-plaintext highlighter-rouge\">\"vertical\"</code>固定(項目を縦方向に並べるため)、\n<code class=\"language-plaintext highlighter-rouge\">size_hint_y</code>は<code class=\"language-plaintext highlighter-rouge\">None</code>固定(ScrollViewに包むため))\nのほか、<br />\n背景色の設定と、スクロール可能にするためminimum_height変更時の処理のbindを行っている。</p>\n\n<h3 id=\"項目追加処理\">項目追加処理</h3>\n<p><code class=\"language-plaintext highlighter-rouge\">add_item</code>が項目追加処理。<br />\nパラメータは<code class=\"language-plaintext highlighter-rouge\">cls</code>で項目表示に使用するクラス(デフォルトは<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>)と、項目表示クラスの初期化パラメータを受け取る。<br />\nこれは項目に表示する内容を柔軟に切り替えられるよう、項目表示クラスを<code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>を継承したクラスに切り替えられるようにするため。</p>\n\n<h3 id=\"レイアウト処理\">レイアウト処理</h3>\n<p>kivyでは、レイアウトの変更命令と実際に変更が行われるまでにディレイがある。<br />\n具体的には、<code class=\"language-plaintext highlighter-rouge\">add_widget(wid)</code> して直後にwid.posを読み出すと実際に追加されたあとの位置が読み出せない。<br />\nこれは、<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>では処理の予約だけ行い、実際に描画が行われるのは別のところ(<code class=\"language-plaintext highlighter-rouge\">mainloop</code>?)で\n他のウィジェットのレイアウト結果を五月雨式に反映していくため、\n描画結果がposに反映されるまでタイムラグが発生するためと思われる。</p>\n\n<p>そこで、<code class=\"language-plaintext highlighter-rouge\">ReorderableList</code>のレイアウトが変更され、処理が終了したタイミングで子ウィジェットに\nレイアウト完了を通知できるよう<code class=\"language-plaintext highlighter-rouge\">do_layout()</code>をオーバライドし、基底クラスの処理が完了した後\n各子ウィジェットの<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>をコールしている。</p>\n\n<h2 id=\"reorderableitem\">ReorderableItem</h2>\n<p><code class=\"language-plaintext highlighter-rouge\">ReorderableItem</code>はリストに表示する項目を制御するクラスで、\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスと<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>を継承している。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>クラスはドラッグ処理を実現するクラス。<br />\nもう一つの基底クラスを<code class=\"language-plaintext highlighter-rouge\">BoxLayout</code>とすることで、派生クラスのレイアウトを柔軟に設定できるようにしている。</p>\n\n<h3 id=\"追加したプロパティ-1\">追加したプロパティ</h3>\n<p>追加したプロパティは以下。</p>\n\n<table>\n  <tbody>\n    <tr>\n      <td>名称</td>\n      <td>内容</td>\n    </tr>\n    <tr>\n      <td>text</td>\n      <td>項目に表示する文字列</td>\n    </tr>\n    <tr>\n      <td>bg_color</td>\n      <td>項目の背景色</td>\n    </tr>\n    <tr>\n      <td>fg_color</td>\n      <td>項目の文字色</td>\n    </tr>\n    <tr>\n      <td>swipe_distance</td>\n      <td>Swipe検出距離</td>\n    </tr>\n  </tbody>\n</table>\n\n<h3 id=\"コンストラクタ-1\">コンストラクタ</h3>\n<p>コンストラクタでは、基底クラスの初期化\nのほか、<br />\n項目内部の構築(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)、\n背景色の設定と、pos/size変更時にドラッグ範囲を変更する処理のbind、\nインスタンス変数の設定を行っている</p>\n\n<h3 id=\"内部ウィジェットの追加処理add_inner_widget\">内部ウィジェットの追加処理(<code class=\"language-plaintext highlighter-rouge\">add_inner_widget()</code>)</h3>\n<p>項目の内部の表示を構築する処理。<br />\nデフォルトではLabelを1個追加している。<br />\n項目の表示内容を変更したい場合は、派生クラスでこの処理をオーバライドし、\n必要な内容を追加していく。</p>\n\n<h3 id=\"ドラッグ開始処理on_touch_down\">ドラッグ開始処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_down()</code>)</h3>\n<p>まず、基底クラスのドラッグ開始処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ対象としての処理(インスタンス変数の設定)を行い、<br />\n自身の描画Canvasを親ウィジェット(<code class=\"language-plaintext highlighter-rouge\">self.parent</code>)のcanvasからcanvas.afterに繋ぎかえる。\nこれはドラッグ中の表示が前面に表示されるようにするためである。</p>\n\n<blockquote>\n  <p>[!NOTE]\n通常、add_widget()すると追加されたウィジェットの描画Canvasは親ウィジェットのCanvasに繋がれる。<br />\nこの親ウィジェットのCanvasに繋がれた描画ウィジェットは後から繋がれたものが前面に表示される。<br />\n(縦方向のBoxLayoutの場合下に表示されているウィジェットが前に表示される)<br />\n重ならない表示であれば問題ないが、ドラッグを行うとドラッグ中のウィジェットが背面に表示されることがある。<br />\nそこで、ドラッグ中のウィジェット他のウィジェットより前面に表示するため、CanvasからCanvas.afterに繋ぎかえ、前面に表示されるようにする。<br />\n仕様を読む限り、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index, canvas='after')</code>でadd_widget時にcanvas.afterに接続できるようなのだが、\n実際にはバグ(仕様制限?)により、indexが0のときのみcanvasパラメータが有効になるらしい。<br />\nこれを回避するため、<code class=\"language-plaintext highlighter-rouge\">parent.add_widget(child, index=index)</code>で通常通りウィジェットを追加した後、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">.</span><span class=\"n\">after</span><span class=\"p\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">.</span><span class=\"n\">canvas</span><span class=\"p\">)</span>\n</code></pre></div>  </div>\n  <p>として描画Canvasを繋ぎかえている。\ncanvas.afterに繋いだ描画Canvasをcanvasに戻す場合は、</p>\n  <div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>    <span class=\"n\">cur_index</span> <span class=\"o\">=</span> <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">children</span><span class=\"p\">.</span><span class=\"n\">index</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>    <span class=\"c1\"># canvas.after から canvasへ繋ぎかえるため\n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">remove_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">)</span>                 <span class=\"c1\"># 一旦削除して(canvasかcanvas.afterは自動的に判別してくれる) \n</span>    <span class=\"n\">parent</span><span class=\"p\">.</span><span class=\"n\">add_widget</span><span class=\"p\">(</span><span class=\"n\">child</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"o\">=</span><span class=\"n\">cur_index</span><span class=\"p\">)</span>   <span class=\"c1\"># 再度同じ場所に挿入\n</span></code></pre></div>  </div>\n  <p>と実行する。  <code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>は描画Canvasがどこに繋がっていても探して削除してくれるので、\nそのまま実行して問題ない。</p>\n</blockquote>\n\n<h3 id=\"ドラッグ中処理on_touch_move\">ドラッグ中処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_move()</code>)</h3>\n<p>まず、基底クラスのドラッグ中処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ中の処理を行う。<br />\n親ウィジェットに繋がっている子ウィジェットをサーチして、自分以外で自分の中心がウィジェットの表示範囲内に入っているウィジェットを探す\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>)<br />\n自分の上端が対象ウィジェットの上端を超えたか、自分の下端が対象ウィジェットの下端を超えた場合は自分と対象ウィジェットを入れ替える。<br />\n(<code class=\"language-plaintext highlighter-rouge\">child.collide_point(*self.center)</code>だけで判断すると、自分より高さが高いウィジェットと入れ替えるときに不都合が起こる)<br />\n位置を交換するには、自分を一旦削除(<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>)して、対象ウィジェットの位置(<code class=\"language-plaintext highlighter-rouge\">i</code>)に繋ぐ(<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>)。<br />\nその後、ドラッグを継続するので、ドラッグ開始時と同様に描画Canvasをcanvas.afterに繋ぎかえる。</p>\n\n<h3 id=\"ドラッグ終了処理on_touch_up\">ドラッグ終了処理(<code class=\"language-plaintext highlighter-rouge\">on_touch_up()</code>)</h3>\n\n<p>まず、基底クラスのドラッグ終了処理を実行する。<br />\n<code class=\"language-plaintext highlighter-rouge\">DragBehavior</code>を継承したクラスの場合、自身がドラッグ対象であればここで<code class=\"language-plaintext highlighter-rouge\">True</code>が返ってくるので\nドラッグ終了の処理を行う。<br />\nドラッグ開始/ドラッグ中処理でcanvas.afterに繋ぎかえた描画Canvasをcanvasに戻すために一旦<code class=\"language-plaintext highlighter-rouge\">remove_widget()</code>してから\n<code class=\"language-plaintext highlighter-rouge\">add_widget()</code>する(これによりドラッグにより表示が移動していた対象ウィジェットが通常位置に戻る)。<br />\nその後、対象ウィジェットの表示位置がドラッグ開始時と変わっていなく、ドラッグした距離が設定値を超えている場合は\nスワイプ処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>または<code class=\"language-plaintext highlighter-rouge\">do_swipe_left()</code>)を実行する。</p>\n\n<h3 id=\"右へswipeしたときの処理do_swipe_right\">右へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、対象ウィジェットを削除する。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"左へswipeしたときの処理do_swipe_right\">左へswipeしたときの処理(<code class=\"language-plaintext highlighter-rouge\">do_swipe_right()</code>)</h3>\n<p>現状、デバッグ用にログ出力のみ。<br />\n処理を変更する場合は派生クラスでオーバライドする。</p>\n\n<h3 id=\"親ウィジェットのレイアウト完了時処理done_parent_layout\">親ウィジェットのレイアウト完了時処理(<code class=\"language-plaintext highlighter-rouge\">done_parent_layout()</code>)</h3>\n<p>親ウィジェットのレイアウト完了時に子ウィジェットすべてのこのメソッドがコールされる。<br />\nドラッグ中であれば必要な処理(現在位置の記憶とドラッグ中位置への移動)を行う。</p>\n\n<h1 id=\"サンプルプルグラム\">サンプルプルグラム</h1>\n\n<p>ソースは↓の「開く」をクリックすると表示されます。<br />\nダウンロードしたいときは\n<a href=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da\" target=\"_blank\">こちら</a>\nからどうぞ。<br />\nサンプルプルグラム</p>\n<dev class=\"accordion_head_close\"></dev>\n<dev class=\"my-gist\">\n  <script src=\"https://gist.github.com/ippei8jp/c113bc3ee167d79c53555be3e48062da.js?file=test1.py\"></script>\n</dev>\n\n",
  "url": "/2025/05/19/kivy_5.html",
  "draft": false,
  "categories": [

  ],
  "title": "kivyでドラッグで並べ替えできるリスト",
  "date": "2025-05-19 00:00:00 +0000",
  "tags": [
    "kivy",
    "python"
  ],
  "layout": "default",
  "slug": "kivy_5",
  "ext": ".md"
}